Skip to content

Instantly share code, notes, and snippets.

@barelyhuman
Created October 30, 2022 13:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save barelyhuman/e829bee7e83be919927ac5c04d819623 to your computer and use it in GitHub Desktop.
Save barelyhuman/e829bee7e83be919927ac5c04d819623 to your computer and use it in GitHub Desktop.
Pure ESM version of sizesnap cli
import glob from 'tiny-glob'
import _xs from 'xstream'
import zlib from 'zlib'
import {promises as fs} from 'node:fs'
import _concat from 'xstream/extra/concat.js'
const xs = _xs.default
const concat = _concat.default
// contained exec of the streams
;(async function main() {
const snapper = createSnapper()
let files = []
let arg
let i = 2
while ((arg = process.argv[i])) {
try {
const res = await glob(arg)
files = files.concat(res)
} catch (err) {}
i += 1
}
const sizeCollection$ = []
files.forEach(file => sizeCollection$.push(size(file, snapper)))
concat(...sizeCollection$).addListener({
error: err => console.error(err),
complete: async () => {
snapper.write()
console.log('.sizesnap.json created!')
},
})
})()
// Generate a steam that generates the object with file's data
function size(file, snapper) {
return xs
.fromPromise(fs.readFile(file))
.map(buffer => ({
original: bytes.pretty(buffer.length),
gz: bytes.pretty(zlib.gzipSync(buffer, {level: 9}).length),
brotli: bytes.pretty(zlib.brotliCompressSync(buffer).length),
}))
.map(obj => {
snapper.add(file, obj)
return obj
})
}
function createSnapper() {
let snapObject = {}
return {
write: () => {
fs.writeFile('.sizesnap.json', JSON.stringify(snapObject, null, 2))
},
add: (file, snap) => (snapObject[file] = snap),
}
}
const sizeDefinitions = {
get b() {
return 1
},
get kb() {
return 1000 * this.b
},
get mb() {
return 1000 * this.kb
},
get gb() {
return 1000 * this.mb
},
get tb() {
return 1000 * this.gb
},
}
const byteRgx = /^([0-9]*[.]?[0-9]*)(b|kb|mb|gb|tb)$/i
const bytes = {
pretty(num) {
const entries = Object.entries(sizeDefinitions).sort((x, y) => y[1] - x[1])
for (const [k, s] of entries) {
if (num > s) return num / s + k.toUpperCase()
}
},
parse(toParse) {
if (!isNaN(toParse)) return Number(toParse)
if (!byteRgx.test(toParse))
throw new Error('Invalid `toParse` value provided to `parse`')
const [_, size, suffix] = byteRgx.exec(toParse)
return Number(size) * sizeDefinitions[suffix.toLowerCase()]
},
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment