Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend global jshint.globals config, merge arrays #84

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 168 additions & 39 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ define(function (require, exports, module) {
}

var resultJH = JSHINT(text,
$.extend({}, defaultConfig.options, config.options),
$.extend({}, defaultConfig.globals, config.globals));
deepExtend(true, defaultConfig.options, config.options),
deepExtend(true, defaultConfig.globals, config.globals));

if (!resultJH) {
var errors = JSHINT.errors,
Expand Down Expand Up @@ -149,42 +149,46 @@ define(function (require, exports, module) {
var result = new $.Deferred(),
file;
configFileName = configFileName || _configFileName;
file = FileSystem.getFileForPath(dir + configFileName);
file.read(function (err, content) {
if (!err) {
var cfg = {},
config;
try {
config = JSON.parse(removeComments(content));
} catch (e) {
console.error("JSHint: error parsing " + file.fullPath + ". Details: " + e);
result.reject(e);
return;
}
// Load any base config defined by "extends".
// The same functionality as in
// jslints -> cli.js -> loadConfig -> if (config['extends'])...
var baseConfigResult = $.Deferred();
if (config.extends) {
var extendFile = FileSystem.getFileForPath(dir + config.extends);
baseConfigResult = _readConfig(extendFile.parentPath, extendFile.name);
delete config.extends;
}
else {
baseConfigResult.resolve({});
if (configFileName === "jshint.globals") {
result.resolve(deepExtend(true, {}, defaultConfig));
} else {
file = FileSystem.getFileForPath(dir + configFileName);
file.read(function (err, content) {
if (!err) {
var cfg = {},
config;
try {
config = JSON.parse(removeComments(content));
} catch (e) {
console.error("JSHint: error parsing " + file.fullPath + ". Details: " + e);
result.reject(e);
return;
}
// Load any base config defined by "extends".
// The same functionality as in
// jslints -> cli.js -> loadConfig -> if (config['extends'])...
var baseConfigResult = $.Deferred();
if (config.extends) {
var extendFile = FileSystem.getFileForPath(dir + config.extends);
baseConfigResult = _readConfig(extendFile.parentPath, extendFile.name);
delete config.extends;
} else {
baseConfigResult.resolve({});
}
baseConfigResult.done(function (baseConfig) {
cfg.globals = deepExtend(true, baseConfig.globals, config.globals);
if (config.globals) { delete config.globals; }
cfg.options = deepExtend(true, baseConfig.options, config);
result.resolve(cfg);
}).fail(function (e) {
result.reject(e);
});

} else {
result.reject(err);
}
baseConfigResult.done(function (baseConfig) {
cfg.globals = $.extend({}, baseConfig.globals, config.globals);
if (config.globals) { delete config.globals; }
cfg.options = $.extend({}, baseConfig.options, config);
result.resolve(cfg);
}).fail(function (e) {
result.reject(e);
});
} else {
result.reject(err);
}
});
});
}
return result.promise();
}

Expand Down Expand Up @@ -216,10 +220,10 @@ define(function (require, exports, module) {
bundle = overrides[pattern];

if (bundle.globals) {
$.extend(true, cfg.globals, bundle.globals);
deepExtend(true, cfg.globals, bundle.globals);
delete bundle.globals;
}
$.extend(true, cfg.options, bundle);
deepExtend(true, cfg.options, bundle);

}
}
Expand Down Expand Up @@ -345,6 +349,131 @@ define(function (require, exports, module) {
return str;
}

/**
* jQuery's extend function, modified to merge arrays when they do not contain any object (only strings or numbers)
* See here:
* http://stackoverflow.com/questions/9399365/deep-extend-like-jquerys-for-nodejs
*
* @param {object} target the destination object or true to make deep copy
* @param {object} successive arguments are the objects to be copied to target
* @returns {Function} extended object
*/
function deepExtend() {
var options, name, src, copy, copyIsArray, clone, s, isMergeArrays, target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false,
toString = Object.prototype.toString,
hasOwn = Object.prototype.hasOwnProperty,
class2type = {
"[object Boolean]": "boolean",
"[object Number]": "number",
"[object String]": "string",
"[object Function]": "function",
"[object Array]": "array",
"[object Date]": "date",
"[object RegExp]": "regexp",
"[object Object]": "object"
},
jQuery = {
isFunction: function (obj) {
return jQuery.type(obj) === "function";
},
isArray: Array.isArray ||
function (obj) {
return jQuery.type(obj) === "array";
},
type: function (obj) {
return obj === null ? String(obj) : class2type[toString.call(obj)] || "object";
},
isPlainObject: function (obj) {
if (!obj || jQuery.type(obj) !== "object" || obj.nodeType) {
return false;
}
try {
if (obj.constructor && !hasOwn.call(obj, "constructor") && !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")) {
return false;
}
} catch (e) {
return false;
}
var key;
for (key in obj) {}
return key === undefined || hasOwn.call(obj, key);
}
};
if (typeof target === "boolean") {
deep = target;
target = arguments[1] || {};
i = 2;
}
if (typeof target !== "object" && !jQuery.isFunction(target)) {
target = {};
}
if (length === i) {
target = this;
--i;
}
for (i; i < length; i++) {
if ((options = arguments[i]) !== null) {
for (name in options) {
if (hasOwn.call(options, name)) {
src = target[name];
copy = options[name];
if (target === copy) {
continue;
}
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
isMergeArrays = true;
for (s in src) {
if (jQuery.isArray(src[s]) || jQuery.isPlainObject(src[s]) || jQuery.isFunction(src[s])) {
isMergeArrays = false;
break;
}
}
if (copyIsArray && isMergeArrays) {
clone = src && jQuery.isArray(src) ? src : [];
clone = clone.concat(copy);
target[name] = arrayUnique(clone);
continue;

} else if (copyIsArray) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// WARNING: RECURSION
target[name] = deepExtend(deep, clone, copy);
} else if (copy !== undefined) {
target[name] = copy;
}
}
}
}
}
return target;
}

/**
* Eliminate duplicate elements from array
*
* @param {array} array the array to be cleaned
* @returns {array} de-duplicated array
*/
function arrayUnique(array) {
var i, j, a = array.concat();
for (i = 0; i < a.length; i += 1) {
for (j = i + 1; j < a.length; j += 1) {
if (a[i] === a[j]) {
a.splice(j, 1);
j += 1;
}
}
}
return a;
}

CodeInspection.register("javascript", {
name: JSHINT_NAME,
scanFile: handleHinter,
Expand Down