From 1aa2f413b117dd5cd7456a506a095bd83bb00553 Mon Sep 17 00:00:00 2001 From: mohamed amr Date: Sun, 30 Apr 2017 06:24:41 +0200 Subject: [PATCH] feat(directives, components):validate directive / component definition Closes #118 --- dist/hint.js | 1882 ++++++++++++++++++++++--------------- hint.js | 4 +- src/modules/components.js | 60 ++ src/modules/directives.js | 85 ++ 4 files changed, 1262 insertions(+), 769 deletions(-) create mode 100644 src/modules/components.js create mode 100644 src/modules/directives.js diff --git a/dist/hint.js b/dist/hint.js index 39896148..04effcd9 100755 --- a/dist/hint.js +++ b/dist/hint.js @@ -6,7 +6,9 @@ require('./src/modules/hintEmitter'); // Load angular hint modules require('./src/modules/controllers'); -// require('./src/modules/directives'); +require('./src/modules/directives'); +require('./src/modules/components'); + // require('./src/modules/dom'); require('./src/modules/events'); // require('./src/modules/interpolation'); @@ -121,7 +123,7 @@ var LEVELS = [ 'suggestion' ]; -},{"./src/modules/controllers":23,"./src/modules/events":24,"./src/modules/hintEmitter":25,"./src/modules/modules":26,"./src/modules/scopes":27}],2:[function(require,module,exports){ +},{"./src/modules/components":24,"./src/modules/controllers":25,"./src/modules/directives":26,"./src/modules/events":27,"./src/modules/hintEmitter":28,"./src/modules/modules":29,"./src/modules/scopes":30}],2:[function(require,module,exports){ module.exports = function debounceOn (fn, timeout, hash) { var timeouts = {}; @@ -153,777 +155,972 @@ function defaultHash () { } },{}],3:[function(require,module,exports){ -/*! - * EventEmitter2 - * https://github.com/hij1nx/EventEmitter2 - * - * Copyright (c) 2013 hij1nx - * Licensed under the MIT license. - */ -;!function(undefined) { - - 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); - } - } - - function configure(conf) { - if (conf) { - this._conf = conf; - - conf.delimiter && (this.delimiter = conf.delimiter); - this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners; - - conf.wildcard && (this.wildcard = conf.wildcard); - conf.newListener && (this.newListener = conf.newListener); - conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak); - - if (this.wildcard) { - this.listenerTree = {}; - } - } else { - this._maxListeners = defaultMaxListeners; - } - } - - function logPossibleMemoryLeak(count, eventName) { - var errorMsg = '(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.'; - - if(this.verboseMemoryLeak){ - errorMsg += ' Event name: %s.'; - console.error(errorMsg, count, eventName); - } else { - console.error(errorMsg, count); - } - - if (console.trace){ - console.trace(); - } - } - - function EventEmitter(conf) { - this._events = {}; - this.newListener = false; - this.verboseMemoryLeak = false; - configure.call(this, conf); - } - EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property - - // - // 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]; - } - } - - 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)); - } +(function (process){ +/*! + * EventEmitter2 + * https://github.com/hij1nx/EventEmitter2 + * + * Copyright (c) 2013 hij1nx + * Licensed under the MIT license. + */ +;!function(undefined) { + + 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); + } + } + + function configure(conf) { + if (conf) { + this._conf = conf; + + conf.delimiter && (this.delimiter = conf.delimiter); + this._maxListeners = conf.maxListeners !== undefined ? conf.maxListeners : defaultMaxListeners; + + conf.wildcard && (this.wildcard = conf.wildcard); + conf.newListener && (this.newListener = conf.newListener); + conf.verboseMemoryLeak && (this.verboseMemoryLeak = conf.verboseMemoryLeak); + + if (this.wildcard) { + this.listenerTree = {}; + } + } else { + this._maxListeners = defaultMaxListeners; + } + } + + function logPossibleMemoryLeak(count, eventName) { + var errorMsg = '(node) warning: possible EventEmitter memory ' + + 'leak detected. ' + count + ' listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.'; + + if(this.verboseMemoryLeak){ + errorMsg += ' Event name: ' + eventName + '.'; + } + + if(typeof process !== 'undefined' && process.emitWarning){ + var e = new Error(errorMsg); + e.name = 'MaxListenersExceededWarning'; + e.emitter = this; + e.count = count; + process.emitWarning(e); + } else { + console.error(errorMsg); + + if (console.trace){ + console.trace(); + } + } + } + + function EventEmitter(conf) { + this._events = {}; + this.newListener = false; + this.verboseMemoryLeak = false; + configure.call(this, conf); + } + EventEmitter.EventEmitter2 = EventEmitter; // backwards compatibility for exporting EventEmitter property + + // + // 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]; + } + } + + 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)); + } + + 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)); + } + + 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); + } + + 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); + } + + // 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); + } + } + + return listeners; + } + + function growListenerTree(type, listener) { + + type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + + // + // 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; + } + } + + var tree = this.listenerTree; + var name = type.shift(); + + while (name !== undefined) { + + if (!tree[name]) { + tree[name] = {}; + } + + tree = tree[name]; + + if (type.length === 0) { + + if (!tree._listeners) { + tree._listeners = listener; + } + else { + if (typeof tree._listeners === 'function') { + tree._listeners = [tree._listeners]; + } + + tree._listeners.push(listener); + + if ( + !tree._listeners.warned && + this._maxListeners > 0 && + tree._listeners.length > this._maxListeners + ) { + tree._listeners.warned = true; + logPossibleMemoryLeak.call(this, tree._listeners.length, name); + } + } + return true; + } + name = type.shift(); + } + return true; + } + + // 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. + + EventEmitter.prototype.delimiter = '.'; + + EventEmitter.prototype.setMaxListeners = function(n) { + if (n !== undefined) { + this._maxListeners = n; + if (!this._conf) this._conf = {}; + this._conf.maxListeners = n; + } + }; + + EventEmitter.prototype.event = ''; + + + EventEmitter.prototype.once = function(event, fn) { + return this._once(event, fn, false); + }; + + EventEmitter.prototype.prependOnceListener = function(event, fn) { + return this._once(event, fn, true); + }; + + EventEmitter.prototype._once = function(event, fn, prepend) { + this._many(event, 1, fn, prepend); + return this; + }; + + EventEmitter.prototype.many = function(event, ttl, fn) { + return this._many(event, ttl, fn, false); + } + + EventEmitter.prototype.prependMany = function(event, ttl, fn) { + return this._many(event, ttl, fn, true); + } + + EventEmitter.prototype._many = function(event, ttl, fn, prepend) { + var self = this; + + if (typeof fn !== 'function') { + throw new Error('many only accepts instances of Function'); + } + + function listener() { + if (--ttl === 0) { + self.off(event, listener); + } + return fn.apply(this, arguments); + } + + listener._origin = fn; + + this._on(event, listener, prepend); + + return self; + }; + + EventEmitter.prototype.emit = function() { + + this._events || init.call(this); + + var type = arguments[0]; + + if (type === 'newListener' && !this.newListener) { + if (!this._events.newListener) { + return false; + } + } + + var al = arguments.length; + var args,l,i,j; + var handler; + + if (this._all && this._all.length) { + handler = this._all.slice(); + if (al > 3) { + args = new Array(al); + for (j = 0; j < al; j++) args[j] = arguments[j]; + } + + for (i = 0, l = handler.length; i < l; i++) { + this.event = type; + switch (al) { + case 1: + handler[i].call(this, type); + break; + case 2: + handler[i].call(this, type, arguments[1]); + break; + case 3: + handler[i].call(this, type, arguments[1], arguments[2]); + break; + default: + handler[i].apply(this, args); + } + } + } + + 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]; + if (typeof handler === 'function') { + this.event = type; + switch (al) { + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + default: + args = new Array(al - 1); + for (j = 1; j < al; j++) args[j - 1] = arguments[j]; + handler.apply(this, args); + } + return true; + } else if (handler) { + // need to make copy of handlers because list can change in the middle + // of emit call + handler = handler.slice(); + } + } + + if (handler && handler.length) { + if (al > 3) { + args = new Array(al - 1); + for (j = 1; j < al; j++) args[j - 1] = arguments[j]; + } + for (i = 0, l = handler.length; i < l; i++) { + this.event = type; + switch (al) { + case 1: + handler[i].call(this); + break; + case 2: + handler[i].call(this, arguments[1]); + break; + case 3: + handler[i].call(this, arguments[1], arguments[2]); + break; + default: + handler[i].apply(this, args); + } + } + return true; + } else if (!this._all && type === 'error') { + if (arguments[1] instanceof Error) { + throw arguments[1]; // Unhandled 'error' event + } else { + throw new Error("Uncaught, unspecified 'error' event."); + } + return false; + } + + return !!this._all; + }; + + EventEmitter.prototype.emitAsync = function() { + + this._events || init.call(this); + + var type = arguments[0]; + + if (type === 'newListener' && !this.newListener) { + if (!this._events.newListener) { return Promise.resolve([false]); } + } + + var promises= []; + + var al = arguments.length; + var args,l,i,j; + var handler; + + if (this._all) { + if (al > 3) { + args = new Array(al); + for (j = 1; j < al; j++) args[j] = arguments[j]; + } + for (i = 0, l = this._all.length; i < l; i++) { + this.event = type; + switch (al) { + case 1: + promises.push(this._all[i].call(this, type)); + break; + case 2: + promises.push(this._all[i].call(this, type, arguments[1])); + break; + case 3: + promises.push(this._all[i].call(this, type, arguments[1], arguments[2])); + break; + default: + promises.push(this._all[i].apply(this, args)); + } + } + } + + 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]; + } + + if (typeof handler === 'function') { + this.event = type; + switch (al) { + case 1: + promises.push(handler.call(this)); + break; + case 2: + promises.push(handler.call(this, arguments[1])); + break; + case 3: + promises.push(handler.call(this, arguments[1], arguments[2])); + break; + default: + args = new Array(al - 1); + for (j = 1; j < al; j++) args[j - 1] = arguments[j]; + promises.push(handler.apply(this, args)); + } + } else if (handler && handler.length) { + handler = handler.slice(); + if (al > 3) { + args = new Array(al - 1); + for (j = 1; j < al; j++) args[j - 1] = arguments[j]; + } + for (i = 0, l = handler.length; i < l; i++) { + this.event = type; + switch (al) { + case 1: + promises.push(handler[i].call(this)); + break; + case 2: + promises.push(handler[i].call(this, arguments[1])); + break; + case 3: + promises.push(handler[i].call(this, arguments[1], arguments[2])); + break; + default: + promises.push(handler[i].apply(this, args)); + } + } + } else if (!this._all && type === 'error') { + if (arguments[1] instanceof Error) { + return Promise.reject(arguments[1]); // Unhandled 'error' event + } else { + return Promise.reject("Uncaught, unspecified 'error' event."); + } + } + + return Promise.all(promises); + }; + + EventEmitter.prototype.on = function(type, listener) { + return this._on(type, listener, false); + }; + + EventEmitter.prototype.prependListener = function(type, listener) { + return this._on(type, listener, true); + }; + + EventEmitter.prototype.onAny = function(fn) { + return this._onAny(fn, false); + }; + + EventEmitter.prototype.prependAny = function(fn) { + return this._onAny(fn, true); + }; + + EventEmitter.prototype.addListener = EventEmitter.prototype.on; + + EventEmitter.prototype._onAny = function(fn, prepend){ + if (typeof fn !== 'function') { + throw new Error('onAny only accepts instances of Function'); + } + + if (!this._all) { + this._all = []; + } + + // Add the function to the event listener collection. + if(prepend){ + this._all.unshift(fn); + }else{ + this._all.push(fn); + } + + return this; + } + + EventEmitter.prototype._on = function(type, listener, prepend) { + if (typeof type === 'function') { + this._onAny(type, listener); + return this; + } + + if (typeof listener !== 'function') { + throw new Error('on only accepts instances of Function'); + } + this._events || init.call(this); + + // To avoid recursion in the case that type == "newListeners"! Before + // adding it to the listeners, first emit "newListeners". + this.emit('newListener', type, listener); + + if (this.wildcard) { + growListenerTree.call(this, type, listener); + return this; + } + + 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') { + // Change to array. + this._events[type] = [this._events[type]]; + } + + // If we've already got an array, just add + if(prepend){ + this._events[type].unshift(listener); + }else{ + this._events[type].push(listener); + } + + // Check for listener leak + if ( + !this._events[type].warned && + this._maxListeners > 0 && + this._events[type].length > this._maxListeners + ) { + this._events[type].warned = true; + logPossibleMemoryLeak.call(this, this._events[type].length, type); + } + } + + return this; + } + + EventEmitter.prototype.off = function(type, listener) { + if (typeof listener !== 'function') { + throw new Error('removeListener only takes instances of Function'); + } + + 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}); + } + + for (var iLeaf=0; iLeaf 0) { + recursivelyGarbageCollect(root[key]); + } + if (Object.keys(obj).length === 0) { + delete root[key]; + } + } + } + recursivelyGarbageCollect(this.listenerTree); + + return this; + }; + + 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); + this.emit("removeListenerAny", fn); + return this; + } + } + } else { + fns = this._all; + for(i = 0, l = fns.length; i < l; i++) + this.emit("removeListenerAny", fns[i]); + this._all = []; + } + return this; + }; + + EventEmitter.prototype.removeListener = EventEmitter.prototype.off; + + EventEmitter.prototype.removeAllListeners = function(type) { + if (arguments.length === 0) { + !this._events || init.call(this); + return this; + } + + if (this.wildcard) { + var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); + var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); + + for (var iLeaf=0; iLeaf 0 && - tree._listeners.length > this._maxListeners - ) { - tree._listeners.warned = true; - logPossibleMemoryLeak.call(this, tree._listeners.length, name); - } - } - return true; - } - name = type.shift(); - } - return true; - } - - // 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. - - EventEmitter.prototype.delimiter = '.'; - - EventEmitter.prototype.setMaxListeners = function(n) { - if (n !== undefined) { - this._maxListeners = n; - if (!this._conf) this._conf = {}; - this._conf.maxListeners = n; - } - }; - - EventEmitter.prototype.event = ''; - - - EventEmitter.prototype.once = function(event, fn) { - return this._once(event, fn, false); - }; - - EventEmitter.prototype.prependOnceListener = function(event, fn) { - return this._once(event, fn, true); - }; - - EventEmitter.prototype._once = function(event, fn, prepend) { - this._many(event, 1, fn, prepend); - return this; - }; - - EventEmitter.prototype.many = function(event, ttl, fn) { - return this._many(event, ttl, fn, false); - } - - EventEmitter.prototype.prependMany = function(event, ttl, fn) { - return this._many(event, ttl, fn, true); - } - - EventEmitter.prototype._many = function(event, ttl, fn, prepend) { - var self = this; - - if (typeof fn !== 'function') { - throw new Error('many only accepts instances of Function'); - } - - function listener() { - if (--ttl === 0) { - self.off(event, listener); - } - return fn.apply(this, arguments); - } - - listener._origin = fn; - - this._on(event, listener, prepend); - - return self; - }; - - EventEmitter.prototype.emit = function() { - - this._events || init.call(this); - - var type = arguments[0]; - - if (type === 'newListener' && !this.newListener) { - if (!this._events.newListener) { - return false; - } - } - - var al = arguments.length; - var args,l,i,j; - var handler; - - if (this._all && this._all.length) { - handler = this._all.slice(); - if (al > 3) { - args = new Array(al); - for (j = 0; j < al; j++) args[j] = arguments[j]; - } - - for (i = 0, l = handler.length; i < l; i++) { - this.event = type; - switch (al) { - case 1: - handler[i].call(this, type); - break; - case 2: - handler[i].call(this, type, arguments[1]); - break; - case 3: - handler[i].call(this, type, arguments[1], arguments[2]); - break; - default: - handler[i].apply(this, args); - } - } - } - - 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]; - if (typeof handler === 'function') { - this.event = type; - switch (al) { - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - default: - args = new Array(al - 1); - for (j = 1; j < al; j++) args[j - 1] = arguments[j]; - handler.apply(this, args); - } - return true; - } else if (handler) { - // need to make copy of handlers because list can change in the middle - // of emit call - handler = handler.slice(); - } - } - - if (handler && handler.length) { - if (al > 3) { - args = new Array(al - 1); - for (j = 1; j < al; j++) args[j - 1] = arguments[j]; - } - for (i = 0, l = handler.length; i < l; i++) { - this.event = type; - switch (al) { - case 1: - handler[i].call(this); - break; - case 2: - handler[i].call(this, arguments[1]); - break; - case 3: - handler[i].call(this, arguments[1], arguments[2]); - break; - default: - handler[i].apply(this, args); - } - } - return true; - } else if (!this._all && type === 'error') { - if (arguments[1] instanceof Error) { - throw arguments[1]; // Unhandled 'error' event - } else { - throw new Error("Uncaught, unspecified 'error' event."); - } - return false; - } - - return !!this._all; - }; - - EventEmitter.prototype.emitAsync = function() { - - this._events || init.call(this); - - var type = arguments[0]; - - if (type === 'newListener' && !this.newListener) { - if (!this._events.newListener) { return Promise.resolve([false]); } } - - var promises= []; - - var al = arguments.length; - var args,l,i,j; - var handler; - - if (this._all) { - if (al > 3) { - args = new Array(al); - for (j = 1; j < al; j++) args[j] = arguments[j]; - } - for (i = 0, l = this._all.length; i < l; i++) { - this.event = type; - switch (al) { - case 1: - promises.push(this._all[i].call(this, type)); - break; - case 2: - promises.push(this._all[i].call(this, type, arguments[1])); - break; - case 3: - promises.push(this._all[i].call(this, type, arguments[1], arguments[2])); - break; - default: - promises.push(this._all[i].apply(this, args)); - } - } - } - - if (this.wildcard) { - handler = []; - var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); - searchListenerTree.call(this, handler, ns, this.listenerTree, 0); + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); } else { - handler = this._events[type]; - } - - if (typeof handler === 'function') { - this.event = type; - switch (al) { - case 1: - promises.push(handler.call(this)); - break; - case 2: - promises.push(handler.call(this, arguments[1])); - break; - case 3: - promises.push(handler.call(this, arguments[1], arguments[2])); - break; - default: - args = new Array(al - 1); - for (j = 1; j < al; j++) args[j - 1] = arguments[j]; - promises.push(handler.apply(this, args)); - } - } else if (handler && handler.length) { - handler = handler.slice(); - if (al > 3) { - args = new Array(al - 1); - for (j = 1; j < al; j++) args[j - 1] = arguments[j]; - } - for (i = 0, l = handler.length; i < l; i++) { - this.event = type; - switch (al) { - case 1: - promises.push(handler[i].call(this)); - break; - case 2: - promises.push(handler[i].call(this, arguments[1])); - break; - case 3: - promises.push(handler[i].call(this, arguments[1], arguments[2])); - break; - default: - promises.push(handler[i].apply(this, args)); - } - } - } else if (!this._all && type === 'error') { - if (arguments[1] instanceof Error) { - return Promise.reject(arguments[1]); // Unhandled 'error' event - } else { - return Promise.reject("Uncaught, unspecified 'error' event."); - } - } - - return Promise.all(promises); - }; - - EventEmitter.prototype.on = function(type, listener) { - return this._on(type, listener, false); - }; - - EventEmitter.prototype.prependListener = function(type, listener) { - return this._on(type, listener, true); - }; - - EventEmitter.prototype.onAny = function(fn) { - return this._onAny(fn, false); - }; - - EventEmitter.prototype.prependAny = function(fn) { - return this._onAny(fn, true); - }; - - EventEmitter.prototype.addListener = EventEmitter.prototype.on; - - EventEmitter.prototype._onAny = function(fn, prepend){ - if (typeof fn !== 'function') { - throw new Error('onAny only accepts instances of Function'); - } - - if (!this._all) { - this._all = []; + queueIndex = -1; } - - // Add the function to the event listener collection. - if(prepend){ - this._all.unshift(fn); - }else{ - this._all.push(fn); - } - - return this; - } - - EventEmitter.prototype._on = function(type, listener, prepend) { - if (typeof type === 'function') { - this._onAny(type, listener); - return this; - } - - if (typeof listener !== 'function') { - throw new Error('on only accepts instances of Function'); - } - this._events || init.call(this); - - // To avoid recursion in the case that type == "newListeners"! Before - // adding it to the listeners, first emit "newListeners". - this.emit('newListener', type, listener); - - if (this.wildcard) { - growListenerTree.call(this, type, listener); - return this; - } - - 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') { - // Change to array. - this._events[type] = [this._events[type]]; - } - - // If we've already got an array, just add - if(prepend){ - this._events[type].unshift(listener); - }else{ - this._events[type].push(listener); - } - - // Check for listener leak - if ( - !this._events[type].warned && - this._maxListeners > 0 && - this._events[type].length > this._maxListeners - ) { - this._events[type].warned = true; - logPossibleMemoryLeak.call(this, this._events[type].length, type); - } - } - - return this; - } - - EventEmitter.prototype.off = function(type, listener) { - if (typeof listener !== 'function') { - throw new Error('removeListener only takes instances of Function'); - } - - 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}); - } - - for (var iLeaf=0; iLeaf 0) { - recursivelyGarbageCollect(root[key]); - } - if (Object.keys(obj).length === 0) { - delete root[key]; - } - } } - recursivelyGarbageCollect(this.listenerTree); + var timeout = runTimeout(cleanUpNextTick); + draining = true; - return this; - }; - - 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); - this.emit("removeListenerAny", fn); - return this; + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + if (currentQueue) { + currentQueue[queueIndex].run(); + } } - } - } else { - fns = this._all; - for(i = 0, l = fns.length; i < l; i++) - this.emit("removeListenerAny", fns[i]); - this._all = []; - } - return this; - }; - - EventEmitter.prototype.removeListener = EventEmitter.prototype.off; - - EventEmitter.prototype.removeAllListeners = function(type) { - if (arguments.length === 0) { - !this._events || init.call(this); - return this; + queueIndex = -1; + len = queue.length; } + currentQueue = null; + draining = false; + runClearTimeout(timeout); +} - if (this.wildcard) { - var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); - var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); - - for (var iLeaf=0; iLeaf 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } } - else { - return []; + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + runTimeout(drainQueue); } +}; - }; +// v8 likes predictible objects +function Item(fun, array) { + this.fun = fun; + this.array = array; +} +Item.prototype.run = function () { + this.fun.apply(null, this.array); +}; +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; - if (typeof define === 'function' && define.amd) { - // AMD. Register as an anonymous module. - define(function() { - return EventEmitter; - }); - } else if (typeof exports === 'object') { - // CommonJS - module.exports = EventEmitter; - } - else { - // Browser global. - window.EventEmitter2 = EventEmitter; - } -}(); +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; -},{}],4:[function(require,module,exports){ +},{}],5:[function(require,module,exports){ module.exports = distance; function distance(a, b) { @@ -946,7 +1143,7 @@ function distance(a, b) { } -},{}],5:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ module.exports = suggestDictionary; var distance = require('./levenstein_distance'); @@ -969,7 +1166,7 @@ function suggestDictionary(dict, opts) { suggestDictionary.distance = distance; -},{"./levenstein_distance":4}],6:[function(require,module,exports){ +},{"./levenstein_distance":5}],7:[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(' '); @@ -978,7 +1175,7 @@ module.exports = list.map(function(eventName) { return 'ng' + eventName.charAt(0).toUpperCase() + eventName.substr(1); }); -},{}],7:[function(require,module,exports){ +},{}],8:[function(require,module,exports){ 'use strict'; module.exports = function summarizeModel (model) { @@ -1015,7 +1212,7 @@ function summarizeProperty (obj) { obj; } -},{}],8:[function(require,module,exports){ +},{}],9:[function(require,module,exports){ var MODULE_NAME = 'Modules'; module.exports = function(modules) { @@ -1024,7 +1221,7 @@ module.exports = function(modules) { }); }; -},{}],9:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ var modData = require('./moduleData'); MODULE_NAME = 'Modules', SEVERITY_WARNING = 2; @@ -1046,14 +1243,14 @@ module.exports = function() { return multiLoaded; }; -},{"./moduleData":16}],10:[function(require,module,exports){ +},{"./moduleData":17}],11:[function(require,module,exports){ var modData = require('./moduleData'); module.exports = function(moduleName, getCreated) { return (getCreated)? modData.createdModules[moduleName] : modData.loadedModules[moduleName]; }; -},{"./moduleData":16}],11:[function(require,module,exports){ +},{"./moduleData":17}],12:[function(require,module,exports){ var MODULE_NAME = 'Modules', SEVERITY_ERROR = 1; module.exports = function(attrs, ngAppFound) { @@ -1067,7 +1264,7 @@ var MODULE_NAME = 'Modules', -},{}],12:[function(require,module,exports){ +},{}],13:[function(require,module,exports){ var getModule = require('./getModule'), dictionary = Object.keys(require('./moduleData').createdModules), suggest = require('suggest-it')(dictionary), @@ -1088,7 +1285,7 @@ module.exports = function(loadedModules) { return undeclaredModules; }; -},{"./getModule":10,"./moduleData":16,"suggest-it":5}],13:[function(require,module,exports){ +},{"./getModule":11,"./moduleData":17,"suggest-it":6}],14:[function(require,module,exports){ var getModule = require('./getModule'); var IGNORED = ['ngHintControllers', 'ngHintDirectives', 'ngHintDom', 'ngHintEvents', @@ -1109,7 +1306,7 @@ module.exports = function(createdModules) { return unusedModules; }; -},{"./getModule":10}],14:[function(require,module,exports){ +},{"./getModule":11}],15:[function(require,module,exports){ var MODULE_NAME = 'Modules', SEVERITY_SUGGESTION = 3; @@ -1132,7 +1329,7 @@ module.exports = function(str) { return true; }; -},{}],15:[function(require,module,exports){ +},{}],16:[function(require,module,exports){ var normalizeAttribute = require('./normalizeAttribute'); module.exports = function(attrs) { @@ -1144,14 +1341,14 @@ module.exports = function(attrs) { } }; -},{"./normalizeAttribute":18}],16:[function(require,module,exports){ +},{"./normalizeAttribute":19}],17:[function(require,module,exports){ module.exports = { createdModules: {}, createdMulti: {}, loadedModules: {} }; -},{}],17:[function(require,module,exports){ +},{}],18:[function(require,module,exports){ var modData = require('./moduleData'), getModule = require('./getModule'); @@ -1161,12 +1358,12 @@ module.exports = function() { } }; -},{"./getModule":10,"./moduleData":16}],18:[function(require,module,exports){ +},{"./getModule":11,"./moduleData":17}],19:[function(require,module,exports){ module.exports = function(attribute) { return attribute.replace(/^(?:data|x)[-_:]/, '').replace(/[:_]/g, '-'); }; -},{}],19:[function(require,module,exports){ +},{}],20:[function(require,module,exports){ var display = require('./display'), formatMultiLoaded = require('./formatMultiLoaded'), getUnusedModules = require('./getUnusedModules'), @@ -1189,7 +1386,7 @@ module.exports = function() { } }; -},{"./display":8,"./formatMultiLoaded":9,"./getUndeclaredModules":12,"./getUnusedModules":13,"./moduleData":16,"./ngViewNoNgRoute":17}],20:[function(require,module,exports){ +},{"./display":9,"./formatMultiLoaded":10,"./getUndeclaredModules":13,"./getUnusedModules":14,"./moduleData":17,"./ngViewNoNgRoute":18}],21:[function(require,module,exports){ var modData = require('./moduleData'); module.exports = function(module, isNgAppMod) { @@ -1205,7 +1402,7 @@ module.exports = function(module, isNgAppMod) { } }; -},{"./moduleData":16}],21:[function(require,module,exports){ +},{"./moduleData":17}],22:[function(require,module,exports){ var getNgAppMod = require('./getNgAppMod'), inAttrsOrClasses = require('./inAttrsOrClasses'), storeDependencies = require('./storeDependencies'), @@ -1241,7 +1438,7 @@ module.exports = function(doms) { } }; -},{"./getNgAppMod":11,"./inAttrsOrClasses":15,"./moduleData":16,"./storeDependencies":20}],22:[function(require,module,exports){ +},{"./getNgAppMod":12,"./inAttrsOrClasses":16,"./moduleData":17,"./storeDependencies":21}],23:[function(require,module,exports){ var storeDependencies = require('./storeDependencies'); var seen = []; @@ -1257,7 +1454,69 @@ var storeUsedModules = module.exports = function(module, modules){ }); } }; -},{"./storeDependencies":20}],23:[function(require,module,exports){ +},{"./storeDependencies":21}],24:[function(require,module,exports){ +'use strict'; + +var MODULE_NAME = 'Components'; + +var SUPPORTED_COMPONENT_OPTIONS = [ + 'bindings', + 'controller', + 'controllerAs', + 'require', + 'template', + 'templateUrl', + 'transclude' +]; + +var originalModule = angular.module; + + +angular.module = function moduleDecorator() { + var module = originalModule.apply(this, arguments); + var originalComponent = module.component; + module.component = function componentDecorator(componentName, componentOptions) { + verifyComponent(componentName, componentOptions); + return originalComponent.apply(this, arguments); + }; + + return module +}; + +function verifyComponent(componentName, componentOptions) { + verifyComponentName(componentName); + verifyComponentOptions(componentName, componentOptions); +} +function verifyComponentName(componentName){ + if(typeof componentName === 'string'){ + if(componentName.slice(0,2).toLowerCase() === 'ng'){ + sendMessageForBadComponentName(componentName); + } + } +} + +function sendMessageForBadComponentName(componentName){ + angular.hint.emit(MODULE_NAME, ':rename Consider renaming `' + componentName + '`because only angular directive should start with ng.'); +} + +function verifyComponentOptions(componentName, componentOptions) { + Object.keys(componentOptions).forEach(function(key){ + if(!isSupportedComponentOption(key)) { + sendMessageForUnSupportedComponentOption(componentName, key); + } + }); +} + +function isSupportedComponentOption(option){ + return (SUPPORTED_COMPONENT_OPTIONS.indexOf(option) >= 0); +}; + +function sendMessageForUnSupportedComponentOption(componentName, componentOption){ + angular.hint.emit(MODULE_NAME, ':`' + componentOption + '` option is not a supported option for `' + componentName + '`component.'); +} + + +},{}],25:[function(require,module,exports){ 'use strict'; var MODULE_NAME = 'Controllers', @@ -1382,7 +1641,94 @@ angular.module = function() { return module; }; -},{}],24:[function(require,module,exports){ +},{}],26:[function(require,module,exports){ +'use strict'; + + +var MODULE_NAME = 'Directives'; + +var SUPPORTED_DIRECTIVE_OPTIONS = [ + 'multiElement', + 'priority', + 'terminal', + 'scope', + 'bindToController', + 'controller', + 'require', + 'controllerAs', + 'restrict', + 'templateNamespace', + 'template', + 'templateUrl', + 'replace', + 'transclude', + 'compile', + 'link' +]; + +var originalModule = angular.module; + + +angular.module = function moduleDecorator(){ + var module = originalModule.apply(this, arguments); + var originalDirective = module.directive; + + module.directive = function directiveDecorator(directiveName, options) { + var directiveFactory; + if (typeof directiveName === 'string') { + if (Array.isArray(options) && options.length > 0) { + directiveFactory = options[options.length - 1]; + } else { + directiveFactory = options; + } + verifyDirective(directiveName, directiveFactory); + } else if (typeof directiveName === 'object') { + Object.keys(directiveName).forEach(function (key) { + directiveFactory = directiveName[key]; + verifyDirective(key, directiveFactory); + }); + } + return originalDirective.apply(this, arguments); + }; + + return module; +}; + + +function verifyDirective(directiveName, directiveFactory) { + verifyDirectiveName(directiveName); + verifyDirectiveOptions(directiveName, directiveFactory); +} +function verifyDirectiveName(directiveName){ + if(typeof directiveName === 'string'){ + if(directiveName.slice(0,2).toLowerCase() === 'ng'){ + sendMessageForBadDirectiveName(directiveName); + } + } +} + +function sendMessageForBadDirectiveName(directiveName){ + angular.hint.emit(MODULE_NAME, ':rename Consider renaming `' + directiveName + '`because only angular directive should start with ng.'); +} + +function verifyDirectiveOptions(directiveName, directiveFactory) { + var options = directiveFactory.call(); + Object.keys(options).forEach(function(key){ + if(!isSupportedDirectiveOption(key)) { + sendMessageForUnSupportedDirectiveOption(directiveName, key); + } + }); +} + +function isSupportedDirectiveOption(option){ + return (SUPPORTED_DIRECTIVE_OPTIONS.indexOf(option) >= 0); +}; + +function sendMessageForUnSupportedDirectiveOption(directiveName, directiveOption){ + angular.hint.emit(MODULE_NAME, ':`' + directiveOption + '` option is not a supported option for `' + directiveName + '`directive.'); +} + +},{}],27:[function(require,module,exports){ 'use strict'; /** @@ -1490,7 +1836,7 @@ function ngEventDirectivesDecorator(ngEventAttrName) { } } -},{"../lib/event-directives":6}],25:[function(require,module,exports){ +},{"../lib/event-directives":7}],28:[function(require,module,exports){ 'use strict'; /** @@ -1504,7 +1850,7 @@ angular.hint = new EventEmitter2({ wildcard: true, delimiter: ':' }); -},{"eventemitter2":3}],26:[function(require,module,exports){ +},{"eventemitter2":3}],29:[function(require,module,exports){ 'use strict'; var getModule = require('./angular-hint-modules/getModule'), @@ -1552,7 +1898,7 @@ angular.module('ngHintModules', []).config(function() { start(); }); -},{"./angular-hint-modules/getModule":10,"./angular-hint-modules/hasNameSpace":14,"./angular-hint-modules/moduleData":16,"./angular-hint-modules/start":19,"./angular-hint-modules/storeNgAppAndView":21,"./angular-hint-modules/storeUsedModules":22}],27:[function(require,module,exports){ +},{"./angular-hint-modules/getModule":11,"./angular-hint-modules/hasNameSpace":15,"./angular-hint-modules/moduleData":17,"./angular-hint-modules/start":20,"./angular-hint-modules/storeNgAppAndView":22,"./angular-hint-modules/storeUsedModules":23}],30:[function(require,module,exports){ 'use strict'; var summarize = require('../lib/summarize-model'); @@ -1891,4 +2237,4 @@ function simpleExtend(dst, src) { return dst; } -},{"../lib/summarize-model":7,"debounce-on":2}]},{},[1]); +},{"../lib/summarize-model":8,"debounce-on":2}]},{},[1]); diff --git a/hint.js b/hint.js index 340b0682..3347881d 100644 --- a/hint.js +++ b/hint.js @@ -5,7 +5,9 @@ require('./src/modules/hintEmitter'); // Load angular hint modules require('./src/modules/controllers'); -// require('./src/modules/directives'); +require('./src/modules/directives'); +require('./src/modules/components'); + // require('./src/modules/dom'); require('./src/modules/events'); // require('./src/modules/interpolation'); diff --git a/src/modules/components.js b/src/modules/components.js new file mode 100644 index 00000000..1262d1bf --- /dev/null +++ b/src/modules/components.js @@ -0,0 +1,60 @@ +'use strict'; + +var MODULE_NAME = 'Components'; + +var SUPPORTED_COMPONENT_OPTIONS = [ + 'bindings', + 'controller', + 'controllerAs', + 'require', + 'template', + 'templateUrl', + 'transclude' +]; + +var originalModule = angular.module; + + +angular.module = function moduleDecorator() { + var module = originalModule.apply(this, arguments); + var originalComponent = module.component; + module.component = function componentDecorator(componentName, componentOptions) { + verifyComponent(componentName, componentOptions); + return originalComponent.apply(this, arguments); + }; + + return module +}; + +function verifyComponent(componentName, componentOptions) { + verifyComponentName(componentName); + verifyComponentOptions(componentName, componentOptions); +} +function verifyComponentName(componentName){ + if(typeof componentName === 'string'){ + if(componentName.slice(0,2).toLowerCase() === 'ng'){ + sendMessageForBadComponentName(componentName); + } + } +} + +function sendMessageForBadComponentName(componentName){ + angular.hint.emit(MODULE_NAME, ':rename Consider renaming `' + componentName + '`because only angular directive should start with ng.'); +} + +function verifyComponentOptions(componentName, componentOptions) { + Object.keys(componentOptions).forEach(function(key){ + if(!isSupportedComponentOption(key)) { + sendMessageForUnSupportedComponentOption(componentName, key); + } + }); +} + +function isSupportedComponentOption(option){ + return (SUPPORTED_COMPONENT_OPTIONS.indexOf(option) >= 0); +}; + +function sendMessageForUnSupportedComponentOption(componentName, componentOption){ + angular.hint.emit(MODULE_NAME, ':`' + componentOption + '` option is not a supported option for `' + componentName + '`component.'); +} + diff --git a/src/modules/directives.js b/src/modules/directives.js new file mode 100644 index 00000000..ad21af34 --- /dev/null +++ b/src/modules/directives.js @@ -0,0 +1,85 @@ +'use strict'; + + +var MODULE_NAME = 'Directives'; + +var SUPPORTED_DIRECTIVE_OPTIONS = [ + 'multiElement', + 'priority', + 'terminal', + 'scope', + 'bindToController', + 'controller', + 'require', + 'controllerAs', + 'restrict', + 'templateNamespace', + 'template', + 'templateUrl', + 'replace', + 'transclude', + 'compile', + 'link' +]; + +var originalModule = angular.module; + + +angular.module = function moduleDecorator(){ + var module = originalModule.apply(this, arguments); + var originalDirective = module.directive; + + module.directive = function directiveDecorator(directiveName, options) { + var directiveFactory; + if (typeof directiveName === 'string') { + if (Array.isArray(options) && options.length > 0) { + directiveFactory = options[options.length - 1]; + } else { + directiveFactory = options; + } + verifyDirective(directiveName, directiveFactory); + } else if (typeof directiveName === 'object') { + Object.keys(directiveName).forEach(function (key) { + directiveFactory = directiveName[key]; + verifyDirective(key, directiveFactory); + }); + } + return originalDirective.apply(this, arguments); + }; + + return module; +}; + + +function verifyDirective(directiveName, directiveFactory) { + verifyDirectiveName(directiveName); + verifyDirectiveOptions(directiveName, directiveFactory); +} +function verifyDirectiveName(directiveName){ + if(typeof directiveName === 'string'){ + if(directiveName.slice(0,2).toLowerCase() === 'ng'){ + sendMessageForBadDirectiveName(directiveName); + } + } +} + +function sendMessageForBadDirectiveName(directiveName){ + angular.hint.emit(MODULE_NAME, ':rename Consider renaming `' + directiveName + '`because only angular directive should start with ng.'); +} + +function verifyDirectiveOptions(directiveName, directiveFactory) { + var options = directiveFactory.call(); + Object.keys(options).forEach(function(key){ + if(!isSupportedDirectiveOption(key)) { + sendMessageForUnSupportedDirectiveOption(directiveName, key); + } + }); +} + +function isSupportedDirectiveOption(option){ + return (SUPPORTED_DIRECTIVE_OPTIONS.indexOf(option) >= 0); +}; + +function sendMessageForUnSupportedDirectiveOption(directiveName, directiveOption){ + angular.hint.emit(MODULE_NAME, ':`' + directiveOption + '` option is not a supported option for `' + directiveName + '`directive.'); +}