Comparing version 0.17.1 to 0.18.0
@@ -10,3 +10,9 @@ #!/usr/bin/env node | ||
process.stdin.pipe(concat({ encoding: "string" }, function(text) { | ||
exitCode = cli.execute(process.argv, text); | ||
try { | ||
exitCode = cli.execute(process.argv, text); | ||
} catch (ex) { | ||
console.error(ex.message); | ||
console.error(ex.stack); | ||
exitCode = 1; | ||
} | ||
})); | ||
@@ -13,0 +19,0 @@ } else { |
@@ -72,2 +72,3 @@ { | ||
"no-octal-escape": 2, | ||
"no-param-reassign": 0, | ||
"no-path-concat": 0, | ||
@@ -139,2 +140,3 @@ "no-plusplus": 0, | ||
"new-parens": 2, | ||
"newline-after-var": 0, | ||
"one-var": 0, | ||
@@ -152,2 +154,3 @@ "operator-assignment": [0, "always"], | ||
"space-before-blocks": [0, "always"], | ||
"space-before-function-paren": [0, "always"], | ||
"space-before-function-parentheses": [0, "always"], | ||
@@ -154,0 +157,0 @@ "space-in-brackets": [0, "never"], |
@@ -58,2 +58,3 @@ /** | ||
} catch (e) { | ||
debug("Error reading YAML file: " + filePath); | ||
e.message = "Cannot read config file: " + filePath + "\nError: " + e.message; | ||
@@ -140,2 +141,3 @@ throw e; | ||
for (i = 0; i < numFiles; i++) { | ||
localConfigFile = localConfigFiles[i]; | ||
@@ -264,3 +266,3 @@ localConfig = loadConfig(localConfigFile); | ||
debug("Constructing config for " + filePath); | ||
debug("Constructing config for " + (filePath ? filePath : "text")); | ||
@@ -267,0 +269,0 @@ config = this.cache[directory]; |
@@ -997,2 +997,3 @@ /** | ||
var scope = this.getScope(), | ||
specialScope = currentConfig.ecmaFeatures.globalReturn || currentConfig.ecmaFeatures.modules, | ||
variables, | ||
@@ -1002,2 +1003,7 @@ i, | ||
// Special Node.js scope means we need to start one level deeper | ||
if (scope.type === "global" && specialScope) { | ||
scope = scope.childScopes[0]; | ||
} | ||
do { | ||
@@ -1004,0 +1010,0 @@ variables = scope.variables; |
@@ -91,2 +91,16 @@ /** | ||
/** | ||
* Declares all relevant identifiers for module imports. | ||
* @param {ASTNode} node The AST node representing an import. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function declareImports(node) { | ||
declare([node.local.name]); | ||
if (node.imported && node.imported.name !== node.local.name) { | ||
declare([node.imported.name]); | ||
} | ||
} | ||
/** | ||
* Declares all relevant identifiers for classes. | ||
@@ -143,3 +157,5 @@ * @param {ASTNode} node The AST node representing a class. | ||
node.elements.forEach(function(element) { | ||
declarations.push(element.name); | ||
if (element) { | ||
declarations.push(element.name); | ||
} | ||
}); | ||
@@ -190,2 +206,6 @@ break; | ||
"ImportSpecifier": declareImports, | ||
"ImportDefaultSpecifier": declareImports, | ||
"ImportNamespaceSpecifier": declareImports, | ||
"BlockStatement": function(node) { | ||
@@ -192,0 +212,0 @@ var statements = node.body; |
/** | ||
* @fileoverview Rule to flag non-camelcased identifiers | ||
* @author Nicholas C. Zakas | ||
* @copyright 2015 Dieter Oberkofler. All rights reserved. | ||
*/ | ||
@@ -40,2 +41,9 @@ | ||
var options = context.options[0] || {}, | ||
properties = options.properties || ""; | ||
if (properties !== "always" && properties !== "never") { | ||
properties = "always"; | ||
} | ||
return { | ||
@@ -67,2 +75,14 @@ | ||
// Properties have their own rules | ||
} else if (node.parent.type === "Property") { | ||
// "never" check properties | ||
if (properties === "never") { | ||
return; | ||
} | ||
if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { | ||
report(node); | ||
} | ||
// Report anything that is underscored that isn't a CallExpression | ||
@@ -73,4 +93,5 @@ } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { | ||
} | ||
}; | ||
}; |
@@ -18,11 +18,14 @@ /** | ||
* Determines whether the current FunctionExpression node is a get, set, or | ||
* shorthand method in an object literal. | ||
* shorthand method in an object literal or a class. | ||
* @returns {boolean} True if the node is a get, set, or shorthand method. | ||
*/ | ||
function isObjectMethod() { | ||
function isObjectOrClassMethod() { | ||
var parent = context.getAncestors().pop(); | ||
return (parent.type === "Property" && ( | ||
parent.method || | ||
parent.kind === "get" || | ||
parent.kind === "set" | ||
return (parent.type === "MethodDefinition" || ( | ||
parent.type === "Property" && ( | ||
parent.method || | ||
parent.kind === "get" || | ||
parent.kind === "set" | ||
) | ||
)); | ||
@@ -36,3 +39,3 @@ } | ||
if (!name && !isObjectMethod()) { | ||
if (!name && !isObjectOrClassMethod()) { | ||
context.report(node, "Missing function expression name."); | ||
@@ -39,0 +42,0 @@ } |
@@ -422,3 +422,3 @@ /** | ||
if (node.loc.start.column === children[0].loc.start.column) { | ||
if (children.length && node.loc.start.column === children[0].loc.start.column) { | ||
indents = 0; | ||
@@ -425,0 +425,0 @@ } |
@@ -23,21 +23,2 @@ /** | ||
/** | ||
* Gets an object literal property's key as the identifier name or string value. | ||
* @param {ASTNode} property Property node whose key to retrieve. | ||
* @returns {string} The property's key. | ||
*/ | ||
function getKey(property) { | ||
return property.key.name || property.key.value; | ||
} | ||
/** | ||
* Gets the number of characters in a key, including quotes around string keys. | ||
* @param {ASTNode} property Property of on object literal. | ||
* @returns {int} Width of the key, including string quotes where present. | ||
*/ | ||
function getKeyWidth(property) { | ||
var key = property.key; | ||
return (key.type === "Identifier" ? key.name : key.raw).length; | ||
} | ||
/** | ||
* Gets the last element of an array. | ||
@@ -91,4 +72,4 @@ * @param {Array} arr An array. | ||
var messages = { | ||
key: "{{error}} space after key \"{{key}}\".", | ||
value: "{{error}} space before value for key \"{{key}}\"." | ||
key: "{{error}} space after {{computed}}key \"{{key}}\".", | ||
value: "{{error}} space before value for {{computed}}key \"{{key}}\"." | ||
}; | ||
@@ -113,17 +94,14 @@ | ||
/** | ||
* Gets the whitespace around the colon in an object literal property. | ||
* @param {ASTNode} property Property node from an object literal. | ||
* @returns {Object} Whitespace before and after the property's colon. | ||
* Gets an object literal property's key as the identifier name or string value. | ||
* @param {ASTNode} property Property node whose key to retrieve. | ||
* @returns {string} The property's key. | ||
*/ | ||
function getPropertyWhitespace(property) { | ||
var whitespace = /^(\s*):(\s*)/.exec(context.getSource().slice( | ||
property.key.range[1], property.value.range[0] | ||
)); | ||
function getKey(property) { | ||
var key = property.key; | ||
if (whitespace) { | ||
return { | ||
beforeColon: whitespace[1], | ||
afterColon: whitespace[2] | ||
}; | ||
if (property.computed) { | ||
return context.getSource().slice(key.range[0], key.range[1]); | ||
} | ||
return property.key.name || property.key.value; | ||
} | ||
@@ -149,2 +127,3 @@ | ||
error: diff > 0 ? "Extra" : "Missing", | ||
computed: property.computed ? "computed " : "", | ||
key: getKey(property) | ||
@@ -156,2 +135,49 @@ }); | ||
/** | ||
* Gets the number of characters in a key, including quotes around string | ||
* keys and braces around computed property keys. | ||
* @param {ASTNode} property Property of on object literal. | ||
* @returns {int} Width of the key. | ||
*/ | ||
function getKeyWidth(property) { | ||
var key = property.key, | ||
startToken, endToken; | ||
// [computed]: value | ||
if (property.computed) { | ||
startToken = context.getTokenBefore(key); | ||
endToken = context.getTokenAfter(key); | ||
return endToken.range[1] - startToken.range[0]; | ||
} | ||
// name: value | ||
if (key.type === "Identifier") { | ||
return key.name.length; | ||
} | ||
// "literal": value | ||
// 42: value | ||
if (key.type === "Literal") { | ||
return key.raw.length; | ||
} | ||
} | ||
/** | ||
* Gets the whitespace around the colon in an object literal property. | ||
* @param {ASTNode} property Property node from an object literal. | ||
* @returns {Object} Whitespace before and after the property's colon. | ||
*/ | ||
function getPropertyWhitespace(property) { | ||
var whitespace = /(\s*):(\s*)/.exec(context.getSource().slice( | ||
property.key.range[1], property.value.range[0] | ||
)); | ||
if (whitespace) { | ||
return { | ||
beforeColon: whitespace[1], | ||
afterColon: whitespace[2] | ||
}; | ||
} | ||
} | ||
/** | ||
* Verifies correct vertical alignment of a group of properties. | ||
@@ -158,0 +184,0 @@ * @param {ASTNode[]} properties List of Property AST nodes. |
@@ -11,11 +11,12 @@ /** | ||
var CAPS_ALLOWED = [ | ||
"Object", | ||
"Array", | ||
"Boolean", | ||
"Date", | ||
"Error", | ||
"Function", | ||
"Number", | ||
"Object", | ||
"RegExp", | ||
"String", | ||
"Boolean", | ||
"Date", | ||
"Array", | ||
"Symbol", | ||
"RegExp" | ||
"Symbol" | ||
]; | ||
@@ -143,3 +144,3 @@ | ||
return node.callee.object.type === "Identifier" && | ||
node.callee.object.name === "Date"; | ||
node.callee.object.name === "Date"; | ||
} | ||
@@ -146,0 +147,0 @@ return false; |
@@ -39,3 +39,3 @@ /** | ||
case "AssignmentExpression": | ||
return isConstant(node.right); | ||
return (node.operator === "=") && isConstant(node.right); | ||
case "SequenceExpression": | ||
@@ -42,0 +42,0 @@ return isConstant(node.expressions[node.expressions.length - 1]); |
@@ -26,11 +26,41 @@ /** | ||
function checkParams(node) { | ||
var dups = {}; | ||
var params = {}, | ||
dups = {}; | ||
/** | ||
* Marks a given param as either seen or duplicated. | ||
* @param {string} name The name of the param to mark. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function markParam(name) { | ||
if (params.hasOwnProperty(name)) { | ||
dups[name] = 1; | ||
} else { | ||
params[name] = 1; | ||
} | ||
} | ||
// loop through and find each duplicate param | ||
node.params.map(function(param) { | ||
return param.name; | ||
}).forEach(function(param, i, params) { | ||
var lastPos = params.lastIndexOf(param); | ||
if (i !== lastPos) { | ||
dups[param] = [i, lastPos]; | ||
node.params.forEach(function(param) { | ||
switch (param.type) { | ||
case "Identifier": | ||
markParam(param.name); | ||
break; | ||
case "ObjectPattern": | ||
param.properties.forEach(function(property) { | ||
markParam(property.key.name); | ||
}); | ||
break; | ||
case "ArrayPattern": | ||
param.elements.forEach(function(element) { | ||
markParam(element.name); | ||
}); | ||
break; | ||
// no default | ||
} | ||
@@ -37,0 +67,0 @@ }); |
@@ -5,2 +5,3 @@ /** | ||
* @copyright Nicholas C. Zakas. All rights reserved. | ||
* @copyright 2015 Dieter Oberkofler. All rights reserved. | ||
*/ | ||
@@ -18,16 +19,26 @@ "use strict"; | ||
"BlockStatement": function(node) { | ||
var ancestors = context.getAncestors(), | ||
parent = ancestors[ancestors.length - 1], | ||
var parent = node.parent, | ||
parentType = parent.type, | ||
hasHandler = !!(parent.handler || (parent.handlers && parent.handlers.length)), | ||
isFinallyBlock = (parentType === "TryStatement") && (parent.finalizer === node); | ||
comments, | ||
i; | ||
if (/Function|CatchClause/.test(parentType) || | ||
(isFinallyBlock && !hasHandler)) { | ||
// if the body is not empty, we can just return immediately | ||
if (node.body.length !== 0) { | ||
return; | ||
} | ||
if (node.body.length === 0) { | ||
context.report(node, "Empty block statement."); | ||
// a function is generally allowed to be empty | ||
if (parentType === "FunctionDeclaration" || parentType === "FunctionExpression" || parentType === "ArrowFunctionExpression") { | ||
return; | ||
} | ||
// any other block is only allowed to be empty, if it contains an empty comment | ||
comments = context.getComments(node).trailing; | ||
for (i = 0; i < comments.length; i++) { | ||
if (comments[i].value.trim() === "empty") { | ||
return; | ||
} | ||
} | ||
context.report(node, "Empty block statement."); | ||
}, | ||
@@ -34,0 +45,0 @@ |
@@ -14,4 +14,3 @@ /** | ||
var inCatch = false, | ||
exceptionName = null; | ||
var catchStack = []; | ||
@@ -21,9 +20,7 @@ return { | ||
"CatchClause": function(node) { | ||
inCatch = true; | ||
exceptionName = node.param.name; | ||
catchStack.push(node.param.name); | ||
}, | ||
"CatchClause:exit": function() { | ||
inCatch = false; | ||
exceptionName = null; | ||
catchStack.pop(); | ||
}, | ||
@@ -33,5 +30,7 @@ | ||
if (inCatch) { | ||
if (catchStack.length > 0) { | ||
if (node.left.name === exceptionName) { | ||
var exceptionName = catchStack[catchStack.length - 1]; | ||
if (node.left.name && node.left.name === exceptionName) { | ||
context.report(node, "Do not assign to the exception parameter."); | ||
@@ -38,0 +37,0 @@ } |
@@ -56,12 +56,2 @@ /** | ||
/** | ||
* Checks if a node name match the JSX tag convention. | ||
* @param {String} name - Name of the node to check. | ||
* @returns {boolean} Whether or not the node name match the JSX tag convention. | ||
*/ | ||
var tagConvention = /^[a-z]|\-/; | ||
function isTagName(name) { | ||
return tagConvention.test(name); | ||
} | ||
//------------------------------------------------------------------------------ | ||
@@ -80,28 +70,2 @@ // Rule Definition | ||
/** | ||
* Compare an identifier with the variables declared in the scope | ||
* @param {ASTNode} node - Identifier or JSXIdentifier node | ||
* @returns {void} | ||
*/ | ||
function checkIdentifierInJSX(node) { | ||
var scope = context.getScope(), | ||
variables = scope.variables, | ||
i, | ||
len; | ||
while (scope.type !== "global") { | ||
scope = scope.upper; | ||
variables = scope.variables.concat(variables); | ||
} | ||
for (i = 0, len = variables.length; i < len; i++) { | ||
if (variables[i].name === node.name) { | ||
return; | ||
} | ||
} | ||
context.report(node, NOT_DEFINED_MESSAGE, { name: node.name }); | ||
} | ||
/** | ||
* Temporary function to fix escope issue. Remove once we upgrade to | ||
@@ -156,8 +120,2 @@ * escope 3.x. | ||
}); | ||
}, | ||
"JSXOpeningElement": function(node) { | ||
if (!isTagName(node.name.name)) { | ||
checkIdentifierInJSX(node.name); | ||
} | ||
} | ||
@@ -164,0 +122,0 @@ |
@@ -54,4 +54,6 @@ /** | ||
/** | ||
* Determines if a reference is a read operation. | ||
* @param {Reference} ref - an escope Reference | ||
* @returns {Boolean} whether the given reference represents a read operation | ||
* @private | ||
*/ | ||
@@ -63,5 +65,33 @@ function isReadRef(ref) { | ||
/** | ||
* Determine if an identifier is referencing the enclosing function name. | ||
* @param {Reference} ref The reference to check. | ||
* @returns {boolean} True if it's a self-reference, false if not. | ||
* @private | ||
*/ | ||
function isSelfReference(ref) { | ||
if (ref.from.type === "function" && ref.from.block.id) { | ||
return ref.identifier.name === ref.from.block.id.name; | ||
} | ||
return false; | ||
} | ||
/** | ||
* Determines if a reference should be counted as a read. A reference should | ||
* be counted only if it's a read and it's not a reference to the containing | ||
* function declaration name. | ||
* @param {Reference} ref The reference to check. | ||
* @returns {boolean} True if it's a value read reference, false if not. | ||
* @private | ||
*/ | ||
function isValidReadRef(ref) { | ||
return isReadRef(ref) && !isSelfReference(ref); | ||
} | ||
/** | ||
* Gets an array of local variables without read references. | ||
* @param {Scope} scope - an escope Scope object | ||
* @returns {Variable[]} most of the local variables with no read references | ||
* @private | ||
*/ | ||
@@ -83,4 +113,6 @@ function getUnusedLocals(scope) { | ||
} | ||
var type = variables[i].defs[0].type; | ||
var def = variables[i].defs[0], | ||
type = def.type; | ||
// skip catch variables | ||
@@ -90,2 +122,8 @@ if (type === "CatchClause") { | ||
} | ||
// skip any setter argument | ||
if (type === "Parameter" && def.node.parent.type === "Property" && def.node.parent.kind === "set") { | ||
continue; | ||
} | ||
// if "args" option is "none", skip any parameter | ||
@@ -101,3 +139,3 @@ if (config.args === "none" && type === "Parameter") { | ||
if (variables[i].references.filter(isReadRef).length === 0 && !isExported(variables[i])) { | ||
if (variables[i].references.filter(isValidReadRef).length === 0 && !isExported(variables[i])) { | ||
unused.push(variables[i]); | ||
@@ -119,3 +157,3 @@ } | ||
if (config.vars === "all") { | ||
var unresolvedRefs = globalScope.through.filter(isReadRef).map(function(ref) { | ||
var unresolvedRefs = globalScope.through.filter(isValidReadRef).map(function(ref) { | ||
return ref.identifier.name; | ||
@@ -122,0 +160,0 @@ }); |
@@ -22,6 +22,11 @@ /** | ||
function checkFunction(node) { | ||
var ancestors = context.getAncestors(), | ||
previousToken, nextToken; | ||
var previousToken, nextToken; | ||
if (!/CallExpression|NewExpression/.test(ancestors.pop().type)) { | ||
if (node.type === "ArrowFunctionExpression" && | ||
/(?:Call|New|Logical|Binary|Conditional|Update)Expression/.test(node.parent.type) | ||
) { | ||
return; | ||
} | ||
if (!/CallExpression|NewExpression/.test(node.parent.type)) { | ||
previousToken = context.getTokenBefore(node); | ||
@@ -28,0 +33,0 @@ nextToken = context.getTokenAfter(node); |
/** | ||
* @fileoverview A rule to ensure the use of a single variable declaration. | ||
* @author Ian Christian Myers | ||
* @copyright 2015 Danny Fritz. All rights reserved. | ||
* @copyright 2013 Ian Christian Myers. All rights reserved. | ||
@@ -15,2 +16,4 @@ */ | ||
var MODE = context.options[0] || "always"; | ||
//-------------------------------------------------------------------------- | ||
@@ -22,2 +25,7 @@ // Helpers | ||
/** | ||
* Increments the functionStack counter. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function startFunction() { | ||
@@ -27,2 +35,7 @@ functionStack.push(false); | ||
/** | ||
* Decrements the functionStack counter. | ||
* @returns {void} | ||
* @private | ||
*/ | ||
function endFunction() { | ||
@@ -32,7 +45,13 @@ functionStack.pop(); | ||
function checkDeclarations(node) { | ||
/** | ||
* Determines if there is more than one var statement in the current scope. | ||
* @returns {boolean} Returns true if it is the first var declaration, false if not. | ||
* @private | ||
*/ | ||
function hasOnlyOneVar() { | ||
if (functionStack[functionStack.length - 1]) { | ||
context.report(node, "Combine this with the previous 'var' statement."); | ||
return true; | ||
} else { | ||
functionStack[functionStack.length - 1] = true; | ||
return false; | ||
} | ||
@@ -51,3 +70,14 @@ } | ||
"VariableDeclaration": checkDeclarations, | ||
"VariableDeclaration": function(node) { | ||
var declarationCount = node.declarations.length; | ||
if (MODE === "never") { | ||
if (declarationCount > 1) { | ||
context.report(node, "Split 'var' declaration into multiple statements."); | ||
} | ||
} else { | ||
if (hasOnlyOneVar()) { | ||
context.report(node, "Combine this with the previous 'var' statement."); | ||
} | ||
} | ||
}, | ||
@@ -54,0 +84,0 @@ "Program:exit": endFunction, |
@@ -12,2 +12,3 @@ /** | ||
module.exports = function(context) { | ||
var int32Hint = context.options[0] ? context.options[0].int32Hint === true : false; | ||
@@ -42,3 +43,5 @@ var OPERATORS = [ | ||
if (!isSpaced(node.left, node.right)) { | ||
report(node); | ||
if (!(int32Hint && context.getSource(node).substr(-2) === "|0")) { | ||
report(node); | ||
} | ||
} | ||
@@ -45,0 +48,0 @@ } |
@@ -158,11 +158,14 @@ /** | ||
if (jsdocParams[i] && (name !== jsdocParams[i])) { | ||
context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", { | ||
name: name, | ||
jsdocName: jsdocParams[i] | ||
}); | ||
} else if (!params[name]) { | ||
context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", { | ||
name: name | ||
}); | ||
// TODO(nzakas): Figure out logical things to do with destructured, default, rest params | ||
if (param.type === "Identifier") { | ||
if (jsdocParams[i] && (name !== jsdocParams[i])) { | ||
context.report(jsdocNode, "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.", { | ||
name: name, | ||
jsdocName: jsdocParams[i] | ||
}); | ||
} else if (!params[name]) { | ||
context.report(jsdocNode, "Missing JSDoc for parameter '{{name}}'.", { | ||
name: name | ||
}); | ||
} | ||
} | ||
@@ -169,0 +172,0 @@ }); |
@@ -31,2 +31,12 @@ /** | ||
/** | ||
* Check to see if its a ES6 import declaration | ||
* @param {ASTNode} node - any node | ||
* @returns {Boolean} whether the given node represents a import declaration | ||
*/ | ||
function looksLikeImport(node) { | ||
return node.type === "ImportDeclaration" || node.type === "ImportSpecifier" || | ||
node.type === "ImportDefaultSpecifier" || node.type === "ImportNamespaceSpecifier"; | ||
} | ||
/** | ||
* Checks whether this variable is on top of the block body | ||
@@ -42,3 +52,3 @@ * @param {ASTNode} node - The node to check | ||
for (; i < l; ++i) { | ||
if (!looksLikeDirective(statements[i])) { | ||
if (!looksLikeDirective(statements[i]) && !looksLikeImport(statements[i])) { | ||
break; | ||
@@ -45,0 +55,0 @@ } |
{ | ||
"name": "eslint", | ||
"version": "0.17.1", | ||
"version": "0.18.0", | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
@@ -5,0 +5,0 @@ "description": "An AST-based pattern checker for JavaScript.", |
@@ -9,3 +9,3 @@ [![NPM version][npm-image]][npm-url] | ||
[Website](http://eslint.org) | [Documentation](http://eslint.org/docs) | [Contributing](http://eslint.org/docs/developer-guide/contributing.html) | [Twitter](https://twitter.com/geteslint) | [Mailing List](https://groups.google.com/group/eslint) | ||
[Website](http://eslint.org) | [Configuring](http://eslint.org/docs/user-guide/configuring) | [Rules](http://eslint.org/docs/user-guide/rules) | [Contributing](http://eslint.org/docs/developer-guide/contributing.html) | [Twitter](https://twitter.com/geteslint) | [Mailing List](https://groups.google.com/group/eslint) | ||
@@ -12,0 +12,0 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/JavaScript code. In many ways, it is similar to JSLint and JSHint with a few exceptions: |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
493364
181
12583