Skip to content

Commit aede612

Browse files
Use isComputed when available (#966)
* Attempt to use isComputed * Fix some failures * Point ember-table back at Addepar * Use correct path to isComputed * Pass object and key into isComputed and inspectValue * Get value from object * Update to ember canary * Point to commit for ember-table * Use object[key] rather than get(object, key) * Allow passing already computedValue * Fix error with removing listener * Add hacks to check for computed * Fix remaining failures * Set back to stable Ember version, disallow beta failures * Allow beta failures again * Fix lint * Run normal tests before ember-try
1 parent 2237dc1 commit aede612

File tree

11 files changed

+533
-589
lines changed

11 files changed

+533
-589
lines changed

.travis.yml

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ jobs:
2424
- env: EMBER_TRY_SCENARIO=ember-canary
2525

2626
include:
27+
# runs tests with current locked deps and linting
28+
- stage: test
29+
script:
30+
- yarn lint:hbs
31+
- yarn lint:js
32+
- yarn test
33+
2734
# runs tests for ember_debug against each supported Ember version
2835
- stage: ember debug test
2936
env: EMBER_TRY_SCENARIO=ember-2.7
@@ -34,18 +41,12 @@ jobs:
3441
- env: EMBER_TRY_SCENARIO=ember-lts-2.12
3542
- env: EMBER_TRY_SCENARIO=ember-lts-2.16
3643
- env: EMBER_TRY_SCENARIO=ember-lts-2.18
44+
- env: EMBER_TRY_SCENARIO=ember-lts-3.4
3745
- env: EMBER_TRY_SCENARIO=ember-release
3846
- env: EMBER_TRY_SCENARIO=ember-beta
3947
- env: EMBER_TRY_SCENARIO=ember-canary
4048
- env: EMBER_TRY_SCENARIO=ember-default
4149

42-
# runs tests with current locked deps and linting
43-
- stage: test
44-
script:
45-
- yarn lint:hbs
46-
- yarn lint:js
47-
- yarn test
48-
4950
before_install:
5051
- curl -o- -L https://yarnpkg.com/install.sh | bash
5152
- export PATH=$HOME/.yarn/bin:$PATH

app/routes/model-types.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default TabRoute.extend({
1212
model() {
1313
const port = this.get('port');
1414
return new Promise(function(resolve) {
15-
port.one('data:modelTypesAdded', this, function(message) {
15+
port.one('data:modelTypesAdded', function(message) {
1616
resolve(message.modelTypes);
1717
});
1818
port.send('data:getModelTypes');

ember_debug/libs/promise-assembler.js

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
/**
2-
Original implementation and the idea behind the `PromiseAssembler`,
3-
`Promise` model, and other work related to promise inspection was done
4-
by Stefan Penner (@stefanpenner) thanks to McGraw Hill Education (@mhelabs)
5-
and Yapp Labs (@yapplabs).
2+
Original implementation and the idea behind the `PromiseAssembler`,
3+
`Promise` model, and other work related to promise inspection was done
4+
by Stefan Penner (@stefanpenner) thanks to McGraw Hill Education (@mhelabs)
5+
and Yapp Labs (@yapplabs).
66
*/
77

88
import Promise from 'ember-debug/models/promise';
9+
910
const Ember = window.Ember;
1011
const { Object: EmberObject, Evented, A, computed, RSVP, isNone } = Ember;
1112

1213
let PromiseAssembler = EmberObject.extend(Evented, {
1314
// RSVP lib to debug
1415
RSVP,
1516

17+
isStarted: false,
18+
1619
all: computed(function() { return A(); }),
1720

1821
promiseIndex: computed(function() { return {}; }),
@@ -40,25 +43,30 @@ let PromiseAssembler = EmberObject.extend(Evented, {
4043
this.RSVP.on('rejected', this.promiseRejected);
4144
this.RSVP.on('fulfilled', this.promiseFulfilled);
4245
this.RSVP.on('created', this.promiseCreated);
46+
47+
this.isStarted = true;
4348
},
4449

4550
stop() {
46-
this.RSVP.configure('instrument', false);
47-
this.RSVP.off('chained', this.promiseChained);
48-
this.RSVP.off('rejected', this.promiseRejected);
49-
this.RSVP.off('fulfilled', this.promiseFulfilled);
50-
this.RSVP.off('created', this.promiseCreated);
51-
52-
this.get('all').forEach(item => {
53-
item.destroy();
54-
});
55-
this.set('all', A());
56-
this.set('promiseIndex', {});
57-
58-
this.promiseChained = null;
59-
this.promiseRejected = null;
60-
this.promiseFulfilled = null;
61-
this.promiseCreated = null;
51+
if (this.isStarted) {
52+
this.RSVP.configure('instrument', false);
53+
this.RSVP.off('chained', this.promiseChained);
54+
this.RSVP.off('rejected', this.promiseRejected);
55+
this.RSVP.off('fulfilled', this.promiseFulfilled);
56+
this.RSVP.off('created', this.promiseCreated);
57+
58+
this.get('all').forEach(item => {
59+
item.destroy();
60+
});
61+
this.set('all', A());
62+
this.set('promiseIndex', {});
63+
64+
this.promiseChained = null;
65+
this.promiseRejected = null;
66+
this.promiseFulfilled = null;
67+
this.promiseCreated = null;
68+
this.isStarted = false;
69+
}
6270
},
6371

6472
willDestroy() {

ember_debug/object-inspector.js

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,36 @@
11
import PortMixin from 'ember-debug/mixins/port-mixin';
22
import { compareVersion } from 'ember-debug/utils/version';
3+
import { isComputed, isDescriptor, getDescriptorFor } from 'ember-debug/utils/type-check';
34

45
const Ember = window.Ember;
56
const {
67
Object: EmberObject, inspect: emberInspect, meta: emberMeta, typeOf,
7-
computed, get, set, ComputedProperty, guidFor, isNone, removeObserver,
8+
computed, get, set, guidFor, isNone, removeObserver,
89
Mixin, addObserver, cacheFor, VERSION
910
} = Ember;
1011
const { oneWay } = computed;
1112

1213
const keys = Object.keys || Ember.keys;
1314

14-
function inspectValue(value) {
15+
/**
16+
* Determine the type and get the value of the passed property
17+
* @param {*} object The parent object we will look for `key` on
18+
* @param {string} key The key for the property which points to a computed, EmberObject, etc
19+
* @param {*} computedValue A value that has already been computed with calculateCP
20+
* @return {{inspect: (string|*), type: string}|{computed: boolean, inspect: string, type: string}|{inspect: string, type: string}}
21+
*/
22+
function inspectValue(object, key, computedValue) {
1523
let string;
24+
const value = computedValue ? computedValue : object[key];
25+
26+
// TODO: this is not very clean. We should refactor calculateCP, etc, rather than passing computedValue
27+
if (computedValue) {
28+
return { type: `type-${typeOf(value)}`, inspect: inspect(value) };
29+
}
30+
1631
if (value instanceof EmberObject) {
1732
return { type: 'type-ember-object', inspect: value.toString() };
18-
} else if (isComputed(value)) {
33+
} else if (isComputed(object, key)) {
1934
string = '<computed>';
2035
return { type: 'type-descriptor', inspect: string, computed: true };
2136
} else if (isDescriptor(value)) {
@@ -25,11 +40,6 @@ function inspectValue(value) {
2540
}
2641
}
2742

28-
function isDescriptor(value) {
29-
// Ember >= 1.11
30-
return value && typeof value === 'object' && value.isDescriptor;
31-
}
32-
3343
function inspect(value) {
3444
if (typeof value === 'function') {
3545
return 'function() { ... }';
@@ -360,7 +370,7 @@ export default EmberObject.extend(PortMixin, {
360370
if (!name && typeof mixin.toString === 'function') {
361371
try {
362372
name = mixin.toString();
363-
} catch (e) {
373+
} catch(e) {
364374
name = '(Unable to convert Object to string)';
365375
}
366376
}
@@ -407,7 +417,7 @@ export default EmberObject.extend(PortMixin, {
407417
}
408418

409419
if (!value || !(value instanceof CalculateCPError)) {
410-
value = inspectValue(value);
420+
value = inspectValue(object, property, value);
411421
value.computed = true;
412422

413423

@@ -424,7 +434,7 @@ export default EmberObject.extend(PortMixin, {
424434

425435
let handler = () => {
426436
let value = get(object, property);
427-
value = inspectValue(value);
437+
value = inspectValue(object, property, value);
428438
value.computed = computed;
429439

430440
this.sendMessage('updateProperty', { objectId, property, value, mixinIndex });
@@ -501,8 +511,8 @@ function addProperties(properties, hash) {
501511
}
502512
}
503513

504-
if (isComputed(hash[prop])) {
505-
options.dependentKeys = (hash[prop]._dependentKeys || []).map((key) => key.toString());
514+
if (isComputed(hash, prop)) {
515+
options.dependentKeys = (getDescriptorFor(hash, prop)._dependentKeys || []).map((key) => key.toString());
506516
if (!options.isService) {
507517
if (typeof hash[prop]._getter === 'function') {
508518
options.code = Function.prototype.toString.call(hash[prop]._getter);
@@ -512,7 +522,7 @@ function addProperties(properties, hash) {
512522
}
513523
options.readOnly = hash[prop]._readOnly;
514524
}
515-
replaceProperty(properties, prop, hash[prop], options);
525+
replaceProperty(properties, prop, inspectValue(hash, prop), options);
516526
}
517527
}
518528

@@ -531,7 +541,7 @@ function replaceProperty(properties, name, value, options) {
531541
properties.splice(i, 1);
532542
}
533543

534-
let prop = { name, value: inspectValue(value) };
544+
let prop = { name, value };
535545
prop.isMandatorySetter = options.isMandatorySetter;
536546
prop.readOnly = options.readOnly;
537547
prop.dependentKeys = options.dependentKeys || [];
@@ -611,7 +621,7 @@ function calculateCPs(object, mixinDetails, errorsForObject, expensiveProperties
611621
if (cache !== undefined || expensiveProperties.indexOf(item.name) === -1) {
612622
let value = calculateCP(object, item.name, errorsForObject);
613623
if (!value || !(value instanceof CalculateCPError)) {
614-
item.value = inspectValue(value);
624+
item.value = inspectValue(object, item.name, value);
615625
item.value.computed = true;
616626
}
617627
}
@@ -778,7 +788,6 @@ function getDebugInfo(object) {
778788

779789
let meta = Ember.meta(object);
780790
for (let prop in object) {
781-
782791
// when in Ember 3.1
783792
if (compareVersion(VERSION, '3.1.0') !== -1) {
784793
// in Ember 3.1+ CP's are eagerly invoked via a normal
@@ -798,9 +807,7 @@ function getDebugInfo(object) {
798807
return debugInfo;
799808
}
800809

801-
function isComputed(value) {
802-
return value instanceof ComputedProperty;
803-
}
810+
804811

805812
function toArray(errors) {
806813
return keys(errors).map(key => errors[key]);
@@ -810,7 +817,7 @@ function calculateCP(object, property, errorsForObject) {
810817
delete errorsForObject[property];
811818
try {
812819
return get(object, property);
813-
} catch (error) {
820+
} catch(error) {
814821
errorsForObject[property] = { property, error };
815822
return new CalculateCPError();
816823
}

ember_debug/promise-debug.js

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,10 @@ export default EmberObject.extend(PortMixin, {
113113
this.get('promiseAssembler').on('chained', this, this.promiseChained);
114114

115115
this.get('releaseMethods').pushObject(() => {
116-
117116
this.get('promiseAssembler').off('created', this, this.promiseUpdated);
118117
this.get('promiseAssembler').off('fulfilled', this, this.promiseUpdated);
119118
this.get('promiseAssembler').off('rejected', this, this.promiseUpdated);
120-
this.get('promiseAssembler').off('fulfilled', this, this.promiseChained);
121-
119+
this.get('promiseAssembler').off('chained', this, this.promiseChained);
122120
});
123121

124122
this.promisesUpdated(this.get('promiseAssembler').find());
@@ -166,8 +164,8 @@ export default EmberObject.extend(PortMixin, {
166164
serialized.children = this.promiseIds(promise.get('children'));
167165
}
168166
serialized.parent = promise.get('parent.guid');
169-
serialized.value = this.inspectValue(promise.get('value'));
170-
serialized.reason = this.inspectValue(promise.get('reason'));
167+
serialized.value = this.inspectValue(promise, 'value');
168+
serialized.reason = this.inspectValue(promise, 'reason');
171169
if (promise.get('createdAt')) {
172170
serialized.createdAt = promise.get('createdAt').getTime();
173171
}
@@ -182,12 +180,18 @@ export default EmberObject.extend(PortMixin, {
182180
return promises.map(promise => promise.get('guid'));
183181
},
184182

185-
inspectValue(value) {
183+
/**
184+
* Inspect the promise and pass to object inspector
185+
* @param {Promise} promise The promise object
186+
* @param {string} key The key for the property on the promise
187+
* @return {*|{inspect: (string|*), type: string}|{computed: boolean, inspect: string, type: string}|{inspect: string, type: string}}
188+
*/
189+
inspectValue(promise, key) {
186190
let objectInspector = this.get('objectInspector');
187-
let inspected = objectInspector.inspectValue(value);
191+
let inspected = objectInspector.inspectValue(promise, key);
188192

189193
if (inspected.type === 'type-ember-object' || inspected.type === "type-array") {
190-
inspected.objectId = objectInspector.retainObject(value);
194+
inspected.objectId = objectInspector.retainObject(promise.get(key));
191195
this.get('releaseMethods').pushObject(function() {
192196
objectInspector.releaseObject(inspected.objectId);
193197
});

ember_debug/utils/type-check.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
const Ember = window.Ember;
2+
const { ComputedProperty } = Ember;
3+
4+
/**
5+
* Check if given key on the passed object is a computed property
6+
* @param object
7+
* @param key
8+
* @return {boolean|*}
9+
*/
10+
export function isComputed(object, key) {
11+
// Ember > 3.10
12+
if (Ember.Debug.isComputed) {
13+
return Ember.Debug.isComputed(object, key) || getDescriptorFor(object, key);
14+
}
15+
16+
// Ember < 3.10
17+
return object[key] instanceof ComputedProperty;
18+
}
19+
20+
export function isDescriptor(value) {
21+
// Ember >= 1.11
22+
return value && typeof value === 'object' && value.isDescriptor;
23+
}
24+
25+
/**
26+
* This allows us to pass in a COMPUTED_DECORATOR function and get the descriptor for it.
27+
* It should be implemented Ember side eventually.
28+
* @param {EmberObject} object The object we are inspecting
29+
* @param {String} key The key for the property on the object
30+
*/
31+
export function getDescriptorFor(object, key) {
32+
if (Ember.Debug.isComputed) {
33+
return Ember.__loader.require('@ember/-internals/metal').descriptorForDecorator(object[key]);
34+
}
35+
36+
return object[key];
37+
}

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@
4646
"broccoli-stew": "^2.1.0",
4747
"broccoli-string-replace": "^0.1.1",
4848
"compare-versions": "^3.4.0",
49-
"del": "4.1.0",
50-
"ember-cli": "~3.10.0-beta.1",
49+
"del": "^4.1.1",
50+
"ember-cli": "^3.9.0",
5151
"ember-cli-app-version": "^3.2.0",
5252
"ember-cli-babel": "^7.7.3",
5353
"ember-cli-dependency-checker": "^3.1.0",
@@ -73,23 +73,23 @@
7373
"ember-maybe-import-regenerator": "^0.1.6",
7474
"ember-qunit": "^4.4.1",
7575
"ember-resolver": "^5.0.1",
76-
"ember-source": "~3.9.1",
76+
"ember-source": "^3.9.1",
7777
"ember-source-channel-url": "^1.1.0",
7878
"ember-svg-jar": "^1.2.2",
79-
"ember-table": "Addepar/ember-table#master",
79+
"ember-table": "Addepar/ember-table#a1d5122a902efe176d9740f04dc26a06247792b9",
8080
"ember-test-selectors": "^2.1.0",
8181
"ember-truth-helpers": "^2.1.0",
8282
"ember-try": "^1.1.0",
8383
"eslint-plugin-ember": "^6.3.0",
8484
"fstream": "^1.0.8",
85-
"gulp": "4.0.1",
86-
"gulp-zip": "4.2.0",
85+
"gulp": "^4.0.2",
86+
"gulp-zip": "^4.2.0",
8787
"js-string-escape": "^1.0.0",
8888
"loader.js": "^4.7.0",
8989
"mkdirp": "^0.5.1",
9090
"qunit-dom": "^0.8.4",
9191
"rimraf": "^2.5.2",
92-
"sass": "^1.19.0",
92+
"sass": "^1.20.1",
9393
"stylelint": "^10.0.1",
9494
"stylelint-config-ship-shape": "^0.5.2",
9595
"yauzl": "^2.10.0"

0 commit comments

Comments
 (0)