From cd3795240431c3081fc7e5e21510f185b0123b05 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Sun, 11 Feb 2018 18:22:48 -0800 Subject: [PATCH 1/4] Implement deprecate API and deprecate APIs --- lib/grunt.js | 3 + lib/grunt/deprecate.js | 116 +++++++++++++++++++++++++++++++++++ test/grunt/deprecate_test.js | 66 ++++++++++++++++++++ 3 files changed, 185 insertions(+) create mode 100644 lib/grunt/deprecate.js create mode 100644 test/grunt/deprecate_test.js diff --git a/lib/grunt.js b/lib/grunt.js index 4540d7ca2..e228818db 100644 --- a/lib/grunt.js +++ b/lib/grunt.js @@ -37,6 +37,9 @@ var verbose = grunt.verbose = log.verbose; grunt.package = require('../package.json'); grunt.version = grunt.package.version; +// Include internal deprecate lib that adds deprecations +require('./grunt/deprecate'); + // Expose specific grunt lib methods on grunt. function gExpose(obj, methodName, newMethodName) { grunt[newMethodName || methodName] = obj[methodName].bind(obj); diff --git a/lib/grunt/deprecate.js b/lib/grunt/deprecate.js new file mode 100644 index 000000000..5cb8e55af --- /dev/null +++ b/lib/grunt/deprecate.js @@ -0,0 +1,116 @@ +var grunt = require('../grunt'); + +function deprecate(obj, property, message) { + if (Array.isArray(obj)) { + obj.forEach(function(item) { + deprecate(item.obj, item.property, item.message); + }); + return; + } + var logged = false; + function warn() { + var hideDeprecation = grunt.option('hide-deprecations'); + if (!hideDeprecation && !logged) { + if (grunt.option('stack')) { + grunt.log.warn(Error(message).stack); + } else { + grunt.log.warn(message); + } + logged = true; + } + } + var orig = obj[property]; + Object.defineProperty(obj, property, { + enumerable: true, + configurable: true, + set: function(val) { + warn(); + orig = val; + }, + get: function() { + warn(); + return orig; + } + }); +} +module.exports = deprecate; + +deprecate([ + { + obj: grunt.util, + property: '_', + message: 'grunt.util._ has been deprecated. Please install and require ' + + '"lodash" directly. https://www.npmjs.com/package/lodash' + }, + { + obj: grunt.util, + property: 'async', + message: 'grunt.util.async has been deprecated. Please install and require ' + + '"async" directly. https://www.npmjs.com/package/async' + }, + { + obj: grunt.util, + property: 'namespace', + message: 'grunt.util.namespace has been deprecated. Please install and ' + + 'require "getobject" directly. https://www.npmjs.com/package/getobject' + }, + { + obj: grunt.util, + property: 'hooker', + message: 'grunt.util.hooker has been deprecated. Please install and require ' + + '"hooker" directly. https://www.npmjs.com/package/hooker' + }, + { + obj: grunt.util, + property: 'exit', + message: 'grunt.util.exit has been deprecated. Please install and require ' + + '"exit" directly. https://www.npmjs.com/package/exit' + }, + { + obj: grunt.util, + property: 'toArray', + message: 'grunt.util.toArray has been deprecated. Please install and ' + + 'require "lodash.toarray" directly. https://www.npmjs.com/package/lodash.toarray' + }, + { + obj: grunt.util, + property: 'repeat', + message: 'grunt.util.repeat has been deprecated. Please use ' + + '`new Array(num + 1).join(str || \' \')` or another library.' + }, + { + obj: grunt.file, + property: 'glob', + message: 'grunt.file.glob has been deprecated. Please install and require ' + + '"glob" directly. https://www.npmjs.com/package/glob' + }, + { + obj: grunt.file, + property: 'minimatch', + message: 'grunt.file.minimatch has been deprecated. Please install and ' + + 'require "minimatch" directly. https://www.npmjs.com/package/minimatch' + }, + { + obj: grunt.file, + property: 'findup', + message: 'grunt.file.findup has been deprecated. Please install and require ' + + '"findup-sync" directly. https://www.npmjs.com/package/findup-sync' + }, + { + obj: grunt.file, + property: 'readYAML', + message: 'grunt.file.readYAML has been deprecated. Please install and ' + + 'require "js-yaml" directly. https://www.npmjs.com/package/js-yaml' + }, + { + obj: grunt.file, + property: 'readJSON', + message: 'grunt.file.readJSON has been deprecated. Please use require("file.json") directly.' + }, + { + obj: grunt, + property: 'event', + message: 'grunt.event has been deprecated. Please install and require ' + + '"eventemitter2" directly. https://www.npmjs.com/package/eventemitter2' + }, +]); diff --git a/test/grunt/deprecate_test.js b/test/grunt/deprecate_test.js new file mode 100644 index 000000000..030e73944 --- /dev/null +++ b/test/grunt/deprecate_test.js @@ -0,0 +1,66 @@ +'use strict'; + +var grunt = require('../../lib/grunt'); +var deprecate = require('../../lib/grunt/deprecate'); + +exports.deprecate = { + setUp: function(done) { + this.oldGruntLogWarn = grunt.log.warn; + this.oldHideDeprecations = grunt.option('hide-deprecations'); + this.oldStack = grunt.option('stack'); + grunt.option('hide-deprecations', false); + grunt.option('stack', false); + var api = {val: function() {}}; + var util = {api: api}; + this.fixture = {util: util}; + done(); + }, + tearDown: function(done) { + this.fixture = null; + grunt.log.warn = this.oldGruntLogWarn; + grunt.option('hide-deprecations', this.oldHideDeprecations); + grunt.option('stack', this.oldStack); + done(); + }, + 'deprecate warning on get': function(test) { + test.expect(1); + grunt.log.warn = function(message) { + test.equal(message, 'this api is deprecated', 'grunt.log.warn should have got the deprecation message when getting a deprecated api.'); + test.done(); + }; + deprecate(this.fixture.util, 'api', 'this api is deprecated'); + this.fixture.util.api.val(); + }, + 'deprecate warning on set': function(test) { + test.expect(1); + grunt.log.warn = function(message) { + test.equal(message, 'this api is deprecated', 'grunt.log.warn should have got the deprecation message when setting a deprecated api.'); + test.done(); + }; + deprecate(this.fixture.util, 'api', 'this api is deprecated'); + this.fixture.util.api = {}; + }, + 'hide deprecations': function(test) { + test.expect(1); + grunt.option('hide-deprecations', true); + grunt.log.warn = function(message) { + test.equal(message, 'did not show deprecation message', 'grunt.log.warn should not have displayed a deprecation message with hide-deprecations enabled.'); + test.done(); + }; + deprecate(this.fixture.util, 'api', 'this api is deprecated'); + this.fixture.util.api.val(); + grunt.log.warn('did not show deprecation message'); + }, + 'deprecations with stack trace': function(test) { + test.expect(2); + grunt.option('stack', true); + grunt.log.warn = function(message) { + message = message.split(grunt.util.linefeed); + test.equal(message[0], 'Error: this api is deprecated', 'grunt.log.warn should not have displayed a deprecation message with stack trace.'); + test.ok(message.length > 1); + test.done(); + }; + deprecate(this.fixture.util, 'api', 'this api is deprecated'); + this.fixture.util.api.val(); + }, +}; From d14e96be43258a4c041efae01be232e08c67b980 Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Sun, 11 Feb 2018 18:40:34 -0800 Subject: [PATCH 2/4] Windows tests still use \n --- test/grunt/deprecate_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/grunt/deprecate_test.js b/test/grunt/deprecate_test.js index 030e73944..6ae8eb65d 100644 --- a/test/grunt/deprecate_test.js +++ b/test/grunt/deprecate_test.js @@ -55,7 +55,7 @@ exports.deprecate = { test.expect(2); grunt.option('stack', true); grunt.log.warn = function(message) { - message = message.split(grunt.util.linefeed); + message = message.split('\n'); test.equal(message[0], 'Error: this api is deprecated', 'grunt.log.warn should not have displayed a deprecation message with stack trace.'); test.ok(message.length > 1); test.done(); From b3a50f8b0147af734c3f18897b3170d1bb9f700d Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Mon, 12 Feb 2018 08:38:53 -0800 Subject: [PATCH 3/4] Fix review comments Deprecations live separately from deprecate API Dont change original val on set deprecate doesnt accept array, just iterate and call deprecate --- lib/deprecations.js | 85 ++++++++++++++++++++++++++++++++++++++++ lib/grunt.js | 4 +- lib/grunt/deprecate.js | 89 +----------------------------------------- 3 files changed, 88 insertions(+), 90 deletions(-) create mode 100644 lib/deprecations.js diff --git a/lib/deprecations.js b/lib/deprecations.js new file mode 100644 index 000000000..a411e8695 --- /dev/null +++ b/lib/deprecations.js @@ -0,0 +1,85 @@ +var grunt = require('./grunt'); +var deprecate = require('./grunt/deprecate'); + +var deprecations = [ + { + obj: grunt.util, + property: '_', + message: 'grunt.util._ has been deprecated. Please install and require ' + + '"lodash" directly. https://www.npmjs.com/package/lodash' + }, + { + obj: grunt.util, + property: 'async', + message: 'grunt.util.async has been deprecated. Please install and require ' + + '"async" directly. https://www.npmjs.com/package/async' + }, + { + obj: grunt.util, + property: 'namespace', + message: 'grunt.util.namespace has been deprecated. Please install and ' + + 'require "getobject" directly. https://www.npmjs.com/package/getobject' + }, + { + obj: grunt.util, + property: 'hooker', + message: 'grunt.util.hooker has been deprecated. Please install and require ' + + '"hooker" directly. https://www.npmjs.com/package/hooker' + }, + { + obj: grunt.util, + property: 'exit', + message: 'grunt.util.exit has been deprecated. Please install and require ' + + '"exit" directly. https://www.npmjs.com/package/exit' + }, + { + obj: grunt.util, + property: 'toArray', + message: 'grunt.util.toArray has been deprecated. Please install and ' + + 'require "lodash.toarray" directly. https://www.npmjs.com/package/lodash.toarray' + }, + { + obj: grunt.util, + property: 'repeat', + message: 'grunt.util.repeat has been deprecated. Please use ' + + '`new Array(num + 1).join(str || \' \')` or another library.' + }, + { + obj: grunt.file, + property: 'glob', + message: 'grunt.file.glob has been deprecated. Please install and require ' + + '"glob" directly. https://www.npmjs.com/package/glob' + }, + { + obj: grunt.file, + property: 'minimatch', + message: 'grunt.file.minimatch has been deprecated. Please install and ' + + 'require "minimatch" directly. https://www.npmjs.com/package/minimatch' + }, + { + obj: grunt.file, + property: 'findup', + message: 'grunt.file.findup has been deprecated. Please install and require ' + + '"findup-sync" directly. https://www.npmjs.com/package/findup-sync' + }, + { + obj: grunt.file, + property: 'readYAML', + message: 'grunt.file.readYAML has been deprecated. Please install and ' + + 'require "js-yaml" directly. https://www.npmjs.com/package/js-yaml' + }, + { + obj: grunt.file, + property: 'readJSON', + message: 'grunt.file.readJSON has been deprecated. Please use require("file.json") directly.' + }, + { + obj: grunt, + property: 'event', + message: 'grunt.event has been deprecated. Please install and require ' + + '"eventemitter2" directly. https://www.npmjs.com/package/eventemitter2' + }, +]; +deprecations.forEach(function(item) { + deprecate(item.obj, item.property, item.message); +}); diff --git a/lib/grunt.js b/lib/grunt.js index e228818db..13bdb94b8 100644 --- a/lib/grunt.js +++ b/lib/grunt.js @@ -37,8 +37,8 @@ var verbose = grunt.verbose = log.verbose; grunt.package = require('../package.json'); grunt.version = grunt.package.version; -// Include internal deprecate lib that adds deprecations -require('./grunt/deprecate'); +// Apply deprecations. +require('./deprecations'); // Expose specific grunt lib methods on grunt. function gExpose(obj, methodName, newMethodName) { diff --git a/lib/grunt/deprecate.js b/lib/grunt/deprecate.js index 5cb8e55af..30068e7a7 100644 --- a/lib/grunt/deprecate.js +++ b/lib/grunt/deprecate.js @@ -1,12 +1,6 @@ var grunt = require('../grunt'); function deprecate(obj, property, message) { - if (Array.isArray(obj)) { - obj.forEach(function(item) { - deprecate(item.obj, item.property, item.message); - }); - return; - } var logged = false; function warn() { var hideDeprecation = grunt.option('hide-deprecations'); @@ -23,9 +17,8 @@ function deprecate(obj, property, message) { Object.defineProperty(obj, property, { enumerable: true, configurable: true, - set: function(val) { + set: function() { warn(); - orig = val; }, get: function() { warn(); @@ -34,83 +27,3 @@ function deprecate(obj, property, message) { }); } module.exports = deprecate; - -deprecate([ - { - obj: grunt.util, - property: '_', - message: 'grunt.util._ has been deprecated. Please install and require ' + - '"lodash" directly. https://www.npmjs.com/package/lodash' - }, - { - obj: grunt.util, - property: 'async', - message: 'grunt.util.async has been deprecated. Please install and require ' + - '"async" directly. https://www.npmjs.com/package/async' - }, - { - obj: grunt.util, - property: 'namespace', - message: 'grunt.util.namespace has been deprecated. Please install and ' + - 'require "getobject" directly. https://www.npmjs.com/package/getobject' - }, - { - obj: grunt.util, - property: 'hooker', - message: 'grunt.util.hooker has been deprecated. Please install and require ' + - '"hooker" directly. https://www.npmjs.com/package/hooker' - }, - { - obj: grunt.util, - property: 'exit', - message: 'grunt.util.exit has been deprecated. Please install and require ' + - '"exit" directly. https://www.npmjs.com/package/exit' - }, - { - obj: grunt.util, - property: 'toArray', - message: 'grunt.util.toArray has been deprecated. Please install and ' + - 'require "lodash.toarray" directly. https://www.npmjs.com/package/lodash.toarray' - }, - { - obj: grunt.util, - property: 'repeat', - message: 'grunt.util.repeat has been deprecated. Please use ' + - '`new Array(num + 1).join(str || \' \')` or another library.' - }, - { - obj: grunt.file, - property: 'glob', - message: 'grunt.file.glob has been deprecated. Please install and require ' + - '"glob" directly. https://www.npmjs.com/package/glob' - }, - { - obj: grunt.file, - property: 'minimatch', - message: 'grunt.file.minimatch has been deprecated. Please install and ' + - 'require "minimatch" directly. https://www.npmjs.com/package/minimatch' - }, - { - obj: grunt.file, - property: 'findup', - message: 'grunt.file.findup has been deprecated. Please install and require ' + - '"findup-sync" directly. https://www.npmjs.com/package/findup-sync' - }, - { - obj: grunt.file, - property: 'readYAML', - message: 'grunt.file.readYAML has been deprecated. Please install and ' + - 'require "js-yaml" directly. https://www.npmjs.com/package/js-yaml' - }, - { - obj: grunt.file, - property: 'readJSON', - message: 'grunt.file.readJSON has been deprecated. Please use require("file.json") directly.' - }, - { - obj: grunt, - property: 'event', - message: 'grunt.event has been deprecated. Please install and require ' + - '"eventemitter2" directly. https://www.npmjs.com/package/eventemitter2' - }, -]); From 7f9a9dc861c801a98e6a013b451c2f0079d6e6dc Mon Sep 17 00:00:00 2001 From: Kyle Robinson Young Date: Tue, 6 Mar 2018 19:05:59 -0800 Subject: [PATCH 4/4] Fixing deprecations in Grunt internally --- internal-tasks/subgrunt.js | 4 +++- lib/grunt.js | 3 ++- lib/grunt/config.js | 10 +++++---- lib/grunt/fail.js | 5 +++-- lib/grunt/file.js | 15 +++++++------ lib/grunt/help.js | 3 ++- lib/grunt/task.js | 45 ++++++++++++++++++++------------------ lib/grunt/template.js | 5 +++-- lib/util/task.js | 4 ++-- package.json | 3 +++ 10 files changed, 56 insertions(+), 41 deletions(-) diff --git a/internal-tasks/subgrunt.js b/internal-tasks/subgrunt.js index dba8d833e..52d4cdfc3 100644 --- a/internal-tasks/subgrunt.js +++ b/internal-tasks/subgrunt.js @@ -1,11 +1,13 @@ 'use strict'; +var asyncLib = require('async'); + module.exports = function(grunt) { // Run sub-grunt files, because right now, testing tasks is a pain. grunt.registerMultiTask('subgrunt', 'Run a sub-gruntfile.', function() { var path = require('path'); - grunt.util.async.forEachSeries(this.filesSrc, function(gruntfile, next) { + asyncLib.forEachSeries(this.filesSrc, function(gruntfile, next) { grunt.log.write('Loading ' + gruntfile + '...'); grunt.util.spawn({ grunt: true, diff --git a/lib/grunt.js b/lib/grunt.js index 13bdb94b8..49482c548 100644 --- a/lib/grunt.js +++ b/lib/grunt.js @@ -2,6 +2,7 @@ // Nodejs libs. var path = require('path'); +var exit = require('exit'); // This allows grunt to require() .coffee files. require('coffeescript/register'); @@ -145,7 +146,7 @@ grunt.tasks = function(tasks, options, done) { done(); } else { // Otherwise, explicitly exit. - util.exit(0); + exit(0); } } }); diff --git a/lib/grunt/config.js b/lib/grunt/config.js index ef2bf8094..41b75b3f4 100644 --- a/lib/grunt/config.js +++ b/lib/grunt/config.js @@ -1,6 +1,8 @@ 'use strict'; var grunt = require('../grunt'); +var _ = require('lodash'); +var getobject = require('getobject'); // Get/set config data. If value was passed, set. Otherwise, get. var config = module.exports = function(prop, value) { @@ -30,7 +32,7 @@ config.getPropString = function(prop) { config.getRaw = function(prop) { if (prop) { // Prop was passed, get that specific property's value. - return grunt.util.namespace.get(config.data, config.getPropString(prop)); + return getobject.get(config.data, config.getPropString(prop)); } else { // No prop was passed, return the entire config.data object. return config.data; @@ -69,12 +71,12 @@ config.process = function(raw) { // Set config data. config.set = function(prop, value) { - return grunt.util.namespace.set(config.data, config.getPropString(prop), value); + return getobject.set(config.data, config.getPropString(prop), value); }; // Deep merge config data. config.merge = function(obj) { - grunt.util._.merge(config.data, obj); + _.merge(config.data, obj); return config.data; }; @@ -89,7 +91,7 @@ config.init = function(obj) { // exception (use this inside of a task). config.requires = function() { var p = grunt.util.pluralize; - var props = grunt.util.toArray(arguments).map(config.getPropString); + var props = _.toArray(arguments).map(config.getPropString); var msg = 'Verifying propert' + p(props.length, 'y/ies') + ' ' + grunt.log.wordlist(props) + ' exist' + p(props.length, 's') + ' in config...'; diff --git a/lib/grunt/fail.js b/lib/grunt/fail.js index 631e249ac..58eeb8625 100644 --- a/lib/grunt/fail.js +++ b/lib/grunt/fail.js @@ -1,6 +1,7 @@ 'use strict'; var grunt = require('../grunt'); +var exit = require('exit'); // The module to be exported. var fail = module.exports = {}; @@ -45,7 +46,7 @@ function dumpStack(e) { fail.fatal = function(e, errcode) { writeln(e, 'fatal'); dumpStack(e); - grunt.util.exit(typeof errcode === 'number' ? errcode : fail.code.FATAL_ERROR); + exit(typeof errcode === 'number' ? errcode : fail.code.FATAL_ERROR); }; // Keep track of error and warning counts. @@ -61,7 +62,7 @@ fail.warn = function(e, errcode) { if (!grunt.option('force')) { dumpStack(e); grunt.log.writeln().fail('Aborted due to warnings.'); - grunt.util.exit(typeof errcode === 'number' ? errcode : fail.code.WARNING); + exit(typeof errcode === 'number' ? errcode : fail.code.WARNING); } }; diff --git a/lib/grunt/file.js b/lib/grunt/file.js index f8a694e5a..df068d1a6 100644 --- a/lib/grunt/file.js +++ b/lib/grunt/file.js @@ -5,12 +5,13 @@ var grunt = require('../grunt'); // Nodejs libs. var fs = require('fs'); var path = require('path'); +var _ = require('lodash'); // The module to be exported. var file = module.exports = {}; // External libs. -file.glob = require('glob'); +var glob = file.glob = require('glob'); file.minimatch = require('minimatch'); file.findup = require('findup-sync'); var YAML = require('js-yaml'); @@ -42,7 +43,7 @@ var processPatterns = function(patterns, fn) { // Filepaths to return. var result = []; // Iterate over flattened patterns array. - grunt.util._.flattenDeep(patterns).forEach(function(pattern) { + _.flattenDeep(patterns).forEach(function(pattern) { // If the first character is ! it should be omitted var exclusion = pattern.indexOf('!') === 0; // If the pattern is an exclusion, remove the ! @@ -51,10 +52,10 @@ var processPatterns = function(patterns, fn) { var matches = fn(pattern); if (exclusion) { // If an exclusion, remove matching files. - result = grunt.util._.difference(result, matches); + result = _.difference(result, matches); } else { // Otherwise add matching files. - result = grunt.util._.union(result, matches); + result = _.union(result, matches); } }); return result; @@ -89,7 +90,7 @@ file.isMatch = function() { // Return an array of all file paths that match the given wildcard patterns. file.expand = function() { - var args = grunt.util.toArray(arguments); + var args = _.toArray(arguments); // If the first argument is an options object, save those options to pass // into the file.glob.sync method. var options = grunt.util.kindOf(args[0]) === 'object' ? args.shift() : {}; @@ -101,7 +102,7 @@ file.expand = function() { // Return all matching filepaths. var matches = processPatterns(patterns, function(pattern) { // Find all matching files for this pattern. - return file.glob.sync(pattern, options); + return glob.sync(pattern, options); }); // Filter result set? if (options.filter) { @@ -134,7 +135,7 @@ var extDotRe = { // Build a multi task "files" object dynamically. file.expandMapping = function(patterns, destBase, options) { - options = grunt.util._.defaults({}, options, { + options = _.defaults({}, options, { extDot: 'first', rename: function(destBase, destPath) { return path.join(destBase || '', destPath); diff --git a/lib/grunt/help.js b/lib/grunt/help.js index c01f727da..dd21717e5 100644 --- a/lib/grunt/help.js +++ b/lib/grunt/help.js @@ -4,6 +4,7 @@ var grunt = require('../grunt'); // Nodejs libs. var path = require('path'); +var _ = require('lodash'); // Set column widths. var col1len = 0; @@ -18,7 +19,7 @@ exports.initWidths = function() { // Render an array in table form. exports.table = function(arr) { arr.forEach(function(item) { - grunt.log.writetableln(exports.widths, ['', grunt.util._.pad(item[0], col1len), '', item[1]]); + grunt.log.writetableln(exports.widths, ['', _.pad(item[0], col1len), '', item[1]]); }); }; diff --git a/lib/grunt/task.js b/lib/grunt/task.js index 48aec3abf..8fe79faf6 100644 --- a/lib/grunt/task.js +++ b/lib/grunt/task.js @@ -7,6 +7,9 @@ var grunt = require('../grunt'); // Nodejs libs. var path = require('path'); +var glob = require('glob'); +var _ = require('lodash'); +var findup = require('findup-sync'); // Extend generic "task" util lib. var parent = grunt.util.task.create(); @@ -29,7 +32,7 @@ task.registerTask = function(name) { // This task, now that it's been registered. var thisTask = task._tasks[name]; // Metadata about the current task. - thisTask.meta = grunt.util._.clone(registry.meta); + thisTask.meta = _.clone(registry.meta); // Override task function. var _fn = thisTask.fn; thisTask.fn = function(arg) { @@ -51,10 +54,10 @@ task.registerTask = function(name) { // Return an options object with the specified defaults overwritten by task- // specific overrides, via the "options" property. this.options = function() { - var args = [{}].concat(grunt.util.toArray(arguments)).concat([ + var args = [{}].concat(_.toArray(arguments)).concat([ grunt.config([name, 'options']) ]); - var options = grunt.util._.extend.apply(null, args); + var options = _.extend.apply(null, args); grunt.verbose.writeflags(options, 'Options'); return options; }; @@ -95,7 +98,7 @@ task.normalizeMultiTaskFiles = function(data, target) { files.push({src: data.files[prop], dest: grunt.config.process(prop)}); } } else if (Array.isArray(data.files)) { - grunt.util._.flattenDeep(data.files).forEach(function(obj) { + _.flattenDeep(data.files).forEach(function(obj) { var prop; if ('src' in obj || 'dest' in obj) { files.push(obj); @@ -117,17 +120,17 @@ task.normalizeMultiTaskFiles = function(data, target) { } // Process all normalized file objects. - files = grunt.util._(files).chain().forEach(function(obj) { + files = _(files).chain().forEach(function(obj) { if (!('src' in obj) || !obj.src) { return; } // Normalize .src properties to flattened array. if (Array.isArray(obj.src)) { - obj.src = grunt.util._.flatten(obj.src); + obj.src = _.flatten(obj.src); } else { obj.src = [obj.src]; } }).map(function(obj) { // Build options object, removing unwanted properties. - var expandOptions = grunt.util._.extend({}, obj); + var expandOptions = _.extend({}, obj); delete expandOptions.src; delete expandOptions.dest; @@ -135,9 +138,9 @@ task.normalizeMultiTaskFiles = function(data, target) { if (obj.expand) { return grunt.file.expandMapping(obj.src, obj.dest, expandOptions).map(function(mapObj) { // Copy obj properties to result. - var result = grunt.util._.extend({}, obj); + var result = _.extend({}, obj); // Make a clone of the orig obj available. - result.orig = grunt.util._.extend({}, obj); + result.orig = _.extend({}, obj); // Set .src and .dest, processing both as templates. result.src = grunt.config.process(mapObj.src); result.dest = grunt.config.process(mapObj.dest); @@ -150,9 +153,9 @@ task.normalizeMultiTaskFiles = function(data, target) { } // Copy obj properties to result, adding an .orig property. - var result = grunt.util._.extend({}, obj); + var result = _.extend({}, obj); // Make a clone of the orig obj available. - result.orig = grunt.util._.extend({}, obj); + result.orig = _.extend({}, obj); if ('src' in result) { // Expose an expand-on-demand getter method as .src. @@ -163,7 +166,7 @@ task.normalizeMultiTaskFiles = function(data, target) { if (!('result' in fn)) { src = obj.src; // If src is an array, flatten it. Otherwise, make it into an array. - src = Array.isArray(src) ? grunt.util._.flatten(src) : [src]; + src = Array.isArray(src) ? _.flatten(src) : [src]; // Expand src files, memoizing result. fn.result = grunt.file.expand(expandOptions, src); } @@ -211,7 +214,7 @@ task.registerMultiTask = function(name, info, fn) { // Guaranteed to always be the actual task name. var name = thisTask.name; // Arguments (sans target) as an array. - this.args = grunt.util.toArray(arguments).slice(1); + this.args = _.toArray(arguments).slice(1); // If a target wasn't specified, run this task once for each target. if (!target || target === '*') { return task.runAllTargets(name, this.args); @@ -224,11 +227,11 @@ task.registerMultiTask = function(name, info, fn) { // and/or target-specific overrides, via the "options" property. this.options = function() { var targetObj = grunt.config([name, target]); - var args = [{}].concat(grunt.util.toArray(arguments)).concat([ + var args = [{}].concat(_.toArray(arguments)).concat([ grunt.config([name, 'options']), grunt.util.kindOf(targetObj) === 'object' ? targetObj.options : {} ]); - var options = grunt.util._.extend.apply(null, args); + var options = _.extend.apply(null, args); grunt.verbose.writeflags(options, 'Options'); return options; }; @@ -245,7 +248,7 @@ task.registerMultiTask = function(name, info, fn) { Object.defineProperty(this, 'filesSrc', { enumerable: true, get: function() { - return grunt.util._(this.files).chain().map('src').flatten().uniq().value(); + return _(this.files).chain().map('src').flatten().uniq().value(); }.bind(this) }); // Call original task function, passing in the target and any other args. @@ -317,7 +320,7 @@ function loadTask(filepath) { grunt.verbose.write(msg).ok(); // Log registered/renamed/unregistered tasks. ['un', ''].forEach(function(prefix) { - var list = grunt.util._.chain(registry[prefix + 'tasks']).uniq().sort().value(); + var list = _.chain(registry[prefix + 'tasks']).uniq().sort().value(); if (list.length > 0) { regCount++; grunt.verbose.writeln((prefix ? '- ' : '+ ') + grunt.log.wordlist(list)); @@ -345,7 +348,7 @@ function loadTasksMessage(info) { // Load tasks and handlers from a given directory. function loadTasks(tasksdir) { try { - var files = grunt.file.glob.sync('*.{js,coffee}', {cwd: tasksdir, maxDepth: 1}); + var files = glob.sync('*.{js,coffee}', {cwd: tasksdir, maxDepth: 1}); // Load tasks from files. files.forEach(function(filename) { loadTask(path.join(tasksdir, filename)); @@ -371,7 +374,7 @@ task.loadNpmTasks = function(name) { loadTasksMessage('"' + name + '" local Npm module'); var root = path.resolve('node_modules'); var pkgfile = path.join(root, name, 'package.json'); - var pkg = grunt.file.exists(pkgfile) ? grunt.file.readJSON(pkgfile) : {keywords: []}; + var pkg = grunt.file.exists(pkgfile) ? require(pkgfile) : {keywords: []}; // Process collection plugins. if (pkg.keywords && pkg.keywords.indexOf('gruntcollection') !== -1) { @@ -379,7 +382,7 @@ task.loadNpmTasks = function(name) { Object.keys(pkg.dependencies).forEach(function(depName) { // Npm sometimes pulls dependencies out if they're shared, so find // upwards if not found locally. - var filepath = grunt.file.findup('node_modules/' + depName, { + var filepath = findup('node_modules/' + depName, { cwd: path.resolve('node_modules', name), nocase: true }); @@ -418,7 +421,7 @@ task.init = function(tasks, options) { gruntfile = null; } else { gruntfile = grunt.option('gruntfile') || - grunt.file.findup('Gruntfile.{js,coffee}', {nocase: true}); + findup('Gruntfile.{js,coffee}', {nocase: true}); msg = 'Reading "' + (gruntfile ? path.basename(gruntfile) : '???') + '" Gruntfile...'; } diff --git a/lib/grunt/template.js b/lib/grunt/template.js index d1967df95..bfc278cc5 100644 --- a/lib/grunt/template.js +++ b/lib/grunt/template.js @@ -6,6 +6,7 @@ var grunt = require('../grunt'); var template = module.exports = {}; // External libs. +var _ = require('lodash'); template.date = require('dateformat'); // Format today's date. @@ -42,7 +43,7 @@ template.setDelimiters = function(name) { // Get the appropriate delimiters. var delimiters = allDelimiters[name in allDelimiters ? name : 'config']; // Tell Lo-Dash which delimiters to use. - grunt.util._.extend(grunt.util._.templateSettings, delimiters.lodash); + _.extend(_.templateSettings, delimiters.lodash); // Return the delimiters. return delimiters; }; @@ -63,7 +64,7 @@ template.process = function(tmpl, options) { // As long as tmpl contains template tags, render it and get the result, // otherwise just use the template string. while (tmpl.indexOf(delimiters.opener) >= 0) { - tmpl = grunt.util._.template(tmpl, options)(data); + tmpl = _.template(tmpl, options)(data); // Abort if template didn't change - nothing left to process! if (tmpl === last) { break; } last = tmpl; diff --git a/lib/util/task.js b/lib/util/task.js index d39ce1b02..368e960de 100644 --- a/lib/util/task.js +++ b/lib/util/task.js @@ -2,7 +2,7 @@ 'use strict'; - var grunt = require('../grunt'); + var _ = require('lodash'); // Construct-o-rama. function Task() { @@ -230,7 +230,7 @@ async = true; // The returned function should execute asynchronously in case // someone tries to do this.async()(); inside a task (WTF). - return grunt.util._.once(function(success) { + return _.once(function(success) { setTimeout(function() { complete(success); }, 1); }); }; diff --git a/package.json b/package.json index b90f90eed..7d701212d 100644 --- a/package.json +++ b/package.json @@ -37,11 +37,13 @@ "tool" ], "dependencies": { + "async": "~2.6.0", "coffeescript": "~1.10.0", "dateformat": "~1.0.12", "eventemitter2": "~0.4.13", "exit": "~0.1.1", "findup-sync": "~0.3.0", + "getobject": "~0.1.0", "glob": "~7.0.0", "grunt-cli": "~1.2.0", "grunt-known-options": "~1.1.0", @@ -49,6 +51,7 @@ "grunt-legacy-util": "~1.0.0", "iconv-lite": "~0.4.13", "js-yaml": "~3.5.2", + "lodash": "~4.17.5", "minimatch": "~3.0.2", "nopt": "~3.0.6", "path-is-absolute": "~1.0.0",