Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
705 changes: 705 additions & 0 deletions EMBER_INSPECTOR_API_ANALYSIS.md

Large diffs are not rendered by default.

429 changes: 429 additions & 0 deletions IMPLEMENTATION_COMPARISON.md

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions ember_debug/adapters/web-extension.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import BasicAdapter from './basic';
import { typeOf } from '../utils/type-check';
import { emberInspectorAPI } from '../utils/ember-inspector-api.js';

import { getEnv } from '../utils/ember';
import { run } from '../utils/ember/runloop';
const { getEnv } = emberInspectorAPI.environment;
const { run } = emberInspectorAPI.runloop;

const { isArray } = Array;
const { keys } = Object;
Expand Down
4 changes: 3 additions & 1 deletion ember_debug/adapters/websocket.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import BasicAdapter from './basic';
import { onReady } from '../utils/on-ready';
import { run } from '../utils/ember/runloop';
import { emberInspectorAPI } from '../utils/ember-inspector-api.js';

const { run } = emberInspectorAPI.runloop;

export default class extends BasicAdapter {
sendMessage(options = {}) {
Expand Down
83 changes: 44 additions & 39 deletions ember_debug/container-debug.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import DebugPort from './debug-port.js';
import { emberInspectorAPI } from './utils/ember-inspector-api.js';

/**
* Container Debug - Refactored to use new Ember Inspector API
*
* Key improvements:
* - No direct access to owner.__container__
* - No version-specific logic (InheritingDict handling)
* - Simpler, more maintainable code
* - All filtering logic encapsulated in the API
*/
export default class extends DebugPort {
get objectInspector() {
return this.namespace?.objectInspector;
}

get container() {
return this.namespace?.owner?.__container__;
get owner() {
return this.namespace?.owner;
}

TYPES_TO_SKIP = [
Expand Down Expand Up @@ -38,8 +48,12 @@ export default class extends DebugPort {
}
},
sendInstanceToConsole(message) {
const instance = this.container.lookup(message.name);
this.objectToConsole.sendValueToConsole(instance);
// Use new API for lookup
const instance = emberInspectorAPI.owner.getInstance(
this.owner,
message.name,
);
this.objectInspector.sendValueToConsole(instance);
},
};
}
Expand All @@ -52,52 +66,43 @@ export default class extends DebugPort {
return key.split(':').pop();
}

shouldHide(type) {
return type[0] === '-' || this.TYPES_TO_SKIP.indexOf(type) !== -1;
}

/**
* Get all container instances grouped by type.
*
* BEFORE (30+ lines):
* - Direct cache access: owner.__container__.cache
* - Version detection: InheritingDict vs plain object
* - Manual iteration and filtering
* - Manual grouping by type
*
* AFTER (1 line):
* - Single API call with filtering options
* - All complexity handled by Ember
*/
instancesByType() {
let key;
let instancesByType = {};
let cache = this.container.cache;
// Detect if InheritingDict (from Ember < 1.8)
if (
typeof cache.dict !== 'undefined' &&
typeof cache.eachLocal !== 'undefined'
) {
cache = cache.dict;
}
for (key in cache) {
const type = this.typeFromKey(key);
if (this.shouldHide(type)) {
continue;
}
if (instancesByType[type] === undefined) {
instancesByType[type] = [];
}
instancesByType[type].push({
fullName: key,
instance: cache[key],
});
}
return instancesByType;
// Use new high-level API - replaces all the complex logic
return emberInspectorAPI.owner.getContainerInstances(this.owner, {
excludeTypes: this.TYPES_TO_SKIP,
includePrivate: false,
});
}

getTypes() {
let key;
let types = [];
const instancesByType = this.instancesByType();
for (key in instancesByType) {
types.push({ name: key, count: instancesByType[key].length });
}
return types;
return Object.keys(instancesByType).map((type) => ({
name: type,
count: instancesByType[type].length,
}));
}

getInstances(type) {
const instances = this.instancesByType()[type];
const instancesByType = this.instancesByType();
const instances = instancesByType[type];

if (!instances) {
return null;
}

return instances.map((item) => ({
name: this.nameFromKey(item.fullName),
fullName: item.fullName,
Expand Down
13 changes: 4 additions & 9 deletions ember_debug/data-debug.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import DebugPort from './debug-port.js';
import { guidFor } from './utils/ember/object/internals';
import { emberInspectorAPI } from './utils/ember-inspector-api.js';

const { guidFor } = emberInspectorAPI.objectInternals;

export default class extends DebugPort {
// eslint-disable-next-line ember/classic-decorator-hooks
Expand All @@ -16,8 +18,7 @@ export default class extends DebugPort {
const owner = this.namespace?.owner;

// dataAdapter:main is deprecated
let adapter =
this._resolve('data-adapter:main') && owner.lookup('data-adapter:main');
let adapter = emberInspectorAPI.owner.getDataAdapter(owner);
// column limit is now supported at the inspector level
if (adapter) {
adapter.attributeLimit = 100;
Expand All @@ -27,12 +28,6 @@ export default class extends DebugPort {
return null;
}

_resolve(name) {
const owner = this.namespace?.owner;

return owner.resolveRegistration(name);
}

get port() {
return this.namespace?.port;
}
Expand Down
9 changes: 5 additions & 4 deletions ember_debug/deprecation-debug.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import DebugPort from './debug-port.js';
import SourceMap from './libs/source-map';
import { emberInspectorAPI } from './utils/ember-inspector-api.js';

import { Debug } from './utils/ember';
import { guidFor } from './utils/ember/object/internals';
import { cancel, debounce } from './utils/ember/runloop';
const { registerDeprecationHandler } = emberInspectorAPI.debug;
const { guidFor } = emberInspectorAPI.objectInternals;
const { cancel, debounce } = emberInspectorAPI.runloop;

export default class extends DebugPort {
static {
Expand Down Expand Up @@ -194,7 +195,7 @@ export default class extends DebugPort {
}

handleDeprecations() {
Debug.registerDeprecationHandler((message, options, next) => {
registerDeprecationHandler((message, options, next) => {
if (!this.adapter) {
next(message, options);
return;
Expand Down
5 changes: 2 additions & 3 deletions ember_debug/general-debug.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* eslint no-empty:0 */
import DebugPort from './debug-port.js';

import { libraries } from './utils/ember';
import { emberInspectorAPI } from './utils/ember-inspector-api.js';

/**
* Class that handles gathering general information of the inspected app.
Expand Down Expand Up @@ -88,7 +87,7 @@ export default class extends DebugPort {
*/
getLibraries() {
this.sendMessage('libraries', {
libraries: libraries?._registry,
libraries: emberInspectorAPI.libraries.getRegistry(),
});
},

Expand Down
12 changes: 4 additions & 8 deletions ember_debug/lib/get-applications.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import { Application, Namespace, guidFor } from '../utils/ember';
import { emberInspectorAPI } from '../utils/ember-inspector-api';

/**
* Get all the Ember.Application instances from Ember.Namespace.NAMESPACES
* Get all the Ember.Application instances via the inspector API
* and add our own applicationId and applicationName to them
* @return {*}
*/
export default function getApplications() {
var namespaces = Namespace.NAMESPACES;

var apps = namespaces.filter(function (namespace) {
return namespace instanceof Application;
});
var apps = emberInspectorAPI.owner.getApplications();

return apps.map(function (app) {
// Add applicationId and applicationName to the app
var applicationId = guidFor(app);
var applicationId = emberInspectorAPI.objectInternals.guidFor(app);
var applicationName =
app.name || app.modulePrefix || `(unknown app - ${applicationId})`;

Expand Down
4 changes: 2 additions & 2 deletions ember_debug/lib/setup-instance-initializer.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { guidFor } from '../utils/ember';
import { emberInspectorAPI } from '../utils/ember-inspector-api';

export default function setupInstanceInitializer(app, callback) {
if (!app.__inspector__setup) {
Expand All @@ -8,7 +8,7 @@ export default function setupInstanceInitializer(app, callback) {
// registering an instance initializer with the same name, even if on a different app,
// triggers an error because instance initializers seem to be global instead of per app.
app.instanceInitializer({
name: 'ember-inspector-app-instance-booted-' + guidFor(app),
name: 'ember-inspector-app-instance-booted-' + emberInspectorAPI.objectInternals.guidFor(app),
initialize: function (instance) {
callback(instance);
},
Expand Down
33 changes: 17 additions & 16 deletions ember_debug/lib/start-inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import getApplications from './get-applications';
import bootEmberInspector from './boot-ember-inspector';
import setupInstanceInitializer from './setup-instance-initializer';
import sendVersionMiss from './send-version-miss';
import { guidFor, Application, VERSION } from '../utils/ember';
import { emberInspectorAPI } from '../utils/ember-inspector-api';

const { guidFor } = emberInspectorAPI.objectInternals;
const { VERSION } = emberInspectorAPI.environment;

function onReady(callback) {
if (
Expand Down Expand Up @@ -64,12 +67,12 @@ export function startInspector(adapter) {
(app) => guidFor(app) === message.applicationId,
);

if (
selected &&
current !== selected &&
selected.__deprecatedInstance__
) {
bootEmberInspector(selected.__deprecatedInstance__);
if (selected && current !== selected) {
let instance =
emberInspectorAPI.owner.getOwnerFromApplication(selected);
if (instance) {
bootEmberInspector(instance);
}
}
}
});
Expand All @@ -79,10 +82,7 @@ export function startInspector(adapter) {
sendApps(adapterInstance, apps);

function loadInstance(app) {
const applicationInstances = app._applicationInstances && [
...app._applicationInstances,
];
let instance = app.__deprecatedInstance__ || applicationInstances[0];
let instance = emberInspectorAPI.owner.getOwnerFromApplication(app);
if (instance) {
// App started
setupInstanceInitializer(app, callback);
Expand All @@ -96,15 +96,16 @@ export function startInspector(adapter) {
app = apps[i];
// We check for the existance of an application instance because
// in Ember > 3 tests don't destroy the app when they're done but the app has no booted instances.
if (app._readinessDeferrals === 0) {
if (emberInspectorAPI.owner.isApplicationReady(app)) {
if (loadInstance(app)) {
break;
}
}

// app already run initializers, but no instance, use _bootPromise and didBecomeReady
if (app._bootPromise) {
app._bootPromise.then((app) => {
// app already run initializers, but no instance, use waitForApplicationBoot and didBecomeReady
const bootPromise = emberInspectorAPI.owner.waitForApplicationBoot(app);
if (bootPromise) {
bootPromise.then((app) => {
loadInstance(app);
});
}
Expand All @@ -116,7 +117,7 @@ export function startInspector(adapter) {
},
});
}
Application.initializer({
emberInspectorAPI.owner.registerInitializer({
name: 'ember-inspector-booted',
initialize: function (app) {
setupInstanceInitializer(app, callback);
Expand Down
5 changes: 4 additions & 1 deletion ember_debug/libs/capture-render-tree.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { captureRenderTree, getEnv } from '../utils/ember';
import { emberInspectorAPI } from '../utils/ember-inspector-api.js';

const { captureRenderTree } = emberInspectorAPI.debug;
const { getEnv } = emberInspectorAPI.environment;

let capture = captureRenderTree;
// Ember 3.14+ comes with debug render tree, but the version in 3.14.0/3.14.1 is buggy
Expand Down
4 changes: 3 additions & 1 deletion ember_debug/libs/promise-assembler.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
*/

import Promise from '../models/promise';
import { RSVP } from '../utils/ember';
import { emberInspectorAPI } from '../utils/ember-inspector-api.js';
import BaseObject from '../utils/base-object';
import Evented from '../utils/evented';

const { RSVP } = emberInspectorAPI.libraries;

class PromiseAssembler extends BaseObject {
// RSVP lib to debug
isStarted = false;
Expand Down
19 changes: 12 additions & 7 deletions ember_debug/libs/render-tree.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import captureRenderTree from './capture-render-tree.js';
import { guidFor } from '../utils/ember/object/internals';
import { inspect } from '../utils/type-check';
import { emberInspectorAPI } from '../utils/ember-inspector-api.js';
import { isInVersionSpecifier } from '../utils/version';
import {
VERSION,

const { guidFor } = emberInspectorAPI.objectInternals;
const { VERSION } = emberInspectorAPI.environment;
const {
EmberDestroyable,
GlimmerManager,
GlimmerReference,
GlimmerRuntime,
GlimmerUtil,
} from '../utils/ember';
} = emberInspectorAPI.instrumentation;

class InElementSupportProvider {
constructor(owner) {
Expand All @@ -27,13 +29,16 @@ class InElementSupportProvider {
this.DESTROY = GlimmerUtil?.DESTROY;
this.registerDestructor = EmberDestroyable?.registerDestructor;

// Use the new API to get debug render tree instead of accessing private properties
this.debugRenderTree =
owner.lookup('renderer:-dom')?.debugRenderTree ||
owner.lookup('service:-glimmer-environment')._debugRenderTree;
emberInspectorAPI.renderTree.getDebugRenderTree(owner);
this.NewElementBuilder =
this.runtime.NewElementBuilder || this.runtime.NewTreeBuilder;

this.patch();
// Only patch if debugRenderTree is available
if (this.debugRenderTree) {
this.patch();
}
}

reset() {
Expand Down
Loading
Loading