├── .gitignore ├── README.md ├── examples ├── install-from-cache-example.js ├── install-from-cache-multiple.js └── serverless-example.js ├── lib ├── cli.js ├── index.js ├── installDeps.js └── utils │ ├── asyncReduce.js │ ├── dirSum.js │ ├── execPromise.js │ ├── flattie.js │ ├── fs.js │ ├── getHash.js │ ├── hashFile.js │ └── prefix.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | cache 9 | .cache 10 | other 11 | serverless-test 12 | two 13 | 14 | # production 15 | /build 16 | /functions-build 17 | 18 | # misc 19 | .DS_Store 20 | .env.local 21 | .env.development.local 22 | .env.test.local 23 | .env.production.local 24 | 25 | npm-debug.log* 26 | yarn-debug.log* 27 | yarn-error.log* 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Cache me outside 2 | 3 | 4 | 5 | Caching tool for quicker builds in CI systems 6 | 7 | 8 | - [Usage](#usage) 9 | * [1. Configure the files you want to cache](#1-configure-the-files-you-want-to-cache) 10 | * [2. Add to your build step](#2-add-to-your-build-step) 11 | - [API](#api) 12 | - [How it works](#how-it-works) 13 | 14 | 15 | ## Usage 16 | 17 | 18 | ### 1. Configure the files you want to cache 19 | 20 | 21 | 22 | ```js 23 | /* code from ./install-from-cache-example.js */ 24 | const path = require('path') 25 | const cacheMeOutside = require('../lib') // require('cache-me-outside') 26 | 27 | /* cache destination folder */ 28 | // const cacheFolder = path.join('/opt/build/cache', 'storage') 29 | const cacheFolder = path.join(__dirname, '.cache') 30 | /* Array of folders to cache */ 31 | const contentsToCache = [ 32 | { 33 | contents: path.join(__dirname, '../node_modules'), 34 | handleCacheUpdate: 'npm install', 35 | shouldCacheUpdate: async ({ cacheManifest, actions }) => { 36 | console.log('cacheManifest', cacheManifest) 37 | console.log(actions) 38 | /* Your custom invalidation logic */ 39 | 40 | /* 41 | - Dates cache last updated 42 | - Make remote api request 43 | - Diff dependencies files like package.json 44 | - Whatever you want 45 | */ 46 | 47 | // This example uses changes to package.json to invalid cached 'node_modules' folder 48 | const packageJson = path.join(__dirname, '../package.json') 49 | const packageJsonChanged = await actions.diff(packageJson) 50 | console.log('packageJsonChanged', packageJsonChanged) 51 | const updateCache = packageJsonChanged 52 | return updateCache // Boolean 53 | }, 54 | }, 55 | // ... add more folders if you want 56 | ] 57 | 58 | // Run cacheMeOutside 59 | cacheMeOutside(cacheFolder, contentsToCache).then((cacheInfo) => { 60 | console.log('Success! You are ready to rock') 61 | cacheInfo.forEach((info) => { 62 | console.log(info.cacheDir) 63 | }) 64 | }) 65 | ``` 66 | 67 | 68 | ### 2. Add to your build step 69 | 70 | Now that we have configured what we want to cache, we need to add this to our build step. 71 | 72 | Inside `package.json`, or whatever build tool you are using, run the `catch-me-outside` script before your build step. 73 | 74 | ```json 75 | { 76 | "scripts": { 77 | "prebuild": "node ./install-from-cache-example.js", 78 | "build": "react-scripts build" 79 | } 80 | } 81 | ``` 82 | 83 | Inside of CI system: `npm run build` will run through the diagram below. 84 | 85 | 1. Check for the cached files 86 | 2. If no cache, run the `handleCacheUpdate` commands or function (ie `npm install`) 87 | 3. Then save the contents to the cache directory for the next run. 88 | 89 | If any of `shouldCacheUpdate` return true, the cached files are invalidated and `handleCacheUpdate` is ran again. 90 | 91 | If you omit `shouldCacheUpdate`, the hash of the folder contents will be used, so if any file changes within the contents you are caching, the `handleCacheUpdate` will run. 92 | 93 | 94 | ## API 95 | 96 | 97 | 98 | ```js 99 | /* code from install-from-cache-multiple.js */ 100 | const path = require('path') 101 | const cacheMeOutside = require('../lib') // require('cache-me-outside') 102 | 103 | /* Netlify cache folder */ 104 | //let cacheFolder = path.join('/opt/build/cache', 'my-cache-folder') 105 | let cacheFolder = path.join(__dirname, '.cache') 106 | /* Array of folders to cache */ 107 | const contentsToCache = [ 108 | { 109 | /** 110 | * Directory of files to cache 111 | * @type {String} 112 | */ 113 | contents: path.join(__dirname, '../node_modules'), 114 | /** 115 | * Command or Function to run on `shouldCacheUpdate = true` 116 | * @type {String|Function} 117 | */ 118 | handleCacheUpdate: 'npm install && echo "this runs when cache is invalid"', 119 | /** 120 | * Sets whether or not cache should get updated 121 | * @param {object} api 122 | * @param {object} api.cacheManifest - contains useful info for custom invalidation 123 | * @param {object} api.actions - contains helpful functions for diffing 124 | * @return {Boolean} Returns true or false 125 | */ 126 | shouldCacheUpdate: async ({ cacheManifest, actions }) => { 127 | // This example uses changes to package.json to invalid cached 'node_modules' folder 128 | const packageJson = path.join(__dirname, '../package.json') 129 | const packageJsonChanged = await actions.diff(packageJson) 130 | // You can check multiple files or run custom logic 131 | return packageJsonChanged 132 | }, 133 | }, 134 | { 135 | contents: path.join(__dirname, '../other/node_modules'), 136 | shouldCacheUpdate: function() { 137 | /* your custom cache invalidation logic here */ 138 | return false 139 | }, 140 | handleCacheUpdate: 'yarn install' 141 | }, 142 | { 143 | contents: path.join(__dirname, '../serverless-test/.serverless'), 144 | handleCacheUpdate: () => { 145 | console.log('run my custom stuff here') 146 | } 147 | // if `shouldCacheUpdate` omitted will use contents folder hash 148 | }, 149 | ] 150 | 151 | /* 152 | // local cache folder for testing 153 | cacheFolder = path.resolve('./cache') 154 | /**/ 155 | 156 | // Run cacheMeOutside 157 | cacheMeOutside(cacheFolder, contentsToCache).then((cacheInfo) => { 158 | console.log('Success! You are ready to rock') 159 | cacheInfo.forEach((info) => { 160 | console.log(info.cacheDir) 161 | }) 162 | }) 163 | ``` 164 | 165 | 166 | When the cache is saved it generates a `cache.json` manifest file. This is passed into `shouldCacheUpdate` if you want to use it to invalidate your cache. 167 | 168 | ```json 169 | { 170 | "createdOn": 1534296638475, 171 | "createdOnDate": "Wed, 15 Aug 2018 01:30:38 GMT", 172 | "modifiedOn": 1534300695541, 173 | "cacheDir": "/Users/davidwells/Netlify/cache-magic/cache/Netlify/cache-magic/serverless-test", 174 | "cacheDirContents": "/Users/davidwells/Netlify/cache-magic/cache/Netlify/cache-magic/serverless-test/.serverless", 175 | "contents": { 176 | "src": "/Users/davidwells/Netlify/cache-magic/serverless-test/.serverless", 177 | "hash": "0496d16c0a8b1d43ca2d3c77ca48a8e237fdb625", 178 | "files": { 179 | "stuff.txt": "11b80f260a5eea9e867a23ab7f96aff77080ff90" 180 | } 181 | } 182 | } 183 | ``` 184 | 185 | ## How it works 186 | 187 | ``` 188 | 189 | 190 | ┌───────────────────────────────────────┐ 191 | │ │ 192 | │ npm run build │ 193 | │ │ 194 | │ "node ./cache-me-script.js" │ 195 | │ │ 196 | └───────────────────────────────────────┘ 197 | │ 198 | Does cache exist? 199 | │ 200 | │ 201 | ├───────────Yes───────────┐ 202 | │ │ 203 | │ │ 204 | ┌────────────No───────────┘ │ 205 | │ ▼ 206 | │ ┌───────────────────────────┐ 207 | │ │ │ 208 | │ │ Check if Cache is valid │ 209 | │ │ via `shouldCacheUpdate` │ 210 | │ │ │ 211 | │ │ │ 212 | ▼ └───────────────────────────┘ 213 | ┌───────────────────────────┐ │ 214 | │ │ Is cache valid? 215 | │ Run `handleCacheUpdate` │ │ 216 | │ command or function │◀────────────Not valid───────────────┴─────────────Valid─────┐ 217 | │ │ │ 218 | │ │ │ 219 | └───────────────────────────┘ │ 220 | │ ▼ 221 | │ ┌────────────────────────────────────────────┐ 222 | ▼ │ │ 223 | ┌────────────────────────────┐ │ Cache is good and no files that would │ 224 | │ │ │ trigger an update have changed. │ 225 | │ Copy contents to cache │ │ │ 226 | │ directory for next run │ │ Copy cache contents to source destination │ 227 | │ │ │ │ 228 | │ │ └────────────────────────────────────────────┘ 229 | └────────────────────────────┘ 230 | ``` 231 | -------------------------------------------------------------------------------- /examples/install-from-cache-example.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const cacheMeOutside = require('../lib') // require('cache-me-outside') 3 | 4 | /* cache destination folder */ 5 | // const cacheFolder = path.join('/opt/build/cache', 'storage') 6 | const cacheFolder = path.join(__dirname, '.cache') 7 | /* Array of folders to cache */ 8 | const contentsToCache = [ 9 | { 10 | contents: path.join(__dirname, '../node_modules'), 11 | handleCacheUpdate: 'npm install', 12 | shouldCacheUpdate: async ({ cacheManifest, actions }) => { 13 | console.log('cacheManifest', cacheManifest) 14 | console.log(actions) 15 | /* Your custom invalidation logic */ 16 | 17 | /* 18 | - Dates cache last updated 19 | - Make remote api request 20 | - Diff dependencies files like package.json 21 | - Whatever you want 22 | */ 23 | 24 | // This example uses changes to package.json to invalid cached 'node_modules' folder 25 | const packageJson = path.join(__dirname, '../package.json') 26 | const packageJsonChanged = await actions.diff(packageJson) 27 | console.log('packageJsonChanged', packageJsonChanged) 28 | const updateCache = packageJsonChanged 29 | return updateCache // Boolean 30 | }, 31 | }, 32 | // ... add more folders if you want 33 | ] 34 | 35 | // Run cacheMeOutside 36 | cacheMeOutside(cacheFolder, contentsToCache).then((cacheInfo) => { 37 | console.log('Success! You are ready to rock') 38 | cacheInfo.forEach((info) => { 39 | console.log(info.cacheDir) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /examples/install-from-cache-multiple.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const cacheMeOutside = require('../lib') // require('cache-me-outside') 3 | 4 | /* Netlify cache folder */ 5 | //let cacheFolder = path.join('/opt/build/cache', 'my-cache-folder') 6 | let cacheFolder = path.join(__dirname, '.cache') 7 | /* Array of folders to cache */ 8 | const contentsToCache = [ 9 | { 10 | /** 11 | * Directory of files to cache 12 | * @type {String} 13 | */ 14 | contents: path.join(__dirname, '../node_modules'), 15 | /** 16 | * Command or Function to run on `shouldCacheUpdate = true` 17 | * @type {String|Function} 18 | */ 19 | handleCacheUpdate: 'npm install && echo "this runs when cache is invalid"', 20 | /** 21 | * Sets whether or not cache should get updated 22 | * @param {object} api 23 | * @param {object} api.cacheManifest - contains useful info for custom invalidation 24 | * @param {object} api.actions - contains helpful functions for diffing 25 | * @return {Boolean} Returns true or false 26 | */ 27 | shouldCacheUpdate: async ({ cacheManifest, actions }) => { 28 | // This example uses changes to package.json to invalid cached 'node_modules' folder 29 | const packageJson = path.join(__dirname, '../package.json') 30 | const packageJsonChanged = await actions.diff(packageJson) 31 | // You can check multiple files or run custom logic 32 | return packageJsonChanged 33 | }, 34 | }, 35 | { 36 | contents: path.join(__dirname, '../other/node_modules'), 37 | shouldCacheUpdate: function() { 38 | /* your custom cache invalidation logic here */ 39 | return false 40 | }, 41 | handleCacheUpdate: 'yarn install' 42 | }, 43 | { 44 | contents: path.join(__dirname, '../serverless-test/.serverless'), 45 | handleCacheUpdate: () => { 46 | console.log('run my custom stuff here') 47 | } 48 | // if `shouldCacheUpdate` omitted will use contents folder hash 49 | }, 50 | ] 51 | 52 | /* 53 | // local cache folder for testing 54 | cacheFolder = path.resolve('./cache') 55 | /**/ 56 | 57 | // Run cacheMeOutside 58 | cacheMeOutside(cacheFolder, contentsToCache).then((cacheInfo) => { 59 | console.log('Success! You are ready to rock') 60 | cacheInfo.forEach((info) => { 61 | console.log(info.cacheDir) 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /examples/serverless-example.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const cacheMeOutside = require('../lib') // require('cache-me-outside') 3 | 4 | /* cache destination folder */ 5 | // const cacheFolder = path.join('/opt/build/cache', 'storage') 6 | const cacheFolder = path.join(__dirname, '.cache') 7 | /* Array of folders to cache */ 8 | const cacheInstructions = [ 9 | { 10 | contents: path.join(__dirname, '../other/node_modules'), 11 | shouldCacheUpdate: async ({ cacheManifest, actions }) => { 12 | /* 13 | - Dates cache last updated 14 | - Make remote api request 15 | - Diff dependencies files like package.json 16 | - Whatever you want 17 | */ 18 | console.log('cacheManifest', cacheManifest) 19 | // const { files, src } = cacheManifest.contents 20 | // This example uses changes to package.json to invalid cached 'node_modules' folder 21 | const filePath = path.join(path.join(__dirname, '../serverless-test'), 'serverless.yml') 22 | const fileChanged = await actions.diff(filePath) 23 | console.log('fileChanged', fileChanged) 24 | return fileChanged // Boolean 25 | }, 26 | /* Run cache update as simple command */ 27 | // handleCacheUpdate: 'npm install', 28 | /* Custom cache update functionality */ 29 | handleCacheUpdate: async (api) => { 30 | console.log('UPDATE CACHE', api) 31 | await api.actions.runCommand('npm install') 32 | }, 33 | /* Custom cache restore functionality */ 34 | handleCacheRestore: async (api) => { 35 | console.log('RESTORE CACHE', api) 36 | await api.actions.restoreCache() 37 | }, 38 | /* Custom cache persistance functionality */ 39 | handleCacheSave: async (api) => { 40 | console.log('SAVE CACHE', api) 41 | await api.actions.saveCache() 42 | }, 43 | }, 44 | // ... add more folders if you want 45 | ] 46 | 47 | // Run cacheMeOutside 48 | cacheMeOutside(cacheFolder, cacheInstructions).then((cacheInfo) => { 49 | console.log('Success! You are ready to rock', cacheInfo) 50 | }) 51 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | const minimist = require('minimist') 2 | const args = minimist(process.argv.slice(2)) 3 | 4 | // we're being used from the command line 5 | switch (args.exec) { 6 | case 'foo': 7 | console.log('do foo') 8 | break 9 | case 'bar': 10 | // for simple testing in the monorepo 11 | console.log('do bar') 12 | break 13 | default: 14 | // export our node module interface 15 | console.log('default thing') 16 | } 17 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | const path = require('path') 3 | const getHash = require('./utils/getHash') 4 | // const installDeps = require('./installDeps') 5 | const execPromise = require('./utils/execPromise') 6 | const hashFolder = require('./utils/dirSum') 7 | const checkForDiffs = require('./utils/asyncReduce') 8 | const hashFile = require('./utils/hashFile') 9 | const { flattie } = require('./utils/flattie') 10 | const { 11 | fileExists, 12 | createDirectory, 13 | copyDirectory, 14 | removeDirectory, 15 | writeFile, 16 | readFile 17 | } = require('./utils/fs') 18 | 19 | const cwd = process.cwd() 20 | const homeDir = os.homedir() 21 | 22 | function nicePath(filePath = '') { 23 | return filePath.replace(cwd, '') 24 | } 25 | 26 | async function cacheMeOutside(cacheFolder, cacheInstructions) { 27 | const options = {} 28 | const currentWorkingDir = cwd 29 | const defaultOptions = { 30 | cwd: currentWorkingDir, 31 | contents: currentWorkingDir, 32 | directory: currentWorkingDir 33 | } 34 | const opts = Object.assign(defaultOptions, options) 35 | 36 | // console.log('directory', directory) 37 | const cacheDirectory = cacheFolder || path.resolve('./opt/buildhome/cache') 38 | 39 | // coerse single path into array 40 | if (!Array.isArray(cacheInstructions)) { 41 | cacheInstructions = [ 42 | { 43 | path: cacheInstructions, 44 | invalidateOn: opts.invalidateOn, 45 | } 46 | ] 47 | } 48 | 49 | /* disable exists check for right meow 50 | if (Array.isArray(directory)) { 51 | // console.log(directory) 52 | const checkFilesParallel = directory.map(async (dir) => { 53 | console.log('dir.path', dir.path) 54 | const exists = await fileExists(dir.path) 55 | console.log('exists') 56 | return exists 57 | }) 58 | const directoryData = await Promise.all(checkFilesParallel).then((data) => { 59 | return data.map((exists, i) => { 60 | const obj = directory[i] 61 | obj.exists = exists 62 | return obj 63 | }) 64 | }) 65 | 66 | const everythingExists = directoryData.filter((d) => { 67 | return !d.exists 68 | }) 69 | // console.log(directoryData) 70 | if (everythingExists.length) { 71 | everythingExists.forEach((err) => { 72 | console.log(`Error: ${err.path} NOT FOUND`) 73 | }) 74 | throw new Error('Supplied content paths invalid') 75 | } 76 | } 77 | */ 78 | 79 | // // Todo check for multiple folders 80 | // const directoryExists = await fileExists(cwd) 81 | // if (!directoryExists) { 82 | // console.log(`${cwd} does not exist`) 83 | // return false 84 | // } 85 | 86 | const checkCacheParallel = cacheInstructions.map(async (instructions) => { 87 | return checkCache(instructions, { 88 | cacheDirectory 89 | }) 90 | }) 91 | 92 | return Promise.all(checkCacheParallel) 93 | } 94 | 95 | async function checkCache(instructions, { cacheDirectory }) { 96 | const d = instructions 97 | const directory = d.contents 98 | 99 | const parentDirectory = path.dirname(directory) 100 | // console.log('parentDirectory', parentDirectory) 101 | const cleanDir = directory.replace(homeDir, '') || '_base' 102 | 103 | const cacheContentDirectory = path.join(cacheDirectory, cleanDir) 104 | // console.log('cacheContentDirectory', cacheContentDirectory) 105 | const cacheContentsDirectory = path.dirname(cacheContentDirectory) 106 | // console.log('cacheContentsDirectory', cacheContentsDirectory) 107 | const cacheDetailsPath = path.join(cacheContentsDirectory, 'cache.json') 108 | // console.log('cacheDetailsPath', cacheDetailsPath) 109 | const niceDirPath = nicePath(directory) 110 | 111 | let cacheData 112 | try { 113 | cacheData = await getCacheFile(cacheDetailsPath) 114 | } catch (e) { 115 | console.log(`cacheData error from ${cacheDetailsPath}`) 116 | console.log(e) 117 | } 118 | 119 | const firstRun = (typeof cacheData === 'undefined') ? true : false 120 | if (firstRun) { 121 | console.log(`No 'cache.json' found in ${cacheContentsDirectory}`) 122 | } 123 | 124 | let shouldCacheUpdate = false 125 | let shouldUpdateFn = defaultShouldUpdate 126 | if (d.shouldCacheUpdate && typeof d.shouldCacheUpdate === 'function') { 127 | shouldUpdateFn = d.shouldCacheUpdate 128 | } 129 | function diffWrapper(filePath) { 130 | return diff(filePath, cacheDetailsPath) 131 | } 132 | console.log(`1. 🔍 Checking for changes in ${niceDirPath} ...`) 133 | 134 | // Run custom or default shouldCacheUpdate 135 | shouldCacheUpdate = await shouldUpdateFn({ 136 | directory, 137 | cacheDirectory, 138 | cacheContentDirectory, 139 | actions: { 140 | diff: diffWrapper 141 | }, 142 | cacheManifest: cacheData, 143 | settings: d 144 | }) 145 | 146 | let currentCacheData = {} 147 | try { 148 | currentCacheData = await getCacheFile(cacheDetailsPath) || {} 149 | } catch (e) { 150 | console.log(`cacheData error from ${cacheDetailsPath}`) 151 | console.log(e) 152 | } 153 | 154 | /* If shouldn't update and it's not the first run. Exit early */ 155 | let cacheRestoreFailure = false 156 | if (!shouldCacheUpdate && !firstRun) { 157 | console.log(`2. 👍 No changes detected in ${niceDirPath}\n`) 158 | console.log(` Cache created on ${currentCacheData.createdAt}`) 159 | console.log(` Cache updated on ${currentCacheData.updatedAt}`) 160 | console.log() 161 | /* Copy cached files to their proper source location */ 162 | /* Run Restore cache function */ 163 | const handleCacheRestore = d.handleCacheRestore || restoreCachedFiles 164 | const payload = { 165 | isNoOp: false, // TODO add check if skip handleCacheRestore logic if we need to. 166 | directory, 167 | cacheDirectory, 168 | cacheContentDirectory, 169 | actions: { 170 | restoreCache: () => restoreCachedFiles({ directory, cacheContentDirectory }), 171 | }, 172 | cacheManifest: cacheData, 173 | settings: d 174 | } 175 | try { 176 | await handleCacheRestore(payload) 177 | } catch (e) { 178 | console.log('❌ Cache Restore error', e) 179 | cacheRestoreFailure = true 180 | shouldCacheUpdate = true 181 | // throw new Error(e) 182 | } 183 | 184 | if (!cacheRestoreFailure) { 185 | return Promise.resolve(currentCacheData) 186 | } 187 | } 188 | 189 | if (!cacheData || shouldCacheUpdate) { 190 | console.log(`2. 👩‍🎤 Changes detected in ${niceDirPath}. Running cache update logic\n`) 191 | /* Clear out cache directory */ 192 | await removeDirectory(cacheContentDirectory) 193 | 194 | // Run handleCacheUpdate cmd/function 195 | if (d.handleCacheUpdate) { 196 | // Handle CLI commands 197 | if (typeof d.handleCacheUpdate === 'string') { 198 | console.log(`3. ⚙️ Running command "${d.handleCacheUpdate}" in ${parentDirectory}...\n`) 199 | await execPromise(d.handleCacheUpdate, { 200 | cwd: parentDirectory 201 | }) 202 | } 203 | // Handle custom functions 204 | if (typeof d.handleCacheUpdate === 'function') { 205 | console.log('3. ⚙️ Running handleCacheUpdate function...\n') 206 | await d.handleCacheUpdate({ 207 | directory, 208 | cacheDirectory, 209 | cacheContentDirectory, 210 | actions: { 211 | runCommand: (cmd, cwd = parentDirectory) => execPromise(cmd, { cwd: cwd }), 212 | }, 213 | cacheManifest: cacheData, // TODO refactor shape 214 | settings: d, 215 | }) 216 | } 217 | // TODO use smart heuristic to determine how to update caches 218 | } 219 | 220 | /* Run Restore cache function */ 221 | const handleCacheSave = d.handleCacheSave || saveCache 222 | try { 223 | await handleCacheSave({ 224 | directory, 225 | cacheDirectory, 226 | cacheContentDirectory, 227 | actions: { 228 | saveCache: () => saveCache({ directory, cacheContentDirectory }), 229 | }, 230 | cacheManifest: cacheData, 231 | settings: d, 232 | }) 233 | } catch (e) { 234 | console.log('❌ Cache Save error') 235 | throw new Error(e) 236 | } 237 | } 238 | 239 | console.log(`6. Saving cache info...`) 240 | 241 | const date = new Date() 242 | const now = date.toISOString() 243 | const info = { 244 | // createdOn: currentCacheData.createdOn || now, 245 | createdAt: currentCacheData.createdAt || now, 246 | updatedAt: now 247 | } 248 | 249 | if (currentCacheData.diffs) { 250 | info.diffs = currentCacheData.diffs 251 | } 252 | 253 | const folderHash = await hashFolder(directory) 254 | 255 | const defaultInfo = { 256 | ...info, 257 | cacheDir: path.dirname(cacheContentDirectory), 258 | cacheDirContents: cacheContentDirectory, 259 | contents: { 260 | src: directory, 261 | hash: folderHash.hash, 262 | files: folderHash.files 263 | } 264 | } 265 | 266 | const contents = JSON.stringify(defaultInfo, null, 2) 267 | // Save cache data for next run 268 | await writeFile(cacheDetailsPath, contents) 269 | console.log(`✓ Dependencies cached for next run!`) 270 | console.log(`Cache Location: ${cacheContentDirectory}`) 271 | 272 | return Promise.resolve(defaultInfo) 273 | } 274 | 275 | // "build": "npm-install-cache && npm run build" 276 | module.exports = cacheMeOutside 277 | module.exports.getHash = getHash 278 | 279 | async function restoreCachedFiles({ directory, cacheContentDirectory }) { 280 | const niceDirPath = nicePath(directory) 281 | console.log(`3. 👯 Restoring cached contents 282 | - from "${cacheContentDirectory}" 283 | - to src "${directory}"\n`) 284 | try { 285 | await copyDirectory(cacheContentDirectory, directory) 286 | } catch (e) { 287 | console.log('❌ Cache Copy error') 288 | throw new Error(e) 289 | } 290 | console.log(`4. ✅ Finished Restoring cached contents to src directory "${niceDirPath}"\n`) 291 | } 292 | 293 | async function saveCache({ directory, cacheContentDirectory }) { 294 | console.log(`4. Copying over ${directory} to ${cacheContentDirectory}...\n`) 295 | await copyDirectory(directory, cacheContentDirectory) 296 | console.log(`5. ✓ Dependencies copied to cache ${cacheContentDirectory}\n`) 297 | } 298 | 299 | /* Default should update checks for folder hash change */ 300 | async function defaultShouldUpdate(cacheData) { 301 | // console.log('DEFUALT defaultShouldUpdate') 302 | if (!cacheData || !cacheData.contents || !cacheData.contents.hash) { 303 | // No cache, is first run 304 | return true 305 | } 306 | const cacheHash = cacheData.contents.hash 307 | let folderHash = {} 308 | try { 309 | folderHash = await hashFolder(cacheData.contents.src) 310 | } catch(e) { 311 | if (e.code !== 'ENOENT') { 312 | throw new Error(e) 313 | } 314 | } 315 | 316 | if (folderHash.hash !== cacheHash) { 317 | console.log(`\nDetected changes in "${cacheData.contents.src}\n`) 318 | /* Do deep comparsion to find hash changes */ 319 | const fileChanges = findChanges(cacheData.contents, folderHash) 320 | if (fileChanges.length) { 321 | const parentDir = path.basename(cacheData.contents.src) 322 | fileChanges.forEach(({ fileName, type }) => { 323 | console.log(`- "${path.join(parentDir, fileName)}" ${type}`) 324 | }) 325 | } 326 | console.log('\nTIME TO PURGE CACHE & RENEW SRC DIR\n') 327 | return true 328 | } 329 | 330 | if (folderHash.hash === cacheData.contents.hash) { 331 | console.log(`\nNO changes to folder ${cacheData.contents.src}\n`) 332 | // console.log(cacheData) 333 | } 334 | 335 | return false 336 | } 337 | 338 | function findChanges(one, two) { 339 | const y = flattie(one) 340 | const z = flattie(two) 341 | const yKeys = Object.keys(y) 342 | const zKeys = Object.keys(z) 343 | // Use longest array 344 | const array = (yKeys.length >= zKeys.length) ? yKeys : zKeys 345 | const foundDiffs = [] 346 | for (let index = 0; index < array.length; index++) { 347 | const key = array[index] 348 | if (y[key] !== z[key]) { 349 | // console.log('Old', y[key]) 350 | // console.log('New', z[key]) 351 | let type = 'changed' 352 | if (typeof y[key] === 'undefined') { 353 | type = 'added' 354 | } else if (typeof z[key] === 'undefined') { 355 | type = 'removed' 356 | } 357 | if (key !== 'src' && key !== 'hash' && !key.endsWith('hash')) { 358 | const fileName = key 359 | .replace(/^files\./g, '') 360 | .replace(/\.files\.(?!files\.)/g, '/') 361 | foundDiffs.push({ fileName, type }) 362 | } 363 | } 364 | } 365 | return foundDiffs 366 | } 367 | 368 | async function diff(filePath, cacheFile) { 369 | let cacheData = {} 370 | try { 371 | cacheData = await getCacheFile(cacheFile) || {} 372 | } catch (e) { 373 | console.log(`cacheData error from ${cacheFile}`) 374 | } 375 | // No change file exists 376 | if (!cacheData.diffs || !Object.keys(cacheData.diffs).length || !cacheData.diffs[filePath]) { 377 | // console.log('previousDiff.diffs', cacheData.diffs) 378 | const prev = cacheData.diffs || {} 379 | 380 | const newContents = { 381 | ...cacheData, 382 | ...{ 383 | diffs: Object.assign({}, prev, { 384 | [`${filePath}`]: await getHash(filePath), 385 | }) 386 | }, 387 | } 388 | 389 | // TODO make atomic write 390 | await writeFile(cacheFile, JSON.stringify(newContents, null, 2)) 391 | // no difference 392 | return false 393 | } 394 | // console.log('filePath', filePath) 395 | const currentHash = await getHash(filePath) 396 | // console.log('cacheData', cacheData) 397 | 398 | // Hashes match, no difference 399 | if (cacheData && cacheData.diffs && cacheData.diffs[filePath] === currentHash) { 400 | // console.log(`NO DIFFs in ${filePath}`) 401 | return false 402 | } 403 | 404 | // hashes do not match. There is difference 405 | if (cacheData && cacheData.diffs && cacheData.diffs[filePath] !== currentHash) { 406 | console.log(`┃ "${filePath}" has changed`) 407 | console.log(`┃ Old hash: ${cacheData.diffs[filePath]}`) 408 | console.log(`┃ New hash: ${currentHash}`) 409 | 410 | const diffKeys = Object.keys(cacheData.diffs) 411 | const t = await checkForDiffs(diffKeys, filePath, cacheData) 412 | const newDiffs = t.reduce((acc, hash, i) => { 413 | const fileName = diffKeys[i] 414 | acc[fileName] = hash 415 | return acc 416 | }, {}) 417 | 418 | const newContents = { 419 | ...cacheData, 420 | ...{ 421 | diffs: newDiffs 422 | }, 423 | } 424 | // Write new hash for next run 425 | await writeFile(cacheFile, JSON.stringify(newContents, null, 2)) 426 | return true 427 | } 428 | } 429 | 430 | async function getCacheFile(filePath) { 431 | const fileDoesExist = await fileExists(filePath) 432 | if (!fileDoesExist) { 433 | return 434 | } 435 | 436 | return readFile(filePath).then((data) => JSON.parse(data)) 437 | } 438 | 439 | module.exports.diff = diff 440 | -------------------------------------------------------------------------------- /lib/installDeps.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const execPromise = require('./utils/execPromise') 3 | const { fileExists } = require('./utils/fs') 4 | 5 | module.exports = function npmInstall(opts, dir) { 6 | const lockFilePath = path.join(opts.cwd, 'package-lock.json') 7 | return fileExists(lockFilePath).then((hasLock) => { 8 | if (hasLock) { 9 | // run faster ci command if package-lock.json exists 10 | return execPromise(`npm ci`, opts) 11 | } 12 | return execPromise(`npm install`, opts) 13 | }) 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/asyncReduce.js: -------------------------------------------------------------------------------- 1 | const getHash = require('./getHash') 2 | 3 | async function asyncReduce(array, handler, startingValue) { 4 | let result = startingValue 5 | 6 | for (let value of array) { 7 | // `await` will transform result of the function to the promise, 8 | // even it is a synchronous call 9 | result = await handler(result, value) 10 | } 11 | 12 | return result 13 | } 14 | 15 | function checkForDiffs(diffKeys, filePath, cacheData) { 16 | return asyncReduce(diffKeys, 17 | async (resolvedLinks, current) => { 18 | if (current === filePath) { 19 | const hashPromise = await getHash(filePath) 20 | return resolvedLinks.concat(hashPromise) 21 | } 22 | const valuePromise = await Promise.resolve(cacheData.diffs[current]) 23 | return resolvedLinks.concat(valuePromise) 24 | }, []) 25 | } 26 | 27 | module.exports = checkForDiffs 28 | -------------------------------------------------------------------------------- /lib/utils/dirSum.js: -------------------------------------------------------------------------------- 1 | 2 | var crypto = require('crypto') 3 | var fs = require('fs') 4 | 5 | function _summarize(method, hashes) { 6 | var keys = Object.keys(hashes) 7 | keys.sort() 8 | 9 | var obj = {} 10 | obj.files = hashes 11 | var hash = crypto.createHash(method) 12 | for (var i = 0; i < keys.length; i++) { 13 | if (typeof (hashes[keys[i]]) === 'string') { 14 | hash.update(hashes[keys[i]]) 15 | } else if (typeof (hashes[keys[i]]) === 'object') { 16 | hash.update(hashes[keys[i]].hash) 17 | } else { 18 | console.error('Unknown type found in hash: ' + typeof (hashes[keys[i]])) 19 | } 20 | } 21 | 22 | obj.hash = hash.digest('hex') 23 | return obj 24 | } 25 | 26 | function digest(root, method, callback) { 27 | if (!root || typeof (root) !== 'string') { 28 | throw new TypeError('root is required (string)') 29 | } 30 | if (method) { 31 | if (typeof (method) === 'string') { 32 | // NO-OP 33 | } else if (typeof (method) === 'function') { 34 | callback = method 35 | method = 'md5' 36 | } else { 37 | throw new TypeError('hash must be a string') 38 | } 39 | } else { 40 | throw new TypeError('callback is required (function)') 41 | } 42 | if (!callback) { 43 | throw new TypeError('callback is required (function)') 44 | } 45 | 46 | var hashes = {} 47 | 48 | fs.readdir(root, function(err, files) { 49 | if (err) return callback(err) 50 | 51 | if (files.length === 0) { 52 | return callback(undefined, {hash: '', files: {}}) 53 | } 54 | 55 | var hashed = 0 56 | files.forEach(function(f) { 57 | var path = root + '/' + f 58 | fs.stat(path, function(err, stats) { 59 | if (err) return callback(err) 60 | 61 | if (stats.isDirectory()) { 62 | return digest(path, method, function(err, hash) { 63 | if (err) return hash 64 | 65 | hashes[f] = hash 66 | if (++hashed >= files.length) { 67 | return callback(undefined, _summarize(method, hashes)) 68 | } 69 | }) 70 | } else if (stats.isFile()) { 71 | fs.readFile(path, 'utf8', function(err, data) { 72 | if (err) return callback(err) 73 | 74 | var hash = crypto.createHash(method) 75 | hash.update(data) 76 | hashes[f] = hash.digest('hex') 77 | 78 | if (++hashed >= files.length) { 79 | return callback(undefined, _summarize(method, hashes)) 80 | } 81 | }) 82 | } else { 83 | console.error('Skipping hash of %s', f) 84 | if (++hashed > files.length) { 85 | return callback(undefined, _summarize(method, hashes)) 86 | } 87 | } 88 | }) 89 | }) 90 | }) 91 | } 92 | 93 | module.exports = function hashFolder(contents, algo) { 94 | const algorithm = algo || 'sha1' 95 | return new Promise((resolve, reject) => { 96 | digest(contents, algorithm, function(err, hashes) { 97 | if (err) { 98 | return reject(err) 99 | } 100 | return resolve(hashes) 101 | }) 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /lib/utils/execPromise.js: -------------------------------------------------------------------------------- 1 | const childProcess = require('child_process') 2 | const exec = childProcess.exec 3 | 4 | module.exports = function execPromise(script, opts) { 5 | const options = opts || {} 6 | return new Promise((resolve, reject) => { 7 | const process = exec(script, options, (error, stdout, stderr) => { 8 | if (error) { 9 | return reject(stderr) 10 | } 11 | return resolve(stdout) 12 | }) 13 | process.stdout.on('data', (data) => { 14 | console.log(` ${data}`) 15 | }) 16 | process.stderr.on('data', (data) => { 17 | console.log(` ${data.toString()}`) 18 | }) 19 | process.on('exit', (code) => { 20 | // console.log('child process exited with code ' + code.toString()) 21 | }) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /lib/utils/flattie.js: -------------------------------------------------------------------------------- 1 | function iter(output, nullish, sep, val, key) { 2 | var k, pfx = key ? (key + sep) : key; 3 | 4 | if (val == null) { 5 | if (nullish) output[key] = val; 6 | } else if (typeof val != 'object') { 7 | output[key] = val; 8 | } else if (Array.isArray(val)) { 9 | for (k=0; k < val.length; k++) { 10 | iter(output, nullish, sep, val[k], pfx + k); 11 | } 12 | } else { 13 | for (k in val) { 14 | iter(output, nullish, sep, val[k], pfx + k); 15 | } 16 | } 17 | } 18 | 19 | function flattie(input, glue, toNull) { 20 | var output = {}; 21 | if (typeof input == 'object') { 22 | iter(output, !!toNull, glue || '.', input, ''); 23 | } 24 | return output; 25 | } 26 | 27 | module.exports = { 28 | flattie, 29 | } -------------------------------------------------------------------------------- /lib/utils/fs.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const path = require('path') 3 | const rimraf = require('rimraf') 4 | const isInvalidFilePath = require('is-invalid-path') 5 | const execPromise = require('./execPromise') 6 | const prefix = require('./prefix') 7 | const consolePrefix = prefix('') 8 | 9 | module.exports = { 10 | writeFile: writeFile, 11 | readFile: readFile, 12 | fileExists: fileExists, 13 | createDirectory: createDirectory, 14 | removeDirectory: removeDirectory, 15 | copyDirectory: copyDirectory, 16 | } 17 | 18 | function createDirectory(dist) { 19 | // Valid path is a path 20 | if (isInvalidFilePath(dist) || isInvalidFilePath(dist)) { 21 | throw new Error(`Not a valid file path. ${dist}`) 22 | } 23 | const makeDirectoryCommand = `mkdir -p ${dist}` 24 | return execPromise(makeDirectoryCommand) 25 | } 26 | 27 | function removeDirectory(dir) { 28 | if (isInvalidFilePath(dir) || isInvalidFilePath(dir)) { 29 | throw new Error(`Not a valid file path. ${dir}`) 30 | } 31 | return new Promise((resolve, reject) => { 32 | rimraf(dir, function (error) { 33 | if (error) { 34 | return reject(error) 35 | } 36 | return resolve(true) 37 | }) 38 | }) 39 | } 40 | 41 | async function copyDirectory(src, dist) { 42 | const finalSrc = src.replace(/\/$/, '') 43 | // Valid path is a path 44 | if (isInvalidFilePath(src) || isInvalidFilePath(dist)) { 45 | throw new Error('Not a valid file path') 46 | } 47 | 48 | const dir = path.dirname(dist) 49 | const dirExists = await fileExists(dist) 50 | if (!dirExists) { 51 | await createDirectory(dir) 52 | } 53 | 54 | const copyCommand = `rsync -ahr ${finalSrc}/ ${dist} --recursive` 55 | // const copyCommand = `cp -r ${src}/* ${dist}` 56 | return execPromise(copyCommand) 57 | } 58 | 59 | function writeFile(file, contents) { 60 | return new Promise(async (resolve, reject) => { 61 | const dir = path.dirname(file) 62 | const dirExists = await fileExists(dir) 63 | if (!dirExists) { 64 | await createDirectory(dir) 65 | } 66 | fs.writeFile(file, contents, (error) => { 67 | if (error) { 68 | return reject(error) 69 | } 70 | return resolve() 71 | }) 72 | }) 73 | } 74 | 75 | function readFile(filePath) { 76 | return new Promise((resolve, reject) => { 77 | fs.readFile(filePath, 'utf8', (error, data) => { 78 | if (error) { 79 | return reject(error) 80 | } 81 | return resolve(data) 82 | }) 83 | }) 84 | } 85 | 86 | function fileExists(filePath) { 87 | return new Promise((resolve, reject) => { 88 | fs.access(filePath, fs.F_OK, (err) => { 89 | if (err) { 90 | // console.log(`${consolePrefix} No ${filePath} found. Proceeding`) 91 | return resolve(false) // eslint-disable-line 92 | } 93 | return resolve(true) 94 | }) 95 | }) 96 | } 97 | 98 | // Future window support 99 | function copySyncWindows(src, dist) { 100 | const srcWindows = src.replace(/\//gim, '\\') 101 | const distWindows = dist.replace(/\//gim, '\\') 102 | // Valid path is a path 103 | if (isInvalidFilePath(src) || isInvalidFilePath(dist)) { 104 | throw new Error('Not a valid file path') 105 | } 106 | execSync("xcopy /y /q \"" + srcWindows + "\\*\" \"" + distWindows + "\\\"") // eslint-disable-line 107 | } 108 | -------------------------------------------------------------------------------- /lib/utils/getHash.js: -------------------------------------------------------------------------------- 1 | const hashFile = require('./hashFile') 2 | 3 | async function getHash(file, algorithm) { 4 | const hashAlgorithm = algorithm || 'sha1' 5 | const hash = await hashFile(file, hashAlgorithm) 6 | return hash 7 | } 8 | 9 | module.exports = getHash 10 | -------------------------------------------------------------------------------- /lib/utils/hashFile.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const crypto = require('crypto') 3 | 4 | module.exports = function hashFile(filename, algorithm) { 5 | return new Promise((resolve, reject) => { 6 | // Algorithm depends on availability of OpenSSL on platform 7 | // Another algorithms: 'sha1', 'md5', 'sha256', 'sha512' ... 8 | let shasum = crypto.createHash(algorithm) 9 | try { 10 | let s = fs.ReadStream(filename) 11 | s.on('data', (data) => { 12 | shasum.update(data) 13 | }) 14 | // making digest 15 | s.on('end', () => { 16 | const hash = shasum.digest('hex') 17 | return resolve(hash) 18 | }) 19 | } catch (error) { 20 | console.log(error) 21 | return reject(new Error('calc fail')) 22 | } 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /lib/utils/prefix.js: -------------------------------------------------------------------------------- 1 | // console prefix 2 | module.exports = function prefix (context) { 3 | return '' // `Cache(${context}):\n` 4 | } 5 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cache-me-outside", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cache-me-outside", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "is-invalid-path": "^1.0.2", 13 | "rimraf": "^2.6.2" 14 | }, 15 | "devDependencies": { 16 | "markdown-magic": "^0.1.25" 17 | } 18 | }, 19 | "node_modules/ansi-red": { 20 | "version": "0.1.1", 21 | "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", 22 | "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", 23 | "dev": true, 24 | "dependencies": { 25 | "ansi-wrap": "0.1.0" 26 | }, 27 | "engines": { 28 | "node": ">=0.10.0" 29 | } 30 | }, 31 | "node_modules/ansi-wrap": { 32 | "version": "0.1.0", 33 | "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", 34 | "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", 35 | "dev": true, 36 | "engines": { 37 | "node": ">=0.10.0" 38 | } 39 | }, 40 | "node_modules/argparse": { 41 | "version": "1.0.10", 42 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 43 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 44 | "dev": true, 45 | "dependencies": { 46 | "sprintf-js": "~1.0.2" 47 | } 48 | }, 49 | "node_modules/array-union": { 50 | "version": "1.0.2", 51 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 52 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 53 | "dev": true, 54 | "dependencies": { 55 | "array-uniq": "^1.0.1" 56 | }, 57 | "engines": { 58 | "node": ">=0.10.0" 59 | } 60 | }, 61 | "node_modules/array-uniq": { 62 | "version": "1.0.3", 63 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 64 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 65 | "dev": true, 66 | "engines": { 67 | "node": ">=0.10.0" 68 | } 69 | }, 70 | "node_modules/asap": { 71 | "version": "2.0.6", 72 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 73 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", 74 | "dev": true 75 | }, 76 | "node_modules/autolinker": { 77 | "version": "0.15.3", 78 | "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.15.3.tgz", 79 | "integrity": "sha1-NCQX2PLzRhsUzwkIjV7fh5HcmDI=", 80 | "dev": true 81 | }, 82 | "node_modules/balanced-match": { 83 | "version": "1.0.0", 84 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 85 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 86 | }, 87 | "node_modules/brace-expansion": { 88 | "version": "1.1.11", 89 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 90 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 91 | "dependencies": { 92 | "balanced-match": "^1.0.0", 93 | "concat-map": "0.0.1" 94 | } 95 | }, 96 | "node_modules/buffer-from": { 97 | "version": "1.1.1", 98 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 99 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 100 | "dev": true 101 | }, 102 | "node_modules/caseless": { 103 | "version": "0.11.0", 104 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", 105 | "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", 106 | "dev": true 107 | }, 108 | "node_modules/coffee-script": { 109 | "version": "1.12.7", 110 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", 111 | "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", 112 | "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", 113 | "dev": true, 114 | "bin": { 115 | "cake": "bin/cake", 116 | "coffee": "bin/coffee" 117 | }, 118 | "engines": { 119 | "node": ">=0.8.0" 120 | } 121 | }, 122 | "node_modules/commander": { 123 | "version": "2.17.1", 124 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", 125 | "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", 126 | "dev": true 127 | }, 128 | "node_modules/concat-map": { 129 | "version": "0.0.1", 130 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 131 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 132 | }, 133 | "node_modules/concat-stream": { 134 | "version": "1.6.2", 135 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 136 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 137 | "dev": true, 138 | "engines": [ 139 | "node >= 0.8" 140 | ], 141 | "dependencies": { 142 | "buffer-from": "^1.0.0", 143 | "inherits": "^2.0.3", 144 | "readable-stream": "^2.2.2", 145 | "typedarray": "^0.0.6" 146 | } 147 | }, 148 | "node_modules/core-util-is": { 149 | "version": "1.0.2", 150 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 151 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 152 | "dev": true 153 | }, 154 | "node_modules/deepmerge": { 155 | "version": "1.5.2", 156 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", 157 | "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", 158 | "dev": true, 159 | "engines": { 160 | "node": ">=0.10.0" 161 | } 162 | }, 163 | "node_modules/diacritics-map": { 164 | "version": "0.1.0", 165 | "resolved": "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz", 166 | "integrity": "sha1-bfwP+dAQAKLt8oZTccrDFulJd68=", 167 | "dev": true, 168 | "engines": { 169 | "node": ">=0.8.0" 170 | } 171 | }, 172 | "node_modules/esprima": { 173 | "version": "4.0.1", 174 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 175 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 176 | "dev": true, 177 | "bin": { 178 | "esparse": "bin/esparse.js", 179 | "esvalidate": "bin/esvalidate.js" 180 | }, 181 | "engines": { 182 | "node": ">=4" 183 | } 184 | }, 185 | "node_modules/expand-range": { 186 | "version": "1.8.2", 187 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", 188 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", 189 | "dev": true, 190 | "dependencies": { 191 | "fill-range": "^2.1.0" 192 | }, 193 | "engines": { 194 | "node": ">=0.10.0" 195 | } 196 | }, 197 | "node_modules/extend-shallow": { 198 | "version": "2.0.1", 199 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 200 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 201 | "dev": true, 202 | "dependencies": { 203 | "is-extendable": "^0.1.0" 204 | }, 205 | "engines": { 206 | "node": ">=0.10.0" 207 | } 208 | }, 209 | "node_modules/fill-range": { 210 | "version": "2.2.4", 211 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", 212 | "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", 213 | "dev": true, 214 | "dependencies": { 215 | "is-number": "^2.1.0", 216 | "isobject": "^2.0.0", 217 | "randomatic": "^3.0.0", 218 | "repeat-element": "^1.1.2", 219 | "repeat-string": "^1.5.2" 220 | }, 221 | "engines": { 222 | "node": ">=0.10.0" 223 | } 224 | }, 225 | "node_modules/find-up": { 226 | "version": "2.1.0", 227 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 228 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 229 | "dev": true, 230 | "dependencies": { 231 | "locate-path": "^2.0.0" 232 | }, 233 | "engines": { 234 | "node": ">=4" 235 | } 236 | }, 237 | "node_modules/for-in": { 238 | "version": "1.0.2", 239 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 240 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 241 | "dev": true, 242 | "engines": { 243 | "node": ">=0.10.0" 244 | } 245 | }, 246 | "node_modules/fs-extra": { 247 | "version": "1.0.0", 248 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", 249 | "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", 250 | "dev": true, 251 | "dependencies": { 252 | "graceful-fs": "^4.1.2", 253 | "jsonfile": "^2.1.0", 254 | "klaw": "^1.0.0" 255 | } 256 | }, 257 | "node_modules/fs.realpath": { 258 | "version": "1.0.0", 259 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 260 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 261 | }, 262 | "node_modules/glob": { 263 | "version": "7.1.2", 264 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 265 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 266 | "dependencies": { 267 | "fs.realpath": "^1.0.0", 268 | "inflight": "^1.0.4", 269 | "inherits": "2", 270 | "minimatch": "^3.0.4", 271 | "once": "^1.3.0", 272 | "path-is-absolute": "^1.0.0" 273 | }, 274 | "engines": { 275 | "node": "*" 276 | } 277 | }, 278 | "node_modules/globby": { 279 | "version": "6.1.0", 280 | "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", 281 | "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", 282 | "dev": true, 283 | "dependencies": { 284 | "array-union": "^1.0.1", 285 | "glob": "^7.0.3", 286 | "object-assign": "^4.0.1", 287 | "pify": "^2.0.0", 288 | "pinkie-promise": "^2.0.0" 289 | }, 290 | "engines": { 291 | "node": ">=0.10.0" 292 | } 293 | }, 294 | "node_modules/graceful-fs": { 295 | "version": "4.1.11", 296 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 297 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 298 | "dev": true, 299 | "engines": { 300 | "node": ">=0.4.0" 301 | } 302 | }, 303 | "node_modules/gray-matter": { 304 | "version": "2.1.1", 305 | "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", 306 | "integrity": "sha1-MELZrewqHe1qdwep7SOA+KF6Qw4=", 307 | "dev": true, 308 | "dependencies": { 309 | "ansi-red": "^0.1.1", 310 | "coffee-script": "^1.12.4", 311 | "extend-shallow": "^2.0.1", 312 | "js-yaml": "^3.8.1", 313 | "toml": "^2.3.2" 314 | }, 315 | "engines": { 316 | "node": ">=0.10.0" 317 | } 318 | }, 319 | "node_modules/http-basic": { 320 | "version": "2.5.1", 321 | "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz", 322 | "integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=", 323 | "dev": true, 324 | "dependencies": { 325 | "caseless": "~0.11.0", 326 | "concat-stream": "^1.4.6", 327 | "http-response-object": "^1.0.0" 328 | } 329 | }, 330 | "node_modules/http-response-object": { 331 | "version": "1.1.0", 332 | "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz", 333 | "integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=", 334 | "dev": true 335 | }, 336 | "node_modules/inflight": { 337 | "version": "1.0.6", 338 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 339 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 340 | "dependencies": { 341 | "once": "^1.3.0", 342 | "wrappy": "1" 343 | } 344 | }, 345 | "node_modules/inherits": { 346 | "version": "2.0.3", 347 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 348 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 349 | }, 350 | "node_modules/is-buffer": { 351 | "version": "1.1.6", 352 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 353 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 354 | "dev": true 355 | }, 356 | "node_modules/is-extendable": { 357 | "version": "0.1.1", 358 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 359 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 360 | "dev": true, 361 | "engines": { 362 | "node": ">=0.10.0" 363 | } 364 | }, 365 | "node_modules/is-invalid-path": { 366 | "version": "1.0.2", 367 | "resolved": "https://registry.npmjs.org/is-invalid-path/-/is-invalid-path-1.0.2.tgz", 368 | "integrity": "sha512-6KLcFrPCEP3AFXMfnWrIFkZpYNBVzZAoBJJDEZKtI3LXkaDjM3uFMJQjxiizUuZTZ9Oh9FNv/soXbx5TcpaDmA==", 369 | "engines": { 370 | "node": ">=6.0" 371 | } 372 | }, 373 | "node_modules/is-local-path": { 374 | "version": "0.1.6", 375 | "resolved": "https://registry.npmjs.org/is-local-path/-/is-local-path-0.1.6.tgz", 376 | "integrity": "sha1-gV0USxTVac7L6tTVaTCX8Aqb9sU=", 377 | "dev": true 378 | }, 379 | "node_modules/is-number": { 380 | "version": "2.1.0", 381 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", 382 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", 383 | "dev": true, 384 | "dependencies": { 385 | "kind-of": "^3.0.2" 386 | }, 387 | "engines": { 388 | "node": ">=0.10.0" 389 | } 390 | }, 391 | "node_modules/is-plain-object": { 392 | "version": "2.0.4", 393 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 394 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 395 | "dev": true, 396 | "dependencies": { 397 | "isobject": "^3.0.1" 398 | }, 399 | "engines": { 400 | "node": ">=0.10.0" 401 | } 402 | }, 403 | "node_modules/is-plain-object/node_modules/isobject": { 404 | "version": "3.0.1", 405 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 406 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 407 | "dev": true, 408 | "engines": { 409 | "node": ">=0.10.0" 410 | } 411 | }, 412 | "node_modules/isarray": { 413 | "version": "1.0.0", 414 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 415 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 416 | "dev": true 417 | }, 418 | "node_modules/isobject": { 419 | "version": "2.1.0", 420 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 421 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 422 | "dev": true, 423 | "dependencies": { 424 | "isarray": "1.0.0" 425 | }, 426 | "engines": { 427 | "node": ">=0.10.0" 428 | } 429 | }, 430 | "node_modules/js-yaml": { 431 | "version": "3.12.0", 432 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", 433 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", 434 | "dev": true, 435 | "dependencies": { 436 | "argparse": "^1.0.7", 437 | "esprima": "^4.0.0" 438 | }, 439 | "bin": { 440 | "js-yaml": "bin/js-yaml.js" 441 | } 442 | }, 443 | "node_modules/jsonfile": { 444 | "version": "2.4.0", 445 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", 446 | "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", 447 | "dev": true, 448 | "optionalDependencies": { 449 | "graceful-fs": "^4.1.6" 450 | } 451 | }, 452 | "node_modules/kind-of": { 453 | "version": "3.2.2", 454 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 455 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 456 | "dev": true, 457 | "dependencies": { 458 | "is-buffer": "^1.1.5" 459 | }, 460 | "engines": { 461 | "node": ">=0.10.0" 462 | } 463 | }, 464 | "node_modules/klaw": { 465 | "version": "1.3.1", 466 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", 467 | "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", 468 | "dev": true, 469 | "optionalDependencies": { 470 | "graceful-fs": "^4.1.9" 471 | } 472 | }, 473 | "node_modules/lazy-cache": { 474 | "version": "2.0.2", 475 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", 476 | "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", 477 | "dev": true, 478 | "dependencies": { 479 | "set-getter": "^0.1.0" 480 | }, 481 | "engines": { 482 | "node": ">=0.10.0" 483 | } 484 | }, 485 | "node_modules/list-item": { 486 | "version": "1.1.1", 487 | "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", 488 | "integrity": "sha1-DGXQDih8tmPMs8s4Sad+iewmilY=", 489 | "dev": true, 490 | "dependencies": { 491 | "expand-range": "^1.8.1", 492 | "extend-shallow": "^2.0.1", 493 | "is-number": "^2.1.0", 494 | "repeat-string": "^1.5.2" 495 | }, 496 | "engines": { 497 | "node": ">=0.10.0" 498 | } 499 | }, 500 | "node_modules/locate-path": { 501 | "version": "2.0.0", 502 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 503 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 504 | "dev": true, 505 | "dependencies": { 506 | "p-locate": "^2.0.0", 507 | "path-exists": "^3.0.0" 508 | }, 509 | "engines": { 510 | "node": ">=4" 511 | } 512 | }, 513 | "node_modules/markdown-link": { 514 | "version": "0.1.1", 515 | "resolved": "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz", 516 | "integrity": "sha1-MsXGUZmmRXMWMi0eQinRNAfIx88=", 517 | "dev": true, 518 | "engines": { 519 | "node": ">=0.10.0" 520 | } 521 | }, 522 | "node_modules/markdown-magic": { 523 | "version": "0.1.25", 524 | "resolved": "https://registry.npmjs.org/markdown-magic/-/markdown-magic-0.1.25.tgz", 525 | "integrity": "sha512-NBVMv2IPdKaRIXcL8qmLkfq9O17tkByTr8sRkJ4l76tkp401hxCUA0r9mkhtnGJRevCqZ2KoHrIf9WYQUn8ztA==", 526 | "dev": true, 527 | "dependencies": { 528 | "commander": "^2.9.0", 529 | "deepmerge": "^1.3.0", 530 | "find-up": "^2.1.0", 531 | "fs-extra": "^1.0.0", 532 | "globby": "^6.1.0", 533 | "is-local-path": "^0.1.6", 534 | "markdown-toc": "^1.0.2", 535 | "sync-request": "^3.0.1" 536 | }, 537 | "bin": { 538 | "markdown": "cli.js", 539 | "md-magic": "cli.js" 540 | } 541 | }, 542 | "node_modules/markdown-toc": { 543 | "version": "1.2.0", 544 | "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz", 545 | "integrity": "sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg==", 546 | "dev": true, 547 | "dependencies": { 548 | "concat-stream": "^1.5.2", 549 | "diacritics-map": "^0.1.0", 550 | "gray-matter": "^2.1.0", 551 | "lazy-cache": "^2.0.2", 552 | "list-item": "^1.1.1", 553 | "markdown-link": "^0.1.1", 554 | "minimist": "^1.2.0", 555 | "mixin-deep": "^1.1.3", 556 | "object.pick": "^1.2.0", 557 | "remarkable": "^1.7.1", 558 | "repeat-string": "^1.6.1", 559 | "strip-color": "^0.1.0" 560 | }, 561 | "bin": { 562 | "markdown-toc": "cli.js" 563 | }, 564 | "engines": { 565 | "node": ">=0.10.0" 566 | } 567 | }, 568 | "node_modules/math-random": { 569 | "version": "1.0.1", 570 | "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", 571 | "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", 572 | "dev": true 573 | }, 574 | "node_modules/minimatch": { 575 | "version": "3.0.4", 576 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 577 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 578 | "dependencies": { 579 | "brace-expansion": "^1.1.7" 580 | }, 581 | "engines": { 582 | "node": "*" 583 | } 584 | }, 585 | "node_modules/minimist": { 586 | "version": "1.2.0", 587 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 588 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 589 | "dev": true 590 | }, 591 | "node_modules/mixin-deep": { 592 | "version": "1.3.1", 593 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", 594 | "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", 595 | "deprecated": "Critical bug fixed in v2.0.1, please upgrade to the latest version.", 596 | "dev": true, 597 | "dependencies": { 598 | "for-in": "^1.0.2", 599 | "is-extendable": "^1.0.1" 600 | }, 601 | "engines": { 602 | "node": ">=0.10.0" 603 | } 604 | }, 605 | "node_modules/mixin-deep/node_modules/is-extendable": { 606 | "version": "1.0.1", 607 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 608 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 609 | "dev": true, 610 | "dependencies": { 611 | "is-plain-object": "^2.0.4" 612 | }, 613 | "engines": { 614 | "node": ">=0.10.0" 615 | } 616 | }, 617 | "node_modules/object-assign": { 618 | "version": "4.1.1", 619 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 620 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 621 | "dev": true, 622 | "engines": { 623 | "node": ">=0.10.0" 624 | } 625 | }, 626 | "node_modules/object.pick": { 627 | "version": "1.3.0", 628 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 629 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 630 | "dev": true, 631 | "dependencies": { 632 | "isobject": "^3.0.1" 633 | }, 634 | "engines": { 635 | "node": ">=0.10.0" 636 | } 637 | }, 638 | "node_modules/object.pick/node_modules/isobject": { 639 | "version": "3.0.1", 640 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 641 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 642 | "dev": true, 643 | "engines": { 644 | "node": ">=0.10.0" 645 | } 646 | }, 647 | "node_modules/once": { 648 | "version": "1.4.0", 649 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 650 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 651 | "dependencies": { 652 | "wrappy": "1" 653 | } 654 | }, 655 | "node_modules/p-limit": { 656 | "version": "1.3.0", 657 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 658 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 659 | "dev": true, 660 | "dependencies": { 661 | "p-try": "^1.0.0" 662 | }, 663 | "engines": { 664 | "node": ">=4" 665 | } 666 | }, 667 | "node_modules/p-locate": { 668 | "version": "2.0.0", 669 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 670 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 671 | "dev": true, 672 | "dependencies": { 673 | "p-limit": "^1.1.0" 674 | }, 675 | "engines": { 676 | "node": ">=4" 677 | } 678 | }, 679 | "node_modules/p-try": { 680 | "version": "1.0.0", 681 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 682 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 683 | "dev": true, 684 | "engines": { 685 | "node": ">=4" 686 | } 687 | }, 688 | "node_modules/path-exists": { 689 | "version": "3.0.0", 690 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 691 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 692 | "dev": true, 693 | "engines": { 694 | "node": ">=4" 695 | } 696 | }, 697 | "node_modules/path-is-absolute": { 698 | "version": "1.0.1", 699 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 700 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 701 | "engines": { 702 | "node": ">=0.10.0" 703 | } 704 | }, 705 | "node_modules/pify": { 706 | "version": "2.3.0", 707 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 708 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 709 | "dev": true, 710 | "engines": { 711 | "node": ">=0.10.0" 712 | } 713 | }, 714 | "node_modules/pinkie": { 715 | "version": "2.0.4", 716 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 717 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 718 | "dev": true, 719 | "engines": { 720 | "node": ">=0.10.0" 721 | } 722 | }, 723 | "node_modules/pinkie-promise": { 724 | "version": "2.0.1", 725 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 726 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 727 | "dev": true, 728 | "dependencies": { 729 | "pinkie": "^2.0.0" 730 | }, 731 | "engines": { 732 | "node": ">=0.10.0" 733 | } 734 | }, 735 | "node_modules/process-nextick-args": { 736 | "version": "2.0.0", 737 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 738 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 739 | "dev": true 740 | }, 741 | "node_modules/promise": { 742 | "version": "7.3.1", 743 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 744 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 745 | "dev": true, 746 | "dependencies": { 747 | "asap": "~2.0.3" 748 | } 749 | }, 750 | "node_modules/qs": { 751 | "version": "6.5.2", 752 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 753 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", 754 | "dev": true, 755 | "engines": { 756 | "node": ">=0.6" 757 | } 758 | }, 759 | "node_modules/randomatic": { 760 | "version": "3.1.0", 761 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", 762 | "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", 763 | "dev": true, 764 | "dependencies": { 765 | "is-number": "^4.0.0", 766 | "kind-of": "^6.0.0", 767 | "math-random": "^1.0.1" 768 | }, 769 | "engines": { 770 | "node": ">= 0.10.0" 771 | } 772 | }, 773 | "node_modules/randomatic/node_modules/is-number": { 774 | "version": "4.0.0", 775 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", 776 | "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", 777 | "dev": true, 778 | "engines": { 779 | "node": ">=0.10.0" 780 | } 781 | }, 782 | "node_modules/randomatic/node_modules/kind-of": { 783 | "version": "6.0.2", 784 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 785 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", 786 | "dev": true, 787 | "engines": { 788 | "node": ">=0.10.0" 789 | } 790 | }, 791 | "node_modules/readable-stream": { 792 | "version": "2.3.6", 793 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 794 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 795 | "dev": true, 796 | "dependencies": { 797 | "core-util-is": "~1.0.0", 798 | "inherits": "~2.0.3", 799 | "isarray": "~1.0.0", 800 | "process-nextick-args": "~2.0.0", 801 | "safe-buffer": "~5.1.1", 802 | "string_decoder": "~1.1.1", 803 | "util-deprecate": "~1.0.1" 804 | } 805 | }, 806 | "node_modules/remarkable": { 807 | "version": "1.7.1", 808 | "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.1.tgz", 809 | "integrity": "sha1-qspJchALZqZCpjoQIcpLrBvjv/Y=", 810 | "dev": true, 811 | "dependencies": { 812 | "argparse": "~0.1.15", 813 | "autolinker": "~0.15.0" 814 | }, 815 | "bin": { 816 | "remarkable": "bin/remarkable.js" 817 | }, 818 | "engines": { 819 | "node": ">= 0.10.0" 820 | } 821 | }, 822 | "node_modules/remarkable/node_modules/argparse": { 823 | "version": "0.1.16", 824 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", 825 | "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", 826 | "dev": true, 827 | "dependencies": { 828 | "underscore": "~1.7.0", 829 | "underscore.string": "~2.4.0" 830 | } 831 | }, 832 | "node_modules/repeat-element": { 833 | "version": "1.1.2", 834 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", 835 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", 836 | "dev": true, 837 | "engines": { 838 | "node": ">=0.10.0" 839 | } 840 | }, 841 | "node_modules/repeat-string": { 842 | "version": "1.6.1", 843 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 844 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 845 | "dev": true, 846 | "engines": { 847 | "node": ">=0.10" 848 | } 849 | }, 850 | "node_modules/rimraf": { 851 | "version": "2.6.2", 852 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 853 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 854 | "dependencies": { 855 | "glob": "^7.0.5" 856 | }, 857 | "bin": { 858 | "rimraf": "bin.js" 859 | } 860 | }, 861 | "node_modules/safe-buffer": { 862 | "version": "5.1.2", 863 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 864 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 865 | "dev": true 866 | }, 867 | "node_modules/set-getter": { 868 | "version": "0.1.0", 869 | "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", 870 | "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", 871 | "dev": true, 872 | "dependencies": { 873 | "to-object-path": "^0.3.0" 874 | }, 875 | "engines": { 876 | "node": ">=0.10.0" 877 | } 878 | }, 879 | "node_modules/sprintf-js": { 880 | "version": "1.0.3", 881 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 882 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 883 | "dev": true 884 | }, 885 | "node_modules/string_decoder": { 886 | "version": "1.1.1", 887 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 888 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 889 | "dev": true, 890 | "dependencies": { 891 | "safe-buffer": "~5.1.0" 892 | } 893 | }, 894 | "node_modules/strip-color": { 895 | "version": "0.1.0", 896 | "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", 897 | "integrity": "sha1-EG9l09PmotlAHKwOsM6LinArT3s=", 898 | "dev": true, 899 | "engines": { 900 | "node": ">=0.10.0" 901 | } 902 | }, 903 | "node_modules/sync-request": { 904 | "version": "3.0.1", 905 | "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz", 906 | "integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=", 907 | "dev": true, 908 | "dependencies": { 909 | "concat-stream": "^1.4.7", 910 | "http-response-object": "^1.0.1", 911 | "then-request": "^2.0.1" 912 | } 913 | }, 914 | "node_modules/then-request": { 915 | "version": "2.2.0", 916 | "resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz", 917 | "integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=", 918 | "dev": true, 919 | "dependencies": { 920 | "caseless": "~0.11.0", 921 | "concat-stream": "^1.4.7", 922 | "http-basic": "^2.5.1", 923 | "http-response-object": "^1.1.0", 924 | "promise": "^7.1.1", 925 | "qs": "^6.1.0" 926 | } 927 | }, 928 | "node_modules/to-object-path": { 929 | "version": "0.3.0", 930 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 931 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 932 | "dev": true, 933 | "dependencies": { 934 | "kind-of": "^3.0.2" 935 | }, 936 | "engines": { 937 | "node": ">=0.10.0" 938 | } 939 | }, 940 | "node_modules/toml": { 941 | "version": "2.3.3", 942 | "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.3.tgz", 943 | "integrity": "sha512-O7L5hhSQHxuufWUdcTRPfuTh3phKfAZ/dqfxZFoxPCj2RYmpaSGLEIs016FCXItQwNr08yefUB5TSjzRYnajTA==", 944 | "dev": true 945 | }, 946 | "node_modules/typedarray": { 947 | "version": "0.0.6", 948 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 949 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 950 | "dev": true 951 | }, 952 | "node_modules/underscore": { 953 | "version": "1.7.0", 954 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", 955 | "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", 956 | "dev": true 957 | }, 958 | "node_modules/underscore.string": { 959 | "version": "2.4.0", 960 | "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", 961 | "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", 962 | "dev": true, 963 | "engines": { 964 | "node": "*" 965 | } 966 | }, 967 | "node_modules/util-deprecate": { 968 | "version": "1.0.2", 969 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 970 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 971 | "dev": true 972 | }, 973 | "node_modules/wrappy": { 974 | "version": "1.0.2", 975 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 976 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 977 | } 978 | }, 979 | "dependencies": { 980 | "ansi-red": { 981 | "version": "0.1.1", 982 | "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", 983 | "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", 984 | "dev": true, 985 | "requires": { 986 | "ansi-wrap": "0.1.0" 987 | } 988 | }, 989 | "ansi-wrap": { 990 | "version": "0.1.0", 991 | "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", 992 | "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", 993 | "dev": true 994 | }, 995 | "argparse": { 996 | "version": "1.0.10", 997 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 998 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 999 | "dev": true, 1000 | "requires": { 1001 | "sprintf-js": "~1.0.2" 1002 | } 1003 | }, 1004 | "array-union": { 1005 | "version": "1.0.2", 1006 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", 1007 | "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", 1008 | "dev": true, 1009 | "requires": { 1010 | "array-uniq": "^1.0.1" 1011 | } 1012 | }, 1013 | "array-uniq": { 1014 | "version": "1.0.3", 1015 | "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", 1016 | "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", 1017 | "dev": true 1018 | }, 1019 | "asap": { 1020 | "version": "2.0.6", 1021 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", 1022 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", 1023 | "dev": true 1024 | }, 1025 | "autolinker": { 1026 | "version": "0.15.3", 1027 | "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-0.15.3.tgz", 1028 | "integrity": "sha1-NCQX2PLzRhsUzwkIjV7fh5HcmDI=", 1029 | "dev": true 1030 | }, 1031 | "balanced-match": { 1032 | "version": "1.0.0", 1033 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 1034 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" 1035 | }, 1036 | "brace-expansion": { 1037 | "version": "1.1.11", 1038 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1039 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1040 | "requires": { 1041 | "balanced-match": "^1.0.0", 1042 | "concat-map": "0.0.1" 1043 | } 1044 | }, 1045 | "buffer-from": { 1046 | "version": "1.1.1", 1047 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", 1048 | "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", 1049 | "dev": true 1050 | }, 1051 | "caseless": { 1052 | "version": "0.11.0", 1053 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", 1054 | "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", 1055 | "dev": true 1056 | }, 1057 | "coffee-script": { 1058 | "version": "1.12.7", 1059 | "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", 1060 | "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==", 1061 | "dev": true 1062 | }, 1063 | "commander": { 1064 | "version": "2.17.1", 1065 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", 1066 | "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==", 1067 | "dev": true 1068 | }, 1069 | "concat-map": { 1070 | "version": "0.0.1", 1071 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1072 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 1073 | }, 1074 | "concat-stream": { 1075 | "version": "1.6.2", 1076 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", 1077 | "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", 1078 | "dev": true, 1079 | "requires": { 1080 | "buffer-from": "^1.0.0", 1081 | "inherits": "^2.0.3", 1082 | "readable-stream": "^2.2.2", 1083 | "typedarray": "^0.0.6" 1084 | } 1085 | }, 1086 | "core-util-is": { 1087 | "version": "1.0.2", 1088 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 1089 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", 1090 | "dev": true 1091 | }, 1092 | "deepmerge": { 1093 | "version": "1.5.2", 1094 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-1.5.2.tgz", 1095 | "integrity": "sha512-95k0GDqvBjZavkuvzx/YqVLv/6YYa17fz6ILMSf7neqQITCPbnfEnQvEgMPNjH4kgobe7+WIL0yJEHku+H3qtQ==", 1096 | "dev": true 1097 | }, 1098 | "diacritics-map": { 1099 | "version": "0.1.0", 1100 | "resolved": "https://registry.npmjs.org/diacritics-map/-/diacritics-map-0.1.0.tgz", 1101 | "integrity": "sha1-bfwP+dAQAKLt8oZTccrDFulJd68=", 1102 | "dev": true 1103 | }, 1104 | "esprima": { 1105 | "version": "4.0.1", 1106 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 1107 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 1108 | "dev": true 1109 | }, 1110 | "expand-range": { 1111 | "version": "1.8.2", 1112 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", 1113 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", 1114 | "dev": true, 1115 | "requires": { 1116 | "fill-range": "^2.1.0" 1117 | } 1118 | }, 1119 | "extend-shallow": { 1120 | "version": "2.0.1", 1121 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", 1122 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", 1123 | "dev": true, 1124 | "requires": { 1125 | "is-extendable": "^0.1.0" 1126 | } 1127 | }, 1128 | "fill-range": { 1129 | "version": "2.2.4", 1130 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", 1131 | "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", 1132 | "dev": true, 1133 | "requires": { 1134 | "is-number": "^2.1.0", 1135 | "isobject": "^2.0.0", 1136 | "randomatic": "^3.0.0", 1137 | "repeat-element": "^1.1.2", 1138 | "repeat-string": "^1.5.2" 1139 | } 1140 | }, 1141 | "find-up": { 1142 | "version": "2.1.0", 1143 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", 1144 | "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", 1145 | "dev": true, 1146 | "requires": { 1147 | "locate-path": "^2.0.0" 1148 | } 1149 | }, 1150 | "for-in": { 1151 | "version": "1.0.2", 1152 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", 1153 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", 1154 | "dev": true 1155 | }, 1156 | "fs-extra": { 1157 | "version": "1.0.0", 1158 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", 1159 | "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", 1160 | "dev": true, 1161 | "requires": { 1162 | "graceful-fs": "^4.1.2", 1163 | "jsonfile": "^2.1.0", 1164 | "klaw": "^1.0.0" 1165 | } 1166 | }, 1167 | "fs.realpath": { 1168 | "version": "1.0.0", 1169 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1170 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 1171 | }, 1172 | "glob": { 1173 | "version": "7.1.2", 1174 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", 1175 | "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", 1176 | "requires": { 1177 | "fs.realpath": "^1.0.0", 1178 | "inflight": "^1.0.4", 1179 | "inherits": "2", 1180 | "minimatch": "^3.0.4", 1181 | "once": "^1.3.0", 1182 | "path-is-absolute": "^1.0.0" 1183 | } 1184 | }, 1185 | "globby": { 1186 | "version": "6.1.0", 1187 | "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", 1188 | "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", 1189 | "dev": true, 1190 | "requires": { 1191 | "array-union": "^1.0.1", 1192 | "glob": "^7.0.3", 1193 | "object-assign": "^4.0.1", 1194 | "pify": "^2.0.0", 1195 | "pinkie-promise": "^2.0.0" 1196 | } 1197 | }, 1198 | "graceful-fs": { 1199 | "version": "4.1.11", 1200 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", 1201 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", 1202 | "dev": true 1203 | }, 1204 | "gray-matter": { 1205 | "version": "2.1.1", 1206 | "resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-2.1.1.tgz", 1207 | "integrity": "sha1-MELZrewqHe1qdwep7SOA+KF6Qw4=", 1208 | "dev": true, 1209 | "requires": { 1210 | "ansi-red": "^0.1.1", 1211 | "coffee-script": "^1.12.4", 1212 | "extend-shallow": "^2.0.1", 1213 | "js-yaml": "^3.8.1", 1214 | "toml": "^2.3.2" 1215 | } 1216 | }, 1217 | "http-basic": { 1218 | "version": "2.5.1", 1219 | "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-2.5.1.tgz", 1220 | "integrity": "sha1-jORHvbW2xXf4pj4/p4BW7Eu02/s=", 1221 | "dev": true, 1222 | "requires": { 1223 | "caseless": "~0.11.0", 1224 | "concat-stream": "^1.4.6", 1225 | "http-response-object": "^1.0.0" 1226 | } 1227 | }, 1228 | "http-response-object": { 1229 | "version": "1.1.0", 1230 | "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-1.1.0.tgz", 1231 | "integrity": "sha1-p8TnWq6C87tJBOT0P2FWc7TVGMM=", 1232 | "dev": true 1233 | }, 1234 | "inflight": { 1235 | "version": "1.0.6", 1236 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1237 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1238 | "requires": { 1239 | "once": "^1.3.0", 1240 | "wrappy": "1" 1241 | } 1242 | }, 1243 | "inherits": { 1244 | "version": "2.0.3", 1245 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 1246 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 1247 | }, 1248 | "is-buffer": { 1249 | "version": "1.1.6", 1250 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 1251 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", 1252 | "dev": true 1253 | }, 1254 | "is-extendable": { 1255 | "version": "0.1.1", 1256 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", 1257 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", 1258 | "dev": true 1259 | }, 1260 | "is-invalid-path": { 1261 | "version": "1.0.2", 1262 | "resolved": "https://registry.npmjs.org/is-invalid-path/-/is-invalid-path-1.0.2.tgz", 1263 | "integrity": "sha512-6KLcFrPCEP3AFXMfnWrIFkZpYNBVzZAoBJJDEZKtI3LXkaDjM3uFMJQjxiizUuZTZ9Oh9FNv/soXbx5TcpaDmA==" 1264 | }, 1265 | "is-local-path": { 1266 | "version": "0.1.6", 1267 | "resolved": "https://registry.npmjs.org/is-local-path/-/is-local-path-0.1.6.tgz", 1268 | "integrity": "sha1-gV0USxTVac7L6tTVaTCX8Aqb9sU=", 1269 | "dev": true 1270 | }, 1271 | "is-number": { 1272 | "version": "2.1.0", 1273 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", 1274 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", 1275 | "dev": true, 1276 | "requires": { 1277 | "kind-of": "^3.0.2" 1278 | } 1279 | }, 1280 | "is-plain-object": { 1281 | "version": "2.0.4", 1282 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", 1283 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", 1284 | "dev": true, 1285 | "requires": { 1286 | "isobject": "^3.0.1" 1287 | }, 1288 | "dependencies": { 1289 | "isobject": { 1290 | "version": "3.0.1", 1291 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 1292 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 1293 | "dev": true 1294 | } 1295 | } 1296 | }, 1297 | "isarray": { 1298 | "version": "1.0.0", 1299 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", 1300 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", 1301 | "dev": true 1302 | }, 1303 | "isobject": { 1304 | "version": "2.1.0", 1305 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", 1306 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", 1307 | "dev": true, 1308 | "requires": { 1309 | "isarray": "1.0.0" 1310 | } 1311 | }, 1312 | "js-yaml": { 1313 | "version": "3.12.0", 1314 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", 1315 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", 1316 | "dev": true, 1317 | "requires": { 1318 | "argparse": "^1.0.7", 1319 | "esprima": "^4.0.0" 1320 | } 1321 | }, 1322 | "jsonfile": { 1323 | "version": "2.4.0", 1324 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", 1325 | "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", 1326 | "dev": true, 1327 | "requires": { 1328 | "graceful-fs": "^4.1.6" 1329 | } 1330 | }, 1331 | "kind-of": { 1332 | "version": "3.2.2", 1333 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 1334 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 1335 | "dev": true, 1336 | "requires": { 1337 | "is-buffer": "^1.1.5" 1338 | } 1339 | }, 1340 | "klaw": { 1341 | "version": "1.3.1", 1342 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", 1343 | "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", 1344 | "dev": true, 1345 | "requires": { 1346 | "graceful-fs": "^4.1.9" 1347 | } 1348 | }, 1349 | "lazy-cache": { 1350 | "version": "2.0.2", 1351 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", 1352 | "integrity": "sha1-uRkKT5EzVGlIQIWfio9whNiCImQ=", 1353 | "dev": true, 1354 | "requires": { 1355 | "set-getter": "^0.1.0" 1356 | } 1357 | }, 1358 | "list-item": { 1359 | "version": "1.1.1", 1360 | "resolved": "https://registry.npmjs.org/list-item/-/list-item-1.1.1.tgz", 1361 | "integrity": "sha1-DGXQDih8tmPMs8s4Sad+iewmilY=", 1362 | "dev": true, 1363 | "requires": { 1364 | "expand-range": "^1.8.1", 1365 | "extend-shallow": "^2.0.1", 1366 | "is-number": "^2.1.0", 1367 | "repeat-string": "^1.5.2" 1368 | } 1369 | }, 1370 | "locate-path": { 1371 | "version": "2.0.0", 1372 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", 1373 | "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", 1374 | "dev": true, 1375 | "requires": { 1376 | "p-locate": "^2.0.0", 1377 | "path-exists": "^3.0.0" 1378 | } 1379 | }, 1380 | "markdown-link": { 1381 | "version": "0.1.1", 1382 | "resolved": "https://registry.npmjs.org/markdown-link/-/markdown-link-0.1.1.tgz", 1383 | "integrity": "sha1-MsXGUZmmRXMWMi0eQinRNAfIx88=", 1384 | "dev": true 1385 | }, 1386 | "markdown-magic": { 1387 | "version": "0.1.25", 1388 | "resolved": "https://registry.npmjs.org/markdown-magic/-/markdown-magic-0.1.25.tgz", 1389 | "integrity": "sha512-NBVMv2IPdKaRIXcL8qmLkfq9O17tkByTr8sRkJ4l76tkp401hxCUA0r9mkhtnGJRevCqZ2KoHrIf9WYQUn8ztA==", 1390 | "dev": true, 1391 | "requires": { 1392 | "commander": "^2.9.0", 1393 | "deepmerge": "^1.3.0", 1394 | "find-up": "^2.1.0", 1395 | "fs-extra": "^1.0.0", 1396 | "globby": "^6.1.0", 1397 | "is-local-path": "^0.1.6", 1398 | "markdown-toc": "^1.0.2", 1399 | "sync-request": "^3.0.1" 1400 | } 1401 | }, 1402 | "markdown-toc": { 1403 | "version": "1.2.0", 1404 | "resolved": "https://registry.npmjs.org/markdown-toc/-/markdown-toc-1.2.0.tgz", 1405 | "integrity": "sha512-eOsq7EGd3asV0oBfmyqngeEIhrbkc7XVP63OwcJBIhH2EpG2PzFcbZdhy1jutXSlRBBVMNXHvMtSr5LAxSUvUg==", 1406 | "dev": true, 1407 | "requires": { 1408 | "concat-stream": "^1.5.2", 1409 | "diacritics-map": "^0.1.0", 1410 | "gray-matter": "^2.1.0", 1411 | "lazy-cache": "^2.0.2", 1412 | "list-item": "^1.1.1", 1413 | "markdown-link": "^0.1.1", 1414 | "minimist": "^1.2.0", 1415 | "mixin-deep": "^1.1.3", 1416 | "object.pick": "^1.2.0", 1417 | "remarkable": "^1.7.1", 1418 | "repeat-string": "^1.6.1", 1419 | "strip-color": "^0.1.0" 1420 | } 1421 | }, 1422 | "math-random": { 1423 | "version": "1.0.1", 1424 | "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", 1425 | "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", 1426 | "dev": true 1427 | }, 1428 | "minimatch": { 1429 | "version": "3.0.4", 1430 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 1431 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 1432 | "requires": { 1433 | "brace-expansion": "^1.1.7" 1434 | } 1435 | }, 1436 | "minimist": { 1437 | "version": "1.2.0", 1438 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", 1439 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", 1440 | "dev": true 1441 | }, 1442 | "mixin-deep": { 1443 | "version": "1.3.1", 1444 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", 1445 | "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", 1446 | "dev": true, 1447 | "requires": { 1448 | "for-in": "^1.0.2", 1449 | "is-extendable": "^1.0.1" 1450 | }, 1451 | "dependencies": { 1452 | "is-extendable": { 1453 | "version": "1.0.1", 1454 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", 1455 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", 1456 | "dev": true, 1457 | "requires": { 1458 | "is-plain-object": "^2.0.4" 1459 | } 1460 | } 1461 | } 1462 | }, 1463 | "object-assign": { 1464 | "version": "4.1.1", 1465 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", 1466 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", 1467 | "dev": true 1468 | }, 1469 | "object.pick": { 1470 | "version": "1.3.0", 1471 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", 1472 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", 1473 | "dev": true, 1474 | "requires": { 1475 | "isobject": "^3.0.1" 1476 | }, 1477 | "dependencies": { 1478 | "isobject": { 1479 | "version": "3.0.1", 1480 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", 1481 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", 1482 | "dev": true 1483 | } 1484 | } 1485 | }, 1486 | "once": { 1487 | "version": "1.4.0", 1488 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1489 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1490 | "requires": { 1491 | "wrappy": "1" 1492 | } 1493 | }, 1494 | "p-limit": { 1495 | "version": "1.3.0", 1496 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", 1497 | "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", 1498 | "dev": true, 1499 | "requires": { 1500 | "p-try": "^1.0.0" 1501 | } 1502 | }, 1503 | "p-locate": { 1504 | "version": "2.0.0", 1505 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", 1506 | "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", 1507 | "dev": true, 1508 | "requires": { 1509 | "p-limit": "^1.1.0" 1510 | } 1511 | }, 1512 | "p-try": { 1513 | "version": "1.0.0", 1514 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", 1515 | "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", 1516 | "dev": true 1517 | }, 1518 | "path-exists": { 1519 | "version": "3.0.0", 1520 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 1521 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", 1522 | "dev": true 1523 | }, 1524 | "path-is-absolute": { 1525 | "version": "1.0.1", 1526 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1527 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1528 | }, 1529 | "pify": { 1530 | "version": "2.3.0", 1531 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", 1532 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", 1533 | "dev": true 1534 | }, 1535 | "pinkie": { 1536 | "version": "2.0.4", 1537 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", 1538 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", 1539 | "dev": true 1540 | }, 1541 | "pinkie-promise": { 1542 | "version": "2.0.1", 1543 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", 1544 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", 1545 | "dev": true, 1546 | "requires": { 1547 | "pinkie": "^2.0.0" 1548 | } 1549 | }, 1550 | "process-nextick-args": { 1551 | "version": "2.0.0", 1552 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", 1553 | "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", 1554 | "dev": true 1555 | }, 1556 | "promise": { 1557 | "version": "7.3.1", 1558 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", 1559 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", 1560 | "dev": true, 1561 | "requires": { 1562 | "asap": "~2.0.3" 1563 | } 1564 | }, 1565 | "qs": { 1566 | "version": "6.5.2", 1567 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 1568 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", 1569 | "dev": true 1570 | }, 1571 | "randomatic": { 1572 | "version": "3.1.0", 1573 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz", 1574 | "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==", 1575 | "dev": true, 1576 | "requires": { 1577 | "is-number": "^4.0.0", 1578 | "kind-of": "^6.0.0", 1579 | "math-random": "^1.0.1" 1580 | }, 1581 | "dependencies": { 1582 | "is-number": { 1583 | "version": "4.0.0", 1584 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", 1585 | "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", 1586 | "dev": true 1587 | }, 1588 | "kind-of": { 1589 | "version": "6.0.2", 1590 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", 1591 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", 1592 | "dev": true 1593 | } 1594 | } 1595 | }, 1596 | "readable-stream": { 1597 | "version": "2.3.6", 1598 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", 1599 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", 1600 | "dev": true, 1601 | "requires": { 1602 | "core-util-is": "~1.0.0", 1603 | "inherits": "~2.0.3", 1604 | "isarray": "~1.0.0", 1605 | "process-nextick-args": "~2.0.0", 1606 | "safe-buffer": "~5.1.1", 1607 | "string_decoder": "~1.1.1", 1608 | "util-deprecate": "~1.0.1" 1609 | } 1610 | }, 1611 | "remarkable": { 1612 | "version": "1.7.1", 1613 | "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-1.7.1.tgz", 1614 | "integrity": "sha1-qspJchALZqZCpjoQIcpLrBvjv/Y=", 1615 | "dev": true, 1616 | "requires": { 1617 | "argparse": "~0.1.15", 1618 | "autolinker": "~0.15.0" 1619 | }, 1620 | "dependencies": { 1621 | "argparse": { 1622 | "version": "0.1.16", 1623 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", 1624 | "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", 1625 | "dev": true, 1626 | "requires": { 1627 | "underscore": "~1.7.0", 1628 | "underscore.string": "~2.4.0" 1629 | } 1630 | } 1631 | } 1632 | }, 1633 | "repeat-element": { 1634 | "version": "1.1.2", 1635 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", 1636 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", 1637 | "dev": true 1638 | }, 1639 | "repeat-string": { 1640 | "version": "1.6.1", 1641 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 1642 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", 1643 | "dev": true 1644 | }, 1645 | "rimraf": { 1646 | "version": "2.6.2", 1647 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", 1648 | "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", 1649 | "requires": { 1650 | "glob": "^7.0.5" 1651 | } 1652 | }, 1653 | "safe-buffer": { 1654 | "version": "5.1.2", 1655 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1656 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1657 | "dev": true 1658 | }, 1659 | "set-getter": { 1660 | "version": "0.1.0", 1661 | "resolved": "https://registry.npmjs.org/set-getter/-/set-getter-0.1.0.tgz", 1662 | "integrity": "sha1-12nBgsnVpR9AkUXy+6guXoboA3Y=", 1663 | "dev": true, 1664 | "requires": { 1665 | "to-object-path": "^0.3.0" 1666 | } 1667 | }, 1668 | "sprintf-js": { 1669 | "version": "1.0.3", 1670 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 1671 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 1672 | "dev": true 1673 | }, 1674 | "string_decoder": { 1675 | "version": "1.1.1", 1676 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", 1677 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", 1678 | "dev": true, 1679 | "requires": { 1680 | "safe-buffer": "~5.1.0" 1681 | } 1682 | }, 1683 | "strip-color": { 1684 | "version": "0.1.0", 1685 | "resolved": "https://registry.npmjs.org/strip-color/-/strip-color-0.1.0.tgz", 1686 | "integrity": "sha1-EG9l09PmotlAHKwOsM6LinArT3s=", 1687 | "dev": true 1688 | }, 1689 | "sync-request": { 1690 | "version": "3.0.1", 1691 | "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-3.0.1.tgz", 1692 | "integrity": "sha1-yqEjWq+Im6UBB2oYNMQ2gwqC+3M=", 1693 | "dev": true, 1694 | "requires": { 1695 | "concat-stream": "^1.4.7", 1696 | "http-response-object": "^1.0.1", 1697 | "then-request": "^2.0.1" 1698 | } 1699 | }, 1700 | "then-request": { 1701 | "version": "2.2.0", 1702 | "resolved": "https://registry.npmjs.org/then-request/-/then-request-2.2.0.tgz", 1703 | "integrity": "sha1-ZnizL6DKIY/laZgbvYhxtZQGDYE=", 1704 | "dev": true, 1705 | "requires": { 1706 | "caseless": "~0.11.0", 1707 | "concat-stream": "^1.4.7", 1708 | "http-basic": "^2.5.1", 1709 | "http-response-object": "^1.1.0", 1710 | "promise": "^7.1.1", 1711 | "qs": "^6.1.0" 1712 | } 1713 | }, 1714 | "to-object-path": { 1715 | "version": "0.3.0", 1716 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", 1717 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", 1718 | "dev": true, 1719 | "requires": { 1720 | "kind-of": "^3.0.2" 1721 | } 1722 | }, 1723 | "toml": { 1724 | "version": "2.3.3", 1725 | "resolved": "https://registry.npmjs.org/toml/-/toml-2.3.3.tgz", 1726 | "integrity": "sha512-O7L5hhSQHxuufWUdcTRPfuTh3phKfAZ/dqfxZFoxPCj2RYmpaSGLEIs016FCXItQwNr08yefUB5TSjzRYnajTA==", 1727 | "dev": true 1728 | }, 1729 | "typedarray": { 1730 | "version": "0.0.6", 1731 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1732 | "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", 1733 | "dev": true 1734 | }, 1735 | "underscore": { 1736 | "version": "1.7.0", 1737 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", 1738 | "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", 1739 | "dev": true 1740 | }, 1741 | "underscore.string": { 1742 | "version": "2.4.0", 1743 | "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", 1744 | "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", 1745 | "dev": true 1746 | }, 1747 | "util-deprecate": { 1748 | "version": "1.0.2", 1749 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1750 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", 1751 | "dev": true 1752 | }, 1753 | "wrappy": { 1754 | "version": "1.0.2", 1755 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1756 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1757 | } 1758 | } 1759 | } 1760 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cache-me-outside", 3 | "version": "1.0.0", 4 | "description": "Caching tool for quicker builds in CI systems", 5 | "main": "lib/index.js", 6 | "files": [ 7 | "lib", 8 | "package.json", 9 | "package-lock.json", 10 | "README.md" 11 | ], 12 | "scripts": { 13 | "test": "echo \"Error: no test specified\" && exit 1", 14 | "docs": "md-magic --path '**/*.md' --ignore 'node_modules'", 15 | "publish": "git push origin && git push origin --tags", 16 | "release:patch": "npm version patch && npm publish", 17 | "release:minor": "npm version minor && npm publish", 18 | "release:major": "npm version major && npm publish" 19 | }, 20 | "homepage": "https://github.com/DavidWells/cache-me-outside#readme", 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/DavidWells/cache-me-outside" 24 | }, 25 | "author": "David Wells", 26 | "license": "MIT", 27 | "dependencies": { 28 | "is-invalid-path": "^1.0.2", 29 | "rimraf": "^2.6.2" 30 | }, 31 | "devDependencies": { 32 | "markdown-magic": "^0.1.25" 33 | } 34 | } 35 | --------------------------------------------------------------------------------