Skip to content

Commit 6a250ba

Browse files
patricklxRobbieTheWagner
authored andcommitted
set the names of known mixins (#1055)
remove properties set by mixins unless different value caused them to hide the class with only merged mixins from Object.extend(mix1, mix2)
1 parent dc462f0 commit 6a250ba

2 files changed

Lines changed: 140 additions & 38 deletions

File tree

ember_debug/object-inspector.js

Lines changed: 82 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ let HAS_GLIMMER_TRACKING = false;
1717
try {
1818
glimmer = Ember.__loader.require('@glimmer/reference');
1919
metal = Ember.__loader.require('@ember/-internals/metal');
20-
HAS_GLIMMER_TRACKING = glimmer &&
21-
glimmer.value &&
22-
glimmer.validate &&
23-
metal &&
24-
metal.track &&
20+
HAS_GLIMMER_TRACKING = glimmer &&
21+
glimmer.value &&
22+
glimmer.validate &&
23+
metal &&
24+
metal.track &&
2525
metal.tagForProperty;
2626
} catch (e) {
2727
glimmer = null;
@@ -30,6 +30,39 @@ try {
3030

3131
const keys = Object.keys || Ember.keys;
3232

33+
/**
34+
* Add Known Ember Mixins and Classes so we can label them correctly in the inspector
35+
*/
36+
const emberNames = new Map([
37+
[Ember.Evented, 'Evented Mixin'],
38+
[Ember.PromiseProxyMixin, 'PromiseProxy Mixin'],
39+
[Ember.MutableArray, 'MutableArray Mixin'],
40+
[Ember.MutableEnumerable, 'MutableEnumerable Mixin'],
41+
[Ember.NativeArray, 'NativeArray Mixin'],
42+
[Ember.Observable, 'Observable Mixin'],
43+
[Ember.ControllerMixin, 'Controller Mixin'],
44+
[Ember.TargetActionSupport, 'TargetActionSupport Mixin'],
45+
[Ember.ActionHandler, 'ActionHandler Mixin'],
46+
[Ember.CoreObject, 'CoreObject'],
47+
[Ember.Object, 'EmberObject'],
48+
[Ember.Component, 'Component'],
49+
]);
50+
51+
try {
52+
const Views = Ember.__loader.require('@ember/-internals/views');
53+
emberNames.set(Views.ViewStateSupport, 'ViewStateSupport Mixin');
54+
emberNames.set(Views.ViewMixin, 'View Mixin');
55+
emberNames.set(Views.ActionSupport, 'ActionSupport Mixin');
56+
emberNames.set(Views.ClassNamesSupport, 'ClassNamesSupport Mixin');
57+
emberNames.set(Views.ChildViewsSupport, 'ChildViewsSupport Mixin');
58+
emberNames.set(Views.ViewStateSupport , 'ViewStateSupport Mixin');
59+
// this one is not a Mixin, but an .extend({}), which results in a class
60+
emberNames.set(Views.CoreView, 'CoreView');
61+
} catch (e) {
62+
// do nothing
63+
}
64+
65+
3366
/**
3467
* Determine the type and get the value of the passed property
3568
* @param {*} object The parent object we will look for `key` on
@@ -132,7 +165,7 @@ function isMandatorySetter(descriptor) {
132165
return false;
133166
}
134167

135-
function getTagTrackedProps(tag, ownTag, level=0) {
168+
function getTagTrackedProps(tag, ownTag, level = 0) {
136169
const props = [];
137170
// do not include tracked properties from dependencies
138171
if (!tag || level > 1) {
@@ -179,7 +212,7 @@ export default EmberObject.extend(PortMixin, {
179212

180213
updateCurrentObject() {
181214
if (this.currentObject) {
182-
const {object, mixinDetails, objectId} = this.currentObject;
215+
const { object, mixinDetails, objectId } = this.currentObject;
183216
mixinDetails.forEach((mixin, mixinIndex) => {
184217
mixin.properties.forEach(item => {
185218
if (item.overridden) {
@@ -193,7 +226,7 @@ export default EmberObject.extend(PortMixin, {
193226
let value = null;
194227
let changed = false;
195228
const values = this.objectPropertyValues[objectId] = this.objectPropertyValues[objectId] || {};
196-
const tracked = this.trackedTags[objectId] = this.trackedTags[objectId] || {};
229+
const tracked = this.trackedTags[objectId] = this.trackedTags[objectId] || {};
197230

198231
const desc = Object.getOwnPropertyDescriptor(object, item.name);
199232
const isSetter = desc && isMandatorySetter(desc);
@@ -525,26 +558,28 @@ export default EmberObject.extend(PortMixin, {
525558
mixinDetailsForObject(object) {
526559
const mixins = [];
527560

528-
const mixin = {
561+
const own = ownMixins(object);
562+
563+
const objectMixin = {
529564
id: guidFor(object),
530565
name: getClassName(object),
531-
properties: ownProperties(object)
566+
properties: ownProperties(object, own)
532567
};
533568

534-
mixins.push(mixin);
569+
mixins.push(objectMixin);
535570

536571
// insert ember mixins
537-
for (let mixin of ownMixins(object)) {
538-
let name = (mixin[Ember.NAME_KEY] || mixin.ownerConstructor || '').toString();
572+
for (let mixin of own) {
573+
let name = (mixin[Ember.NAME_KEY] || mixin.ownerConstructor || emberNames.get(mixin) || '').toString();
539574

540-
if (typeof mixin.toString === 'function') {
575+
if (!name && (typeof mixin.toString === 'function')) {
541576
try {
542577
name = mixin.toString();
543578

544579
if (name === '(unknown)') {
545580
name = '(unknown mixin)';
546581
}
547-
} catch(e) {
582+
} catch (e) {
548583
name = '(Unable to convert Object to string)';
549584
}
550585
}
@@ -596,7 +631,7 @@ export default EmberObject.extend(PortMixin, {
596631
let objectId = this.retainObject(object);
597632

598633
let errorsForObject = this.get('_errorsFor')[objectId] = {};
599-
const tracked = this.trackedTags[objectId] = this.trackedTags[objectId] || {};
634+
const tracked = this.trackedTags[objectId] = this.trackedTags[objectId] || {};
600635
calculateCPs(object, mixinDetails, errorsForObject, expensiveProperties, tracked);
601636

602637
this.currentObject = { object, mixinDetails, objectId };
@@ -629,7 +664,7 @@ export default EmberObject.extend(PortMixin, {
629664

630665
function getClassName(object) {
631666
let name = '';
632-
let className = object.constructor.name;
667+
let className = emberNames.get(object.constructor) || object.constructor.name;
633668

634669
if ('toString' in object && object.toString !== Function.prototype.toString) {
635670
name = object.toString();
@@ -677,10 +712,9 @@ function ownMixins(object) {
677712
return mixins;
678713
}
679714

680-
function ownProperties(object) {
715+
function ownProperties(object, ownMixins) {
681716
let meta = Ember.meta(object);
682-
let parentMeta = meta.parent;
683-
717+
684718
if (Array.isArray(object)) {
685719
// slice to max 101, for performance and so that the object inspector will show a `more items` indicator above 100
686720
object = object.slice(0, 101);
@@ -689,13 +723,36 @@ function ownProperties(object) {
689723
let props = Object.getOwnPropertyDescriptors(object);
690724
delete props.constructor;
691725

726+
// meta has the correct descriptors for CPs
692727
meta.forEachDescriptors((name, desc) => {
693-
// TODO: Need to add a way to get own descriptors only from meta
694-
if (!parentMeta || !parentMeta.peekDescriptors(name)) {
728+
// only for own properties
729+
if (props[name]) {
695730
props[name] = desc;
696731
}
697732
});
698733

734+
// remove properties set by mixins
735+
// especially for Object.extend(mixin1, mixin2), where a new class is created which holds the merged properties
736+
// if all properties are removed, it will be marked as useless mixin and will not be shown
737+
ownMixins.forEach((m) => {
738+
if (m.mixins) {
739+
m.mixins.forEach((mix) => {
740+
Object.keys(mix.properties || {}).forEach((k) => {
741+
const pDesc = Object.getOwnPropertyDescriptor(mix.properties, k);
742+
if (pDesc && props[k] && pDesc.get && pDesc.get === props[k].get) {
743+
delete props[k];
744+
}
745+
if (pDesc && props[k] && 'value' in pDesc && pDesc.value === props[k].value) {
746+
delete props[k];
747+
}
748+
if (pDesc && props[k] && pDesc._getter === props[k]._getter) {
749+
delete props[k];
750+
}
751+
})
752+
})
753+
}
754+
});
755+
699756
Object.keys(props).forEach(k => {
700757
if (typeof props[k].value === 'function') {
701758
return;
@@ -910,7 +967,7 @@ function calculateCPs(object, mixinDetails, errorsForObject, expensiveProperties
910967
tagInfo.revision = glimmer.value(object, item.name);
911968
item.dependentKeys = getTrackedDependencies(object, item.name, tagInfo.tag);
912969
} else {
913-
value = calculateCP(object, item.name, errorsForObject);
970+
value = calculateCP(object, item.name, errorsForObject);
914971
}
915972
if (!value || !(value instanceof CalculateCPError)) {
916973
item.value = inspectValue(object, item.name, value);
@@ -1080,13 +1137,13 @@ function calculateCP(object, property, errorsForObject) {
10801137
return object.objectAt(property);
10811138
}
10821139
return get(object, property);
1083-
} catch(error) {
1140+
} catch (error) {
10841141
errorsForObject[property] = { property, error };
10851142
return new CalculateCPError();
10861143
}
10871144
}
10881145

1089-
function CalculateCPError() {}
1146+
function CalculateCPError() { }
10901147

10911148
function errorsToSend(errors) {
10921149
return toArray(errors).map(error => ({ property: error.property }));

tests/ember_debug/object-inspector-test.js

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,21 @@ module('Ember Debug - Object Inspector', function(hooks) {
220220

221221
test('Correct mixin order with es6 class', function (assert) {
222222

223-
// eslint-disable-next-line ember/no-new-mixins
224-
const MyMixin = Mixin.create({
223+
class MyMixinClass extends Mixin {
224+
toString() {
225+
return 'MyMixin';
226+
}
227+
}
228+
const MyMixin = MyMixinClass.create({
225229
a: 'custom',
226230
});
227231

228-
// eslint-disable-next-line ember/no-new-mixins
229-
const MyMixin2 = Mixin.create({
232+
class MyMixin2Class extends Mixin {
233+
toString() {
234+
return 'MyMixin2';
235+
}
236+
}
237+
const MyMixin2 = MyMixin2Class.create({
230238
b: 'custom2',
231239
});
232240

@@ -249,13 +257,12 @@ module('Ember Debug - Object Inspector', function(hooks) {
249257
'Own Properties',
250258
'Foo',
251259
'FooBar',
252-
'(unknown)',
253-
'(unknown mixin)',
254-
'(unknown mixin)',
260+
'MyMixin',
261+
'MyMixin2',
255262
'Bar',
256263
'Baz',
257264
'EmberObject',
258-
'(unknown mixin)',
265+
'Observable Mixin',
259266
'CoreObject'
260267
];
261268

@@ -264,6 +271,47 @@ module('Ember Debug - Object Inspector', function(hooks) {
264271
});
265272
});
266273

274+
test('Correct mixin properties', function (assert) {
275+
276+
// eslint-disable-next-line ember/no-new-mixins
277+
class MyMixin extends Mixin {
278+
toString() {
279+
return 'MyMixin1';
280+
}
281+
}
282+
// eslint-disable-next-line ember/no-new-mixins
283+
class MyMixin2 extends Mixin {
284+
toString() {
285+
return 'MyMixin2';
286+
}
287+
}
288+
289+
const mix1 = MyMixin.create({a: 'custom1'});
290+
const mix2 = MyMixin2.create({b: 'custom2'});
291+
292+
class Foo extends EmberObject.extend(mix1, mix2) {}
293+
294+
const instance = Foo.create({
295+
ownProp: 'b'
296+
});
297+
298+
objectInspector.sendObject(instance);
299+
300+
const details = message.details;
301+
302+
assert.equal(details[0].properties.length, 1, 'should not show mixin properties');
303+
assert.equal(details[0].properties[0].name, 'ownProp');
304+
305+
assert.equal(details[2].name, 'MyMixin1');
306+
assert.equal(details[2].properties.length, 1, 'should only show own mixin properties');
307+
assert.equal(details[2].properties[0].value.inspect, inspect('custom1'));
308+
309+
assert.equal(details[3].name, 'MyMixin2');
310+
assert.equal(details[3].properties.length, 1, 'should only show own mixin properties');
311+
assert.equal(details[3].properties[0].value.inspect, inspect('custom2'));
312+
});
313+
314+
267315
test('Computed properties are correctly calculated', function(assert) {
268316
let inspected = EmberObject.extend({
269317
hi: computed(function() {
@@ -459,11 +507,7 @@ module('Ember Debug - Object Inspector', function(hooks) {
459507

460508
test('Property grouping can be customized using _debugInfo', function(assert) {
461509
// eslint-disable-next-line ember/no-new-mixins
462-
let mixinToSkip = Mixin.create({
463-
toString() {
464-
return 'MixinToSkip';
465-
}
466-
});
510+
let mixinToSkip = Mixin.create({});
467511

468512
let Inspected = EmberObject.extend(mixinToSkip, {
469513
name: 'Teddy',
@@ -518,6 +562,7 @@ module('Ember Debug - Object Inspector', function(hooks) {
518562

519563
assert.equal(message.details[3].name, 'TestObject');
520564
assert.equal(message.details[3].properties.length, 3, 'Correctly merges properties');
565+
assert.equal(message.details[3].properties[0].name, 'toString');
521566
assert.equal(message.details[3].properties[1].name, 'hasChildren');
522567
assert.equal(message.details[3].properties[2].name, 'expensiveProperty', 'property name is correct');
523568
assert.equal(message.details[3].properties[2].value.isCalculated, undefined, 'Does not calculate expensive properties');

0 commit comments

Comments
 (0)