Permalink
Browse files

v0.10.7

  • Loading branch information...
1 parent dd6163e commit 0d99ac7038355e5163ba751270afded8fdc0a14b @btford btford committed Mar 7, 2016
Showing with 1,303 additions and 1,303 deletions.
  1. +1,301 −1,301 dist/hint.js
  2. +1 −1 manifest.json
  3. +1 −1 package.json
View
2,602 dist/hint.js
@@ -618,1584 +618,1584 @@ var LEVELS = [
'suggestion'
];
-},{"./src/modules/controllers":25,"./src/modules/events":26,"./src/modules/hintEmitter":27,"./src/modules/modules":28,"./src/modules/scopes":29}],4:[function(require,module,exports){
-module.exports = function debounceOn (fn, timeout, hash) {
- var timeouts = {};
+},{"./src/modules/controllers":21,"./src/modules/events":22,"./src/modules/hintEmitter":23,"./src/modules/modules":24,"./src/modules/scopes":25}],4:[function(require,module,exports){
+'use strict';
- timeout = typeof timeout === 'number' ? timeout : (hash = timeout, 100);
- hash = typeof hash === 'function' ? hash : defaultHash;
+var list = 'click submit mouseenter mouseleave mousemove mousedown mouseover mouseup dblclick keyup keydown keypress blur focus submit cut copy paste'.split(' ');
- return function () {
- var key = hash.apply(null, arguments);
- var args = arguments;
- if (typeof timeouts[key] === 'undefined') {
- timeouts[key] = setTimeout(function () {
- delete timeouts[key];
- fn.apply(null, args);
- }, timeout);
- }
- return function cancel () {
- if (timeouts[key]) {
- clearTimeout(timeouts[key]);
- delete timeouts[key];
- return true;
- }
- return false;
- };
- };
+module.exports = list.map(function(eventName) {
+ return 'ng' + eventName.charAt(0).toUpperCase() + eventName.substr(1);
+});
+
+},{}],5:[function(require,module,exports){
+'use strict';
+
+module.exports = function summarizeModel (model) {
+
+ if (model instanceof Array) {
+ return JSON.stringify(model.map(summarizeProperty));
+ } else if (typeof model === 'object') {
+ return JSON.stringify(Object.
+ keys(model).
+ filter(isAngularPrivatePropertyName).
+ reduce(shallowSummary, {}));
+ } else {
+ return model;
+ }
+
+ function shallowSummary (obj, prop) {
+ obj[prop] = summarizeProperty(model[prop]);
+ return obj;
+ }
};
-function defaultHash () {
- return Array.prototype.join.call(arguments, '::');
+function isAngularPrivatePropertyName (key) {
+ return !(key[0] === '$' && key[1] === '$') && key !== '$parent' && key !== '$root';
}
-},{}],5:[function(require,module,exports){
-/*!
- * EventEmitter2
- * https://github.com/hij1nx/EventEmitter2
- *
- * Copyright (c) 2013 hij1nx
- * Licensed under the MIT license.
- */
-;!function(undefined) {
+// TODO: handle DOM nodes, fns, etc better.
+function summarizeProperty (obj) {
+ return obj instanceof Array ?
+ { '~array-length': obj.length } :
+ obj === null ?
+ null :
+ typeof obj === 'object' ?
+ { '~object': true } :
+ obj;
+}
- var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
- return Object.prototype.toString.call(obj) === "[object Array]";
- };
- var defaultMaxListeners = 10;
+},{}],6:[function(require,module,exports){
+var MODULE_NAME = 'Modules';
- function init() {
- this._events = {};
- if (this._conf) {
- configure.call(this, this._conf);
- }
+module.exports = function(modules) {
+ modules.forEach(function(module) {
+ angular.hint.emit(MODULE_NAME, module.message, module.severity);
+ });
+};
+
+},{}],7:[function(require,module,exports){
+var modData = require('./moduleData');
+ MODULE_NAME = 'Modules',
+ SEVERITY_WARNING = 2;
+
+module.exports = function() {
+ var multiLoaded = [];
+ for(var modName in modData.createdMulti) {
+ var message = 'Multiple modules with name "' + modName + '" are being created and they will ' +
+ 'overwrite each other.';
+ var multi = modData.createdMulti[modName];
+ var multiLength = multi.length;
+ var details = {
+ existingModule: multi[multiLength - 1],
+ overwrittenModules: multi.slice(0, multiLength - 1)
+ };
+ multiLoaded
+ .push({module: details, message: message, name: MODULE_NAME, severity: SEVERITY_WARNING});
}
+ return multiLoaded;
+};
- function configure(conf) {
- if (conf) {
+},{"./moduleData":14}],8:[function(require,module,exports){
+var modData = require('./moduleData');
- this._conf = conf;
+module.exports = function(moduleName, getCreated) {
+ return (getCreated)? modData.createdModules[moduleName] : modData.loadedModules[moduleName];
+};
- conf.delimiter && (this.delimiter = conf.delimiter);
- conf.maxListeners && (this._events.maxListeners = conf.maxListeners);
- conf.wildcard && (this.wildcard = conf.wildcard);
- conf.newListener && (this.newListener = conf.newListener);
+},{"./moduleData":14}],9:[function(require,module,exports){
+var MODULE_NAME = 'Modules',
+ SEVERITY_ERROR = 1;
+ module.exports = function(attrs, ngAppFound) {
+ if(attrs['ng-app'] && ngAppFound) {
+ angular.hint.emit(MODULE_NAME, 'ng-app may only be included once. The module "' +
+ attrs['ng-app'].value + '" was not used to bootstrap because ng-app was already included.',
+ SEVERITY_ERROR);
+ }
+ return attrs['ng-app'] ? attrs['ng-app'].value : undefined;
+ };
- if (this.wildcard) {
- this.listenerTree = {};
+
+
+},{}],10:[function(require,module,exports){
+var getModule = require('./getModule'),
+ dictionary = Object.keys(require('./moduleData').createdModules),
+ suggest = require('suggest-it')(dictionary),
+ SEVERITY_ERROR = 1;
+
+module.exports = function(loadedModules) {
+ var undeclaredModules = [];
+ for(var module in loadedModules) {
+ var cModule = getModule(module, true);
+ if(!cModule) {
+ var match = suggest(module),
+ suggestion = (match) ? '; Try: "'+match+'"' : '',
+ message = 'Module "'+module+'" was loaded but does not exist'+suggestion+'.';
+
+ undeclaredModules.push({module: null, message: message, severity: SEVERITY_ERROR});
+ }
+ }
+ return undeclaredModules;
+};
+
+},{"./getModule":8,"./moduleData":14,"suggest-it":29}],11:[function(require,module,exports){
+var getModule = require('./getModule');
+
+var IGNORED = ['ngHintControllers', 'ngHintDirectives', 'ngHintDom', 'ngHintEvents',
+ 'ngHintInterpolation', 'ngHintModules', 'ngHintScopes', 'ng', 'ngLocale', 'protractorBaseModule_'],
+ SEVERITY_WARNING = 2;
+
+module.exports = function(createdModules) {
+ var unusedModules = [];
+ for(var module in createdModules) {
+ if(!getModule(module)) {
+ var cModule = createdModules[module],
+ message = 'Module "' + cModule.name + '" was created but never loaded.';
+ if(IGNORED.indexOf(cModule.name) === -1) {
+ unusedModules.push({module: cModule, message: message, severity: SEVERITY_WARNING});
}
}
}
+ return unusedModules;
+};
- function EventEmitter(conf) {
- this._events = {};
- this.newListener = false;
- configure.call(this, conf);
+},{"./getModule":8}],12:[function(require,module,exports){
+var MODULE_NAME = 'Modules',
+ SEVERITY_SUGGESTION = 3;
+
+module.exports = function(str) {
+ if (str === 'ng') {
+ return true;
}
- //
- // Attention, function return type now is array, always !
- // It has zero elements if no any matches found and one or more
- // elements (leafs) if there are matches
- //
- function searchListenerTree(handlers, type, tree, i) {
- if (!tree) {
- return [];
+ if(str.charAt(0).toUpperCase() === str.charAt(0)) {
+ angular.hint.emit(MODULE_NAME, 'The best practice for' +
+ ' module names is to use dot.case or lowerCamelCase. Check the name of "' + str + '".',
+ SEVERITY_SUGGESTION);
+ return false;
+ }
+ if(str.toLowerCase() === str && str.indexOf('.') === -1) {
+ angular.hint.emit(MODULE_NAME, 'Module names should be namespaced' +
+ ' with a dot (app.dashboard) or lowerCamelCase (appDashboard). Check the name of "' + str + '".', SEVERITY_SUGGESTION);
+ return false;
+ }
+ return true;
+};
+
+},{}],13:[function(require,module,exports){
+var normalizeAttribute = require('./normalizeAttribute');
+
+module.exports = function(attrs) {
+ for(var i = 0, length = attrs.length; i < length; i++) {
+ if(normalizeAttribute(attrs[i].nodeName) === 'ng-view' ||
+ attrs[i].value.indexOf('ng-view') > -1) {
+ return true;
}
- var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,
- typeLength = type.length, currentType = type[i], nextType = type[i+1];
- if (i === typeLength && tree._listeners) {
- //
- // If at the end of the event(s) list and the tree has listeners
- // invoke those listeners.
- //
- if (typeof tree._listeners === 'function') {
- handlers && handlers.push(tree._listeners);
- return [tree];
- } else {
- for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {
- handlers && handlers.push(tree._listeners[leaf]);
- }
- return [tree];
- }
+ }
+};
+
+},{"./normalizeAttribute":16}],14:[function(require,module,exports){
+module.exports = {
+ createdModules: {},
+ createdMulti: {},
+ loadedModules: {}
+};
+
+},{}],15:[function(require,module,exports){
+var modData = require('./moduleData'),
+ getModule = require('./getModule');
+
+module.exports = function() {
+ if(modData.ngViewExists && !getModule('ngRoute')) {
+ return {message: 'Directive "ngView" was used in the application however "ngRoute" was not loaded into any module.'};
+ }
+};
+
+},{"./getModule":8,"./moduleData":14}],16:[function(require,module,exports){
+module.exports = function(attribute) {
+ return attribute.replace(/^(?:data|x)[-_:]/, '').replace(/[:_]/g, '-');
+};
+
+},{}],17:[function(require,module,exports){
+var display = require('./display'),
+ formatMultiLoaded = require('./formatMultiLoaded'),
+ getUnusedModules = require('./getUnusedModules'),
+ getUndeclaredModules = require('./getUndeclaredModules'),
+ modData = require('./moduleData'),
+ ngViewNoNgRoute = require('./ngViewNoNgRoute');
+
+module.exports = function() {
+ var unusedModules = getUnusedModules(modData.createdModules),
+ undeclaredModules = getUndeclaredModules(modData.loadedModules),
+ multiLoaded = formatMultiLoaded(),
+ noNgRoute = ngViewNoNgRoute();
+ if(unusedModules.length || undeclaredModules.length || multiLoaded.length || noNgRoute) {
+ var toSend = unusedModules.concat(undeclaredModules)
+ .concat(multiLoaded);
+ if(noNgRoute) {
+ toSend = toSend.concat(noNgRoute);
}
+ display(toSend);
+ }
+};
- if ((currentType === '*' || currentType === '**') || tree[currentType]) {
- //
- // If the event emitted is '*' at this part
- // or there is a concrete match at this patch
- //
- if (currentType === '*') {
- for (branch in tree) {
- if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
- listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1));
- }
- }
- return listeners;
- } else if(currentType === '**') {
- endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*'));
- if(endReached && tree._listeners) {
- // The next element has a _listeners, add it to the handlers.
- listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));
- }
+},{"./display":6,"./formatMultiLoaded":7,"./getUndeclaredModules":10,"./getUnusedModules":11,"./moduleData":14,"./ngViewNoNgRoute":15}],18:[function(require,module,exports){
+var modData = require('./moduleData');
- for (branch in tree) {
- if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
- if(branch === '*' || branch === '**') {
- if(tree[branch]._listeners && !endReached) {
- listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));
- }
- listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
- } else if(branch === nextType) {
- listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2));
- } else {
- // No match on this one, shift into the tree but not in the type array.
- listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
- }
- }
- }
- return listeners;
- }
+module.exports = function(module, isNgAppMod) {
+ var name = module.name || module;
+ if(!isNgAppMod){
+ module.requires.forEach(function(dependency){
+ modData.loadedModules[dependency] = dependency;
+ });
+ }
+ else {
+ modData.loadedModules[name] = name;
+ modData.ngAppMod = name;
+ }
+};
- listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1));
+},{"./moduleData":14}],19:[function(require,module,exports){
+var getNgAppMod = require('./getNgAppMod'),
+ inAttrsOrClasses = require('./inAttrsOrClasses'),
+ storeDependencies = require('./storeDependencies'),
+ modData = require('./moduleData');
+
+module.exports = function(doms) {
+ var bothFound,
+ ngViewFound,
+ elem,
+ isElemName,
+ isInAttrsOrClasses,
+ ngAppMod;
+
+ for(var i = 0; i < doms.length; i++) {
+ elem = doms[i];
+ var attributes = elem.attributes;
+ isElemName = elem.nodeName.toLowerCase() === 'ng-view';
+ isInAttrsOrClasses = inAttrsOrClasses(attributes);
+
+ ngViewFound = isElemName || isInAttrsOrClasses;
+
+ ngAppMod = getNgAppMod(attributes, modData.ngAppFound);
+ modData.ngAppFound = modData.ngAppFound || ngAppMod;
+
+ if(ngAppMod) {
+ storeDependencies(ngAppMod, true);
}
+ modData.ngViewExists = ngViewFound ? true : modData.ngViewExists;
- xTree = tree['*'];
- if (xTree) {
- //
- // If the listener tree will allow any match for this part,
- // then recursively explore all branches of the tree
- //
- searchListenerTree(handlers, type, xTree, i+1);
+ if(bothFound) {
+ break;
}
+ }
+};
- xxTree = tree['**'];
- if(xxTree) {
- if(i < typeLength) {
- if(xxTree._listeners) {
- // If we have a listener on a '**', it will catch all, so add its handler.
- searchListenerTree(handlers, type, xxTree, typeLength);
- }
+},{"./getNgAppMod":9,"./inAttrsOrClasses":13,"./moduleData":14,"./storeDependencies":18}],20:[function(require,module,exports){
+var storeDependencies = require('./storeDependencies');
- // Build arrays of matching next branches and others.
- for(branch in xxTree) {
- if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {
- if(branch === nextType) {
- // We know the next element will match, so jump twice.
- searchListenerTree(handlers, type, xxTree[branch], i+2);
- } else if(branch === currentType) {
- // Current node matches, move into the tree.
- searchListenerTree(handlers, type, xxTree[branch], i+1);
- } else {
- isolatedBranch = {};
- isolatedBranch[branch] = xxTree[branch];
- searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1);
- }
- }
- }
- } else if(xxTree._listeners) {
- // We have reached the end and still on a '**'
- searchListenerTree(handlers, type, xxTree, typeLength);
- } else if(xxTree['*'] && xxTree['*']._listeners) {
- searchListenerTree(handlers, type, xxTree['*'], typeLength);
- }
- }
+var seen = [];
- return listeners;
+var storeUsedModules = module.exports = function(module, modules){
+ var name = module.name || module;
+ if(module && seen.indexOf(name) === -1) {
+ seen.push(name);
+ storeDependencies(module);
+ module.requires.forEach(function(modName) {
+ var mod = modules[modName];
+ storeUsedModules(mod, modules);
+ });
}
+};
+},{"./storeDependencies":18}],21:[function(require,module,exports){
+'use strict';
- function growListenerTree(type, listener) {
+var MODULE_NAME = 'Controllers',
+ CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/,
+ CATEGORY_CONTROLLER_NAME = 'Name controllers according to best practices',
+ CATEGORY_GLOBAL_CONTROLLER = 'Using global functions as controllers is against Angular best practices and depricated in Angular 1.3 and up',
+ SEVERITY_ERROR = 1,
+ SEVERITY_WARNING = 2;
- type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
+// local state
+var nameToControllerMap = {};
- //
- // Looks for two consecutive '**', if so, don't add the event at all.
- //
- for(var i = 0, len = type.length; i+1 < len; i++) {
- if(type[i] === '**' && type[i+1] === '**') {
- return;
- }
+/**
+* Decorates $controller with a patching function to
+* log a message if the controller is instantiated on the window
+*/
+angular.module('ngHintControllers', []).
+ config(['$provide', '$controllerProvider', function ($provide, $controllerProvider) {
+ $provide.decorator('$controller', ['$delegate', controllerDecorator]);
+
+ var originalRegister = $controllerProvider.register;
+ $controllerProvider.register = function(name, constructor) {
+ stringOrObjectRegister(name);
+ originalRegister.apply($controllerProvider, arguments);
}
+ }]);
- var tree = this.listenerTree;
- var name = type.shift();
+function controllerDecorator($delegate) {
+ return function(ctrl) {
+ if (typeof ctrl === 'string') {
+ var match = ctrl.match(CNTRL_REG);
+ var ctrlName = (match && match[1]) || ctrl;
- while (name) {
+ if (!nameToControllerMap[ctrlName]) {
+ sendMessageForControllerName(ctrlName);
+ }
- if (!tree[name]) {
- tree[name] = {};
+ if (!nameToControllerMap[ctrlName] && typeof window[ctrlName] === 'function') {
+ sendMessageForGlobalController(ctrlName);
}
+ }
+ return $delegate.apply(this, arguments);
+ };
+}
- tree = tree[name];
+/**
+* Save details of the controllers as they are instantiated
+* for use in decoration.
+* Hint about the best practices for naming controllers.
+*/
+var originalModule = angular.module;
- if (type.length === 0) {
+function stringOrObjectRegister(controllerName) {
+ if ((controllerName !== null) && (typeof controllerName === 'object')) {
+ Object.keys(controllerName).forEach(processController);
+ } else {
+ processController(controllerName);
+ }
+}
- if (!tree._listeners) {
- tree._listeners = listener;
- }
- else if(typeof tree._listeners === 'function') {
- tree._listeners = [tree._listeners, listener];
- }
- else if (isArray(tree._listeners)) {
+function processController(ctrlName) {
+ nameToControllerMap[ctrlName] = true;
+ sendMessageForControllerName(ctrlName);
+}
- tree._listeners.push(listener);
+function sendMessageForGlobalController(name) {
+ angular.hint.emit(MODULE_NAME + ':global',
+ 'add `' + name + '` to a module',
+ angular.version.minor <= 2 ? SEVERITY_WARNING : SEVERITY_ERROR,
+ CATEGORY_GLOBAL_CONTROLLER);
+}
- if (!tree._listeners.warned) {
+function sendMessageForControllerName(name) {
+ var newName = name;
+ if (!startsWithUpperCase(name)) {
+ newName = title(newName);
+ }
+ if (!endsWithController(name)) {
+ newName = addControllerSuffix(newName);
+ }
+ if (name !== newName) {
+ angular.hint.emit(MODULE_NAME + ':rename',
+ 'Consider renaming `' + name + '` to `' + newName + '`.',
+ SEVERITY_WARNING,
+ CATEGORY_CONTROLLER_NAME);
+ }
+}
- var m = defaultMaxListeners;
+function startsWithUpperCase(name) {
+ var firstChar = name.charAt(0);
+ return firstChar === firstChar.toUpperCase() &&
+ firstChar !== firstChar.toLowerCase();
+}
- if (typeof this._events.maxListeners !== 'undefined') {
- m = this._events.maxListeners;
- }
+function title (name) {
+ return name[0].toUpperCase() + name.substr(1);
+}
- if (m > 0 && tree._listeners.length > m) {
+var CONTROLLER_RE = /Controller$/;
+function endsWithController(name) {
+ return CONTROLLER_RE.test(name);
+}
- tree._listeners.warned = true;
- console.error('(node) warning: possible EventEmitter memory ' +
- 'leak detected. %d listeners added. ' +
- 'Use emitter.setMaxListeners() to increase limit.',
- tree._listeners.length);
- console.trace();
- }
- }
- }
- return true;
- }
- name = type.shift();
- }
- return true;
- }
+var RE = /(Ctrl|Kontroller)?$/;
+function addControllerSuffix(name) {
+ return name.replace(RE, 'Controller');
+}
- // By default EventEmitters will print a warning if more than
- // 10 listeners are added to it. This is a useful default which
- // helps finding memory leaks.
- //
- // Obviously not all Emitters should be limited to 10. This function allows
- // that to be increased. Set to zero for unlimited.
+/*
+ * decorate angular module API
+ */
- EventEmitter.prototype.delimiter = '.';
+angular.module = function() {
+ var module = originalModule.apply(this, arguments),
+ originalController = module.controller;
- EventEmitter.prototype.setMaxListeners = function(n) {
- this._events || init.call(this);
- this._events.maxListeners = n;
- if (!this._conf) this._conf = {};
- this._conf.maxListeners = n;
+ module.controller = function(controllerName, controllerConstructor) {
+ stringOrObjectRegister(controllerName);
+ return originalController.apply(this, arguments);
};
- EventEmitter.prototype.event = '';
+ return module;
+};
- EventEmitter.prototype.once = function(event, fn) {
- this.many(event, 1, fn);
- return this;
- };
+},{}],22:[function(require,module,exports){
+'use strict';
- EventEmitter.prototype.many = function(event, ttl, fn) {
- var self = this;
+/**
+* Load necessary functions from /lib into variables.
+*/
+var ngEventAttributes = require('../lib/event-directives'),
+ MODULE_NAME = 'Events';
- if (typeof fn !== 'function') {
- throw new Error('many only accepts instances of Function');
- }
+/*
+ * Remove string expressions except property accessors.
+ * ex. abc["def"] = "gef"; // `removeStringExp` will remove "gef" but not "def".
+ */
+function removeStringExp(str) {
+ return str.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
+ function(match, pos, full) {
+ // this is our lookaround code so that our regex doesn't become so
+ // complicated.
+ if (pos !== 0 && (match.length + pos) !== full.length &&
+ full[pos - 1] === '[' && full[pos + match.length] === ']') {
+ return match;
+ }
+ return '';
+ });
+}
- function listener() {
- if (--ttl === 0) {
- self.off(event, listener);
+var getFunctionNames = function(str) {
+ if (typeof str !== 'string') {
+ return [];
+ }
+ // There are still a bunch of corner cases here where we aren't going to be able to handle
+ // but we shouldn't break the user's app and we should handle most common cases.
+ // example of corner cases: we can't check for properties inside of function
+ // arguments like `move(a.b.c)` with the current implementation
+ // or property accessors with parentheses in them
+ // like `prop["hello (world)"] = "test";`.
+ // To fully fix these issues we would need a full blown expression parser.
+ var results = removeStringExp(str.replace(/\s+/g, ''))
+ .replace(/\(.*?\)/g, '')
+ .split(/[\+\-\/\|\<\>\^=&!%~?:;]/g).map(function(x) {
+ if (isNaN(+x)) {
+ if (x.match(/\w+\(.*\)$/)){
+ return x.substr(0, x.indexOf('('));
+ }
+ return x;
}
- fn.apply(this, arguments);
- }
+ }).filter(function(x){
+ return x;
+ });
+ return results;
+};
- listener._origin = fn;
+/**
+* Decorate $provide in order to examine ng-event directives
+* and hint about their effective use.
+*/
+angular.module('ngHintEvents', [])
+ .config(['$provide', function($provide) {
+ for (var i = 0; i < ngEventAttributes.length; i++) {
+ try {
+ $provide.decorator(ngEventAttributes[i] + 'Directive',
+ ['$delegate', '$parse', ngEventDirectivesDecorator(ngEventAttributes[i])]);
+ } catch(e) {}
+ }
+ }]);
- this.on(event, listener);
+function ngEventDirectivesDecorator(ngEventAttrName) {
+ return function ($delegate, $parse) {
+ var originalCompileFn = $delegate[0].compile;
- return self;
- };
+ $delegate[0].compile = function(element, attrs, transclude) {
+ var linkFn = originalCompileFn.apply(this, arguments);
- EventEmitter.prototype.emit = function() {
+ return function ngEventHandler(scope, element, attrs) {
+ var boundFuncs = getFunctionNames(attrs[ngEventAttrName]);
- this._events || init.call(this);
+ // guard against any parsing errors since the parsing code
+ // to split the expression is pretty simple and naive.
+ try {
+ boundFuncs.forEach(function(boundFn) {
+ var property, propChain, lastProp = '';
+ while((property = boundFn.match(/^.+?([^\.\[])*/)) !== null) {
+ property = property[0];
+ propChain = lastProp + property;
+ if ($parse(propChain)(scope) === undefined) {
+ angular.hint.emit(MODULE_NAME + ':undef', propChain + ' is undefined');
+ }
+ boundFn = boundFn.replace(property, '');
+ lastProp += property;
+ if(boundFn.charAt(0) === '.') {
+ lastProp += '.';
+ boundFn = boundFn.substr(1);
+ }
+ }
+ });
+ } catch (e) {
+ angular.hint.emit(MODULE_NAME + ':undef', '' +
+ 'parsing error: please inform the angular-hint ' +
+ 'or batarang teams. expression: ' + boundFuncs.join(''));
+ }
- var type = arguments[0];
+ return linkFn.apply(this, arguments);
+ };
+ };
+ return $delegate;
+ }
+}
- if (type === 'newListener' && !this.newListener) {
- if (!this._events.newListener) { return false; }
- }
+},{"../lib/event-directives":4}],23:[function(require,module,exports){
+'use strict';
- // Loop through the *_all* functions and invoke them.
- if (this._all) {
- var l = arguments.length;
- var args = new Array(l - 1);
- for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
- for (i = 0, l = this._all.length; i < l; i++) {
- this.event = type;
- this._all[i].apply(this, args);
- }
- }
+/**
+ * We use EventEmitter2 here in order to have scoped events
+ * For instance:
+ * hint.emit('scope:digest', {
+ */
+var EventEmitter2 = require('eventemitter2').EventEmitter2;
- // If there is no 'error' event listener then throw.
- if (type === 'error') {
+angular.hint = new EventEmitter2({
+ wildcard: true,
+ delimiter: ':'
+});
+},{"eventemitter2":27}],24:[function(require,module,exports){
+'use strict';
- if (!this._all &&
- !this._events.error &&
- !(this.wildcard && this.listenerTree.error)) {
+var getModule = require('./angular-hint-modules/getModule'),
+ start = require('./angular-hint-modules/start'),
+ storeNgAppAndView = require('./angular-hint-modules/storeNgAppAndView'),
+ storeUsedModules = require('./angular-hint-modules/storeUsedModules'),
+ hasNameSpace = require('./angular-hint-modules/hasNameSpace'),
+ modData = require('./angular-hint-modules/moduleData');
- if (arguments[1] instanceof Error) {
- throw arguments[1]; // Unhandled 'error' event
- } else {
- throw new Error("Uncaught, unspecified 'error' event.");
- }
- return false;
- }
- }
+var doc = Array.prototype.slice.call(document.getElementsByTagName('*')),
+ originalAngularModule = angular.module,
+ modules = {};
- var handler;
+storeNgAppAndView(doc);
- if(this.wildcard) {
- handler = [];
- var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
- searchListenerTree.call(this, handler, ns, this.listenerTree, 0);
- }
- else {
- handler = this._events[type];
- }
+angular.module = function(name, requiresOriginal) {
+ var module = originalAngularModule.apply(this, arguments),
+ name = module.name;
- if (typeof handler === 'function') {
- this.event = type;
- if (arguments.length === 1) {
- handler.call(this);
- }
- else if (arguments.length > 1)
- switch (arguments.length) {
- case 2:
- handler.call(this, arguments[1]);
- break;
- case 3:
- handler.call(this, arguments[1], arguments[2]);
- break;
- // slower
- default:
- var l = arguments.length;
- var args = new Array(l - 1);
- for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
- handler.apply(this, args);
- }
- return true;
- }
- else if (handler) {
- var l = arguments.length;
- var args = new Array(l - 1);
- for (var i = 1; i < l; i++) args[i - 1] = arguments[i];
+ module.requiresOriginal = requiresOriginal;
+ modules[name] = module;
+ var modToCheck = getModule(name, true);
+ //check arguments to determine if called as setter or getter
+ var modIsSetter = arguments.length > 1;
- var listeners = handler.slice();
- for (var i = 0, l = listeners.length; i < l; i++) {
- this.event = type;
- listeners[i].apply(this, args);
- }
- return (listeners.length > 0) || !!this._all;
- }
- else {
- return !!this._all;
+ if (modIsSetter) {
+ hasNameSpace(name);
+ }
+
+ if(modToCheck && modToCheck.requiresOriginal !== module.requiresOriginal && modIsSetter) {
+ if(!modData.createdMulti[name]) {
+ modData.createdMulti[name] = [getModule(name,true)];
}
+ modData.createdMulti[name].push(module);
+ }
+ modData.createdModules[name] = module;
+ return module;
+};
- };
+angular.module('ngHintModules', []).config(function() {
+ var ngAppMod = modules[modData.ngAppMod];
+ if (ngAppMod) {
+ storeUsedModules(ngAppMod, modules);
+ }
+ start();
+});
- EventEmitter.prototype.on = function(type, listener) {
+},{"./angular-hint-modules/getModule":8,"./angular-hint-modules/hasNameSpace":12,"./angular-hint-modules/moduleData":14,"./angular-hint-modules/start":17,"./angular-hint-modules/storeNgAppAndView":19,"./angular-hint-modules/storeUsedModules":20}],25:[function(require,module,exports){
+'use strict';
- if (typeof type === 'function') {
- this.onAny(type);
- return this;
- }
+var summarize = require('../lib/summarize-model');
+var debounceOn = require('debounce-on');
- if (typeof listener !== 'function') {
- throw new Error('on only accepts instances of Function');
- }
- this._events || init.call(this);
+var hint = angular.hint;
- // To avoid recursion in the case that type == "newListeners"! Before
- // adding it to the listeners, first emit "newListeners".
- this.emit('newListener', type, listener);
+hint.emit = hint.emit || function () {};
- if(this.wildcard) {
- growListenerTree.call(this, type, listener);
- return this;
- }
+module.exports = angular.module('ngHintScopes', []).config(['$provide', function ($provide) {
+ $provide.decorator('$rootScope', ['$delegate', '$parse', decorateRootScope]);
+ $provide.decorator('$compile', ['$delegate', decorateDollaCompile]);
+}]);
- if (!this._events[type]) {
- // Optimize the case of one listener. Don't need the extra array object.
- this._events[type] = listener;
- }
- else if(typeof this._events[type] === 'function') {
- // Adding the second element, need to change to array.
- this._events[type] = [this._events[type], listener];
- }
- else if (isArray(this._events[type])) {
- // If we've already got an array, just append.
- this._events[type].push(listener);
+function decorateRootScope($delegate, $parse) {
- // Check for listener leak
- if (!this._events[type].warned) {
+ var perf = window.performance || { now: function () { return 0; } };
- var m = defaultMaxListeners;
+ var scopes = {},
+ watching = {};
- if (typeof this._events.maxListeners !== 'undefined') {
- m = this._events.maxListeners;
- }
+ var debouncedEmitModelChange = debounceOn(emitModelChange, 10);
- if (m > 0 && this._events[type].length > m) {
+ hint.watch = function (scopeId, path) {
+ path = typeof path === 'string' ? path.split('.') : path;
- this._events[type].warned = true;
- console.error('(node) warning: possible EventEmitter memory ' +
- 'leak detected. %d listeners added. ' +
- 'Use emitter.setMaxListeners() to increase limit.',
- this._events[type].length);
- console.trace();
- }
+ if (!watching[scopeId]) {
+ watching[scopeId] = {};
+ }
+
+ for (var i = 1, ii = path.length; i <= ii; i += 1) {
+ var partialPath = path.slice(0, i).join('.');
+ if (watching[scopeId][partialPath]) {
+ continue;
}
+ var get = gettterer(scopeId, partialPath);
+ var value = summarize(get());
+ watching[scopeId][partialPath] = {
+ get: get,
+ value: value
+ };
+ hint.emit('model:change', {
+ id: convertIdToOriginalType(scopeId),
+ path: partialPath,
+ value: value
+ });
}
- return this;
};
- EventEmitter.prototype.onAny = function(fn) {
-
- if (typeof fn !== 'function') {
- throw new Error('onAny only accepts instances of Function');
+ hint.assign = function (scopeId, path, value) {
+ var scope;
+ if (scope = scopes[scopeId]) {
+ scope.$apply(function () {
+ return $parse(path).assign(scope, value);
+ });
}
+ };
- if(!this._all) {
- this._all = [];
+ hint.inspectScope = function (scopeId) {
+ var scope;
+ if (scope = scopes[scopeId]) {
+ window.$scope = scope;
}
+ };
- // Add the function to the event listener collection.
- this._all.push(fn);
- return this;
+ hint.unwatch = function (scopeId, unwatchPath) {
+ Object.keys(watching[scopeId]).
+ forEach(function (path) {
+ if (path.indexOf(unwatchPath) === 0) {
+ delete watching[scopeId][path];
+ }
+ });
};
- EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+ var scopePrototype = ('getPrototypeOf' in Object) ?
+ Object.getPrototypeOf($delegate) : $delegate.__proto__;
- EventEmitter.prototype.off = function(type, listener) {
- if (typeof listener !== 'function') {
- throw new Error('removeListener only takes instances of Function');
+ var _watch = scopePrototype.$watch;
+ var _digestEvents = [];
+ var skipNextPerfWatchers = false;
+ scopePrototype.$watch = function (watchExpression, reactionFunction) {
+ // if `skipNextPerfWatchers` is true, this means the previous run of the
+ // `$watch` decorator was a one time binding expression and this invocation
+ // of the $watch function has the `oneTimeInterceptedExpression` (internal angular function)
+ // as the `watchExpression` parameter. If we decorate it with the performance
+ // timers function this will cause us to invoke `oneTimeInterceptedExpression`
+ // on subsequent digest loops and will update the one time bindings
+ // if anything mutated the property.
+ if (skipNextPerfWatchers) {
+ skipNextPerfWatchers = false;
+ return _watch.apply(this, arguments);
}
- var handlers,leafs=[];
-
- if(this.wildcard) {
- var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
- leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
- }
- else {
- // does not use listeners(), so no side effect of creating _events[type]
- if (!this._events[type]) return this;
- handlers = this._events[type];
- leafs.push({_listeners:handlers});
+ if (typeof watchExpression === 'string' &&
+ isOneTimeBindExp(watchExpression)) {
+ skipNextPerfWatchers = true;
+ return _watch.apply(this, arguments);
}
+ var watchStr = humanReadableWatchExpression(watchExpression);
+ var scopeId = this.$id;
+ var expressions = null;
+ if (typeof watchExpression === 'function') {
+ expressions = watchExpression.expressions;
+ if (Object.prototype.toString.call(expressions) === '[object Array]' &&
+ expressions.some(isOneTimeBindExp)) {
+ skipNextPerfWatchers = true;
+ return _watch.apply(this, arguments);
+ }
- for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
- var leaf = leafs[iLeaf];
- handlers = leaf._listeners;
- if (isArray(handlers)) {
-
- var position = -1;
-
- for (var i = 0, length = handlers.length; i < length; i++) {
- if (handlers[i] === listener ||
- (handlers[i].listener && handlers[i].listener === listener) ||
- (handlers[i]._origin && handlers[i]._origin === listener)) {
- position = i;
- break;
- }
- }
-
- if (position < 0) {
- continue;
- }
-
- if(this.wildcard) {
- leaf._listeners.splice(position, 1);
- }
- else {
- this._events[type].splice(position, 1);
- }
+ arguments[0] = function () {
+ var start = perf.now();
+ var ret = watchExpression.apply(this, arguments);
+ var end = perf.now();
+ _digestEvents.push({
+ eventType: 'scope:watch',
+ id: scopeId,
+ watch: watchStr,
+ time: end - start
+ });
+ return ret;
+ };
+ } else {
+ var thatScope = this;
+ arguments[0] = function () {
+ var start = perf.now();
+ var ret = thatScope.$eval(watchExpression);
+ var end = perf.now();
+ _digestEvents.push({
+ eventType: 'scope:watch',
+ id: scopeId,
+ watch: watchStr,
+ time: end - start
+ });
+ return ret;
+ };
+ }
- if (handlers.length === 0) {
- if(this.wildcard) {
- delete leaf._listeners;
- }
- else {
- delete this._events[type];
- }
- }
- return this;
- }
- else if (handlers === listener ||
- (handlers.listener && handlers.listener === listener) ||
- (handlers._origin && handlers._origin === listener)) {
- if(this.wildcard) {
- delete leaf._listeners;
- }
- else {
- delete this._events[type];
- }
- }
+ if (typeof reactionFunction === 'function') {
+ arguments[1] = function () {
+ var start = perf.now();
+ var ret = reactionFunction.apply(this, arguments);
+ var end = perf.now();
+ _digestEvents.push({
+ eventType: 'scope:reaction',
+ id: scopeId,
+ watch: watchStr,
+ time: end - start
+ });
+ return ret;
+ };
}
- return this;
+ return _watch.apply(this, arguments);
};
- EventEmitter.prototype.offAny = function(fn) {
- var i = 0, l = 0, fns;
- if (fn && this._all && this._all.length > 0) {
- fns = this._all;
- for(i = 0, l = fns.length; i < l; i++) {
- if(fn === fns[i]) {
- fns.splice(i, 1);
- return this;
- }
- }
- } else {
- this._all = [];
- }
- return this;
+ var _digest = scopePrototype.$digest;
+ scopePrototype.$digest = function (fn) {
+ _digestEvents = [];
+ var start = perf.now();
+ var ret = _digest.apply(this, arguments);
+ var end = perf.now();
+ hint.emit('scope:digest', {
+ id: this.$id,
+ time: end - start,
+ events: _digestEvents
+ });
+ return ret;
};
- EventEmitter.prototype.removeListener = EventEmitter.prototype.off;
+ var _destroy = scopePrototype.$destroy;
+ scopePrototype.$destroy = function () {
+ var id = this.$id;
- EventEmitter.prototype.removeAllListeners = function(type) {
- if (arguments.length === 0) {
- !this._events || init.call(this);
- return this;
- }
+ hint.emit('scope:destroy', { id: id });
- if(this.wildcard) {
- var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
- var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0);
+ delete scopes[id];
+ delete watching[id];
- for (var iLeaf=0; iLeaf<leafs.length; iLeaf++) {
- var leaf = leafs[iLeaf];
- leaf._listeners = null;
- }
- }
- else {
- if (!this._events[type]) return this;
- this._events[type] = null;
- }
- return this;
+ return _destroy.apply(this, arguments);
};
- EventEmitter.prototype.listeners = function(type) {
- if(this.wildcard) {
- var handlers = [];
- var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
- searchListenerTree.call(this, handlers, ns, this.listenerTree, 0);
- return handlers;
- }
-
- this._events || init.call(this);
-
- if (!this._events[type]) this._events[type] = [];
- if (!isArray(this._events[type])) {
- this._events[type] = [this._events[type]];
- }
- return this._events[type];
- };
- EventEmitter.prototype.listenersAny = function() {
+ var _new = scopePrototype.$new;
+ scopePrototype.$new = function () {
+ var child = _new.apply(this, arguments);
- if(this._all) {
- return this._all;
- }
- else {
- return [];
- }
+ scopes[child.$id] = child;
+ watching[child.$id] = {};
+ hint.emit('scope:new', { parent: this.$id, child: child.$id });
+ setTimeout(function () {
+ emitScopeElt(child);
+ }, 0);
+ return child;
};
- if (typeof define === 'function' && define.amd) {
- // AMD. Register as an anonymous module.
- define(function() {
- return EventEmitter;
+ function emitScopeElt (scope) {
+ var scopeId = scope.$id;
+ var elt = findElt(scopeId);
+ var descriptor = scopeDescriptor(elt, scope);
+ hint.emit('scope:link', {
+ id: scopeId,
+ descriptor: descriptor
});
- } else if (typeof exports === 'object') {
- // CommonJS
- exports.EventEmitter2 = EventEmitter;
- }
- else {
- // Browser global.
- window.EventEmitter2 = EventEmitter;
}
-}();
-},{}],6:[function(require,module,exports){
-module.exports = distance;
+ function findElt (scopeId) {
+ var elts = document.querySelectorAll('.ng-scope');
+ var elt, scope;
-function distance(a, b) {
- var table = [];
- if (a.length === 0 || b.length === 0) return Math.max(a.length, b.length);
- for (var ii = 0, ilen = a.length + 1; ii !== ilen; ++ii) {
- table[ii] = [];
- for (var jj = 0, jlen = b.length + 1; jj !== jlen; ++jj) {
- if (ii === 0 || jj === 0) table[ii][jj] = Math.max(ii, jj);
- else {
- var diagPenalty = Number(a[ii-1] !== b[jj-1]);
- var diag = table[ii - 1][jj - 1] + diagPenalty;
- var top = table[ii - 1][jj] + 1;
- var left = table[ii][jj - 1] + 1;
- table[ii][jj] = Math.min(left, top, diag);
+ for (var i = 0; i < elts.length; i++) {
+ elt = angular.element(elts[i]);
+ scope = elt.scope();
+ if (scope.$id === scopeId) {
+ return elt;
}
}
}
- return table[a.length][b.length];
-}
-
-
-},{}],7:[function(require,module,exports){
-module.exports = suggestDictionary;
-var distance = require('./levenstein_distance');
-
-function suggestDictionary(dict, opts) {
- opts = opts || {};
- var threshold = opts.threshold || 0.5;
- return function suggest(word) {
- var length = word.length;
- return dict.reduce(function (result, dictEntry) {
- var score = distance(dictEntry, word);
- if (result.score > score && score / length < threshold) {
- result.score = score;
- result.word = dictEntry;
- }
- return result;
- }, { score: Infinity }).word;
+ var _apply = scopePrototype.$apply;
+ scopePrototype.$apply = function (fn) {
+ // var start = perf.now();
+ var ret = _apply.apply(this, arguments);
+ // var end = perf.now();
+ // hint.emit('scope:apply', { id: this.$id, time: end - start });
+ debouncedEmitModelChange();
+ return ret;
};
-}
-
-suggestDictionary.distance = distance;
-
-},{"./levenstein_distance":6}],8:[function(require,module,exports){
-'use strict';
-
-var list = 'click submit mouseenter mouseleave mousemove mousedown mouseover mouseup dblclick keyup keydown keypress blur focus submit cut copy paste'.split(' ');
-
-module.exports = list.map(function(eventName) {
- return 'ng' + eventName.charAt(0).toUpperCase() + eventName.substr(1);
-});
-
-},{}],9:[function(require,module,exports){
-'use strict';
-module.exports = function summarizeModel (model) {
-
- if (model instanceof Array) {
- return JSON.stringify(model.map(summarizeProperty));
- } else if (typeof model === 'object') {
- return JSON.stringify(Object.
- keys(model).
- filter(isAngularPrivatePropertyName).
- reduce(shallowSummary, {}));
- } else {
- return model;
- }
- function shallowSummary (obj, prop) {
- obj[prop] = summarizeProperty(model[prop]);
- return obj;
+ function gettterer (scopeId, path) {
+ if (path === '') {
+ return function () {
+ return scopes[scopeId];
+ };
+ }
+ var getter = $parse(path);
+ return function () {
+ return getter(scopes[scopeId]);
+ };
}
-};
-
-function isAngularPrivatePropertyName (key) {
- return !(key[0] === '$' && key[1] === '$') && key !== '$parent' && key !== '$root';
-}
-
-// TODO: handle DOM nodes, fns, etc better.
-function summarizeProperty (obj) {
- return obj instanceof Array ?
- { '~array-length': obj.length } :
- obj === null ?
- null :
- typeof obj === 'object' ?
- { '~object': true } :
- obj;
-}
-
-},{}],10:[function(require,module,exports){
-var MODULE_NAME = 'Modules';
-module.exports = function(modules) {
- modules.forEach(function(module) {
- angular.hint.emit(MODULE_NAME, module.message, module.severity);
- });
-};
-
-},{}],11:[function(require,module,exports){
-var modData = require('./moduleData');
- MODULE_NAME = 'Modules',
- SEVERITY_WARNING = 2;
-
-module.exports = function() {
- var multiLoaded = [];
- for(var modName in modData.createdMulti) {
- var message = 'Multiple modules with name "' + modName + '" are being created and they will ' +
- 'overwrite each other.';
- var multi = modData.createdMulti[modName];
- var multiLength = multi.length;
- var details = {
- existingModule: multi[multiLength - 1],
- overwrittenModules: multi.slice(0, multiLength - 1)
- };
- multiLoaded
- .push({module: details, message: message, name: MODULE_NAME, severity: SEVERITY_WARNING});
+ function emitModelChange () {
+ Object.keys(watching).forEach(function (scopeId) {
+ Object.keys(watching[scopeId]).forEach(function (path) {
+ var model = watching[scopeId][path];
+ var value = summarize(model.get());
+ if (value !== model.value) {
+ hint.emit('model:change', {
+ id: convertIdToOriginalType(scopeId),
+ path: path,
+ oldValue: model.value,
+ value: value
+ });
+ model.value = value;
+ }
+ });
+ });
}
- return multiLoaded;
-};
-
-},{"./moduleData":18}],12:[function(require,module,exports){
-var modData = require('./moduleData');
-
-module.exports = function(moduleName, getCreated) {
- return (getCreated)? modData.createdModules[moduleName] : modData.loadedModules[moduleName];
-};
-
-},{"./moduleData":18}],13:[function(require,module,exports){
-var MODULE_NAME = 'Modules',
- SEVERITY_ERROR = 1;
- module.exports = function(attrs, ngAppFound) {
- if(attrs['ng-app'] && ngAppFound) {
- angular.hint.emit(MODULE_NAME, 'ng-app may only be included once. The module "' +
- attrs['ng-app'].value + '" was not used to bootstrap because ng-app was already included.',
- SEVERITY_ERROR);
- }
- return attrs['ng-app'] ? attrs['ng-app'].value : undefined;
- };
+ hint.emit('scope:new', {
+ parent: null,
+ child: $delegate.$id
+ });
+ scopes[$delegate.$id] = $delegate;
+ watching[$delegate.$id] = {};
+ return $delegate;
+}
-},{}],14:[function(require,module,exports){
-var getModule = require('./getModule'),
- dictionary = Object.keys(require('./moduleData').createdModules),
- suggest = require('suggest-it')(dictionary),
- SEVERITY_ERROR = 1;
+function decorateDollaCompile ($delegate) {
+ var newCompile = function () {
+ var link = $delegate.apply(this, arguments);
-module.exports = function(loadedModules) {
- var undeclaredModules = [];
- for(var module in loadedModules) {
- var cModule = getModule(module, true);
- if(!cModule) {
- var match = suggest(module),
- suggestion = (match) ? '; Try: "'+match+'"' : '',
- message = 'Module "'+module+'" was loaded but does not exist'+suggestion+'.';
+ return function (scope) {
+ var elt = link.apply(this, arguments);
+ var descriptor = scopeDescriptor(elt, scope);
+ hint.emit('scope:link', {
+ id: scope.$id,
+ descriptor: descriptor
+ });
+ return elt;
+ };
+ };
- undeclaredModules.push({module: null, message: message, severity: SEVERITY_ERROR});
+ // TODO: test this
+ // copy private helpers like $$addScopeInfo
+ for (var prop in $delegate) {
+ if ($delegate.hasOwnProperty(prop)) {
+ newCompile[prop] = $delegate[prop];
}
}
- return undeclaredModules;
-};
+ return newCompile;
+}
-},{"./getModule":12,"./moduleData":18,"suggest-it":7}],15:[function(require,module,exports){
-var getModule = require('./getModule');
+var TYPES = [
+ 'ng-app',
+ 'ng-controller',
+ 'ng-repeat',
+ 'ng-include'
+];
-var IGNORED = ['ngHintControllers', 'ngHintDirectives', 'ngHintDom', 'ngHintEvents',
- 'ngHintInterpolation', 'ngHintModules', 'ngHintScopes', 'ng', 'ngLocale', 'protractorBaseModule_'],
- SEVERITY_WARNING = 2;
+function scopeDescriptor (elt, scope) {
+ var val,
+ theseTypes = [],
+ type;
-module.exports = function(createdModules) {
- var unusedModules = [];
- for(var module in createdModules) {
- if(!getModule(module)) {
- var cModule = createdModules[module],
- message = 'Module "' + cModule.name + '" was created but never loaded.';
- if(IGNORED.indexOf(cModule.name) === -1) {
- unusedModules.push({module: cModule, message: message, severity: SEVERITY_WARNING});
+ if (elt) {
+ for (var i = 0, ii = TYPES.length; i < ii; i++) {
+ type = TYPES[i];
+ if (val = elt.attr(type)) {
+ theseTypes.push(type + '="' + val + '"');
}
}
}
- return unusedModules;
-};
-
-},{"./getModule":12}],16:[function(require,module,exports){
-var MODULE_NAME = 'Modules',
- SEVERITY_SUGGESTION = 3;
-
-module.exports = function(str) {
- if (str === 'ng') {
- return true;
+ if (theseTypes.length === 0) {
+ return 'scope.$id=' + scope.$id;
+ } else {
+ return theseTypes.join(' ');
}
+}
- if(str.charAt(0).toUpperCase() === str.charAt(0)) {
- angular.hint.emit(MODULE_NAME, 'The best practice for' +
- ' module names is to use dot.case or lowerCamelCase. Check the name of "' + str + '".',
- SEVERITY_SUGGESTION);
- return false;
+function humanReadableWatchExpression (fn) {
+ if (fn == null) {
+ return null;
}
- if(str.toLowerCase() === str && str.indexOf('.') === -1) {
- angular.hint.emit(MODULE_NAME, 'Module names should be namespaced' +
- ' with a dot (app.dashboard) or lowerCamelCase (appDashboard). Check the name of "' + str + '".', SEVERITY_SUGGESTION);
- return false;
+ if (fn.exp) {
+ fn = fn.exp;
+ } else if (fn.name) {
+ fn = fn.name;
}
- return true;
-};
+ return fn.toString();
+}
-},{}],17:[function(require,module,exports){
-var normalizeAttribute = require('./normalizeAttribute');
+function isOneTimeBindExp(exp) {
+ // this is the same code angular 1.3.15 has to check
+ // for a one time bind expression
+ return exp.charAt(0) === ':' && exp.charAt(1) === ':';
+}
-module.exports = function(attrs) {
- for(var i = 0, length = attrs.length; i < length; i++) {
- if(normalizeAttribute(attrs[i].nodeName) === 'ng-view' ||
- attrs[i].value.indexOf('ng-view') > -1) {
- return true;
- }
- }
-};
+function convertIdToOriginalType(scopeId) {
+ return (angular.version.minor < 3) ? scopeId : parseInt(scopeId, 10);
+}
-},{"./normalizeAttribute":20}],18:[function(require,module,exports){
-module.exports = {
- createdModules: {},
- createdMulti: {},
- loadedModules: {}
-};
+},{"../lib/summarize-model":5,"debounce-on":26}],26:[function(require,module,exports){
+module.exports = function debounceOn (fn, timeout, hash) {
+ var timeouts = {};
-},{}],19:[function(require,module,exports){
-var modData = require('./moduleData'),
- getModule = require('./getModule');
+ timeout = typeof timeout === 'number' ? timeout : (hash = timeout, 100);
+ hash = typeof hash === 'function' ? hash : defaultHash;
-module.exports = function() {
- if(modData.ngViewExists && !getModule('ngRoute')) {
- return {message: 'Directive "ngView" was used in the application however "ngRoute" was not loaded into any module.'};
- }
+ return function () {
+ var key = hash.apply(null, arguments);
+ var args = arguments;
+ if (typeof timeouts[key] === 'undefined') {
+ timeouts[key] = setTimeout(function () {
+ delete timeouts[key];
+ fn.apply(null, args);
+ }, timeout);
+ }
+ return function cancel () {
+ if (timeouts[key]) {
+ clearTimeout(timeouts[key]);
+ delete timeouts[key];
+ return true;
+ }
+ return false;
+ };
+ };
};
-},{"./getModule":12,"./moduleData":18}],20:[function(require,module,exports){
-module.exports = function(attribute) {
- return attribute.replace(/^(?:data|x)[-_:]/, '').replace(/[:_]/g, '-');
-};
+function defaultHash () {
+ return Array.prototype.join.call(arguments, '::');
+}
-},{}],21:[function(require,module,exports){
-var display = require('./display'),
- formatMultiLoaded = require('./formatMultiLoaded'),
- getUnusedModules = require('./getUnusedModules'),
- getUndeclaredModules = require('./getUndeclaredModules'),
- modData = require('./moduleData'),
- ngViewNoNgRoute = require('./ngViewNoNgRoute');
+},{}],27:[function(require,module,exports){
+/*!
+ * EventEmitter2
+ * https://github.com/hij1nx/EventEmitter2
+ *
+ * Copyright (c) 2013 hij1nx
+ * Licensed under the MIT license.
+ */
+;!function(undefined) {
-module.exports = function() {
- var unusedModules = getUnusedModules(modData.createdModules),
- undeclaredModules = getUndeclaredModules(modData.loadedModules),
- multiLoaded = formatMultiLoaded(),
- noNgRoute = ngViewNoNgRoute();
- if(unusedModules.length || undeclaredModules.length || multiLoaded.length || noNgRoute) {
- var toSend = unusedModules.concat(undeclaredModules)
- .concat(multiLoaded);
- if(noNgRoute) {
- toSend = toSend.concat(noNgRoute);
+ var isArray = Array.isArray ? Array.isArray : function _isArray(obj) {
+ return Object.prototype.toString.call(obj) === "[object Array]";
+ };
+ var defaultMaxListeners = 10;
+
+ function init() {
+ this._events = {};
+ if (this._conf) {
+ configure.call(this, this._conf);
}
- display(toSend);
}
-};
-},{"./display":10,"./formatMultiLoaded":11,"./getUndeclaredModules":14,"./getUnusedModules":15,"./moduleData":18,"./ngViewNoNgRoute":19}],22:[function(require,module,exports){
-var modData = require('./moduleData');
+ function configure(conf) {
+ if (conf) {
-module.exports = function(module, isNgAppMod) {
- var name = module.name || module;
- if(!isNgAppMod){
- module.requires.forEach(function(dependency){
- modData.loadedModules[dependency] = dependency;
- });
- }
- else {
- modData.loadedModules[name] = name;
- modData.ngAppMod = name;
- }
-};
+ this._conf = conf;
-},{"./moduleData":18}],23:[function(require,module,exports){
-var getNgAppMod = require('./getNgAppMod'),
- inAttrsOrClasses = require('./inAttrsOrClasses'),
- storeDependencies = require('./storeDependencies'),
- modData = require('./moduleData');
+ conf.delimiter && (this.delimiter = conf.delimiter);
+ conf.maxListeners && (this._events.maxListeners = conf.maxListeners);
+ conf.wildcard && (this.wildcard = conf.wildcard);
+ conf.newListener && (this.newListener = conf.newListener);
-module.exports = function(doms) {
- var bothFound,
- ngViewFound,
- elem,
- isElemName,
- isInAttrsOrClasses,
- ngAppMod;
+ if (this.wildcard) {
+ this.listenerTree = {};
+ }
+ }
+ }
- for(var i = 0; i < doms.length; i++) {
- elem = doms[i];
- var attributes = elem.attributes;
- isElemName = elem.nodeName.toLowerCase() === 'ng-view';
- isInAttrsOrClasses = inAttrsOrClasses(attributes);
+ function EventEmitter(conf) {
+ this._events = {};
+ this.newListener = false;
+ configure.call(this, conf);
+ }
- ngViewFound = isElemName || isInAttrsOrClasses;
+ //
+ // Attention, function return type now is array, always !
+ // It has zero elements if no any matches found and one or more
+ // elements (leafs) if there are matches
+ //
+ function searchListenerTree(handlers, type, tree, i) {
+ if (!tree) {
+ return [];
+ }
+ var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached,
+ typeLength = type.length, currentType = type[i], nextType = type[i+1];
+ if (i === typeLength && tree._listeners) {
+ //
+ // If at the end of the event(s) list and the tree has listeners
+ // invoke those listeners.
+ //
+ if (typeof tree._listeners === 'function') {
+ handlers && handlers.push(tree._listeners);
+ return [tree];
+ } else {
+ for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) {
+ handlers && handlers.push(tree._listeners[leaf]);
+ }
+ return [tree];
+ }
+ }
- ngAppMod = getNgAppMod(attributes, modData.ngAppFound);
- modData.ngAppFound = modData.ngAppFound || ngAppMod;
+ if ((currentType === '*' || currentType === '**') || tree[currentType]) {
+ //
+ // If the event emitted is '*' at this part
+ // or there is a concrete match at this patch
+ //
+ if (currentType === '*') {
+ for (branch in tree) {
+ if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1));
+ }
+ }
+ return listeners;
+ } else if(currentType === '**') {
+ endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*'));
+ if(endReached && tree._listeners) {
+ // The next element has a _listeners, add it to the handlers.
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength));
+ }
- if(ngAppMod) {
- storeDependencies(ngAppMod, true);
+ for (branch in tree) {
+ if (branch !== '_listeners' && tree.hasOwnProperty(branch)) {
+ if(branch === '*' || branch === '**') {
+ if(tree[branch]._listeners && !endReached) {
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength));
+ }
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
+ } else if(branch === nextType) {
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2));
+ } else {
+ // No match on this one, shift into the tree but not in the type array.
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i));
+ }
+ }
+ }
+ return listeners;
+ }
+
+ listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1));
}
- modData.ngViewExists = ngViewFound ? true : modData.ngViewExists;
- if(bothFound) {
- break;
+ xTree = tree['*'];
+ if (xTree) {
+ //
+ // If the listener tree will allow any match for this part,
+ // then recursively explore all branches of the tree
+ //
+ searchListenerTree(handlers, type, xTree, i+1);
}
- }
-};
-},{"./getNgAppMod":13,"./inAttrsOrClasses":17,"./moduleData":18,"./storeDependencies":22}],24:[function(require,module,exports){
-var storeDependencies = require('./storeDependencies');
+ xxTree = tree['**'];
+ if(xxTree) {
+ if(i < typeLength) {
+ if(xxTree._listeners) {
+ // If we have a listener on a '**', it will catch all, so add its handler.
+ searchListenerTree(handlers, type, xxTree, typeLength);
+ }
-var seen = [];
+ // Build arrays of matching next branches and others.
+ for(branch in xxTree) {
+ if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) {
+ if(branch === nextType) {
+ // We know the next element will match, so jump twice.
+ searchListenerTree(handlers, type, xxTree[branch], i+2);
+ } else if(branch === currentType) {
+ // Current node matches, move into the tree.
+ searchListenerTree(handlers, type, xxTree[branch], i+1);
+ } else {
+ isolatedBranch = {};
+ isolatedBranch[branch] = xxTree[branch];
+ searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1);
+ }
+ }
+ }
+ } else if(xxTree._listeners) {
+ // We have reached the end and still on a '**'
+ searchListenerTree(handlers, type, xxTree, typeLength);
+ } else if(xxTree['*'] && xxTree['*']._listeners) {
+ searchListenerTree(handlers, type, xxTree['*'], typeLength);
+ }
+ }
-var storeUsedModules = module.exports = function(module, modules){
- var name = module.name || module;
- if(module && seen.indexOf(name) === -1) {
- seen.push(name);
- storeDependencies(module);
- module.requires.forEach(function(modName) {
- var mod = modules[modName];
- storeUsedModules(mod, modules);
- });
+ return listeners;
}
-};
-},{"./storeDependencies":22}],25:[function(require,module,exports){
-'use strict';
-var MODULE_NAME = 'Controllers',
- CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/,
- CATEGORY_CONTROLLER_NAME = 'Name controllers according to best practices',
- CATEGORY_GLOBAL_CONTROLLER = 'Using global functions as controllers is against Angular best practices and depricated in Angular 1.3 and up',
- SEVERITY_ERROR = 1,
- SEVERITY_WARNING = 2;
-
-// local state
-var nameToControllerMap = {};
+ function growListenerTree(type, listener) {
-/**
-* Decorates $controller with a patching function to
-* log a message if the controller is instantiated on the window
-*/
-angular.module('ngHintControllers', []).
- config(['$provide', '$controllerProvider', function ($provide, $controllerProvider) {
- $provide.decorator('$controller', ['$delegate', controllerDecorator]);
+ type = typeof type === 'string' ? type.split(this.delimiter) : type.slice();
- var originalRegister = $controllerProvider.register;
- $controllerProvider.register = function(name, constructor) {
- stringOrObjectRegister(name);
- originalRegister.apply($controllerProvider, arguments);
+ //
+ // Looks for two consecutive '**', if so, don't add the event at all.
+ //
+ for(var i = 0, len = type.length; i+1 < len; i++) {
+ if(type[i] === '**' && type[i+1] === '**') {
+ return;
+ }
}
- }]);
-function controllerDecorator($delegate) {
- return function(ctrl) {
- if (typeof ctrl === 'string') {
- var match = ctrl.match(CNTRL_REG);
- var ctrlName = (match && match[1]) || ctrl;
+ var tree = this.listenerTree;
+ var name = type.shift();
- if (!nameToControllerMap[ctrlName]) {
- sendMessageForControllerName(ctrlName);
- }
+ while (name) {
- if (!nameToControllerMap[ctrlName] && typeof window[ctrlName] === 'function') {
- sendMessageForGlobalController(ctrlName);
+ if (!tree[name]) {
+ tree[name] = {};
}
- }
- return $delegate.apply(this, arguments);
- };
-}
-
-/**
-* Save details of the controllers as they are instantiated
-* for use in decoration.
-* Hint about the best practices for naming controllers.
-*/
-var originalModule = angular.module;
-function stringOrObjectRegister(controllerName) {
- if ((controllerName !== null) && (typeof controllerName === 'object')) {
- Object.keys(controllerName).forEach(processController);
- } else {
- processController(controllerName);
- }
-}
+ tree = tree[name];
-function processController(ctrlName) {
- nameToControllerMap[ctrlName] = true;
- sendMessageForControllerName(ctrlName);
-}
+ if (type.length === 0) {
-function sendMessageForGlobalController(name) {
- angular.hint.emit(MODULE_NAME + ':global',
- 'add `' + name + '` to a module',
- angular.version.minor <= 2 ? SEVERITY_WARNING : SEVERITY_ERROR,
- CATEGORY_GLOBAL_CONTROLLER);
-}
+ if (!tree._listeners) {
+ tree._listeners = listener;
+ }
+ else if(typeof tree._listeners === 'function') {
+ tree._listeners = [tree._listeners, listener];
+ }
+ else if (isArray(tree._listeners)) {
-function sendMessageForControllerName(name) {
- var newName = name;
- if (!startsWithUpperCase(name)) {
- newName = title(newName);
- }
- if (!endsWithController(name)) {
- newName = addControllerSuffix(newName);
- }
- if (name !== newName) {
- angular.hint.emit(MODULE_NAME + ':rename',
- 'Consider renaming `' + name + '` to `' + newName + '`.',
- SEVERITY_WARNING,
- CATEGORY_CONTROLLER_NAME);
- }
-}
+ tree._listeners.push(listener);
-function startsWithUpperCase(name) {
- var firstChar = name.charAt(0);
- return firstChar === firstChar.toUpperCase() &&
- firstChar !== firstChar.toLowerCase();
-}
+ if (!tree._listeners.warned) {
-function title (name) {
- return name[0].toUpperCase() + name.substr(1);
-}
+ var m = defaultMaxListeners;
-var CONTROLLER_RE = /Controller$/;
-function endsWithController(name) {
- return CONTROLLER_RE.test(name);
-}
+ if (typeof this._events.maxListeners !== 'undefined') {
+ m = this._events.maxListeners;
+ }
-var RE = /(Ctrl|Kontroller)?$/;
-function addControllerSuffix(name) {
- return name.replace(RE, 'Controller');
-}
+ if (m > 0 && tree._listeners.length > m) {
-/*
- * decorate angular module API
- */
+ tree._listeners.warned = true;
+ console.error('(node) warning: possible EventEmitter memory ' +
+ 'leak detected. %d listeners added. ' +
+ 'Use emitter.setMaxListeners() to increase limit.',
+ tree._listeners.length);
+ console.trace();
+ }
+ }
+ }
+ return true;
+ }
+ name = type.shift();
+ }
+ return true;
+ }
-angular.module = function() {
- var module = originalModule.apply(this, arguments),
- originalController = module.controller;
+ // By default EventEmitters will print a warning if more than
+ // 10 listeners are added to it. This is a useful default which
+ // helps finding memory leaks.
+ //
+ // Obviously not all Emitters should be limited to 10. This function allows
+ // that to be increased. Set to zero for unlimited.
- module.controller = function(controllerName, controllerConstructor) {
- stringOrObjectRegister(controllerName);
- return originalController.apply(this, arguments);
+ EventEmitter.prototype.delimiter = '.';
+
+ EventEmitter.prototype.setMaxListeners = function(n) {
+ this._events || init.call(this);
+ this._events.maxListeners = n;
+ if (!this._conf) this._conf = {};
+ this._conf.maxListeners = n;
};
- return module;
-};
+ EventEmitter.prototype.event = '';
-},{}],26:[function(require,module,exports){
-'use strict';
+ EventEmitter.prototype.once = function(event, fn) {
+ this.many(event, 1, fn);
+ return this;
+ };
-/**
-* Load necessary functions from /lib into variables.
-*/
-var ngEventAttributes = require('../lib/event-directives'),
- MODULE_NAME = 'Events';
+ EventEmitter.prototype.many = function(event, ttl, fn) {
+ var self = this;
-/*
- * Remove string expressions except property accessors.
- * ex. abc["def"] = "gef"; // `removeStringExp` will remove "gef" but not "def".
- */
-function removeStringExp(str) {
- return str.replace(/"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'/g,
- function(match, pos, full) {
- // this is our lookaround code so that our regex doesn't become so
- // complicated.
- if (pos !== 0 && (match.length + pos) !== full.length &&
- full[pos - 1] === '[' && full[pos + match.length] === ']') {
- return match;
- }
- return '';
- });
-}
+ if (typeof fn !== 'function') {
+ throw new Error('many only accepts instances of Function');
+ }
-var getFunctionNames = function(str) {
- if (typeof str !== 'string') {
- return [];
- }
- // There are still a bunch of corner cases here where we aren't going to be able to handle
- // but we shouldn't break the user's app and we should handle most common cases.
- // example of corner cases: we can't check for properties inside of function
- // arguments like `move(a.b.c)` with the current implementation
- // or property accessors with parentheses in them
- // like `prop["hello (world)"] = "test";`.
- // To fully fix these issues we would need a full blown expression parser.
- var results = removeStringExp(str.replace(/\s+/g, ''))
- .replace(/\(.*?\)/g, '')
- .split(/[\+\-\/\|\<\>\^=&!%~?:;]/g).map(function(x) {
- if (isNaN(+x)) {
- if (x.match(/\w+\(.*\)$/)){
- return x.substr(0, x.indexOf('('));
- }
- return x;
+ function listener() {
+ if (--ttl === 0) {
+ self.off(event, listener);
}
- }).filter(function(x){
- return x;
- });
- return results;
-};
-
-/**
-* Decorate $provide in order to examine ng-event directives
-* and hint about their effective use.
-*/
-angular.module('ngHintEvents', [])
- .config(['$provide', function($provide) {
- for (var i = 0; i < ngEventAttributes.length; i++) {
- try {
- $provide.decorator(ngEventAttributes[i] + 'Directive',
- ['$delegate', '$parse', ngEventDirectivesDecorator(ngEventAttributes[i])]);
- } catch(e) {}
+ fn.apply(this, arguments);
}
- }]);
-function ngEventDirectivesDecorator(ngEventAttrName) {
- return function ($delegate, $parse) {
- var originalCompileFn = $delegate[0].compile;
-
- $delegate[0].compile = function(element, attrs, transclude) {
- var linkFn = originalCompileFn.apply(this, arguments);
+ listener._origin = fn;
- return function ngEventHandler(scope, element, attrs) {
- var boundFuncs = getFunctionNames(attrs[ngEventAttrName]);
+ this.on(event, listener);
- // guard against any parsing errors since the parsing code
- // to split the expression is pretty simple and naive.
- try {
- boundFuncs.forEach(function(boundFn) {
- var property, propChain, lastProp = '';
- while((property = boundFn.match(/^.+?([^\.\[])*/)) !== null) {
- property = property[0];
- propChain = lastProp + property;
- if ($parse(propChain)(scope) === undefined) {
- angular.hint.emit(MODULE_NAME + ':undef', propChain + ' is undefined');
- }
- boundFn = boundFn.replace(property, '');
- lastProp += property;
- if(boundFn.charAt(0) === '.') {
- lastProp += '.';
- boundFn = boundFn.substr(1);
- }
- }
- });
- } catch (e) {
- angular.hint.emit(MODULE_NAME + ':undef', '' +
- 'parsing error: please inform the angular-hint ' +
- 'or batarang teams. expression: ' + boundFuncs.join(''));
- }
+ return self;
+ };
- return linkFn.apply(this, arguments);
- };
- };
- return $delegate;
- }
-}
+ EventEmitter.prototype.emit = function() {
-},{"../lib/event-directives":8}],27:[function(require,module,exports){
-'use strict';
+ this._events || init.call(this);
-/**
- * We use EventEmitter2 here in order to have scoped events
- * For instance:
- * hint.emit('scope:digest', {
- */
-var EventEmitter2 = require('eventemitter2').EventEmitter2;
+ var type = arguments[0];
-angular.hint = new EventEmitter2({
- wildcard: true,
- delimiter: ':'
-});
-},{"eventemitter2":5}],28:[function(require,module,exports){
-'use strict';
+ if (type === 'newListener' && !this.newListener) {
+ if (!this._events.newListener) { return false; }
+ }
-var getModule = require('./angular-hint-modules/getModule'),
- start = require('./angular-hint-modules/start'),
- storeNgAppAndView = require('./angular-hint-modules/storeNgAppAndView'),
- storeUsedModules = require('./angular-hint-modules/storeUsedModules'),
- hasNameSpace = require('./angular-hint-modules/hasNameSpace'),
- modData = require('./angular-hint-modules/moduleData');
+ // Loop through the *_all* functions and invoke them.
+ if (this._all) {
+ var l = arguments.length;
+ var args = new Array(l - 1);