Files
dynamic-badges-action/node_modules/char-width-table-consumer/src/consumer.js
Rúnar Berg a2d3829b14 Add save svg-badge directly to gist
This adds the posibility of saving an SVG badge generated by the same
shields.io dirictly to the gist. Instead of prepering a JSON file to
be sent to their service, we use their library directly, which outputs
an SVG file that we can save to the user’s gist.

Filenames ending in `.svg` will use this library automatically.

Additionally there is a major refactoring where the older `node:http`
library has been swapped out for `fetch`.

Also swap from node 16 to node 20

fixes #24
2023-10-05 08:29:45 -07:00

80 lines
2.2 KiB
JavaScript

'use strict'
const fs = require('fs')
const bs = require('binary-search')
const { promisify } = require('util')
const readFile = promisify(fs.readFile)
module.exports = class CharWidthTableConsumer {
constructor(data) {
this.data = data
this.emWidth = this.widthOf('m')
}
static create(data) {
return new CharWidthTableConsumer(data)
}
static async load(path) {
const json = await readFile(path)
const data = JSON.parse(json)
return new CharWidthTableConsumer(data)
}
static loadSync(path) {
const json = fs.readFileSync(path)
const data = JSON.parse(json)
return new CharWidthTableConsumer(data)
}
static isControlChar(charCode) {
return charCode <= 31 || charCode === 127
}
widthOfCharCode(charCode) {
if (this.constructor.isControlChar(charCode)) {
return 0.0
}
// https://github.com/darkskyapp/binary-search/pull/18
const index = bs(this.data, charCode, ([lower], needle) => lower - needle)
if (index >= 0) {
// The index matches the beginning of a range.
const [, , width] = this.data[index]
return width
} else {
// The index does not match the beginning of a range, which means it
// should be in the preceeding range A return value of `-x` means the
// needle would be at `x - 1`, and we want to check the element before
// that.
const candidateIndex = -index - 2
const [lower, upper, width] = this.data[candidateIndex]
if (charCode >= lower && charCode <= upper) {
return width
} else {
return undefined
}
}
}
widthOf(text, { guess = true } = {}) {
// Array.from() will split a string into an array of strings, each of
// which contains a single code point.
// https://stackoverflow.com/a/42596897/893113
return Array.from(text).reduce((accumWidth, char) => {
const charWidth = this.widthOfCharCode(char.codePointAt(0))
if (charWidth === undefined) {
if (guess) {
return accumWidth + this.emWidth
} else {
throw Error(
`No width available for character code ${char.codePointAt(0)}`
)
}
} else {
return accumWidth + charWidth
}
}, 0.0)
}
}