Skip to content

Commit

Permalink
feat: 馃幐 add package info to reporting
Browse files Browse the repository at this point in the history
BREAKING CHANGE: 馃Ж Change option --json to --pretty. --json option returns JSON.stringify
result.
  • Loading branch information
mjancarik committed May 28, 2022
1 parent 6945f32 commit 0421305
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 57 deletions.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -62,6 +62,7 @@
"easy-uid": "^2.0.2",
"execa": "^6.1.0",
"fs-extra": "^10.1.0",
"got": "^12.1.0",
"mini-css-extract-plugin": "^2.6.0",
"ora": "^6.1.0",
"postcss-loader": "^6.2.1",
Expand Down
50 changes: 26 additions & 24 deletions src/__tests__/createResultSpec.mjs
Expand Up @@ -16,35 +16,37 @@ beforeAll(async () => {

describe('createResult', () => {
it('should generate result object', async () => {
const result = await module.createResult({ TMP: 'folder' });
const result = await module.createBundleResult({ TMP: 'folder' });

expect(result).toMatchInlineSnapshot(`
Object {
"brotli": Object {
"size": 33,
"speed": Object {
"2g": 2.75,
"3g": 0.66,
"4g": 0.037714285714285714,
"5g": 0.014666666666666666,
"bundle": Object {
"brotli": Object {
"size": 33,
"speed": Object {
"2g": 2.75,
"3g": 0.66,
"4g": 0.037714285714285714,
"5g": 0.014666666666666666,
},
},
},
"gzip": Object {
"size": 122,
"speed": Object {
"2g": 10.166666666666666,
"3g": 2.44,
"4g": 0.13942857142857143,
"5g": 0.05422222222222222,
"gzip": Object {
"size": 122,
"speed": Object {
"2g": 10.166666666666666,
"3g": 2.44,
"4g": 0.13942857142857143,
"5g": 0.05422222222222222,
},
},
},
"minify": Object {
"size": 26000,
"speed": Object {
"2g": 2166.6666666666665,
"3g": 520,
"4g": 29.714285714285715,
"5g": 11.555555555555555,
"minify": Object {
"size": 26000,
"speed": Object {
"2g": 2166.6666666666665,
"3g": 520,
"4g": 29.714285714285715,
"5g": 11.555555555555555,
},
},
},
}
Expand Down
54 changes: 52 additions & 2 deletions src/__tests__/formatSpec.mjs
@@ -1,5 +1,5 @@
import '@jest/globals';
import { formatSize, formatTime } from '../format';
import { formatSize, formatTime, formatNumber, formatDate } from '../format';

describe('format', () => {
describe('formatTime', () => {
Expand All @@ -24,7 +24,7 @@ describe('format', () => {
});
});

describe('formatsize', () => {
describe('formatSize', () => {
it('should return 0 Byte', () => {
expect(formatSize(0)).toEqual('0 Byte');
});
Expand All @@ -45,4 +45,54 @@ describe('format', () => {
expect(formatSize(1024 * 1024)).toEqual('1 MB');
});
});

describe('formatNumber', () => {
it('should return 0', () => {
expect(formatNumber(0)).toEqual('0');
});

it('should return 500', () => {
expect(formatNumber(500)).toEqual('500');
});

it('should return 1K', () => {
expect(formatNumber(1000)).toEqual('1K');
});

it('should return 1.5 M', () => {
expect(formatNumber(1500000)).toEqual('1.5M');
});
});

describe('formatDate', () => {
it('should return 2022-04-01', () => {
expect(formatDate(new Date('2022-04-01T09:29:40.128Z'))).toEqual(
'2022-4-1'
);
});

it('should return 0 seconds ago', () => {
expect(formatDate(new Date())).toEqual('0 seconds ago');
});

it('should return 5 seconds ago', () => {
expect(formatDate(new Date(Date.now() - 5000))).toEqual('5 seconds ago');
});

it('should return 1 minutes ago', () => {
expect(formatDate(new Date(Date.now() - 60000))).toEqual('1 minutes ago');
});

it('should return 1 hours ago', () => {
expect(formatDate(new Date(Date.now() - 60 * 60000))).toEqual(
'1 hours ago'
);
});

it('should return 1 days ago', () => {
expect(formatDate(new Date(Date.now() - 24 * 60 * 60000))).toEqual(
'1 days ago'
);
});
});
});
11 changes: 11 additions & 0 deletions src/constant.mjs
Expand Up @@ -4,3 +4,14 @@ export const SPEED = {
['4g']: 875,
['5g']: 2250,
};

export const API = {
NPM_DOWNLOADS: 'https://api.npmjs.org/downloads/point',
REGISTRY_PACKAGE_INFO: 'https://registry.npmjs.org',
};

export const PERIOD = {
LAST_DAY: 'last-day',
LAST_WEEK: 'last-week',
LAST_MONTH: 'last-month',
};
79 changes: 64 additions & 15 deletions src/createResult.mjs
Expand Up @@ -2,10 +2,11 @@ import zlib from 'node:zlib';
import { promisify } from 'node:util';

import fs from 'fs-extra';
import got from 'got';

import { SPEED } from './constant.mjs';
import { SPEED, API, PERIOD } from './constant.mjs';

export async function createResult({ TMP }) {
export async function createBundleResult({ TMP }) {
const file = await fs.readFile(`${TMP}/blank.bundle.js`);
const gzipFile = await promisify(zlib.gzip)(file, { level: 9 });
const brotliFile = await promisify(zlib.brotliCompress)(file, {
Expand All @@ -14,25 +15,73 @@ export async function createResult({ TMP }) {
});

const result = {
minify: {
size: file.toString().length,
speed: {},
},
gzip: {
size: gzipFile.toString().length,
speed: {},
},
brotli: {
size: brotliFile.toString().length,
speed: {},
bundle: {
minify: {
size: file.toString().length,
speed: {},
},
gzip: {
size: gzipFile.toString().length,
speed: {},
},
brotli: {
size: brotliFile.toString().length,
speed: {},
},
},
};

Object.keys(result).forEach((type) => {
Object.keys(result.bundle).forEach((type) => {
Object.keys(SPEED).forEach((wifi) => {
result[type].speed[wifi] = result[type].size / SPEED[wifi];
result.bundle[type].speed[wifi] = result.bundle[type].size / SPEED[wifi];
});
});

return result;
}

export async function createDownloadsResult({ packages, result }) {
for (let packageName of packages) {
const [day, week, month] = await Promise.all(
Object.keys(PERIOD).map((key) => {
return got
.get(`${API.NPM_DOWNLOADS}/${PERIOD[key]}/${packageName}`)
.json();
})
);

result[packageName] = {
...result[packageName],
downloads: {
day: day.downloads,
week: week.downloads,
month: month.downloads,
},
};
}

return result;
}

export async function createPackageInfo({ packages, result, options }) {
for (let packageName of packages) {
const packageInfo = await got
.get(`${options.registry ?? API.REGISTRY_PACKAGE_INFO}/${packageName}`)
.json();

result[packageName] = {
...result[packageName],
info: {
license: packageInfo.license,
created: new Date(packageInfo.time.created),
updated: new Date(packageInfo.time.modified),
version: packageInfo['dist-tags'].latest,
unpackedSize:
packageInfo.versions[packageInfo['dist-tags'].latest]?.dist
?.unpackedSize,
},
};
}

return result;
}
40 changes: 40 additions & 0 deletions src/format.mjs
@@ -1,3 +1,43 @@
export function formatNumber(number) {
const sizes = ['', 'K', 'M', 'G', 'T'];

if (number == 0) {
return '0';
}

const index = parseInt(Math.floor(Math.log(number) / Math.log(1000)));

return (
Math.round((number / Math.pow(1000, index) + Number.EPSILON) * 100) / 100 +
sizes[index]
);
}

export function formatDate(date) {
const seconds = Math.floor((new Date() - date) / 1000);

let interval = seconds / 2592000;

if (interval >= 1) {
return `${date.getUTCFullYear()}-${
date.getUTCMonth() + 1
}-${date.getUTCDate()}`;
}
interval = seconds / 86400;
if (interval >= 1) {
return Math.floor(interval) + ' days ago';
}
interval = seconds / 3600;
if (interval >= 1) {
return Math.floor(interval) + ' hours ago';
}
interval = seconds / 60;
if (interval >= 1) {
return Math.floor(interval) + ' minutes ago';
}
return Math.floor(seconds) + ' seconds ago';
}

export function formatSize(bytes) {
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];

Expand Down
36 changes: 30 additions & 6 deletions src/index.mjs
@@ -1,17 +1,26 @@
import path from 'node:path';
import util from 'node:util';

import ora from 'ora';
import fs from 'fs-extra';
import { Command } from 'commander';

import { renderSizeTable, renderTimeTable } from './reporter.mjs';
import {
renderPackageInfo,
renderSizeTable,
renderTimeTable,
} from './reporter.mjs';
import { bundle, getExternals } from './webpack.mjs';
import {
createEmptyModule,
createIndex,
installDependencies,
} from './createModule.mjs';
import { createResult } from './createResult.mjs';
import {
createBundleResult,
createDownloadsResult,
createPackageInfo,
} from './createResult.mjs';

const dir = path.resolve('./');
let packageJson = null;
Expand All @@ -33,6 +42,7 @@ program
.option('--external', 'external dependencies to webpack config')
.option('--explain', 'log webpack stats')
.option('--json', 'log only json format')
.option('--pretty', 'log only pretty print object')
.option(
'--bundle',
'bundle all dependencies with external dependencies and tree shaking'
Expand Down Expand Up @@ -66,15 +76,29 @@ program.parse(process.argv);
);
}

const result = await createResult({ TMP });
let result = await createBundleResult({ TMP });

await fs.remove(TMP);

await (!options.json && renderSizeTable({ result, packages }));
await (!options.json && renderTimeTable({ result }));
result = await createDownloadsResult({ result, packages });
result = await createPackageInfo({ result, packages, options });

await (!options.json &&
!options.pretty &&
renderSizeTable({ result, packages }));
await (!options.json && !options.pretty && renderTimeTable({ result }));
await (!options.json &&
!options.pretty &&
renderPackageInfo({ result, packages }));

if (options.json) {
console.log(result);
console.log(JSON.stringify(result));
}

if (options.pretty) {
console.log(
util.inspect(result, { showHidden: false, depth: null, colors: true })
);
}
} catch (error) {
console.error(error);
Expand Down

0 comments on commit 0421305

Please sign in to comment.