Jé pa l'temps #9 - Node.js hacks
🎲 Insert in an array at index
Array.prototype.insert = function (index, item) {
this.splice(index, 0, item);
};
🪓 Delete undefined and null properties from an object
Object.entries(a).reduce((a,[k,v]) => (v === null || v === undefined ? a : {...a, [k]:v}), {})
» Example
{
b: null,
c: undefined,
d: 1,
e: '1',
f: '',
};
// becomes
{
d: 1,
e: '1',
f: '',
};
🛠️ Sort keys of an object
function sortObject(obj) {
return Object.keys(obj).sort().reduce((result, key) => {
result[key] = obj[key];
return result;
}, {});
}
🎉 Get properties which change between two objects
function getObjectDiff(obj1, obj2) {
const diff = Object.keys(obj1).reduce((result, key) => {
if (!obj2.hasOwnProperty(key)) {
result.push(key);
} else if (_.isEqual(obj1[key], obj2[key])) {
const resultKeyIndex = result.indexOf(key);
result.splice(resultKeyIndex, 1);
}
return result;
}, Object.keys(obj2));
return diff;
}
💛 SQL request with templating
function sql(query, args) {
return {
query: query.join('?'),
args,
};
}
sql`SELECT * FROM users WHERE username = ${username}`;
💡 Show all express route
function print (path, layer) {
if (layer.route) {
layer.route.stack.forEach(print.bind(null, path.concat(split(layer.route.path))))
} else if (layer.name === 'router' && layer.handle.stack) {
layer.handle.stack.forEach(print.bind(null, path.concat(split(layer.regexp))))
} else if (layer.method) {
console.log('%s /%s',
layer.method.toUpperCase(),
path.concat(split(layer.regexp)).filter(Boolean).join('/'))
}
}
function split (thing) {
if (typeof thing === 'string') {
return thing.split('/')
} else if (thing.fast_slash) {
return ''
} else {
var match = thing.toString()
.replace('\\/?', '')
.replace('(?=\\/|$)', '$')
.match(/^\/\^((?:\\[.*+?^${}()|[\]\\\/]|[^.*+?^${}()|[\]\\\/])*)\$\//)
return match
? match[1].replace(/\\(.)/g, '$1').split('/')
: '<complex:' + thing.toString() + '>'
}
}
app._router.stack.forEach(print.bind(null, []))
⑹ Reduce error stack trace size
Error.stackTraceLimit = 6; // Set the size you want
👉 Use coverage with mocha watch
nodemon --exec nyc --reporter=lcov --reporter=text mocha
📕 Merge two pdfs together
const hummus = require("hummus");
const memoryStreams = require("memory-streams");
/**
* Concatenate two PDFs in Buffers
* @param {Buffer} firstBuffer
* @param {Buffer} secondBuffer
* @returns {Buffer} - a Buffer containing the concactenated PDFs
*/
export const combinePDFBuffers = (firstBuffer: any, secondBuffer: any) => {
var outStream = new memoryStreams.WritableStream();
try {
var firstPDFStream = new hummus.PDFRStreamForBuffer(firstBuffer);
var secondPDFStream = new hummus.PDFRStreamForBuffer(secondBuffer);
var pdfWriter = hummus.createWriterToModify(
firstPDFStream,
new hummus.PDFStreamForResponse(outStream)
);
pdfWriter.appendPDFPagesFromPDF(secondPDFStream);
pdfWriter.end();
var newBuffer = outStream.toBuffer();
outStream.end();
return newBuffer;
} catch (e) {
outStream.end();
throw new Error(`Error during PDF combination: ${e.message}`);
}
};
🪡 Parallel requester
const EventEmitter = require('events');
class ParallelRequester extends EventEmitter {
constructor({ maxRequests = 4, delay = 0 } = {}) {
super();
this.maxRequests = maxRequests;
this.delay = delay;
this.queue = [];
this.results = [];
this.executingRequests = 0;
this._endRequest = this._endRequest.bind(this);
this._executeNext = this._executeNext.bind(this);
this.on('execute', this._executeNext);
}
add(req) {
if (Array.isArray(req)) {
this.queue.push(...req);
} else {
this.queue.push(req);
}
return this;
}
start() {
if (this.executingRequests < this.maxRequests) {
this.emit('execute');
}
return this;
}
end() {
if (!this.executingRequests && !this.queue.length) {
return [];
}
return new Promise((resolve) => {
this.on('end', () => {
resolve(this.results);
});
});
}
_endRequest() {
this.executingRequests--;
if (this.executingRequests < this.maxRequests && this.queue.length) {
setTimeout(() => {
this.emit('execute');
}, this.delay);
}
if (!this.executingRequests && !this.queue.length) {
this.emit('end');
}
}
_executeNext() {
// console.log('Executing request - ', this.executingRequests, ' currently');
while (this.executingRequests < this.maxRequests && this.queue.length) {
this.executingRequests++;
const request = this.queue.shift();
Promise.resolve(request())
.then((data) => {
this.results.push(data);
this._endRequest();
})
.catch(() => {
this.results.push([]);
this._endRequest();
});
}
}
}
module.exports = {
ParallelRequester,
};
— — — — — — — — — — — — — — — — — — — — — —
La série « Jé pa l’temps » est une série de tutoriels rapides en mode “prise de note” pour avoir une trace de tout ce dont je ne peux me rappeler et pourquoi pas le partager à d’autre. On va à l’essentiel, laissons les jolis pavés à d’autres sites comme medium… LOL !