1
0

interesting: turns out we don't actually need pandoc

This commit is contained in:
Nicola Clark 2024-11-24 00:53:07 -06:00
parent a90b3c888e
commit 0811f1c396
Signed by: nicola
GPG Key ID: 3E1710E7FF08956C
6 changed files with 356 additions and 54 deletions

View File

@ -6,11 +6,6 @@ RUN npm install && npm run build
FROM node:22.11.0-bookworm-slim AS runner FROM node:22.11.0-bookworm-slim AS runner
LABEL maintainer="Nicola Clark <nicola@slottedspoon.dev>" LABEL maintainer="Nicola Clark <nicola@slottedspoon.dev>"
EXPOSE 3000 EXPOSE 3000
ENV LANG=C.UTF-8
RUN apt-get update && \
apt-get install -y pandoc texlive && \
rm -rf /var/lib/apt/lists/*
RUN useradd -u 9999 pdoc
WORKDIR /app WORKDIR /app
COPY package.json package-lock.json ./ COPY package.json package-lock.json ./
COPY --from=builder /app/build ./build COPY --from=builder /app/build ./build

328
package-lock.json generated
View File

@ -8,6 +8,8 @@
"name": "resumarkdown", "name": "resumarkdown",
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"hast": "^0.0.2",
"hastscript": "^9.0.0",
"iconify-icon": "^2.1.0", "iconify-icon": "^2.1.0",
"rehype-document": "^7.0.3", "rehype-document": "^7.0.3",
"rehype-sanitize": "^6.0.0", "rehype-sanitize": "^6.0.0",
@ -1218,6 +1220,15 @@
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/attach-ware": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/attach-ware/-/attach-ware-1.1.1.tgz",
"integrity": "sha512-OpavlXWZkyE7m28fpCWF/RmxCukC1edukJp9IKjEpZs/O11H3896DkLpK7lMiL8ZDx2yxo9FrZQaeHkyJGcIuQ==",
"license": "MIT",
"dependencies": {
"unherit": "^1.0.0"
}
},
"node_modules/axobject-query": { "node_modules/axobject-query": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
@ -1248,6 +1259,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/camelcase": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
"integrity": "sha512-wzLkDa4K/mzI1OSITC+DUyjgIl/ETNHE9QvYgy6J6Jvqyyz4C0Xfd+lQhb19sX2jMpZV4IssUn0VDVmglV+s4g==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/ccount": { "node_modules/ccount": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz",
@ -1331,6 +1351,12 @@
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
} }
}, },
"node_modules/co": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz",
"integrity": "sha512-CQsjCRiNObI8AtTsNIBDRMQ4oMR83CzEswHYahClvul7gKk+lDQiOKv+5qh7LQWf5sh6jkZNispz/QlsZxyNgA==",
"license": "MIT"
},
"node_modules/comma-separated-tokens": { "node_modules/comma-separated-tokens": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
@ -1450,6 +1476,80 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
"integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
"license": "MIT",
"dependencies": {
"domelementtype": "^2.0.1",
"entities": "^2.0.0"
}
},
"node_modules/dom-serializer/node_modules/domelementtype": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause"
},
"node_modules/dom-serializer/node_modules/entities": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
"license": "BSD-2-Clause",
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"license": "BSD-2-Clause",
"dependencies": {
"domelementtype": "1"
}
},
"node_modules/domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"license": "BSD-2-Clause",
"dependencies": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"node_modules/ent": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ent/-/ent-2.2.1.tgz",
"integrity": "sha512-QHuXVeZx9d+tIQAz/XztU0ZwZf2Agg9CcXcgE1rurqvdBeDBrpSwjl8/6XUqMg7tw2Y7uAdKb2sRv+bSEFqQ5A==",
"license": "MIT",
"dependencies": {
"punycode": "^1.4.1"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"license": "BSD-2-Clause"
},
"node_modules/errno": { "node_modules/errno": {
"version": "0.1.8", "version": "0.1.8",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
@ -1503,6 +1603,12 @@
"@esbuild/win32-x64": "0.21.5" "@esbuild/win32-x64": "0.21.5"
} }
}, },
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/esm-env": { "node_modules/esm-env": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz",
@ -1612,6 +1718,23 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/hast": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/hast/-/hast-0.0.2.tgz",
"integrity": "sha512-1MrzC9MtAYhzLix2w++pGEtRyCm6N1fcxCjx+1xJo/92fNDRFemFaum18XWd8No3f+FgT9lv6fKOC8LZRcxxuw==",
"license": "MIT",
"dependencies": {
"bail": "^1.0.0",
"camelcase": "^1.2.1",
"ent": "^2.2.0",
"escape-html": "^1.0.3",
"htmlparser2": "^3.8.3",
"param-case": "^1.1.1",
"property-information": "^2.0.0",
"trim": "0.0.1",
"unified": "^2.1.0"
}
},
"node_modules/hast-util-parse-selector": { "node_modules/hast-util-parse-selector": {
"version": "4.0.0", "version": "4.0.0",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz", "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
@ -1676,10 +1799,46 @@
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/hast/node_modules/bail": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
"integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/hast/node_modules/property-information": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/property-information/-/property-information-2.0.0.tgz",
"integrity": "sha512-8oVcjnCeqANq/exCzgse3D47GBmgOuI47vNya7xBIJhUXeh49AjZuXWw2gTh1UuN4rfwz5pEv2ZFzu45vBby5A==",
"license": "MIT"
},
"node_modules/hast/node_modules/unified": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/unified/-/unified-2.1.4.tgz",
"integrity": "sha512-qa4nA26ms49OczPueTt7G46r89TOlwAJ4pEk2U4mwkV1wNhjttItF03SE/YnfkgWg14tzmAHXGhJp2GhDYwn1A==",
"license": "MIT",
"dependencies": {
"attach-ware": "^1.0.0",
"bail": "^1.0.0",
"extend": "^3.0.0",
"unherit": "^1.0.4",
"vfile": "^1.0.0",
"ware": "^1.3.0"
}
},
"node_modules/hast/node_modules/vfile": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-1.4.0.tgz",
"integrity": "sha512-7Fz639rwERslMqQCuf1/0H4Tqe2q484Xl6X/jsKqrP7IjFcDODFURhv0GekMnImpbj9pTOojtqL7r39LJJkjGA==",
"license": "MIT"
},
"node_modules/hastscript": { "node_modules/hastscript": {
"version": "8.0.0", "version": "9.0.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz", "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-9.0.0.tgz",
"integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==", "integrity": "sha512-jzaLBGavEDKHrc5EfFImKN7nZKKBdSLIdGvCwDZ9TfzbF2ffXiov8CKE445L2Z1Ek2t/m4SKQ2j6Ipv7NyUolw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/hast": "^3.0.0", "@types/hast": "^3.0.0",
@ -1703,6 +1862,20 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"license": "MIT",
"dependencies": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"node_modules/iconify-icon": { "node_modules/iconify-icon": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.1.0.tgz", "resolved": "https://registry.npmjs.org/iconify-icon/-/iconify-icon-2.1.0.tgz",
@ -1754,6 +1927,12 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-core-module": { "node_modules/is-core-module": {
"version": "2.15.1", "version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
@ -1876,6 +2055,12 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
"integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==",
"license": "MIT"
},
"node_modules/magic-string": { "node_modules/magic-string": {
"version": "0.30.11", "version": "0.30.11",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz",
@ -2478,6 +2663,15 @@
"node": ">= 4.4.x" "node": ">= 4.4.x"
} }
}, },
"node_modules/param-case": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-1.1.2.tgz",
"integrity": "sha512-gksk6zeZQxwBm1AHsKh+XDFsTGf1LvdZSkkpSIkfDtzW+EQj/P2PBgNb3Cs0Y9Xxqmbciv2JZe3fWU6Xbher+Q==",
"license": "MIT",
"dependencies": {
"sentence-case": "^1.1.2"
}
},
"node_modules/parse-node-version": { "node_modules/parse-node-version": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
@ -2681,6 +2875,26 @@
"license": "MIT", "license": "MIT",
"optional": true "optional": true
}, },
"node_modules/punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
"license": "MIT"
},
"node_modules/readable-stream": {
"version": "3.6.2",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "4.0.2", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
@ -2711,6 +2925,23 @@
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/rehype-document/node_modules/hastscript": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz",
"integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==",
"license": "MIT",
"dependencies": {
"@types/hast": "^3.0.0",
"comma-separated-tokens": "^2.0.0",
"hast-util-parse-selector": "^4.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/rehype-sanitize": { "node_modules/rehype-sanitize": {
"version": "6.0.0", "version": "6.0.0",
"resolved": "https://registry.npmjs.org/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz", "resolved": "https://registry.npmjs.org/rehype-sanitize/-/rehype-sanitize-6.0.0.tgz",
@ -2840,6 +3071,26 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"license": "MIT"
},
"node_modules/safer-buffer": { "node_modules/safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@ -2867,6 +3118,15 @@
"semver": "bin/semver" "semver": "bin/semver"
} }
}, },
"node_modules/sentence-case": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-1.1.3.tgz",
"integrity": "sha512-laa/UDTPXsrQnoN/Kc8ZO7gTeEjMsuPiDgUCk9N0iINRZvqAMCTXjGl8+tD27op1eF/JHbdUlEUmovDh6AX7sA==",
"license": "MIT",
"dependencies": {
"lower-case": "^1.1.1"
}
},
"node_modules/set-cookie-parser": { "node_modules/set-cookie-parser": {
"version": "2.7.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz",
@ -2941,6 +3201,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"license": "MIT",
"dependencies": {
"safe-buffer": "~5.2.0"
}
},
"node_modules/stringify-entities": { "node_modules/stringify-entities": {
"version": "4.0.4", "version": "4.0.4",
"resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz",
@ -3138,6 +3407,12 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/trim": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
"integrity": "sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==",
"deprecated": "Use String.prototype.trim() instead"
},
"node_modules/trim-lines": { "node_modules/trim-lines": {
"version": "3.0.1", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz",
@ -3212,6 +3487,20 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/unherit": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
"integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
"license": "MIT",
"dependencies": {
"inherits": "^2.0.0",
"xtend": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/unified": { "node_modules/unified": {
"version": "11.0.5", "version": "11.0.5",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz",
@ -3309,6 +3598,12 @@
"lodash.clonedeep": "^4.5.0" "lodash.clonedeep": "^4.5.0"
} }
}, },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
"node_modules/vfile": { "node_modules/vfile": {
"version": "6.0.3", "version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
@ -3518,6 +3813,15 @@
} }
} }
}, },
"node_modules/ware": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz",
"integrity": "sha512-Y2HUDMktriUm+SR2gZWxlrszcgtXExlhQYZ8QJNYbl22jum00KIUcHJ/h/sdAXhWTJcbSkiMYN9Z2tWbWYSrrw==",
"license": "MIT",
"dependencies": {
"wrap-fn": "^0.1.0"
}
},
"node_modules/why-is-node-running": { "node_modules/why-is-node-running": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz",
@ -3535,6 +3839,24 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/wrap-fn": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz",
"integrity": "sha512-xDLdGx0M8JQw9QDAC9s5NUxtg9MI09F6Vbxa2LYoSoCvzJnx2n81YMIfykmXEGsUvuLaxnblJTzhSOjUOX37ag==",
"license": "MIT",
"dependencies": {
"co": "3.1.0"
}
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"license": "MIT",
"engines": {
"node": ">=0.4"
}
},
"node_modules/yaml": { "node_modules/yaml": {
"version": "1.10.2", "version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",

View File

@ -15,6 +15,8 @@
"format": "prettier --write ." "format": "prettier --write ."
}, },
"dependencies": { "dependencies": {
"hast": "^0.0.2",
"hastscript": "^9.0.0",
"iconify-icon": "^2.1.0", "iconify-icon": "^2.1.0",
"rehype-document": "^7.0.3", "rehype-document": "^7.0.3",
"rehype-sanitize": "^6.0.0", "rehype-sanitize": "^6.0.0",

View File

@ -16,20 +16,11 @@
let output: Promise<string> = $derived(renderPreview(markdown, stylesheet)); let output: Promise<string> = $derived(renderPreview(markdown, stylesheet));
let previewFrame = $state<HTMLIFrameElement | undefined>();
async function performRender(event: MouseEvent) { async function performRender(event: MouseEvent) {
event.preventDefault(); event.preventDefault();
const renderResponse = await fetch('/render', { previewFrame?.contentWindow?.postMessage('print');
method: 'POST',
body: await output,
headers: { 'content-type': 'text/html' },
});
if (!renderResponse.ok) {
return;
}
const docURL = URL.createObjectURL(await renderResponse.blob());
window.open(docURL, '_blank');
} }
</script> </script>
@ -37,7 +28,7 @@
{#await output} {#await output}
<p>processing...</p> <p>processing...</p>
{:then result} {:then result}
<iframe title="résumé preview" srcdoc={result}></iframe> <iframe title="résumé preview" srcdoc={result} bind:this={previewFrame}></iframe>
<button type="submit" onclick={performRender}> <button type="submit" onclick={performRender}>
<span>download</span> <span>download</span>
<iconify-icon icon="ion:download-outline" height="1.25em"></iconify-icon> <iconify-icon icon="ion:download-outline" height="1.25em"></iconify-icon>

View File

@ -1,9 +1,32 @@
import { type Element as HastElement, type Root as HastRoot } from 'hast';
import { h } from 'hastscript';
import rehypeDocument from 'rehype-document'; import rehypeDocument from 'rehype-document';
import rehypeSanitize, { defaultSchema } from 'rehype-sanitize'; import rehypeSanitize, { defaultSchema } from 'rehype-sanitize';
import rehypeStringify from 'rehype-stringify'; import rehypeStringify from 'rehype-stringify';
import remarkParse from 'remark-parse'; import remarkParse from 'remark-parse';
import remarkRehype from 'remark-rehype'; import remarkRehype from 'remark-rehype';
import { unified } from 'unified'; import { unified, type Plugin } from 'unified';
const printScript = `
window.addEventListener('message', (evt) => {
if (evt.data === 'print') {
window.print();
}
});
`;
const injectPrintScript: Plugin<[], HastRoot> = function () {
return (tree) => {
const printScriptNode = h('script', printScript);
const htmlNode = tree.children.find(
(node) => node.type === 'element' && node.tagName === 'html',
) as HastElement;
const bodyNode = htmlNode.children.find(
(node) => node.type === 'element' && node.tagName === 'body',
) as HastElement;
bodyNode.children.push(printScriptNode);
};
};
const renderPreview = async (markdown: string, stylesheet: string): Promise<string> => { const renderPreview = async (markdown: string, stylesheet: string): Promise<string> => {
let allowedTags: string[] = ['body', 'head', 'html', 'style']; let allowedTags: string[] = ['body', 'head', 'html', 'style'];
@ -20,6 +43,7 @@ const renderPreview = async (markdown: string, stylesheet: string): Promise<stri
allowDoctypes: true, allowDoctypes: true,
tagNames: allowedTags, tagNames: allowedTags,
}) })
.use(injectPrintScript)
.use(rehypeStringify) .use(rehypeStringify)
.process(markdown), .process(markdown),
); );

View File

@ -1,32 +0,0 @@
import child_process from 'node:child_process';
import { error, type RequestEvent } from '@sveltejs/kit';
export async function POST({ request }: RequestEvent) {
if (!(request.headers.get('Content-Type') ?? 'bad').includes('text/html')) {
error(400, 'request body not HTML');
}
if (!request.body) {
error(400, 'no body in request');
}
const input = await request.text();
const {
status: exitCode,
stderr: err,
stdout: output,
} = child_process.spawnSync('pandoc', ['--sandbox', '-f', 'html', '-t', 'pdf'], {
input,
timeout: 5000,
uid: 9999,
});
if (exitCode !== 0) {
console.error('pandoc errored: ', err.toString());
error(500, 'pandoc returned error response in server');
}
return new Response(output, { headers: { 'content-type': 'application/pdf' } });
}