Skip to content

Instantly share code, notes, and snippets.

@vitch
Last active May 28, 2018 21:01
Show Gist options
  • Save vitch/591d022359bd392535c15c715a59e81a to your computer and use it in GitHub Desktop.
Save vitch/591d022359bd392535c15c715a59e81a to your computer and use it in GitHub Desktop.
// Script to report the services in an ember app as requested on:
// https://github.com/emberjs/ember.js/issues/16134
function findEmberApplication() {
let found = findMetaTag('name', /environment$/);
if (!found) {
throw new Error(`Couldn't find config`);
}
let config = JSON.parse(unescape(found.getAttribute('content')));
let appName = config.modulePrefix;
let application = Ember.Namespace.NAMESPACES_BY_ID[appName];
let owner = application.__deprecatedInstance__; // TODO: Make work with all ember versions
return {
application,
appName,
owner,
};
}
function findServices() {
let { appName, owner } = findEmberApplication();
let servicesPath = `${appName}/services/`;
return Object.keys(requirejs._eak_seen)
.filter((key) => key.startsWith(servicesPath))
.map((key) => key.substr(servicesPath.length))
.map((serviceName) => {
let service;
try {
service = owner.lookup(`service:${serviceName}`);
} catch (e) {
return;
}
return {
serviceName,
service,
};
})
.filter((s) => s && s.service);
}
function eachProp(obj, check) {
return keysInObject(obj)
.map((key) => {
try {
let prop = obj[key];
if (check(prop)) {
return prop;
}
} catch (e) {
return;
}
})
.filter((prop) => prop);
}
function getComputedProperties(obj) {
return eachProp(obj, (prop) => prop instanceof Ember.ComputedProperty);
}
function getAliasedProperties(obj) {
return eachProp(obj, (prop) => prop.isDescriptor && prop.altKey);
}
function getInjectedServices(obj) {
return eachProp(obj, (prop) => prop.isDescriptor && prop.type === 'service');
}
function getObservers(obj) {
return eachProp(obj, (prop) => prop.__ember_observes__);
}
function getServicesInfo() {
let services = findServices();
let servicesInfo = services
.map(({ serviceName, service}) => {
let computedProperties = getComputedProperties(service);
let aliasedProperties = getAliasedProperties(service);
let injectedServices = getInjectedServices(service);
let observers = getObservers(service);
let concatenatedProperties = service.get('concatenatedProperties');
let mergedProperties = service.get('mergedProperties');
let readOnlyComputedProperties = computedProperties.filter((prop) => prop._readOnly);
let involatileComputedProperties = computedProperties.reject((prop) => prop._volatile);
let volatileComputedProperties = computedProperties.filter((prop) => prop._volatile);
return {
counts: {
aliasedProperties: aliasedProperties.length,
computedProperties: computedProperties.length,
concatenatedProperties: concatenatedProperties.length,
injectedServices: injectedServices.length,
involatileComputedProperties: involatileComputedProperties.length,
mergedProperties: mergedProperties.length,
observers: observers.length,
readOnlyComputedProperties: readOnlyComputedProperties.length,
volatileComputedProperties: volatileComputedProperties.length,
},
hasActions: !!service.actions,
isObjectProxy: service instanceof Ember.ObjectProxy,
props: {
aliasedProperties,
computedProperties,
concatenatedProperties,
injectedServices,
involatileComputedProperties,
mergedProperties,
readOnlyComputedProperties,
volatileComputedProperties,
},
serviceName,
service,
};
});
let servicesWhichObjectProxy = servicesInfo.filter((service) => service.isObjectProxy);
let servicesWhichHaveActions = servicesInfo.filter((service) => service.hasActions);
let counts = ['aliasedProperties', 'concatenatedProperties', 'computedProperties', 'injectedServices', 'mergedProperties', 'observers', 'involatileComputedProperties', 'readOnlyComputedProperties', 'volatileComputedProperties']
.reduce((acc, prop) => {
let servicesWithCount = servicesInfo.filter((service) => service.counts[prop]);
let totalCount = servicesWithCount
.reduce((acc, service) => {
acc += service.counts[prop];
return acc;
}, 0);
acc[prop] = {
numServicesWithCount: servicesWithCount.length,
servicesWithCount,
totalCount,
};
return acc;
}, {});
console.log(`
Total services: ${servicesInfo.length}
is an object proxy: ${servicesWhichObjectProxy.length}
injects another service: ${counts.injectedServices.totalCount} properties in ${counts.injectedServices.numServicesWithCount} services
computed properties: ${counts.computedProperties.totalCount} properties in ${counts.computedProperties.numServicesWithCount} services
alias: ${counts.aliasedProperties.totalCount} properties in ${counts.aliasedProperties.numServicesWithCount} services
readonly: ${counts.readOnlyComputedProperties.totalCount} properties in ${counts.readOnlyComputedProperties.numServicesWithCount} services
involatile computed properties: ${counts.involatileComputedProperties.totalCount} properties in ${counts.involatileComputedProperties.numServicesWithCount} services
volatile computed properties: ${counts.volatileComputedProperties.totalCount} properties in ${counts.volatileComputedProperties.numServicesWithCount} services
observers: ${counts.observers.totalCount} properties in ${counts.observers.numServicesWithCount} services
concatenated properties: ${counts.concatenatedProperties.totalCount} properties in ${counts.concatenatedProperties.numServicesWithCount} services
merged properties: ${counts.mergedProperties.totalCount} properties in ${counts.mergedProperties.numServicesWithCount} services
actions: ${servicesWhichHaveActions.length}
`);
return { counts, servicesInfo };
}
function keysInObject(obj) {
let props = [];
for (let prop in obj) {
props.push(prop);
}
return props;
}
// From ember-inspector/ember_debug/general-debug.js
function findMetaTag(attribute, regExp = /.*/) {
let metas = document.querySelectorAll(`meta[${attribute}]`);
for (let i = 0; i < metas.length; i++) {
let match = metas[i].getAttribute(attribute).match(regExp);
if (match) {
return metas[i];
}
}
return null;
}
// Let's do it:
getServicesInfo();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment