Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ember-cli-tree-shake

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ember-cli-tree-shake - npm Package Compare versions

Comparing version 0.0.2 to 0.0.3

lib/component.js

27

lib/components.js

@@ -1,23 +0,16 @@

var Controller = require('./controller');
let Controllers = require('./controllers');
let Component = require('./component');
const LAST_CALL_EXPRESSION = 'extend';
var Controllers = function(tree) {
this.tree = tree;
};
let Components = class Components extends Controllers {
type() {
return 'Component';
}
Controllers.prototype.find = function() {
let foundControllers = [];
this.tree.selectNodesByType('CallExpression').forEach(node => {
if (!node.callee.property || !node.callee.object.property) {
return;
}
if (node.callee.property.name === LAST_CALL_EXPRESSION && node.callee.object.property.name === 'Component') {
foundControllers.push(new Controller(node));
}
});
return foundControllers;
typeClass() {
return Component;
}
};
module.exports = Controllers;
module.exports = Components;

@@ -1,66 +0,35 @@

var ComputedProperty = function(node) {
this.node = node;
};
let Property = require('./property');
ComputedProperty.prototype.name = function() {
return this.node.key.name;
}
let ComputedProperty = class ComputedProperty extends Property {
value() {
return this.node.value;
}
ComputedProperty.prototype.value = function() {
return this.node.value;
}
arguments() {
if (!this.value().arguments) {
return [];
}
ComputedProperty.prototype.arguments = function() {
if (!this.value().arguments) {
return [];
return this.value().arguments;
}
return this.value().arguments;
}
get functionBody() {
const args = this.arguments();
return args[args.length - 1];
}
ComputedProperty.prototype.internalGetters = function() {
const args = this.arguments();
const fn = args[args.length - 1];
const getters = [];
dependants() {
let dependants = [];
this.arguments().forEach((argument) => {
if (argument.type !== 'StringLiteral') {
return;
}
var dfs = (el) => {
if (el && el.childElements) {
el.childElements.forEach((element) => {
if (element.type == 'CallExpression' && element.callee.property && element.callee.property.name === 'get') {
const dependant = element.arguments[0];
dependants.push(argument.value.split('.')[0]);
});
if (dependant.value) {
getters.push(dependant);
}
}
dfs(element.nextSibling);
dfs(element);
});
}
return dependants.concat(super.dependants());
}
if (fn) {
dfs(fn.body);
}
return getters;
}
};
ComputedProperty.prototype.dependants = function() {
let dependants = [];
this.arguments().forEach((argument) => {
if (argument.type !== 'StringLiteral') {
return;
}
dependants.push(argument.value.split('.')[0]);
});
this.internalGetters().forEach((getter) => {
dependants.push(getter.value.split('.')[0]);
});
return dependants;
}
module.exports = ComputedProperty;

@@ -1,2 +0,3 @@

var ComputedProperty = require('./computed-property');
let ComputedProperty = require('./computed-property');
let Property = require('./property');

@@ -14,76 +15,104 @@ const TYPE = 'ObjectExpression';

var Controller = function(node) {
this.node = node;
this._computedProperties = null;
this._observerProperties = null;
};
let Controller = class Controller {
constructor(node) {
this.node = node;
this._computedProperties = null;
this._observerProperties = null;
}
Controller.prototype._computed = function(type) {
let computedProperties = [];
this.node.arguments.forEach((argument) => {
if (!argument.properties) {
return;
}
templatePath() {
return null;
}
argument.properties.forEach((property) => {
if (!property.value) {
methods() {
let methods = [];
this.node.arguments.forEach((argument) => {
if (!argument.properties) {
return;
}
if (property.value.type === 'CallExpression' && property.value.callee.type === 'MemberExpression') {
let callee = property.value.callee
argument.properties.forEach((property) => {
if (property.type !== 'ObjectMethod') {
return;
}
if ((callee.object.name === 'Ember' && callee.property.name === type) || COMPUTED_PROPERTY_MACROS.indexOf(callee.property.name) > 0) {
var computedProperty = new ComputedProperty(property);
computedProperties.push(computedProperty);
}
}
var method = new Property(property);
methods.push(method);
});
return;
});
return;
});
return computedProperties;
};
return methods;
}
Controller.prototype.computed = function() {
if (this._computedProperties) {
return this._computedProperties;
computed() {
if (this._computedProperties) {
return this._computedProperties;
}
let computedProperties = this._computed('computed');
this._computedProperties = computedProperties;
return computedProperties;
}
let computedProperties = this._computed('computed');
observer() {
if (this._observerProperties) {
return this._observerProperties;
}
this._computedProperties = computedProperties;
return computedProperties;
};
let observerProperties = this._computed('observer');
Controller.prototype.observer = function() {
if (this._observerProperties) {
return this._observerProperties;
this._observerProperties = observerProperties;
return observerProperties;
}
let observerProperties = this._computed('observer');
classNameBindings() {
let classNameBindings = [];
this._observerProperties = observerProperties;
return observerProperties;
};
this.node.arguments.forEach((argument) => {
if (!argument.properties) {
return;
}
argument.properties.forEach((property) => {
if (property.key.name === 'classNameBindings' && property.value.elements) {
classNameBindings = property.value.elements.map(function(element) {
return element.value.split(':')[0];
});
}
});
});
Controller.prototype.classNameBindings = function() {
let classNameBindings = [];
return classNameBindings;
}
this.node.arguments.forEach((argument) => {
if (!argument.properties) {
_computed(type) {
let computedProperties = [];
this.node.arguments.forEach((argument) => {
if (!argument.properties) {
return;
}
argument.properties.forEach((property) => {
if (!property.value) {
return;
}
if (property.value.type === 'CallExpression' && property.value.callee.type === 'MemberExpression') {
let callee = property.value.callee
if ((callee.object.name === 'Ember' && callee.property.name === type) || COMPUTED_PROPERTY_MACROS.indexOf(callee.property.name) > 0) {
var computedProperty = new ComputedProperty(property);
computedProperties.push(computedProperty);
}
}
});
return;
}
argument.properties.forEach((property) => {
if (property.key.name === 'classNameBindings' && property.value.elements) {
classNameBindings = property.value.elements.map(function(element) {
return element.value.split(':')[0];
});
}
});
});
return classNameBindings;
};
return computedProperties;
}
}
module.exports = Controller;

@@ -5,20 +5,31 @@ var Controller = require('./controller');

var Controllers = function(tree) {
this.tree = tree;
};
let Controllers = class Controllers {
constructor(tree) {
this.tree = tree;
}
Controllers.prototype.find = function() {
let foundControllers = [];
this.tree.selectNodesByType('CallExpression').forEach(node => {
if (!node.callee.property || !node.callee.object.property) {
return;
}
type() {
return 'Controller';
}
if (node.callee.property.name === LAST_CALL_EXPRESSION && node.callee.object.property.name === 'Controller') {
foundControllers.push(new Controller(node));
}
});
return foundControllers;
};
typeClass() {
return Controller;
}
find() {
let foundControllers = [];
this.tree.selectNodesByType('CallExpression').forEach(node => {
if (!node.callee.property || !node.callee.object.property) {
return;
}
if (node.callee.property.name === LAST_CALL_EXPRESSION && node.callee.object.property.name === this.type()) {
let type = this.typeClass();
foundControllers.push(new type(node));
}
});
return foundControllers;
}
}
module.exports = Controllers;

@@ -10,162 +10,170 @@ const Controllers = require('./controllers');

var DeadComputedProperties = function(tree, paths, filepath) {
this.tree = tree;
this.filepath = filepath;
this.paths = paths;
};
let DeadComputedProperties = class DeadComputedProperties {
constructor(tree, paths, filepath) {
this.tree = tree;
this.filepath = filepath;
this.paths = paths;
}
DeadComputedProperties.prototype.emit = function() {
this.collect().forEach((property) => {
console.log(
colors.yellow('Warning:'),
'Possibly dead computed property',
'"' + colors.green(property.name) + '"',
property.path
);
});
}
emit() {
this.collect().forEach((property) => {
console.log(
colors.yellow('Warning:'),
'Possibly dead computed property',
'"' + colors.green(property.name) + '"',
property.path
);
});
}
DeadComputedProperties.prototype.collect = function() {
var possiblyDead = [];
var controllers = new Controllers(this.tree).find();
var components = new Components(this.tree).find();
collect() {
let possiblyDead = [];
let controllers = new Controllers(this.tree).find();
let components = new Components(this.tree).find();
return this.collectFor(controllers, 'controllers').concat(
this.collectFor(components, 'components')
);
};
return this.collectFor(controllers).concat(
this.collectFor(components)
);
}
DeadComputedProperties.prototype.collectFor = function(type, typePath) {
var possiblyDead = [];
collectFor(type) {
let possiblyDead = [];
type.forEach((node) => {
let dependants = {};
node.computed().forEach((computed) => {
computed.dependants().forEach((dep) => {
dependants[dep] = computed;
type.forEach((node) => {
let dependants = {};
node.computed().forEach((computed) => {
computed.dependants().forEach((dep) => {
dependants[dep] = true;
});
});
});
node.observer().forEach((observer) => {
observer.dependants().forEach((dep) => {
dependants[dep] = observer;
node.observer().forEach((observer) => {
observer.dependants().forEach((dep) => {
dependants[dep] = true;
});
});
});
node.classNameBindings().forEach((binding) => {
dependants[binding] = binding;
});
node.classNameBindings().forEach((binding) => {
dependants[binding] = true;
});
let jsPath = path.relative(this.paths.app + '/' + typePath, this.filepath);
let controllerDirPath = path.dirname(jsPath);
let templatePathPart = '/templates/';
node.methods().forEach((method) => {
method.dependants().forEach((dep) => {
dependants[dep] = true
});
})
if (typePath !== 'controllers') {
templatePathPart += typePath + '/';
}
let jsPath = path.relative(this.paths.app + '/' + node.templatePath(), this.filepath);
let controllerDirPath = path.dirname(jsPath);
let templatePathPart = '/templates/';
let templatePath = path.join(
this.paths.app,
templatePathPart,
path.basename(jsPath, '.js') + '.hbs'
);
let walker, htmlbars;
try {
if (fs.statSync(templatePath)) {
let code = fs.readFileSync(templatePath, 'utf8');
htmlbars = HTMLBarsSyntax.parse(code);
walker = new HTMLBarsSyntax.Walker();
if (node.templatePath()) {
templatePathPart += node.templatePath() + '/';
}
} catch (_) {
}
node.computed().forEach((computed) => {
let maybeDead = true;
let templatePath = path.join(
this.paths.app,
templatePathPart,
path.basename(jsPath, '.js') + '.hbs'
);
let walker, htmlbars;
if (dependants[computed.name()]) {
maybeDead = false;
try {
if (fs.statSync(templatePath)) {
let code = fs.readFileSync(templatePath, 'utf8');
htmlbars = HTMLBarsSyntax.parse(code);
walker = new HTMLBarsSyntax.Walker();
}
} catch (_) {
}
if (walker) {
let visit = (walker, hbsTree) => {
walker.visit(hbsTree, (hbsNode) => {
if (hbsNode.original === computed.name() || (hbsNode.path && hbsNode.path.original === computed.name())) {
maybeDead = false;
}
node.computed().forEach((computed) => {
let maybeDead = true;
if (hbsNode.attributes) {
hbsNode.attributes.forEach((attribute) => {
visit(walker, attribute);
})
}
if (dependants[computed.name()]) {
maybeDead = false;
}
if (hbsNode.parts) {
hbsNode.parts.forEach((part) => {
visit(walker, part);
})
}
if (walker) {
let visit = (walker, hbsTree) => {
walker.visit(hbsTree, (hbsNode) => {
if (hbsNode.original === computed.name() || (hbsNode.path && hbsNode.path.original === computed.name())) {
maybeDead = false;
}
if (hbsNode.pairs) {
hbsNode.pairs.forEach((pair) => {
visit(walker, pair);
})
}
if (hbsNode.attributes) {
hbsNode.attributes.forEach((attribute) => {
visit(walker, attribute);
})
}
if (hbsNode.params) {
hbsNode.params.forEach((param) => {
visit(walker, param);
})
}
if (hbsNode.parts) {
hbsNode.parts.forEach((part) => {
visit(walker, part);
})
}
if (hbsNode.value) {
visit(walker, hbsNode.value);
}
if (hbsNode.pairs) {
hbsNode.pairs.forEach((pair) => {
visit(walker, pair);
})
}
if (hbsNode.hash) {
visit(walker, hbsNode.hash);
}
if (hbsNode.params) {
hbsNode.params.forEach((param) => {
visit(walker, param);
})
}
if (hbsNode.program) {
visit(walker, hbsNode.program);
}
if (hbsNode.value) {
visit(walker, hbsNode.value);
}
if (hbsNode.path && hbsNode.path.original === 'partial') {
let jsPath = path.relative(this.paths.app + '/controllers', this.filepath);
let templatePath = path.join(
this.paths.app,
'/templates/',
hbsNode.params[0].original + '.hbs'
);
if (hbsNode.hash) {
visit(walker, hbsNode.hash);
}
try {
if (fs.statSync(templatePath)) {
let code = fs.readFileSync(templatePath, 'utf8');
partialHtmlbars = HTMLBarsSyntax.parse(code);
partialWalker = new HTMLBarsSyntax.Walker();
if (hbsNode.program) {
visit(walker, hbsNode.program);
}
visit(partialWalker, partialHtmlbars);
if (hbsNode.path && hbsNode.path.original === 'partial') {
let jsPath = path.relative(this.paths.app + '/controllers', this.filepath);
let templatePath = path.join(
this.paths.app,
'/templates/',
hbsNode.params[0].original + '.hbs'
);
try {
if (fs.statSync(templatePath)) {
let code = fs.readFileSync(templatePath, 'utf8');
partialHtmlbars = HTMLBarsSyntax.parse(code);
partialWalker = new HTMLBarsSyntax.Walker();
visit(partialWalker, partialHtmlbars);
}
} catch (_) {
}
} catch (_) {
}
}
});
}
visit(walker, htmlbars);
}
if (maybeDead) {
possiblyDead.push({
'name': computed.name(),
'path': this.filepath
});
}
visit(walker, htmlbars);
}
if (maybeDead) {
possiblyDead.push({
'name': computed.name(),
'path': this.filepath
});
}
});
});
});
return possiblyDead;
return possiblyDead;
}
};
module.exports = DeadComputedProperties;
{
"name": "ember-cli-tree-shake",
"version": "0.0.2",
"version": "0.0.3",
"description": "Use tree shaking to discover dead code in your Ember app",

@@ -5,0 +5,0 @@ "directories": {

@@ -9,3 +9,2 @@ # ember-cli-tree-shake

- Plain function's usage of computed property doesn't get considered as dependency
- Mixins don't get considered when considering aliveness of a property

@@ -12,0 +11,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc