diff --git a/config/plugins/withImageGenerator/index.js b/config/plugins/withImageGenerator/index.js new file mode 100644 index 0000000..584fd64 --- /dev/null +++ b/config/plugins/withImageGenerator/index.js @@ -0,0 +1,43 @@ +const path = require('path'); +const withLatex = (nextConfig = {}) => { + return Object.assign({}, nextConfig, { + webpack(config, options) { + const {isServer, dev} = options; + let outputPath = ''; + if (isServer && dev) { + outputPath = "../"; + } else if (isServer) { + outputPath = "../../"; + } + config.module.rules.push({ + test: /\.png.yml$/, + use: [{ + loader: 'file-loader', + options: { + + publicPath: `${nextConfig.assetPrefix || nextConfig.basePath || ''}/_next/static/images/`, + outputPath: `${outputPath}static/images/`, + name: (name) => { + const fileName = path.basename(name); + const parts = fileName.split('.'); + parts.pop(); + const ext = parts.pop(); + + return `${parts.join('.')}.[hash].${ext}`; + }, + esModule: nextConfig.esModule || false, + }, + }, { + loader: require.resolve('./webpack.js'), + }], + }); + if (typeof nextConfig.webpack === "function") { + return nextConfig.webpack(config, options); + } + + return config; + }, + }); +} + +module.exports = withLatex; diff --git a/config/plugins/withImageGenerator/webpack.js b/config/plugins/withImageGenerator/webpack.js new file mode 100644 index 0000000..7c726cf --- /dev/null +++ b/config/plugins/withImageGenerator/webpack.js @@ -0,0 +1,16 @@ +require('reflect-metadata'); +require('@babel/register')({ + extensions: [".es6", ".es", ".jsx", ".js", ".mjs", ".ts"], +}); +const { generateImage } = require('../../../src/images'); + +module.exports = function (source) { + var callback = this.async(); + const location = this.resourcePath; + generateImage(source, location) + .then((canvas) => { + const buffer = canvas.toBuffer('image/png', {}) + callback(null, buffer); + }) + .catch(callback); +} diff --git a/config/plugins/withLatex/index.js b/config/plugins/withLatex/index.js index c320646..a8b7f0f 100644 --- a/config/plugins/withLatex/index.js +++ b/config/plugins/withLatex/index.js @@ -13,7 +13,6 @@ const withLatex = (nextConfig = {}) => { use: [{ loader: 'file-loader', options: { - publicPath: `${nextConfig.assetPrefix || nextConfig.basePath || ''}/_next/static/images/`, outputPath: `${outputPath}static/images/`, name: "[name]-[hash].pdf", diff --git a/content/articles/hiring/index.yml b/content/articles/hiring/index.yml index 3ca30ab..53332e8 100644 --- a/content/articles/hiring/index.yml +++ b/content/articles/hiring/index.yml @@ -1,5 +1,6 @@ title: How to hire engineers, by an engineer cover: cover.png published: 2022-03-16 +shareImage: ./share.png.yml parts: - main.md diff --git a/content/articles/hiring/share.png.yml b/content/articles/hiring/share.png.yml new file mode 100644 index 0000000..35f1bdb --- /dev/null +++ b/content/articles/hiring/share.png.yml @@ -0,0 +1,3 @@ +generator: share +width: 450 +height: 300 diff --git a/content/articles/my-home-runs-redux/index.yml b/content/articles/my-home-runs-redux/index.yml index cb9084b..65627b3 100644 --- a/content/articles/my-home-runs-redux/index.yml +++ b/content/articles/my-home-runs-redux/index.yml @@ -1,5 +1,6 @@ title: My home runs Redux cover: cover.png published: 2022-03-15 +shareImage: ./share.png.yml parts: - main.md diff --git a/content/articles/my-home-runs-redux/share.png.yml b/content/articles/my-home-runs-redux/share.png.yml new file mode 100644 index 0000000..35f1bdb --- /dev/null +++ b/content/articles/my-home-runs-redux/share.png.yml @@ -0,0 +1,3 @@ +generator: share +width: 450 +height: 300 diff --git a/next.config.js b/next.config.js index c0b0b3a..31a2c00 100644 --- a/next.config.js +++ b/next.config.js @@ -2,6 +2,7 @@ const withPlugins = require("next-compose-plugins"); const withImages = require("./config/plugins/withImages.js"); const withLatex = require('./config/plugins/withLatex'); +const withImageGenerator = require('./config/plugins/withImageGenerator'); const withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true", }); @@ -15,6 +16,7 @@ const nextConfig = { module.exports = withPlugins([ withLatex, + withImageGenerator, [withImages,{ esModule: true, // using ES modules is beneficial in the case of module concatenation and tree shaking. inlineImageLimit: 0, // disable image inlining to data:base64 diff --git a/package.json b/package.json index c69b610..8c598f9 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@babel/plugin-transform-modules-commonjs": "^7.17.7", "@babel/register": "^7.17.7", "@next/bundle-analyzer": "^12.1.0", + "@types/canvas-multiline-text": "^1.0.0", "@types/fs-extra": "^9.0.13", "@types/marked": "^4.0.3", "@types/react": "^17.0.41", @@ -40,6 +41,8 @@ "babel-plugin-styled-components": "^2.0.6", "babel-plugin-transform-typescript-metadata": "^0.3.2", "babel-register-esm": "^1.2.1", + "canvas": "^2.9.1", + "canvas-multiline-text": "^1.0.3", "file-loader": "^6.2.0", "framer-motion": "^6.2.8", "fs-extra": "^10.0.1", diff --git a/src/data/assets/WebpackAssets.ts b/src/data/assets/WebpackAssets.ts index ab1349d..5e79f95 100644 --- a/src/data/assets/WebpackAssets.ts +++ b/src/data/assets/WebpackAssets.ts @@ -4,7 +4,7 @@ import { AssetResolver } from './'; const assetModules = (require as any).context( '../../../content', true, - /\.(png|jpe?g|svg|gif|tex\.yml)$/, + /\.(png|jpe?g|svg|gif|tex\.yml|png\.yml)$/, ) const assets = assetModules.keys().reduce((output, key: string) => ({ ...output, diff --git a/src/data/repos/articles.ts b/src/data/repos/articles.ts index 6626853..add11c4 100644 --- a/src/data/repos/articles.ts +++ b/src/data/repos/articles.ts @@ -23,6 +23,7 @@ export type Article = { published?: string; content: string; stats: ReturnType; + shareImage?: string; pdfs: { a4: string; }; @@ -57,6 +58,9 @@ export class ArticleDB { const cover = structure.cover ? this.#assets.getPath(path.resolve('/', location, structure.cover)) : null; + const shareImage = structure.shareImage + ? this.#assets.getPath(path.resolve('/', location, structure.shareImage)) + : null; const stats = readingTime(articleContent.join('\n')); const article: Article = { @@ -64,6 +68,7 @@ export class ArticleDB { id, cover, content: articleContent.join('\n'), + shareImage, stats, pdfs: { a4: this.#assets.getPath( diff --git a/src/images/generator/Generator.ts b/src/images/generator/Generator.ts new file mode 100644 index 0000000..17034ed --- /dev/null +++ b/src/images/generator/Generator.ts @@ -0,0 +1,5 @@ +import type { Canvas } from "canvas"; + +type ImageGenerator = (data: T, location: string, canvas: Canvas) => Promise; + +export type { ImageGenerator }; diff --git a/src/images/generator/index.ts b/src/images/generator/index.ts new file mode 100644 index 0000000..5c01f08 --- /dev/null +++ b/src/images/generator/index.ts @@ -0,0 +1,8 @@ +import { ImageGenerator } from "./Generator"; +import { shareGenerator } from "./share"; + +const generators: {[name: string]: ImageGenerator} = { + share: shareGenerator, +}; + +export { generators }; diff --git a/src/images/generator/share.ts b/src/images/generator/share.ts new file mode 100644 index 0000000..9b2fc67 --- /dev/null +++ b/src/images/generator/share.ts @@ -0,0 +1,130 @@ +import { loadImage, CanvasRenderingContext2D, Image, createCanvas } from 'canvas'; +import path from 'path'; +import Container from "typedi"; +import { AssetResolver } from "../../data/assets"; +import { ArticleDB } from "../../data/repos/articles"; +import { ImageGenerator } from "./Generator"; +import drawMultiLine from 'canvas-multiline-text'; +import { ProfileDB } from '../../data/repos/profile'; + +const assets = { + getPath: (...source: string[]) => { + return path.join(process.cwd(), 'content', ...source); + }, +} + +function drawImageProp( + ctx: CanvasRenderingContext2D, + img: Image, + x?: number, + y?: number, + w?: number, + h?: number, + offsetX?: number, + offsetY?: number, +) { + + if (arguments.length === 2) { + x = y = 0; + w = ctx.canvas.width; + h = ctx.canvas.height; + } + + // default offset is center + offsetX = typeof offsetX === "number" ? offsetX : 0.5; + offsetY = typeof offsetY === "number" ? offsetY : 0.5; + + // keep bounds [0.0, 1.0] + if (offsetX < 0) offsetX = 0; + if (offsetY < 0) offsetY = 0; + if (offsetX > 1) offsetX = 1; + if (offsetY > 1) offsetY = 1; + + var iw = img.width, + ih = img.height, + r = Math.min(w / iw, h / ih), + nw = iw * r, // new prop. width + nh = ih * r, // new prop. height + cx, cy, cw, ch, ar = 1; + + // decide which gap to fill + if (nw < w) ar = w / nw; + if (Math.abs(ar - 1) < 1e-14 && nh < h) ar = h / nh; // updated + nw *= ar; + nh *= ar; + + // calc source rectangle + cw = iw / (nw / w); + ch = ih / (nh / h); + + cx = (iw - cw) * offsetX; + cy = (ih - ch) * offsetY; + + // make sure source rectangle is valid + if (cx < 0) cx = 0; + if (cy < 0) cy = 0; + if (cw > iw) cw = iw; + if (ch > ih) ch = ih; + + // fill image in dest. rectangle + ctx.drawImage(img, cx, cy, cw, ch, x, y, w, h); +} + +const shareGenerator: ImageGenerator = async (data, location, canvas) => { + const dir = path.dirname(location); + const id = path.basename(dir); + Container.set(AssetResolver, assets) + const articleDB = Container.get(ArticleDB); + const profileDB = Container.get(ProfileDB); + const article = await articleDB.get(id); + const profile = await profileDB.get(); + const ctx = canvas.getContext('2d'); + ctx.antialias = 'subpixel'; + const cover = await loadImage(article.cover); + drawImageProp( + ctx, + cover, + ) + const author = `by ${profile.name}`; + ctx.font = '30px sans'; + const titleSize = ctx.measureText(article.title); + + ctx.font = '16px sans'; + const authorSize = ctx.measureText(author); + const titleHeight = titleSize.actualBoundingBoxDescent + titleSize.actualBoundingBoxAscent; + const authorHeight = authorSize.actualBoundingBoxDescent + authorSize.actualBoundingBoxAscent; + + const offset = 10; + ctx.fillStyle = '#222'; + ctx.fillRect( + 20, + offset, + Math.min(canvas.width - 60, titleSize.width + 20), + titleHeight + 20, + ) + + const authorOffset = offset + titleHeight + 20 + 20; + + ctx.fillRect( + 20, + authorOffset, + Math.min(canvas.width - 60, authorSize.width + 20), + authorHeight + 20, + ) + ctx.fillStyle = '#fff'; + ctx.font = '30px sans'; + ctx.fillText( + article.title, + 30, + 30 + titleSize.actualBoundingBoxAscent / 2, + ) + + ctx.font = '16px sans'; + ctx.fillText( + author, + 30, + authorOffset + 10 + authorSize.actualBoundingBoxAscent / 2, + ) +}; + +export { shareGenerator }; diff --git a/src/images/index.ts b/src/images/index.ts new file mode 100644 index 0000000..83b8ee8 --- /dev/null +++ b/src/images/index.ts @@ -0,0 +1,11 @@ +import { createCanvas } from 'canvas'; +import yaml from 'yaml'; +import { generators } from './generator'; + +export const generateImage = async (source: string, location: string) => { + const definition = yaml.parse(source); + const canvas = createCanvas(definition.width * 2, definition.height * 2) + const generator = generators[definition.generator]; + await generator(definition.data, location, canvas); + return canvas; +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 063cc8d..ddf1b38 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -13,15 +13,13 @@ import { Experience, ExperienceDB } from '../data/repos/experiences'; import { Profile, ProfileDB } from '../data/repos/profile'; type Props = { - resume: string; articles: Article[]; profile: Profile; experiences: Experience[]; }; -const Home: React.FC = ({ resume, articles, profile, experiences }) => { - console.log('resume', resume); +const Home: React.FC = ({ articles, profile, experiences }) => { return ( <> @@ -45,14 +43,11 @@ export async function getStaticProps() { const articleDB = Container.get(ArticleDB); const profileDB = Container.get(ProfileDB); const experienceDB = Container.get(ExperienceDB); - const assets = Container.get(AssetResolver); const articles = await articleDB.list(); const profile = await profileDB.get(); const experiences = await experienceDB.list(); - const resume = assets.getPath('profile', 'a4.tex.yml'); return { props: { - resume, profile, articles, experiences, diff --git a/yarn.lock b/yarn.lock index 8ca7d8f..06d4813 100644 --- a/yarn.lock +++ b/yarn.lock @@ -405,6 +405,21 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@mapbox/node-pre-gyp@^1.0.0": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc" + integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw== + dependencies: + detect-libc "^2.0.0" + https-proxy-agent "^5.0.0" + make-dir "^3.1.0" + node-fetch "^2.6.7" + nopt "^5.0.0" + npmlog "^5.0.1" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.11" + "@mdx-js/mdx@^2.0.0": version "2.1.0" resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-2.1.0.tgz#a984cee27a378619a82d193288031a7b83a54b26" @@ -620,6 +635,11 @@ dependencies: "@types/estree" "*" +"@types/canvas-multiline-text@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/canvas-multiline-text/-/canvas-multiline-text-1.0.0.tgz#0e4128015765f82792107dfd4d657d0405ffac7d" + integrity sha512-zP4L/GdHeJK7MOa4NqQM2D5H5f/Po9yVehDrIYsbnfFfVT0V1b0bjmyDw8Ioiv8bcl+MXWUpZgkrzblrGUgtxA== + "@types/debug@^4.0.0": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" @@ -780,6 +800,11 @@ resolved "https://registry.yarnpkg.com/@webgpu/glslang/-/glslang-0.0.15.tgz#f5ccaf6015241e6175f4b90906b053f88483d1f2" integrity sha512-niT+Prh3Aff8Uf1MVBVUsaNjFj9rJAKDXuoHIKiQbB+6IUP/3J3JIhBNyZ7lDhytvXxw6ppgnwKZdDJ08UMj4Q== +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + acorn-jsx@^5.0.0: version "5.3.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -795,6 +820,13 @@ acorn@^8.0.0, acorn@^8.0.4, acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + ajv-keywords@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -839,6 +871,19 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== +"aproba@^1.0.3 || ^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" + integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== + +are-we-there-yet@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" + integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + are-we-there-yet@~1.1.2: version "1.1.7" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" @@ -1000,6 +1045,22 @@ caniuse-lite@^1.0.30001317: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001322.tgz#2e4c09d11e1e8f852767dab287069a8d0c29d623" integrity sha512-neRmrmIrCGuMnxGSoh+x7zYtQFFgnSY2jaomjU56sCkTA6JINqQrxutF459JpWcWRajvoyn95sOXq4Pqrnyjew== +canvas-multiline-text@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/canvas-multiline-text/-/canvas-multiline-text-1.0.3.tgz#7ac51af6eb1e35e937e8e53a4c8b270b52a4d4b7" + integrity sha512-AVgcWhCBVRP7M9Kw1RBrD9S5gCn1R2jgLjaJPrYywl94x+SMAUAHjB8EtWYopCe4Lj/0ugNsZFKgE3SBR1uY4A== + dependencies: + words-array "^1.0.1" + +canvas@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/canvas/-/canvas-2.9.1.tgz#58ec841cba36cef0675bc7a74ebd1561f0b476b0" + integrity sha512-vSQti1uG/2gjv3x6QLOZw7TctfufaerTWbVe+NSduHxxLGB+qf3kFgQ6n66DSnuoINtVUjrLLIK2R+lxrBG07A== + dependencies: + "@mapbox/node-pre-gyp" "^1.0.0" + nan "^2.15.0" + simple-get "^3.0.3" + ccount@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" @@ -1079,6 +1140,11 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -1125,6 +1191,11 @@ color-string@^1.6.0: color-name "^1.0.0" simple-swizzle "^0.2.2" +color-support@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" + integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== + color@^3.1.3: version "3.2.1" resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164" @@ -1153,7 +1224,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -console-control-strings@^1.0.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= @@ -1211,6 +1282,13 @@ debug@2: dependencies: ms "2.0.0" +debug@4, debug@^4.0.0, debug@^4.1.0, debug@^4.3.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -1218,13 +1296,6 @@ debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.1.0, debug@^4.3.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - decode-named-character-reference@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz#57b2bd9112659cacbc449d3577d7dadb8e1f3d1b" @@ -1280,6 +1351,11 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-libc@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd" + integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w== + diff@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" @@ -1457,6 +1533,13 @@ fs-extra@^2.0.0: graceful-fs "^4.1.2" jsonfile "^2.1.0" +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1467,6 +1550,21 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +gauge@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" + integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.2" + console-control-strings "^1.0.0" + has-unicode "^2.0.1" + object-assign "^4.1.1" + signal-exit "^3.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.2" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -1554,7 +1652,7 @@ has-symbols@^1.0.1: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== -has-unicode@^2.0.0: +has-unicode@^2.0.0, has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= @@ -1644,6 +1742,14 @@ html-void-elements@^2.0.0: resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1920,6 +2026,13 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-dir@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + make-error@^1.1.1: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -2407,11 +2520,31 @@ minimist@^1.2.0, minimist@^1.2.3: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== +minipass@^3.0.0: + version "3.1.6" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.6.tgz#3b8150aa688a711a1521af5e8779c1d3bb4f45ee" + integrity sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ== + dependencies: + yallist "^4.0.0" + +minizlib@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mmd-parser@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/mmd-parser/-/mmd-parser-1.0.4.tgz#87cc05782cb5974ca854f0303fc5147bc9d690e7" @@ -2442,6 +2575,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +nan@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" + integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== + nanoid@^3.1.30: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" @@ -2519,6 +2657,13 @@ node-addon-api@^3.1.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== +node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + node-latex@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/node-latex/-/node-latex-3.1.0.tgz#7e5173321fc434f1e5e5a2b9aee7b740a0a06594" @@ -2535,6 +2680,13 @@ node-releases@^2.0.2: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + npmlog@^4.0.1, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -2545,6 +2697,16 @@ npmlog@^4.0.1, npmlog@^4.1.2: gauge "~2.7.3" set-blocking "~2.0.0" +npmlog@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" + integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== + dependencies: + are-we-there-yet "^2.0.0" + console-control-strings "^1.1.0" + gauge "^3.0.0" + set-blocking "^2.0.0" + number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -2890,7 +3052,7 @@ readable-stream@^2.0.6, readable-stream@^2.1.0, readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.1.1, readable-stream@^3.4.0: +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -3026,6 +3188,13 @@ resize-observer-polyfill@^1.5.1: resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + rimraf@~2.6.2: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -3082,19 +3251,19 @@ semver@^5.4.1, semver@^5.6.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.4: +semver@^7.3.4, semver@^7.3.5: version "7.3.5" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -set-blocking@~2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= @@ -3228,7 +3397,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4": +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -3359,6 +3528,18 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" +tar@^6.1.11: + version "6.1.11" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^3.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + temp@^0.8.3: version "0.8.4" resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.4.tgz#8c97a33a4770072e0a05f919396c7665a7dd59f2" @@ -3415,6 +3596,11 @@ totalist@^1.0.0: resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + troika-three-text@^0.46.2: version "0.46.3" resolved "https://registry.yarnpkg.com/troika-three-text/-/troika-three-text-0.46.3.tgz#abc37056e2c12ae94552ffbc1f116e2e442a8bd5" @@ -3784,6 +3970,11 @@ webgl-sdf-generator@1.1.1: resolved "https://registry.yarnpkg.com/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz#3e1b422b3d87cd3cc77f2602c9db63bc0f6accbd" integrity sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + webpack-bundle-analyzer@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz#2f3c0ca9041d5ee47fa418693cf56b4a518b578b" @@ -3799,13 +3990,26 @@ webpack-bundle-analyzer@4.3.0: sirv "^1.0.7" ws "^7.3.1" -wide-align@^1.1.0: +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +wide-align@^1.1.0, wide-align@^1.1.2: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== dependencies: string-width "^1.0.2 || 2 || 3 || 4" +words-array@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/words-array/-/words-array-1.0.1.tgz#fcd695587744f9bd1c7fe2a05e9d8f87cdd87bac" + integrity sha512-hIe554G5rHAIa2HeIPcvl4zzIeS9DCSLjFM6HbqzTEGmyCZVqMffXpxEGZwweT+ZxbkTdNg78YwwzhQsA7jjPw== + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"