From 05e95280e11c411177f2fbcb65fd83488d6a9d89 Mon Sep 17 00:00:00 2001 From: Chris Thoburn Date: Wed, 26 Apr 2017 13:05:36 -0700 Subject: [PATCH] [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"