UNPKG

rehype-all-the-thumbs-curate

Version:

Supporting rehype-all-the-thumbs by finding elements to be processed

119 lines (118 loc) 4.67 kB
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;