Homelab, Linux, JS & ABAP (~˘▾˘)~
 

[JavaScript] ES2023 Array methods

With ES2023 there are some new Array methods that always return a copy of the original array: toReversed, toSorted, toSpliced, with

const people = [
 { name: "Max", age: 19 },
 { name: "Tom", age: 65 },
 { name: "Liz", age: 43 },
]

// Copying counterpart of the reverse() method
const reversedPeople = people.toReversed()
// [{age: 43, name: "Liz"}, {age: 65, name: "Tom"}, {age: 19, name: "Max"}]

// Copying version of the sort()
const sortedPeople = people.toSorted((a,b) => a.age - b.age)
// [{age: 19, name: "Max"}, {age: 43, name: "Liz"}, {age: 65, name: "Tom"}]

// Copying version of the splice() method
const splicedPeople = people.toSpliced(1,1)
// [{age: 19, name: "Max"}, {age: 43, name: "Liz"}]

// Copying version of using the bracket notation to change the value of a given index
const updatedPeople = people.with(0, { name: "Pat", age: 12})
// [{age: 12, name: "Pat"}, {age: 65, name: "Tom"}, {age: 43, name: "Liz"}]

[JavaScript] Working with Promises in 2024

Since ES2024 there is a new way to create promises by using the withResolver function:

// ES 6 Via Constructor
const promise = new Promise((resolve, reject) => { }

// ES2024 Via factory function
const [promise, resolve, reject] = Promise.withResolver( )

Since ES2018 there is an additional handler called finally:

const promise = fetch("/myAPI")

promise
  .then(response => console.log(response))
  .catch(error => console.error(error))
  .finally(() => console.log("Called in any case"))

And handling multiple Promises has been made easier by the new methods allSettled, any, race which were introduced in ES2020 and ES2015:

// Promise that resolves when all promises are resolved
const promise = Promise.all([promiseA, promiseB])
promise.then(([valueA, valueB]) => console.log(valueA, valueB))

// ES2020 Promise that resolves when all promises are settled (either resolved or rejected)
const promise = Promise.allSettled([promiseA, promiseB])

// ES2020 Promise that resolves when either promiseA or promiseB is resolved
const promise = Promise.any([promiseA, promiseB])

// ES2015 Promise that resolves/rejects when any promise is resolved or rejected
const promise = Promise.race([promiseA, promiseB])

[JavaScript] Regex to check if string only contains the newline escape sequence \n

This is the first time ChatGPT actually helped me to solve a problem. So far the answers have not been so helpful with coding problems, but it seems to work very well with regex. I asked it to create me a regex pattern that checks if a string contains only the newline escape sequence \n and the answer was correct.

const test1 = '\n' //true
const test2 = '\n\n\n\n' //true
const test3 = 'test \n test' //false
const test4 = 'abcdefghij' //false
const test5 = ' ' //false

const myRegex = /^(?:\n)+$/

console.log('test1: ' + myRegex.test(test1))
console.log('test2: ' + myRegex.test(test2))
console.log('test3: ' + myRegex.test(test3))
console.log('test4: ' + myRegex.test(test4))
console.log('test5: ' + myRegex.test(test5))

[nodejs] Extract first page of a PDF using pdf-lib

const { PDFDocument } = require('pdf-lib')

// file = { fileName: 'test1.pdf, content: arraybuffer }     

const originalPdf = await PDFDocument.load(file.content, { ignoreEncryption: true })
const newPdf = await PDFDocument.create()
const [firstPage] = await newPdf.copyPages(originalPdf, [0]) // <-- 0 is the first page
newPdf.addPage(firstPage)
const firstPagePdf = await newPdf.save()

file.content = Buffer.from(firstPagePdf)

[JavaScript] Check if iterator is undefined when using a for…of loop

Just saw this trick, how you can do a for…of loop which also checks if the iterator is null or undefined. Normally, you would check this by another if statement before starting the for..of loop, like here

const d = undefined

if (d) { 
  for (const x of d ) {
  	console.log(x)
  }
} 

or by using a try...catch

try {
  for (const x of d) {
    console.log(value)
  }
} catch (e) {
  console.error(e) // TypeError: undefined is not iterable
}

But instead of if or try...catch, you could use d || [], to check if d is Falsy, and if it’s false, no iterations are performed and no errors are thrown. The disadvantage of this approach is that you create an unneeded array and the readability may be poor depending on the situation.

for (const x of d || []) {
	console.log(x)
}

Of course, the first and the last snippet can also be done in one line

if (d) for (const x of d ) console.log(x) 

for (const x of d || []) console.log(x)

[nodejs] Merge PDFs using pdf-lib

https://github.com/Hopding/pdf-lib

const { PDFDocument } = require('pdf-lib')

// files = [{ fileName: 'test1.pdf, content: arraybuffer },{ fileName: 'test2.pdf, content: arraybuffer }]

mergePdfs: async function (files) {
        try {
            const mergedPdf = await PDFDocument.create()

            for (let file of files) {
                const pdf = await PDFDocument.load(file.content)
                const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices())
                copiedPages.forEach((page) => mergedPdf.addPage(page))
            }

            const mergedPdfFile = await mergedPdf.save()
            const buffer = Buffer.from(mergedPdfFile)
            return await buffer.toString('base64') // return as buffer or base64 encoded file
        } catch (err) {
            console.error(err.message)
        }
}

[PDF.js] Get PDF Viewer when it’s available in DOM and fully initialized

https://github.com/mozilla/pdf.js/wiki/Third-party-viewer-usage

<iframe id="pdf-js-viewer" src="/pdf/web/viewer.html?file=" title="webviewer" frameborder="0" width="100%" height="700" allowfullscreen="" webkitallowfullscreen=""/>
            displayPdf: async function (id) { 
                const pdfArrayBuffer= await getPdf(id)
                const pdfViewerIFrame = await getPdfViewer()
                await pdfViewerIFrame.contentWindow.PDFViewerApplication.initializedPromise
                await pdfViewerIFrame.contentWindow.PDFViewerApplication.open(pdfArrayBuffer)
            },

            getPdfViewer: function (id = 'pdf-js-viewer') {
                return new Promise((resolve, reject) => {
                    let pdfViewerIFrame = document.getElementById(id)
                    //if already loaded in DOM, return it
                    if (pdfViewerIFrame?.contentWindow?.PDFViewerApplication) {
                        resolve(pdfViewerIFrame)
                    } else {
                        //if not loaded yet, set up eventListener
                        document.addEventListener("webviewerloaded", async () => {
                            pdfViewerIFrame = document.getElementById(id)
                            resolve(pdfViewerIFrame)
                        })
                    }
                })
            }

This logic helped me to get the PDFViewerApplication in every situation correctly, for example when reloading the page with F5 or when having the PDF viewer already loaded and just wanting to open another PDF file.