From c4047647ffbfbdb9ffe3bafb76d8f2bb7725960a Mon Sep 17 00:00:00 2001 From: aokonechnikov Date: Tue, 24 Sep 2019 13:00:32 -0400 Subject: [PATCH 1/4] feat: add monorepo support and convert to typescript --- .gitignore | 1 + README.md | 14 +- index.js | 140 ------------- package-lock.json | 502 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 31 +-- src/index.ts | 101 ++++++++++ tsconfig.json | 31 +++ tslint.json | 27 +++ 8 files changed, 690 insertions(+), 157 deletions(-) delete mode 100644 index.js create mode 100644 package-lock.json create mode 100644 src/index.ts create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.gitignore b/.gitignore index 0670764..91068c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules +dist npm-debug.log tmp .DS_Store diff --git a/README.md b/README.md index da382a2..d754aca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # load-grunt-parent-tasks -> Loads de-duped grunt tasks from parent or sibling modules. +> Loads de-duped grunt tasks from parent or sibling modules, or for hoisted monorepos. ## TL;DR @@ -25,7 +25,7 @@ look like this: │   │   ├── Gruntfile.js │   │   ├── node_modules │   │   │   └── Z - │   │   └── package.json (has depencencies X,Y,Z) + │   │   └── package.json (has dependencies X,Y,Z) │   ├── X │   └── Y └── package.json (has dependencies A,X,Y) @@ -49,7 +49,7 @@ a new module which contains project A's package.json with the addition of a │   │   │   ├── grunt-collection │   │   │   │   └── package.json (has dependencies X,Y,Z and 'keywords: ["gruntcollection"]') │   │   │   └── Z - │   │   └── package.json (has depencencies X,Y,Z) + │   │   └── package.json (has dependencies X,Y,Z) │   ├── X │   └── Y └── package.json (has dependencies A,X,Y) @@ -150,6 +150,14 @@ Default: `'grunt-collection'` The `module` option can be changed in case `grunt-collection` ever conflicts with any other package name. +### alwaysCreate + +Type: `boolean` +Default: `'false'` + +Will create the fake package in node_modules even if the cwd is root (this should be set if +you want to hoist grunt tasks in a monorepo) + ## Contributing In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). diff --git a/index.js b/index.js deleted file mode 100644 index 31833f6..0000000 --- a/index.js +++ /dev/null @@ -1,140 +0,0 @@ -/** - * If Grunt task is loaded as a submodule then create a `grunt-collection` module - * in your local `node_modules` folder to trick grunt into loading dependencies - * from a parent folder. This might be necessary if project A contains a Gruntfile.js - * with dependencies X, Y, and Z, and is loaded as a npm dependency of project B - * which contains dependencies A, X and Y. In that scenario NPM will de-dupe - * project A's NPM dependencies when executing `npm install` in project B and will - * look like this: - * - * B - * ├── node_modules - * │   ├── A - * │   │   ├── Gruntfile.js - * │   │   ├── node_modules - * │   │   │   └── Z - * │   │   └── package.json (has depencencies X,Y,Z) - * │   ├── X - * │   └── Y - * └── package.json (has dependencies A,X,Y) - * - * If project A's package.json contains an `install` or `postinstall` script that - * executes it's Gruntfile.js the Grunt task will throw 2 errors: - * - * Local Npm module "X" not found. Is it installed? - * Local Npm module "Y" not found. Is it installed? - * - * Project A's Grunt task will not be able to load the de-duped dependencies because - * they reside in the parents node_modules folder. This can be fixed by dropping in - * a new module which contains project A's package.json with the addition of a - * `keywords` property that contains `"gruntcollection"` in it's array. - * - * B - * ├── node_modules - * │   ├── A - * │   │   ├── Gruntfile.js - * │   │   ├── node_modules - * │   │   │   ├── grunt-collection - * │   │   │   │   └── package.json (has dependencies X,Y,Z and 'keywords: ["gruntcollection"]') - * │   │   │   └── Z - * │   │   └── package.json (has depencencies X,Y,Z) - * │   ├── X - * │   └── Y - * └── package.json (has dependencies A,X,Y) - * - * Then at the beginning of your Gruntfile.js you call `grunt.loadNpmTasks('grunt-collection')`. - * Now Grunt will search up for the current directory to find the modules to load. - * - * See: - * http://stackoverflow.com/questions/15225865/centralise-node-modules-in-project-with-subproject - * https://github.com/gruntjs/grunt/issues/696 - * http://stackoverflow.com/questions/24854215/grunt-doesnt-look-for-node-modules-in-parent-directory-like-node-does - */ -'use strict'; -var path = require('path'); - -/** - * Returns the element as an array. - * @method toArray - * @param {*} el An array or any other data type. - * @return {Array} The element as an array. - */ -function toArray(el) { - return Array.isArray(el) ? el : [el]; -} - -/** - * Creates a resolution for loading a package.json file. - * @method resolveConfig - * @param {String|Object} config The location of a package.json or the contents of the package.json. - * @return {Object} The contents of the package.json. - */ -function resolveConfig(config) { - if (typeof config === 'string') { - return require(path.resolve(config)); - } - return config; -} - -function loadGruntParentTasks(grunt, options) { - var log = function() { - grunt.verbose.writeln(['[loadGruntParentTasks]'.magenta].concat(Array.prototype.slice.call(arguments)).join(' ')); - }; - - options = options || {}; - - log('process.cwd(): ' + process.cwd().cyan); - - var isRoot = process.cwd().split(path.sep).filter(function(name) { - return name === 'node_modules'; - }).length === 0; - - log('isRoot: ' + ('' + isRoot).cyan); - - if (!isRoot) { - var _ = require('lodash'); - var findup = require('findup-sync'); - var globule = require('globule'); - - var config = resolveConfig(options.config || findup('package.json')); - var pattern = toArray(options.pattern || ['grunt-*']); - var scope = toArray(options.scope || ['dependencies', 'optionalDependencies']); - - var gruntCollection = path.resolve('./node_modules/', (options.module || 'grunt-collection')); - var gruntCollectionJson = path.join(gruntCollection, 'package.json'); - - var newPkg = {}; - var names = []; - var deps = {}; - - pattern.push('!grunt', '!grunt-cli'); - - names = scope.reduce(function (result, prop) { - deps[prop] = {}; - return result.concat(Object.keys(config[prop] || {})); - }, []); - - // Create a new depenencies object of grunt tasks to load based on the - // globbing pattern and scope. - globule.match(pattern, names).map(function(name) { - scope.forEach(function (prop) { - if (config[prop] && config[prop][name]) { - deps[prop][name] = config[prop][name]; - } - }); - }); - - newPkg = _.assign({}, config, { - keywords: [ 'gruntcollection' ], - scripts: {} - }, deps); - - log('Writing: ' + ('' + gruntCollectionJson).cyan); - grunt.file.mkdir(gruntCollection); - grunt.file.write(gruntCollectionJson, JSON.stringify(newPkg, null, 2)); - log('loadNpmTasks: ' + 'grunt-collection'.cyan); - grunt.loadNpmTasks('grunt-collection'); - } -} - -module.exports = loadGruntParentTasks; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b2280f2 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,502 @@ +{ + "name": "load-grunt-parent-tasks", + "version": "0.2.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@types/grunt": { + "version": "0.4.25", + "resolved": "https://registry.npmjs.org/@types/grunt/-/grunt-0.4.25.tgz", + "integrity": "sha512-nDlnSBxyDEEVYM+1Ls/rfnQBUnseDFsU7kdrsAXAogyma90udiwnByYg8y8Pu0TGq68YCy2FjYNb1S7zSoumCg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "12.7.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz", + "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "commander": { + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", + "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" + }, + "micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==" + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tslint": { + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.0.tgz", + "integrity": "sha512-2vqIvkMHbnx8acMogAERQ/IuINOq6DFqgF8/VDvhEkBqQh/x6SP0Y+OHnKth9/ZcHQSroOZwUQSN18v8KKF0/g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", + "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } +} diff --git a/package.json b/package.json index 7579756..c6bcfb4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "load-grunt-parent-tasks", "description": "Loads de-duped grunt tasks from parent or sibling modules.", - "version": "0.1.2", + "version": "0.2.0", "homepage": "https://github.com/psyrendust/load-grunt-parent-tasks", "author": { "name": "Larry Gordon", @@ -11,6 +11,10 @@ { "name": "Francisco Cortés", "email": "franklyn.bdn@gmail.com" + }, + { + "name": "Alex Okonechnikov", + "email": "alexo45@gmail.com" } ], "repository": { @@ -20,22 +24,21 @@ "bugs": { "url": "https://github.com/psyrendust/load-grunt-parent-tasks/issues" }, - "licenses": [ - { - "type": "MIT", - "url": "http://psyrendust.mit-license.org/2014/license.html" - } - ], - "engines": { - "node": ">= 0.10.0" + "license": "MIT", + "scripts": { + "build": "npm run lint && npm run compile", + "lint": "tslint './src/**/*.ts'", + "compile": "tsc" }, - "scripts": {}, "dependencies": { - "findup-sync": "^0.1.3", - "globule": "^0.2.0", - "lodash": "^2.4.1" + "findup-sync": "^4.0.0", + "globule": "^1.2.1" + }, + "devDependencies": { + "@types/grunt": "^0.4.25", + "tslint": "^5.20.0", + "typescript": "^3.6.3" }, - "devDependencies": {}, "keywords": [ "grunt", "load", diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..296c0d2 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,101 @@ +import * as path from 'path'; + +interface PassedOptions { + config?: {} | string; + pattern?: string | string[]; + scope?: string | string[]; + module?: string; + alwaysCreate?: boolean; +} + +interface ResolvedOptions { + config: {}; + pattern: string[]; + scope: string[]; + module: string; + alwaysCreate: boolean; +} + +/** + * Returns the element as an array. + */ +function toArray(el: string | string[]): string[] { + return Array.isArray(el) ? el : [el]; +} + +/** + * Creates a resolution for loading a package.json file. + */ +function resolveConfig(config: {} | string): {} { + if (typeof config === 'string') { + return require(path.resolve(config)); + } + return config; +} + +/** + * Sets default options for any options that were not passed + */ +function defaultOptions(options: PassedOptions): ResolvedOptions { + const findup = require('findup-sync'); + return { + alwaysCreate: !!options.alwaysCreate, + config: resolveConfig(options.config || findup('package.json')), + module: options.module || 'grunt-collection', + pattern: toArray(options.pattern || ['grunt-*']), + scope: toArray(options.scope || ['dependencies', 'optionalDependencies']) + }; +} + +function loadGruntParentTasks(grunt: IGrunt, options: PassedOptions = {}) { + const log = (...args: any[]) => { + grunt.log.verbose.writeln(['[loadGruntParentTasks]'.magenta].concat( + Array.prototype.slice.call(args)).join(' ')); + }; + + log('process.cwd(): ' + process.cwd().cyan); + + const isRoot = process.cwd().split(path.sep).filter((name) => name === 'node_modules').length === 0; + + log('isRoot: ' + ('' + isRoot).cyan); + + if (!isRoot || options.alwaysCreate) { + const globule = require('globule'); + const { config, pattern, scope, module: optModule } = defaultOptions(options); + + const gruntCollection = path.resolve('./node_modules/', optModule); + const gruntCollectionJson = path.join(gruntCollection, 'package.json'); + + const deps = { dependencies: {} }; + + pattern.push('!grunt', '!grunt-cli'); + + const names = scope.reduce((result: string[], prop) => { + deps[prop] = {}; + return result.concat(Object.keys(config[prop] || {})); + }, [] as string[]); + + // Create a new dependencies object of grunt tasks to load based on the + // globbing pattern and scope. + globule.match(pattern, names).map((name: string) => { + scope.forEach((prop) => { + if (config[prop] && config[prop][name]) { + deps.dependencies[name] = config[prop][name]; + } + }); + }); + + const newPkg = Object.assign({}, config, { + keywords: ['gruntcollection'], + scripts: {}, + }, deps); + + log('Writing: ' + ('' + gruntCollectionJson).cyan); + grunt.file.mkdir(gruntCollection); + grunt.file.write(gruntCollectionJson, JSON.stringify(newPkg, null, 2)); + log('loadNpmTasks: ' + 'grunt-collection'.cyan); + grunt.loadNpmTasks('grunt-collection'); + } +} + +module.exports = loadGruntParentTasks; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..e7f8ca5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "outDir": "dist", + "rootDir": "src", + "experimentalDecorators": true, + "importHelpers": true, + "inlineSourceMap": false, + "inlineSources": false, + "target": "es5", + "module": "commonjs", + "lib": [ + "esnext", + "dom" + ], + "sourceMap": true, + "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "suppressImplicitAnyIndexErrors": true, + "noUnusedLocals": true, + "allowSyntheticDefaultImports": true, + "skipLibCheck": true, + "strict": true, + "resolveJsonModule": true, + "declaration": true, + "isolatedModules": false, + "allowJs": false, + "noEmit": false + } +} \ No newline at end of file diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..d06b1c6 --- /dev/null +++ b/tslint.json @@ -0,0 +1,27 @@ +{ + "extends": [ + "tslint:recommended" + ], + "linterOptions": { + "exclude": [ + "node_modules/**/*.ts" + ] + }, + "rules": { + "quotemark": [ + true, + "single", + "avoid-escape" + ], + "semicolon": [ + true, + "always" + ], + "indent": [ + true, + "spaces" + ], + "interface-name": false, + "trailing-comma": false + } +} \ No newline at end of file From f217718d6914eb451b0136254653be615523ad89 Mon Sep 17 00:00:00 2001 From: aokonechnikov Date: Tue, 24 Sep 2019 13:06:52 -0400 Subject: [PATCH 2/4] chore: fix package.json for distribution --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index c6bcfb4..e5ea51b 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "name": "Larry Gordon", "email": "lgordon@psyrendust.com" }, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", "contributors": [ { "name": "Francisco Cortés", @@ -53,4 +55,4 @@ "de-duped", "submodules" ] -} +} \ No newline at end of file From f69c2ecbe3f2eccefedc0a1253f22a3e4d6efc62 Mon Sep 17 00:00:00 2001 From: aokonechnikov Date: Tue, 24 Sep 2019 13:24:40 -0400 Subject: [PATCH 3/4] chore: add npmignore --- .npmignore | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .npmignore diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..aaf6372 --- /dev/null +++ b/.npmignore @@ -0,0 +1,6 @@ +src/ +node_modules/ +.vscode/ +*.log +tsconfig.json +tslint.json \ No newline at end of file From bfdd80ad5836f938752583b0e2ec1b37b9b29b9c Mon Sep 17 00:00:00 2001 From: aokonechnikov Date: Tue, 24 Sep 2019 13:49:07 -0400 Subject: [PATCH 4/4] fix: allow proper export --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 296c0d2..9d78022 100644 --- a/src/index.ts +++ b/src/index.ts @@ -98,4 +98,4 @@ function loadGruntParentTasks(grunt: IGrunt, options: PassedOptions = {}) { } } -module.exports = loadGruntParentTasks; +export default loadGruntParentTasks;