glob-uglifyjs
Advanced tools
Comparing version 0.4.3 to 1.0.0-alpha-1
@@ -1,7 +0,7 @@ | ||
import { Options } from "./options"; | ||
import { OptionsDto } from "./options"; | ||
export interface Arguments { | ||
pattern: string; | ||
options: Options; | ||
options: OptionsDto; | ||
} | ||
declare var _default: Arguments; | ||
export default _default; |
#!/usr/bin/env node | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const arguments_1 = require("./arguments"); | ||
const main_1 = require("./main"); | ||
new main_1.GlobsUglifyJs(arguments_1.default.pattern, arguments_1.default.options || {}); | ||
const process = require("process"); | ||
console.log(process.cwd()); | ||
function CliStarter() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
// const start = process.hrtime(); | ||
const globUglifier = new main_1.GlobsUglifyJs(arguments_1.default.pattern, arguments_1.default.options || {}); | ||
yield globUglifier.Uglify(); | ||
// const [sec, nano] = process.hrtime(start); | ||
// console.log(`TIME: ${(sec * 1e9 + nano) / 1e9}`); | ||
}); | ||
} | ||
CliStarter(); |
@@ -1,70 +0,23 @@ | ||
import { Options } from "./options"; | ||
import { OptionsDto } from "./options"; | ||
export declare class GlobsUglifyJs { | ||
constructor(globPattern: string, options?: OptionsDto); | ||
private globOptions; | ||
private globPattern; | ||
private options; | ||
constructor(globPattern: string, options?: Options); | ||
private main(); | ||
private deleteFiles(fileList); | ||
private deleteFile(filePath); | ||
private filesList; | ||
private filesDetails; | ||
GetFilesList(): Promise<string[]>; | ||
Uglify(porcessLimit?: number): Promise<void>; | ||
private handleError(error); | ||
private removeSources(successFiles); | ||
private uglifyItem(file); | ||
private buildOutFilePath(filePath); | ||
private uglifyFile(file, options?); | ||
private startRecursiveUglify(filesList, results?); | ||
private recursiveUglify(file); | ||
private ensureDirectoryExistence(filePath); | ||
private directoryExists(path); | ||
private deleteEmptyDirectories(directoryPath); | ||
private removeDirectory(directoryPath); | ||
private readFilesInDirectory(directoryPath); | ||
/** | ||
* Check if parsed name without extension has minified extension prefix. | ||
* | ||
* @private | ||
* @param {string} nameWithoutExt Parsed file name without extension. | ||
* @returns | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
private hasMinifiedExt(nameWithoutExt); | ||
private resolveOutFilePath(filePath); | ||
/** | ||
* Asynchronously write data to file with flag "wx". | ||
* | ||
* @private | ||
* @param {string} filePath File path. | ||
* @param {string} data Data in "utf-8". | ||
* @returns | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
private writeToFile(filePath, data); | ||
/** | ||
* Asynchronously return files list by pattern. | ||
* | ||
* @private | ||
* @param {string} pattern | ||
* @param {glob.IOptions} [options={}] | ||
* @returns | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
private getGlobs(pattern, options?); | ||
/** | ||
* Validate JS extension. | ||
* | ||
* @private | ||
* @param {string} pattern | ||
* @returns {boolean} True if extension exist. | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
private validateExtension(pattern); | ||
/** | ||
* Add .js to glob pattern. | ||
* | ||
* @private | ||
* @param {string} pattern | ||
* @returns {string} | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
private addJsExtension(pattern); | ||
private getGlobFilesList(pattern, options?); | ||
} |
432
dist/main.js
@@ -14,297 +14,154 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
const options_1 = require("./options"); | ||
const fs = require("fs"); | ||
const fs = require("fs-promise"); | ||
const rejection_error_1 = require("./rejection-error"); | ||
const Directories = require("./utils/directories"); | ||
const JS_EXTENSION = ".js"; | ||
const MINIFY_EXTENSION_PREFIX = ".min"; | ||
class RecursiveUglifyResults { | ||
constructor() { | ||
this.succeed = 0; | ||
this.failed = 0; | ||
} | ||
get Succeed() { | ||
return this.succeed; | ||
} | ||
get Failed() { | ||
return this.failed; | ||
} | ||
OnSucceed() { | ||
this.succeed++; | ||
} | ||
OnFailed() { | ||
this.failed++; | ||
} | ||
} | ||
var Status; | ||
(function (Status) { | ||
Status[Status["Init"] = 0] = "Init"; | ||
Status[Status["Pending"] = 1] = "Pending"; | ||
Status[Status["Completed"] = 2] = "Completed"; | ||
Status[Status["Failed"] = 3] = "Failed"; | ||
})(Status || (Status = {})); | ||
class GlobsUglifyJs { | ||
constructor(globPattern, options) { | ||
this.options = new options_1.default(options); | ||
if (!this.validateExtension(globPattern)) { | ||
globPattern = this.addJsExtension(globPattern); | ||
this.options = new options_1.Options(options); | ||
const globExt = path.extname(globPattern); | ||
if (!globExt) { | ||
globPattern += JS_EXTENSION; | ||
} | ||
else if (globExt === ".") { | ||
globPattern += JS_EXTENSION.slice(1); | ||
} | ||
else { | ||
console.log("Using custom extension: ", globExt); | ||
} | ||
if (this.options.Exclude !== undefined) { | ||
this.globOptions = { ignore: this.options.Exclude }; | ||
} | ||
this.globPattern = path.join(this.options.RootDir, globPattern); | ||
this.main(); | ||
} | ||
main() { | ||
GetFilesList() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let globOptions; | ||
if (this.options.Exclude !== undefined) { | ||
globOptions = { ignore: this.options.Exclude }; | ||
if (this.filesList != null) { | ||
return this.filesList; | ||
} | ||
let filesList; | ||
try { | ||
let filesList = yield this.getGlobs(this.globPattern, globOptions); | ||
if (filesList.length === 0) { | ||
console.log("No files found."); | ||
return; | ||
} | ||
let results = yield this.startRecursiveUglify(filesList.slice(0)); | ||
if (this.options.RemoveSource) { | ||
yield this.deleteFiles(filesList.slice(0)); | ||
yield this.deleteEmptyDirectories(this.options.RootDir); | ||
} | ||
if (results.Failed > 0) { | ||
console.warn(`Failed to minify ${results.Failed} file${(results.Failed > 1) ? "s" : ""}.`); | ||
} | ||
if (results.Succeed > 0) { | ||
console.log(`Successfully minified ${results.Succeed} file${(results.Succeed > 1) ? "s" : ""}.`); | ||
} | ||
filesList = yield this.getGlobFilesList(this.globPattern, this.globOptions); | ||
} | ||
catch (error) { | ||
if (error instanceof rejection_error_1.default) { | ||
error.ThrowError(); | ||
if (this.options.Debug) { | ||
console.error(error); | ||
} | ||
else { | ||
throw error; | ||
} | ||
throw new Error(`Failed to find files by specified glob (${this.globPattern}).`); | ||
} | ||
}); | ||
} | ||
deleteFiles(fileList) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { | ||
let rejected = false; | ||
let file = fileList.shift(); | ||
if (file == null) { | ||
resolve(); | ||
return; | ||
} | ||
yield this.deleteFile(file) | ||
.catch(error => { | ||
rejected = true; | ||
reject(new rejection_error_1.default(error, "deleteFile")); | ||
}); | ||
if (!rejected) { | ||
yield this.deleteFiles(fileList); | ||
resolve(); | ||
} | ||
})); | ||
}); | ||
} | ||
deleteFile(filePath) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
fs.unlink(filePath, error => { | ||
if (error) { | ||
reject(error); | ||
} | ||
else { | ||
resolve(); | ||
} | ||
}); | ||
console.log(`Found ${filesList.length} files with glob pattern ${this.globPattern}`); | ||
this.filesList = filesList; | ||
this.filesDetails = this.filesList.map((value, index) => { | ||
return { Index: index, Status: Status.Init }; | ||
}); | ||
return this.filesList; | ||
}); | ||
} | ||
uglifyFile(file, options) { | ||
Uglify(porcessLimit = 3) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
let filesList; | ||
if (this.filesList == null) { | ||
filesList = yield this.GetFilesList(); | ||
} | ||
else { | ||
filesList = this.filesList; | ||
} | ||
const filesCount = filesList.length; | ||
if (filesCount === 0) { | ||
console.warn(`No files found matching specified glob pattern (${this.globPattern}).`); | ||
return; | ||
} | ||
const results = { | ||
Success: new Array(), | ||
Failed: new Array() | ||
}; | ||
for (let i = 0; i < filesCount; i++) { | ||
const file = filesList[i]; | ||
try { | ||
let outputData = uglifyjs.minify(file, options); | ||
resolve(outputData); | ||
yield this.uglifyItem(file); | ||
results.Success.push(file); | ||
} | ||
catch (error) { | ||
reject(error); | ||
results.Failed.push(file); | ||
this.handleError(error); | ||
} | ||
}); | ||
}); | ||
} | ||
startRecursiveUglify(filesList, results) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve) => __awaiter(this, void 0, void 0, function* () { | ||
if (results == null) { | ||
results = new RecursiveUglifyResults(); | ||
} | ||
let file = filesList.shift(); | ||
if (file != null) { | ||
try { | ||
yield this.recursiveUglify(file); | ||
results.OnSucceed(); | ||
} | ||
catch (error) { | ||
if (error instanceof rejection_error_1.default) { | ||
error.LogError(this.options.Debug); | ||
} | ||
else if (this.options.Debug) { | ||
console.error(error); | ||
} | ||
results.OnFailed(); | ||
} | ||
resolve(yield this.startRecursiveUglify(filesList, results)); | ||
} | ||
else { | ||
resolve(results); | ||
} | ||
})); | ||
}); | ||
} | ||
recursiveUglify(file) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { | ||
} | ||
if (this.options.RemoveSource) { | ||
try { | ||
let outputData = yield this.uglifyFile(file, this.options.MinifyOptions) | ||
.catch(error => { | ||
throw new rejection_error_1.default(error, "uglifyFile", file); | ||
}); | ||
let outPath = this.resolveOutFilePath(file); | ||
yield this.ensureDirectoryExistence(outPath) | ||
.catch(error => { | ||
throw new rejection_error_1.default(error, "ensureDirectoryExistence", file); | ||
}); | ||
yield this.writeToFile(outPath, outputData.code) | ||
.catch(error => { | ||
throw new rejection_error_1.default(error, "writeToFile", file); | ||
}); | ||
resolve(); | ||
yield this.removeSources(results.Success); | ||
} | ||
catch (error) { | ||
reject(error); | ||
this.handleError(error); | ||
} | ||
})); | ||
} | ||
if (results.Failed.length > 0) { | ||
console.warn(`Failed to minify ${results.Failed.length} file${(results.Failed.length > 1) ? "s" : ""}.`); | ||
} | ||
if (results.Success.length > 0) { | ||
console.log(`Successfully minified ${results.Success.length} file${(results.Success.length > 1) ? "s" : ""}.`); | ||
} | ||
}); | ||
} | ||
ensureDirectoryExistence(filePath) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { | ||
let rejected = false; | ||
let dirname = path.dirname(filePath); | ||
let directoryExist = yield this.directoryExists(dirname); | ||
if (directoryExist) { | ||
resolve(); | ||
return; | ||
} | ||
yield this.ensureDirectoryExistence(dirname) | ||
.catch(error => { | ||
reject(error); | ||
rejected = true; | ||
}); | ||
if (rejected) { | ||
return; | ||
} | ||
fs.mkdir(dirname, error => { | ||
if (error) { | ||
reject(error); | ||
} | ||
else { | ||
resolve(); | ||
} | ||
}); | ||
})); | ||
}); | ||
handleError(error) { | ||
if (error instanceof rejection_error_1.RejectionError) { | ||
error.LogError(this.options.Debug); | ||
} | ||
else if (this.options.Debug) { | ||
console.error(error); | ||
} | ||
} | ||
directoryExists(path) { | ||
removeSources(successFiles) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise(resolve => { | ||
fs.stat(path, (error, stats) => { | ||
if (error) { | ||
resolve(false); | ||
} | ||
else { | ||
resolve(stats.isDirectory()); | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
deleteEmptyDirectories(directoryPath) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { | ||
let rejected = false; | ||
let isExist = yield this.directoryExists(directoryPath); | ||
if (!isExist) { | ||
resolve(); // or reject? | ||
return; | ||
for (const file of successFiles) { | ||
try { | ||
yield fs.unlink(file); | ||
} | ||
let files = yield this.readFilesInDirectory(directoryPath); | ||
if (files.length > 0) { | ||
for (let i = 0; i < files.length; i++) { | ||
let file = files[i]; | ||
var fullPath = path.join(directoryPath, file); | ||
yield this.deleteEmptyDirectories(fullPath) | ||
.catch(error => { | ||
reject(new rejection_error_1.default(error, "deleteEmptyDirectories")); | ||
rejected = true; | ||
}); | ||
if (rejected) { | ||
break; | ||
} | ||
} | ||
if (rejected) { | ||
return; | ||
} | ||
files = yield this.readFilesInDirectory(directoryPath); | ||
catch (error) { | ||
throw new rejection_error_1.RejectionError(error, "deleteFile"); | ||
} | ||
if (files.length === 0) { | ||
yield this.removeDirectory(directoryPath) | ||
.catch(error => { | ||
reject(new rejection_error_1.default(error, "removeDirectory")); | ||
rejected = true; | ||
}); | ||
} | ||
if (!rejected) { | ||
resolve(); | ||
} | ||
})); | ||
} | ||
try { | ||
yield Directories.RemoveEmptyDirectories(this.options.RootDir); | ||
} | ||
catch (error) { | ||
throw new rejection_error_1.RejectionError(error, "deleteEmptyDirectories"); | ||
} | ||
}); | ||
} | ||
removeDirectory(directoryPath) { | ||
uglifyItem(file) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
fs.rmdir(directoryPath, error => { | ||
if (error) { | ||
reject(error); | ||
} | ||
else { | ||
resolve(); | ||
} | ||
}); | ||
}); | ||
let outputData; | ||
try { | ||
outputData = yield this.uglifyFile(file, this.options.MinifyOptions); | ||
} | ||
catch (error) { | ||
throw new rejection_error_1.RejectionError(error, "uglifyFile", file); | ||
} | ||
const outPath = this.buildOutFilePath(file); | ||
try { | ||
yield Directories.MakeTree(outPath); | ||
} | ||
catch (error) { | ||
throw new rejection_error_1.RejectionError(error, "ensureDirectoryExistence", file); | ||
} | ||
try { | ||
yield fs.writeFile(outPath, outputData.code, { encoding: "utf-8", flag: "w" }); | ||
} | ||
catch (error) { | ||
throw new rejection_error_1.RejectionError(error, "writeToFile", file); | ||
} | ||
}); | ||
} | ||
readFilesInDirectory(directoryPath) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
fs.readdir(directoryPath, (error, files) => { | ||
if (error) { | ||
reject(error); | ||
} | ||
else { | ||
resolve(files); | ||
} | ||
}); | ||
}); | ||
}); | ||
} | ||
/** | ||
* Check if parsed name without extension has minified extension prefix. | ||
* | ||
* @private | ||
* @param {string} nameWithoutExt Parsed file name without extension. | ||
* @returns | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
hasMinifiedExt(nameWithoutExt) { | ||
let ext = path.extname(nameWithoutExt); | ||
return (ext != null && ext === MINIFY_EXTENSION_PREFIX); | ||
} | ||
resolveOutFilePath(filePath) { | ||
let parsedPath = path.parse(filePath), targetExt = parsedPath.ext; | ||
if (this.options.UseMinExt && !this.hasMinifiedExt(parsedPath.name)) { | ||
buildOutFilePath(filePath) { | ||
const parsedPath = path.parse(filePath); | ||
let targetExt = parsedPath.ext; | ||
if (this.options.UseMinExt && targetExt !== MINIFY_EXTENSION_PREFIX) { | ||
targetExt = MINIFY_EXTENSION_PREFIX + targetExt; | ||
@@ -321,23 +178,12 @@ } | ||
} | ||
/** | ||
* Asynchronously write data to file with flag "wx". | ||
* | ||
* @private | ||
* @param {string} filePath File path. | ||
* @param {string} data Data in "utf-8". | ||
* @returns | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
writeToFile(filePath, data) { | ||
uglifyFile(file, options) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
return new Promise((resolve, reject) => { | ||
fs.writeFile(filePath, data, { encoding: "utf-8", flag: "w" }, (error) => { | ||
if (error) { | ||
reject(error); | ||
} | ||
else { | ||
resolve(); | ||
} | ||
}); | ||
try { | ||
let outputData = uglifyjs.minify(file, options); | ||
resolve(outputData); | ||
} | ||
catch (error) { | ||
reject(error); | ||
} | ||
}); | ||
@@ -349,10 +195,6 @@ }); | ||
* | ||
* @private | ||
* @param {string} pattern | ||
* @param {glob.IOptions} [options={}] | ||
* @returns | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
getGlobs(pattern, options = {}) { | ||
getGlobFilesList(pattern, options = {}) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -371,31 +213,3 @@ return new Promise((resolve, reject) => { | ||
} | ||
/** | ||
* Validate JS extension. | ||
* | ||
* @private | ||
* @param {string} pattern | ||
* @returns {boolean} True if extension exist. | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
validateExtension(pattern) { | ||
let ext = path.extname(pattern); | ||
if (ext.length !== 0 && ext !== JS_EXTENSION) { | ||
console.warn("Using custom extension: ", ext); | ||
} | ||
return (ext != null && ext.length > 0); | ||
} | ||
/** | ||
* Add .js to glob pattern. | ||
* | ||
* @private | ||
* @param {string} pattern | ||
* @returns {string} | ||
* | ||
* @memberOf GlobsUglifyJs | ||
*/ | ||
addJsExtension(pattern) { | ||
return pattern + JS_EXTENSION; | ||
} | ||
} | ||
exports.GlobsUglifyJs = GlobsUglifyJs; |
/// <reference types="uglify-js" /> | ||
import * as uglifyjs from "uglify-js"; | ||
export interface Options { | ||
export interface OptionsDto { | ||
[key: string]: any; | ||
@@ -14,4 +14,4 @@ UseMinExt?: boolean; | ||
} | ||
export default class OptionsConstructor implements Options { | ||
constructor(importData?: Options); | ||
export declare class Options implements OptionsDto { | ||
constructor(importData?: OptionsDto); | ||
private options; | ||
@@ -18,0 +18,0 @@ readonly UseMinExt: boolean; |
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const process = require("process"); | ||
class OptionsConstructor { | ||
class Options { | ||
constructor(importData) { | ||
@@ -55,2 +55,2 @@ this.options = { | ||
} | ||
exports.default = OptionsConstructor; | ||
exports.Options = Options; |
/// <reference types="node" /> | ||
export default class RejectionError { | ||
export declare class RejectionError { | ||
private error; | ||
@@ -8,3 +8,3 @@ private type; | ||
readonly Type: string | undefined; | ||
readonly Error: Error | NodeJS.ErrnoException; | ||
readonly Error: NodeJS.ErrnoException | Error; | ||
readonly UniqId: string | undefined; | ||
@@ -11,0 +11,0 @@ private showErrorDetails(); |
@@ -38,2 +38,2 @@ Object.defineProperty(exports, "__esModule", { value: true }); | ||
} | ||
exports.default = RejectionError; | ||
exports.RejectionError = RejectionError; |
{ | ||
"name": "glob-uglifyjs", | ||
"version": "0.4.3", | ||
"version": "1.0.0-alpha-1", | ||
"description": "Uglify JS files with glob pattern.", | ||
@@ -35,11 +35,16 @@ "main": "dist/main.js", | ||
"devDependencies": { | ||
"@types/mkdirp": "^0.3.29", | ||
"fs-extra": "^2.1.2", | ||
"typescript": "^2.2.2" | ||
}, | ||
"dependencies": { | ||
"@types/fs-promise": "^1.0.2", | ||
"@types/glob": "^5.0.30", | ||
"@types/uglify-js": "^2.6.28", | ||
"@types/yargs": "6.6.0", | ||
"fs-promise": "^2.0.2", | ||
"glob": "^7.1.1", | ||
"mkdirp": "^0.5.1", | ||
"uglify-js": "^2.8.21", | ||
"yargs": "^7.0.2", | ||
"@types/glob": "^5.0.30", | ||
"@types/uglify-js": "^2.6.28", | ||
"@types/yargs": "6.6.0" | ||
"yargs": "^7.0.2" | ||
}, | ||
@@ -46,0 +51,0 @@ "bin": { |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
17
22824
9
3
482
3
1
+ Added@types/fs-promise@^1.0.2
+ Addedfs-promise@^2.0.2
+ Addedmkdirp@^0.5.1
+ Added@types/fs-promise@1.0.3(transitive)
+ Added@types/mz@2.7.8(transitive)
+ Addedany-promise@1.3.0(transitive)
+ Addedfs-extra@2.1.2(transitive)
+ Addedfs-promise@2.0.3(transitive)
+ Addedjsonfile@2.4.0(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addedmz@2.7.0(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedthenify@3.3.1(transitive)
+ Addedthenify-all@1.6.0(transitive)