189 lines
4.6 KiB
JavaScript
189 lines
4.6 KiB
JavaScript
const fs = require('fs')
|
|
const child_process = require('child_process')
|
|
|
|
global.stdin = () => {
|
|
const out = fs.readFileSync(0).toString()
|
|
return out.tryParseJSON()
|
|
}
|
|
|
|
Object.prototype.map = function(cb) {
|
|
return cb(this)
|
|
}
|
|
|
|
Object.prototype.apply = Object.prototype.map
|
|
|
|
String.prototype.lines = function() {
|
|
let res = this.split("\n")
|
|
return res.at(-1) === '' ? res.slice(0, -1) : res
|
|
}
|
|
|
|
String.prototype.reverse = function() {
|
|
return this.split('').reverse().join('')
|
|
}
|
|
|
|
String.prototype.includesAny = function(strings) {
|
|
if (!(strings instanceof Array)) throw new TypeError('strings must be an Array')
|
|
return strings.some(x => this.includes(x))
|
|
}
|
|
|
|
String.prototype.tryParseJSON = function() {
|
|
const str = this.trim()
|
|
if (
|
|
(str.at(0) === '{' && str.at(-1) === '}') ||
|
|
(str.at(0) === '[' && str.at(-1) === ']')
|
|
) {
|
|
try {
|
|
return JSON.parse(str)
|
|
} catch (err) {
|
|
return this.toString()
|
|
}
|
|
}
|
|
|
|
return this.toString()
|
|
}
|
|
|
|
Buffer.prototype.tryParseJSON = function() {
|
|
const out = this.toString().tryParseJSON()
|
|
if (typeof out === 'string') {
|
|
return this
|
|
} else {
|
|
return out
|
|
}
|
|
}
|
|
|
|
global.exec = (command, args, options) => {
|
|
const res = child_process.spawnSync(command, args, options)
|
|
res.stdout = res.stdout?.tryParseJSON()
|
|
res.stderr = res.stderr?.tryParseJSON()
|
|
res.orFail = function() {
|
|
if (res.status !== 0) {
|
|
const cmd = [
|
|
command,
|
|
...((args && Array.isArray(args)) ? args : [])
|
|
].join(' ')
|
|
throw new Error(`command '${cmd}' exited with code ${res.status}`)
|
|
}
|
|
}
|
|
return res
|
|
}
|
|
|
|
global.execnc = (command, args, options) => {
|
|
if (!options) options = {}
|
|
if (!options.stdio) options.stdio = 'inherit'
|
|
return exec(command, args, options)
|
|
}
|
|
|
|
/* wow it's almost like it's my own package and i can include whatever garbage i want :) */
|
|
/* not writing a test for that tho */
|
|
global.apkindex = input => {
|
|
if (!input) input = stdin()
|
|
|
|
return input
|
|
.split("\n\n")
|
|
.filter(str => str.length)
|
|
.map(x => Object.fromEntries(x.lines().map(e => [e.at(0), e.slice(2)])))
|
|
.map(pkg => ({
|
|
...pkg,
|
|
S: Number(pkg.S),
|
|
I: Number(pkg.I),
|
|
t: new Date(Number(pkg.t) * 1000),
|
|
i: pkg.i?.split(' '),
|
|
D: pkg.D?.split(' '),
|
|
p: pkg.p?.split(' ')
|
|
}))
|
|
.map(Object.prune)
|
|
}
|
|
|
|
Array.prototype.sum = function(def = 0) {
|
|
return this.reduce((a, b) => a + b, def)
|
|
}
|
|
|
|
Array.prototype.product = function(def = 1) {
|
|
return this.reduce((a, b) => a * b, def)
|
|
}
|
|
|
|
Array.prototype.sortNum = function(getter = (x => x)) {
|
|
return this.sort((a, b) => getter(a) - getter(b))
|
|
}
|
|
|
|
Array.prototype.partition = function(compareFn) {
|
|
const a = []
|
|
const b = []
|
|
this.forEach((elem, i, arr) => {
|
|
if (compareFn(elem, i, arr)) {
|
|
a.push(elem)
|
|
} else {
|
|
b.push(elem)
|
|
}
|
|
})
|
|
return [a, b]
|
|
}
|
|
|
|
Array.prototype.chunks = function(chunkSize) {
|
|
// inspired by https://stackoverflow.com/questions/8495687/split-array-into-chunks#comment84212474_8495740
|
|
return new Array(Math.ceil(this.length / chunkSize))
|
|
.fill()
|
|
.map((_, i) => this.slice(i * chunkSize, (i + 1) * chunkSize))
|
|
}
|
|
|
|
Array.prototype.transpose = function() {
|
|
return new Array(this[0].length).fill().map((_, i) => this.map(x => x[i]))
|
|
}
|
|
|
|
Array.prototype.shuffle = function() {
|
|
// borrowed from https://stackoverflow.com/a/12646864
|
|
for (let i = this.length - 1; i > 0; i--) {
|
|
const j = Math.floor(Math.random() * (i + 1));
|
|
[this[i], this[j]] = [this[j], this[i]];
|
|
}
|
|
}
|
|
|
|
Set.prototype.union = function(other) {
|
|
if (!other || !(other instanceof Set)) throw new TypeError('other must be a Set')
|
|
return new Set([...this, ...other])
|
|
}
|
|
|
|
Set.prototype.intersection = function(other) {
|
|
if (!other || !(other instanceof Set)) throw new TypeError('other must be a Set')
|
|
return new Set([...this].filter(el => other.has(el)))
|
|
}
|
|
|
|
Set.prototype.difference = function(other) {
|
|
if (!other || !(other instanceof Set)) throw new TypeError('other must be a Set')
|
|
return new Set([...this].filter(el => !other.has(el)))
|
|
}
|
|
|
|
Set.prototype.at = function(index) {
|
|
return [...this].at(index)
|
|
}
|
|
|
|
global.matrix = function(x, y, elem) {
|
|
return new Array(y).fill().map(() => new Array(x).fill().map((_, i) => {
|
|
if (typeof elem === 'function') {
|
|
return elem(i)
|
|
} else {
|
|
return elem
|
|
}
|
|
}))
|
|
}
|
|
|
|
Number.prototype.toXY = function(width) {
|
|
if (!(width && typeof width === 'number')) throw new TypeError('width must be a Number')
|
|
return [ this % width, Math.floor(this / width) ]
|
|
}
|
|
|
|
global.sed = function(filename, cb) {
|
|
let content = fs.readFileSync(filename, 'utf-8')
|
|
content = cb(content)
|
|
fs.writeFileSync(filename, content, 'utf-8')
|
|
}
|
|
|
|
Object.prune = function(obj) {
|
|
if (typeof obj !== 'object') throw new TypeError('obj must be an object')
|
|
for (let key of Object.keys(obj)) {
|
|
if (obj[key] === undefined) {
|
|
delete obj[key]
|
|
}
|
|
}
|
|
return obj
|
|
}
|