New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

whybundled

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

whybundled - npm Package Compare versions

Comparing version 1.1.0 to 1.2.0

fixtures/example-simple-stats.json

8

cli.js

@@ -6,2 +6,3 @@ #!/usr/bin/env node

const chalk = require("chalk");
const createProgressBar = require("./lib/console/progress-bar");
const defaultCommand = require("./commands/default");

@@ -56,6 +57,8 @@ const byCommand = require("./commands/by");

const updateProgressBar = createProgressBar();
if (flags.by) {
byCommand(input[0], flags, input[1]);
byCommand(input[0], flags, input[1], updateProgressBar);
} else {
defaultCommand(input[0], flags, input[1]);
defaultCommand(input[0], flags, input[1], updateProgressBar);
}

@@ -67,1 +70,2 @@

console.log(`🏁 Done in ${rounded}s.`);
process.exit(0);
/* @flow */
/*::
import type { UpdateProgressBar } from '../lib/console/progress-bar';
*/
const { analyze, print, getStats } = require("../lib");
const validate = require("../lib/validate");
const { log, invalidStatsJson } = require("../lib/messages");
const { log, invalidStatsJson } = require("../lib/console/messages");

@@ -10,3 +14,4 @@ module.exports = function byCommand(

flags /*: { limit: number, by: string, ignore?: string } */,
pattern /*: string */
pattern /*: string */,
updateProgressBar /*: UpdateProgressBar */ = () => {}
) {

@@ -21,4 +26,6 @@ const stats = getStats(statsFilePath);

const ignore = flags.ignore ? flags.ignore.split(",") : [];
const report = analyze(stats, ignore).filter(mod => {
return (
const report = analyze(stats, ignore, updateProgressBar);
const modules = report.modules.filter(
mod =>
mod.reasons.some(

@@ -28,6 +35,6 @@ reason =>

) || (mod.depsChains || []).some(deps => deps.indexOf(flags.by) !== -1)
);
});
);
const limit /*: number */ = pattern ? 0 : flags.limit >= 0 ? flags.limit : 20;
print(report, { by: flags.by }, limit);
print(modules, report.chunks, { by: flags.by }, limit);
};

@@ -6,5 +6,7 @@ /* @flow */

const validate = require("../lib/validate");
const { log, invalidStatsJson } = require("../lib/messages");
const { log, invalidStatsJson } = require("../lib/console/messages");
/*::
import type { UpdateProgressBar } from '../lib/console/progress-bar';
type Flags = {

@@ -25,3 +27,4 @@ limit: number,

flags /*: Flags */,
pattern /*: string*/
pattern /*: string*/,
updateProgressBar /*: UpdateProgressBar */ = () => {}
) {

@@ -36,3 +39,4 @@ const stats = getStats(statsFilePath);

const ignore = flags.ignore ? flags.ignore.split(",") : [];
const report = analyze(stats, ignore).filter(module => {
const report = analyze(stats, ignore, updateProgressBar);
const modules = report.modules.filter(module => {
if (pattern && mm.isMatch(module.name, pattern)) {

@@ -56,3 +60,3 @@ return true;

const limit = pattern ? 0 : flags.limit >= 0 ? flags.limit : 20;
print(report, flags, limit);
print(modules, report.chunks, flags, limit);
};
{
"chunks": [
{
"id": 1,
"names": [],
"size": 0,
"modules": [

@@ -5,0 +8,0 @@ {

@@ -17,3 +17,9 @@ // flow-typed signature: a71a6e955d88c74dfbccba23202e0f98

declare module "micromatch" {
declare module.exports: any;
declare module.exports: {
isMatch: (
what: string,
patterns: Array<string> | string,
options?: Object
) => boolean
};
}

@@ -20,0 +26,0 @@

@@ -20,4 +20,41 @@ const stripAnsi = require("strip-ansi");

const logger = createPrint();
print(stats, {}, 0, logger);
print(stats.modules, stats.chunks, {}, 0, logger);
t.snapshot(logger());
});
test("should properly print simple stats.json", t => {
const stats = analyze(getStats(f.find("example-simple-stats.json")));
const logger = createPrint();
print(stats.modules, stats.chunks, {}, 0, logger);
t.snapshot(logger());
});
test("should properly print multi entry stats.json", t => {
const stats = analyze(getStats(f.find("multi-entry-stats.json")));
const logger = createPrint();
print(stats.modules, stats.chunks, {}, 0, logger);
t.snapshot(logger());
});
test("should properly print multi entry stats.json with dynamic import", t => {
const stats = analyze(
getStats(f.find("multi-entry-dynamic-import-stats.json"))
);
const logger = createPrint();
print(stats.modules, stats.chunks, {}, 0, logger);
t.snapshot(logger());
});
test("should properly print multi entry stats.json with no chunks information", t => {
const stats = analyze(getStats(f.find("multi-entry-no-chunks-stats.json")));
const logger = createPrint();
print(stats.modules, stats.chunks, {}, 0, logger);
t.snapshot(logger());
});
test("should properly print stats.json with nested children", t => {
const stats = analyze(getStats(f.find("nested-children-stats.json")));
const logger = createPrint();
print(stats.modules, stats.chunks, {}, 0, logger);
t.snapshot(logger());
});

@@ -21,1 +21,6 @@ const test = require("ava");

});
test("should return true for a valid stats file with children", t => {
const stats = getStats(f.find("valid-with-children.json"));
t.truthy(validate(stats));
});
/* @flow */
/*::
import type { UpdateProgressBar } from "./console/progress-bar";
export type WebpackStats = {
chunks?: Array<WebpackChunk>,
modules: Array<WebpackModule>
modules: Array<WebpackModule>,
children?: Array<WebpackStats>
};
export type WebpackChunk = {
id: number,
size: number,
names: Array<string>,
modules: Array<WebpackModule>

@@ -16,2 +23,3 @@ };

size: string,
chunks: Array<number>,
reasons: Array<WebpackReason>

@@ -31,2 +39,3 @@ };

clearName: string,
chunks: Array<number>,
type: string,

@@ -40,2 +49,4 @@ reasons: Array<WebpackReason>,

name: string,
size: number,
chunks: Array<number>,
clearName: string,

@@ -67,2 +78,9 @@ imported: number,

export type Chunks = {
[key: number]: {
id: number,
size: number,
names: Array<string>
}
}
*/

@@ -97,4 +115,6 @@

const getModuleType = (name /*: string */) =>
name.startsWith("multi ") ? "entry" : isNodeModules(name) ? "module" : "file";
const getModuleType = (name /*?: string */) =>
!name || name.startsWith("multi ")
? "entry"
: isNodeModules(name) ? "module" : "file";

@@ -109,2 +129,4 @@ const flattenChunks = (stats /*: WebpackStats */) /*: Array<WebpackModule> */ =>

const safeModuleSize = (size /*?: number */) => (size ? size : 0);
const joinModules = (modules) /*: { [string]: Module } */ =>

@@ -115,2 +137,4 @@ modules.reduce((acc, module /*: PreModule */) => {

type: module.type,
size: safeModuleSize(module.size),
chunks: module.chunks,
imported: 0,

@@ -136,4 +160,6 @@ reasons: [],

type: module.type,
size: 0,
depsType: "unknown",
reasons: [],
chunks: module.chunks,
locations: [],

@@ -199,2 +225,4 @@ filesIncluded: [],

joined.filesIncluded.push(module.name);
joined.size += safeModuleSize(module.size);
joined.chunks = Array.from(new Set(joined.chunks.concat(module.chunks)));

@@ -216,2 +244,3 @@ acc[module.clearName] = joined;

location: clearName ? getLocation(module.name, clearName) : "",
chunks: module.chunks,
size: module.size,

@@ -246,4 +275,6 @@ reasons: module.reasons

const postProcessModules = (modules, ignore) => {
return Object.keys(modules).reduce((acc, name) => {
const postProcessModules = (modules, ignore, updateProgressBar) => {
return Object.keys(modules).reduce((acc, name, index) => {
updateProgressBar(index + 1, "processing", name);
if (mm.isMatch(name, ignore)) {

@@ -267,3 +298,3 @@ return acc;

module.reasons = module.reasons.filter(
reason => !mm.isMatch(reason.clearName || reason.moduleName, ignore)
reason => !mm.isMatch(reason.clearName || reason.moduleName || "", ignore)
);

@@ -278,10 +309,73 @@

function joinStats(children) {
const flattenChildren = (children, id = "0") =>
children.reduce((acc, child, index) => {
child.id = `${id}.${index}`;
acc = acc.concat(child);
acc = acc.concat(flattenChildren(child.children || [], child.id));
}, []);
return children.reduce(
(acc, child) => {
acc.chunks = child.chunks ? acc.chunks.concat(child.chunks) : acc.chunks;
acc.modules = child.modules
? acc.modules.concat(child.modules)
: acc.modules;
return acc;
},
{ chunks: [], modules: [] }
);
}
function getChunksData(stats /*: WebpackStats */) {
return stats.chunks
? stats.chunks.reduce((acc, chunk) => {
acc[chunk.id] = {
id: chunk.id,
names: chunk.names,
size: chunk.size
};
return acc;
}, {})
: {};
}
module.exports = function analyze(
stats /*: WebpackStats */,
ignore /*: Array<string> */ = []
rawStats /*: WebpackStats */,
ignore /*: Array<string> */ = [],
updateProgressBar /*: UpdateProgressBar */ = () => {}
) {
const stats =
rawStats.children &&
rawStats.children.length &&
(!rawStats.chunks || !rawStats.chunks.length)
? joinStats(rawStats.children)
: rawStats;
const chunks = getChunksData(stats);
const rawModules = flattenChunks(stats);
const ignorePatterns = [].concat(DEFAULT_IGNORE).concat(ignore);
const modules = pickFromModules(rawModules);
return toArray(postProcessModules(joinModules(modules), ignorePatterns));
const joinedModules = joinModules(modules);
const joinedModulesCount = Object.keys(joinedModules).length;
const updateProgressBarWithTotal = (
cur /*: number */,
title /*: string */,
name /*: string */
) =>
updateProgressBar({
title,
text: name,
progress: Math.ceil(cur / joinedModulesCount * 100)
});
return {
modules: toArray(
postProcessModules(
joinedModules,
ignorePatterns,
updateProgressBarWithTotal
)
),
chunks
};
};

@@ -15,3 +15,3 @@ /* @flow */

statsFilePath /*: string */
) /*?: WebpackStats */ {
) /*: WebpackStats */ {
try {

@@ -23,3 +23,3 @@ // $FlowFixMe

try {
return JSON.parse(cleanContent);
return JSON.parse(cleanContent) /* as WebpackStats */;
} catch (e) {

@@ -26,0 +26,0 @@ throw new Error(`Stats file "${statsFilePath}" is not a valid json...`);

@@ -7,3 +7,3 @@ /* @flow */

/*::
import type { Module, Reason, SubReason } from './analyze';
import type { Module, Reason, SubReason, Chunks } from './analyze';
*/

@@ -23,2 +23,5 @@

const isEntry = (reasons /*: Array<Reason>*/) =>
reasons.length === 1 && reasons[0].type === "entry";
const takeSubset = (array /*: Array<any> */, limit) =>

@@ -159,16 +162,65 @@ limit === 0 ? array : array.slice(0, limit);

const printFile = (module /*: Module */, limit, by) => {
const printSize = (size /*: number */, mod = false) => {
const sizeInKiB = Math.ceil(size / 1024);
const level =
sizeInKiB === 0
? "unknown"
: sizeInKiB > 20
? "red"
: sizeInKiB < 20 && sizeInKiB > 10 ? "yellow" : "default";
const sizeFormatted =
level === "unknown"
? chalk.dim("unknown")
: level === "default"
? sizeInKiB + " KiB"
: chalk[level](sizeInKiB + " KiB");
return `${chalk.magenta("size")}: ${sizeFormatted}${
mod ? chalk.dim(" [for all included files]") : ""
}`;
};
const printChunkInfo = (module /*: Module */, chunks /*: Chunks */) => {
return module.chunks.reduce((acc, chunkId) => {
const chunk = chunks[chunkId];
if (!chunk) return acc;
acc =
chunk.names && chunk.names.length
? acc.concat(chunk.names)
: acc.concat(chunk.id);
return acc;
}, []);
};
const printFile = (module /*: Module */, chunks, limit, by) => {
const chunksInfo = printChunkInfo(module, chunks);
const entry = isEntry(module.reasons);
return [
`${fileBadge()} ${chalk.green(module.name)}`,
`${fileBadge()} ${chalk.green(module.name)}${
entry ? " " + entryPointBadge() : ""
}`,
`├─ ${chalk.magenta("imported")}: ${printImportedCount(module.imported)}`,
`└─ ${chalk.magenta("reasons")}:`,
indent(printReasons(module.reasons, limit, by), " ").join("\n")
];
`├─ ${printSize(module.size)}`,
chunksInfo &&
chunksInfo.length &&
`${entry ? "└─" : "├─"} ${chalk.magenta("chunks")}: ${chunksInfo.join(
", "
)}`,
!entry && `└─ ${chalk.magenta("reasons")}:`,
!entry && indent(printReasons(module.reasons, limit, by), " ").join("\n")
].filter(msg => !!msg);
};
const printModule = (module /*: Module */, limit, by) => {
const printModule = (module /*: Module */, chunks, limit, by) => {
const chunksInfo = printChunkInfo(module, chunks);
const entry = isEntry(module.reasons);
return [
`${moduleBadge()} ${chalk.yellow(module.name)}`,
`${moduleBadge()} ${chalk.yellow(module.name)}${
entry ? " " + entryPointBadge() : ""
}`,
`├─ ${chalk.magenta("imported")}: ${printImportedCount(module.imported)}`,
`├─ ${printSize(module.size, true)}`,
printType(module, by, limit).join("\n"),
chunksInfo &&
chunksInfo.length &&
`├─ ${chalk.magenta("chunks")}: ${chunksInfo.join(", ")}`,
`├─ ${chalk.magenta("locations")}: ${

@@ -178,7 +230,7 @@ module.locations.length > 1 ? redBadge("multiple") : ""

indent(printLocations(module.locations)).join("\n"),
`├─ ${chalk.magenta("files")}: `,
`${entry ? "└─" : "├─"} ${chalk.magenta("files")}: `,
indent(printIncludedFiles(module.filesIncluded, limit)).join("\n"),
`└─ ${chalk.magenta("reasons")}:`,
indent(printReasons(module.reasons, limit, by), " ").join("\n")
];
!entry && `└─ ${chalk.magenta("reasons")}:`,
!entry && indent(printReasons(module.reasons, limit, by), " ").join("\n")
].filter(msg => !!msg);
};

@@ -188,2 +240,3 @@

report /*: Array<Module> */,
chunks /*: Chunks */,
flags /*: { by?: string } */,

@@ -199,3 +252,3 @@ limit /*: number */,

logger();
logger(printFile(module, limit, flags.by).join("\n"));
logger(printFile(module, chunks, limit, flags.by).join("\n"));
logger(chalk.dim("--------------------"));

@@ -205,3 +258,3 @@ logger();

logger();
logger(printModule(module, limit, flags.by).join("\n"));
logger(printModule(module, chunks, limit, flags.by).join("\n"));
logger(chalk.dim("--------------------"));

@@ -208,0 +261,0 @@ logger();

@@ -22,8 +22,27 @@ /* @flow */

!stats ||
((!stats.chunks || !stats.chunks[0].modules) && !stats.modules)
((!stats.chunks || !stats.chunks[0].modules) &&
!stats.modules &&
(!stats.children ||
((!stats.children[0].chunks || !stats.children[0].chunks[0].modules) &&
!stats.children[0].modules)))
) {
return false;
}
const samples = (stats.modules || stats.chunks[0].modules).slice(0, 10);
let modules = [];
if (stats.modules) {
modules = stats.modules;
} else if (stats.chunks) {
modules = stats.chunks[0].modules;
} else if (stats.children) {
if (stats.children[0].modules) {
modules = stats.children[0].modules;
} else if (stats.children[0].chunks) {
modules = stats.children[0].chunks[0].modules;
}
}
const samples = modules.slice(0, 10);
return samples.some(isValidModule);
};
{
"name": "whybundled",
"version": "1.1.0",
"version": "1.2.0",
"description": "Answers the question – Why the hell is this module in a bundle?",

@@ -5,0 +5,0 @@ "bin": "./cli.js",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc