rehype-all-the-thumbs-curate
Version:
Supporting rehype-all-the-thumbs by finding elements to be processed
119 lines (118 loc) • 4.67 kB
JavaScript
import {extname, basename, dirname} from "path";
import {createHash} from "crypto";
import {selectAll} from "hast-util-select";
const {isArray} = Array;
export const pathJoin = (...paths) => {
const pathsNoSlashes = paths.map((c, i, a) => {
c = c.startsWith("./") ? c.slice(2) : c;
c = c.startsWith("/") ? c.slice(1) : c;
c = c.endsWith("/") ? c.slice(0, -1) : c;
return c;
});
return pathsNoSlashes.reduce((p, c) => {
if (c === "" || c === " ") {
return p;
}
return c.startsWith("..") ? pathJoin(...[...p.slice(0, -1), c.slice(2)]).split("/") : [...p, c];
}, []).join("/");
};
const trimmedHash = (n) => (b) => createHash("sha256").update(b).digest("hex").slice(0, n);
const merge = (paths, fallback, obj) => Object.entries(paths).reduce((acc, [prop, prepFn]) => prop in obj ? prepFn(acc, obj[prop]) : prop in fallback ? {...acc, [prop]: fallback[prop]} : acc, {});
const parseStringsAndSwapPath = (readPath, writePath) => ({[readPath]: (a, s) => ({...a, [writePath]: JSON.parse(s)})});
const noChangeJustSwapPath = (readPath, writePath) => ({[readPath]: (a, s) => ({...a, [writePath]: s})});
const noChange = (spath) => ({[spath]: (a, s) => ({...a, [spath]: s})});
const parseIfString = (spath) => ({
[spath]: (a, maybeS) => ({...a, [spath]: maybeS})
});
const HASTpaths = {
...noChange("selectedBy"),
...noChangeJustSwapPath("dataSourceprefix", "sourcePrefix"),
...noChangeJustSwapPath("dataDestbasepath", "destBasePath"),
...noChangeJustSwapPath("dataPathTmpl", "pathTmpl"),
...parseStringsAndSwapPath("dataHashlen", "hashlen"),
...parseStringsAndSwapPath("dataClean", "clean"),
...parseStringsAndSwapPath("dataWidths", "widths"),
...parseStringsAndSwapPath("dataWidthratio", "widthratio"),
...parseStringsAndSwapPath("dataBreaks", "breaks"),
...{dataAddclassnames: (a, sa) => ({...a, addclassnames: sa.split(" ")})},
...{dataTypes: (a, s) => ({...a, types: s.split(",").reduce((p, c) => ({...p, [c]: {}}), {})})}
};
const NORMpaths = {
...noChange("selectedBy"),
...noChange("sourcePrefix"),
...noChange("destBasePath"),
...noChange("filepathPrefix"),
...noChange("pathTmpl"),
...noChange("hashlen"),
...noChange("clean"),
...noChange("addclassnames"),
...parseIfString("widths"),
...parseIfString("widthatio"),
...parseIfString("breaks"),
...parseIfString("types")
};
const mergeNode = (fallback, ob) => merge(HASTpaths, fallback, ob.properties);
const mergeConfig = (fallback, ob = {}) => merge(NORMpaths, fallback, ob);
export const attacher = (config) => {
const select = !config || !config.select ? 'picture[thumbnails="true"]>img' : typeof config.select === "function" ? config.select() : config.select;
const defaults = {
selectedBy: select,
sourcePrefix: "/",
destBasePath: "/",
hashlen: 8,
clean: true,
types: {webp: {}, jpg: {}},
breaks: [640, 980, 1020],
widths: [100, 250, 450, 600],
addclassnames: ["all-thumbed"],
widthratio: 1.7778,
pathTmpl: "/optim/{{filename}}-{{width}}w-{{hash}}.{{ext}}"
};
const cfg = mergeConfig(defaults, config);
return (tree, vfile, next) => {
const selected = selectAll(select, tree);
const srcsCompact = selected.map((node) => ({node, src: node.properties.src})).map(({src, node}) => ({
src,
...mergeConfig(cfg, mergeNode(cfg, node))
}));
const srcs = srcsCompact.reduce((p, _s) => {
const s = _s;
const partOfSet = {
breaks: s.breaks,
types: s.types,
widths: s.widths
};
Object.entries(s.types).forEach(([format, opts]) => {
s.widths.forEach((width) => {
var _a, _b;
let ext = extname(s.src).slice(1);
ext = ext === "" ? "Buffer" : ext;
s.data = {...s.data, _id: s.src};
p.push({
selectedBy: s.selectedBy,
addclassnames: s.addclassnames,
input: {
ext,
fileName: basename(s.src, `.${ext}`),
filepathPrefix: dirname(s.src),
rawFilePath: s.src
},
output: {
width,
format: {[format]: opts},
pathTmpl: (_b = (_a = s.pathTmpl) != null ? _a : cfg.pathTmpl) != null ? _b : defaults.pathTmpl,
hash: trimmedHash(s.hashlen),
...(s == null ? void 0 : s.widthRatio) ? {widthRatio: s.widthRatio} : {}
},
partOfSet
});
});
});
return p;
}, []);
const vfile_srcs = isArray(vfile.srcs) ? [...vfile.srcs, ...srcs] : srcs;
vfile.srcs = vfile_srcs;
next(null, tree, vfile);
};
};
export default attacher;