Skip to content

Commit

Permalink
bring back tracked dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
patricklx committed Oct 21, 2022
1 parent 619a11d commit 14bc4aa
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 14 deletions.
10 changes: 9 additions & 1 deletion app/components/object-inspector/dependent-keys.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@
<ul class="m-0 p-0 list-none">
{{#each @keys as |depKey|}}
<li class="mixin__property-dependency-item relative text-base12 text-sm">
{{#if (match depKey "")}}
<span
class="mixin__property-dependency-name subkey"
data-label="object-property-name"
>
{{depKey}}
</span>
{{else}}
{{svg-jar
"dependent-key-bullet"
width="9px"
height="9px"
}}

<span
class="mixin__property-dependency-name"
data-label="object-property-name"
>
{{depKey}}
</span>
{{/if}}
</li>
{{/each}}
</ul>
Expand Down
5 changes: 5 additions & 0 deletions app/styles/object_inspector.scss
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@
}
}

.mixin__property-dependency-name.subkey {
left: -11px;
position: relative;
}

.mixin__property-dependency-item:first-child:before {
display: none;
}
Expand Down
79 changes: 73 additions & 6 deletions ember_debug/object-inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,35 @@ try {
tagValue = GlimmerValidator.value || GlimmerValidator.valueForTag;
tagValidate = GlimmerValidator.validate || GlimmerValidator.validateTag;
track = GlimmerValidator.track;

// patch tagFor to add debug info, older versions already have _propertyKey
const tagFor = GlimmerValidator.tagFor;
GlimmerValidator.tagFor = function (...args) {
const tag = tagFor.call(this, ...args);
const [obj, key] = args;
if (
(!tag._propertyKey || !tag._object) &&
typeof obj === 'object' &&
typeof key === 'string'
) {
tag._propertyKey = key;
tag._object = obj;
}
return tag;
};
const trackedData = GlimmerValidator.trackedData;
GlimmerValidator.trackedData = function (...args) {
const r = trackedData.call(this, ...args);
if (r.getter && args.length === 2) {
const [key] = args;
const getter = r.getter;
r.getter = function (self) {
GlimmerValidator.tagFor(self, key);
return getter.call(this, self);
};
}
return r;
};
} catch (e) {
try {
// Fallback to the previous implementation
Expand Down Expand Up @@ -228,14 +257,22 @@ function getTagTrackedProps(tag, ownTag, level = 0) {
if (!tag || level > 1) {
return props;
}
if (tag.subtag) {
if (tag.subtag._propertyKey) props.push(tag.subtag._propertyKey);
const subtags = tag.subtags || (Array.isArray(tag.subtag) ? tag.subtag : []);
if (tag.subtag && !Array.isArray(tag.subtag)) {
if (tag.subtag._propertyKey)
props.push(
(tag.subtag._object ? getClassName(tag.subtag._object) + '.' : '') +
tag.subtag._propertyKey
);
props.push(...getTagTrackedProps(tag.subtag, ownTag, level + 1));
}
if (tag.subtags) {
tag.subtags.forEach((t) => {
if (subtags) {
subtags.forEach((t) => {
if (t === ownTag) return;
if (t._propertyKey) props.push(t._propertyKey);
if (t._propertyKey)
props.push(
(t._object ? getClassName(t._object) + '.' : '') + t._propertyKey
);
props.push(...getTagTrackedProps(t, ownTag, level + 1));
});
}
Expand All @@ -252,7 +289,28 @@ function getTrackedDependencies(object, property, tag) {
}
if (HAS_GLIMMER_TRACKING) {
const ownTag = tagForProperty(object, property);
dependentKeys.push(...getTagTrackedProps(tag, ownTag));
const props = getTagTrackedProps(tag, ownTag);
const mapping = {};
props.forEach((p) => {
const [objName, ...props] = p.split('.');
mapping[objName] = mapping[objName] || new Set();
props.forEach((p) => mapping[objName].add(p));
});

Object.entries(mapping).forEach(([objName, props]) => {
if (props.size > 1) {
dependentKeys.push(objName);
props.forEach((p) => {
dependentKeys.push(' • -- ' + p);
});
}
if (props.size === 1) {
dependentKeys.push(objName + '.' + [...props][0]);
}
if (props.size === 0) {
dependentKeys.push(objName);
}
});
}

return [...new Set([...dependentKeys])];
Expand Down Expand Up @@ -770,6 +828,15 @@ function getClassName(object) {
(emberNames.get(object.constructor) || object.constructor.name)) ||
'';

// check if object is a primitive value
if (object !== Object(object)) {
return typeof object;
}

if (Array.isArray(object)) {
return 'array';
}

if (object.constructor && object.constructor.prototype === object) {
let { constructor } = object;

Expand Down
43 changes: 36 additions & 7 deletions tests/ember_debug/object-inspector-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,32 @@ module('Ember Debug - Object Inspector', function (hooks) {
}
let date = new Date();

class ObjectWithTracked {
@tracked item1 = 'item1';
@tracked item2 = 'item2';
}

class Parent {
// eslint-disable-next-line constructor-super
constructor(param) {
Object.assign(this, param);
}

@tracked trackedProperty = 'tracked';
objectWithTracked = new ObjectWithTracked();

id = null;
name = 'My Object';

toString() {
return 'Parent Object';
}

get getterWithTracked() {
const a = this.objectWithTracked.item1 + this.objectWithTracked.item2;
return a + this.trackedProperty;
}

get(k) {
return this[k];
}
Expand Down Expand Up @@ -219,31 +232,36 @@ module('Ember Debug - Object Inspector', function (hooks) {

assert.strictEqual(
firstDetail.properties.length,
5,
6,
'methods are included'
);

let idProperty = firstDetail.properties[0];
let objectWithTrackedProperty = firstDetail.properties[0];
assert.strictEqual(objectWithTrackedProperty.name, 'objectWithTracked');
assert.strictEqual(objectWithTrackedProperty.value.type, 'type-object');
assert.strictEqual(objectWithTrackedProperty.value.inspect, '{ }');

let idProperty = firstDetail.properties[1];
assert.strictEqual(idProperty.name, 'id');
assert.strictEqual(idProperty.value.type, 'type-number');
assert.strictEqual(idProperty.value.inspect, '1');

let nullProperty = firstDetail.properties[1];
let nullProperty = firstDetail.properties[2];
assert.strictEqual(nullProperty.name, 'name');
assert.strictEqual(nullProperty.value.type, 'type-string');
assert.strictEqual(nullProperty.value.inspect, '"My Object"');

let prop = firstDetail.properties[2];
let prop = firstDetail.properties[3];

assert.strictEqual(prop.name, 'toString');
assert.strictEqual(prop.value.type, 'type-function');

prop = firstDetail.properties[3];
prop = firstDetail.properties[4];
assert.strictEqual(prop.name, 'nullVal');
assert.strictEqual(prop.value.type, 'type-null');
assert.strictEqual(prop.value.inspect, 'null');

prop = firstDetail.properties[4];
prop = firstDetail.properties[5];
assert.strictEqual(prop.name, 'dateVal');
assert.strictEqual(prop.value.type, 'type-date');
assert.strictEqual(prop.value.inspect, date.toString());
Expand All @@ -254,12 +272,23 @@ module('Ember Debug - Object Inspector', function (hooks) {
assert.strictEqual(prop.value.type, 'type-function');

prop = secondDetail.properties[1];
assert.strictEqual(prop.name, 'getterWithTracked');
assert.strictEqual(prop.value.type, 'type-string');
assert.strictEqual(prop.value.inspect, '"item1item2tracked"');
const dependentKeys =
compareVersion(VERSION, '3.16.10') === 0
? 'item1, item2, trackedProperty'
: 'ObjectWithTracked, • -- item1, • -- item2,Object:My Object.trackedProperty';
assert.strictEqual(prop.dependentKeys.toString(), dependentKeys);

prop = secondDetail.properties[2];
assert.strictEqual(prop.name, 'get');
assert.strictEqual(prop.value.type, 'type-function');

prop = secondDetail.properties[2];
prop = secondDetail.properties[3];
assert.strictEqual(prop.name, 'aCP');
assert.strictEqual(prop.value.type, 'type-boolean');
assert.strictEqual(prop.dependentKeys.toString(), '');
});

skip('Correct mixin order with es6 class', async function (assert) {
Expand Down

0 comments on commit 14bc4aa

Please sign in to comment.