aboutsummaryrefslogtreecommitdiff
path: root/material-symbols-plugin.js
diff options
context:
space:
mode:
authorTim Keller <tjk@tjkeller.xyz>2025-06-13 13:42:21 -0500
committerTim Keller <tjk@tjkeller.xyz>2025-06-13 13:42:21 -0500
commitb4d0b0293812afba9637c7e636bfa51366a030f7 (patch)
tree93b9e2d5ce841b76f5c41741a8ebca4a745571b0 /material-symbols-plugin.js
parent4154e0cc1744996788b6727cd2ef4a0d3a42095e (diff)
downloadmaterial-svg-atlas-plugin-webpack-b4d0b0293812afba9637c7e636bfa51366a030f7.tar.xz
material-svg-atlas-plugin-webpack-b4d0b0293812afba9637c7e636bfa51366a030f7.zip
cleanup package and fix bug from not importing fs/path in utils
Diffstat (limited to 'material-symbols-plugin.js')
-rw-r--r--material-symbols-plugin.js149
1 files changed, 0 insertions, 149 deletions
diff --git a/material-symbols-plugin.js b/material-symbols-plugin.js
deleted file mode 100644
index 48b1123..0000000
--- a/material-symbols-plugin.js
+++ /dev/null
@@ -1,149 +0,0 @@
-const fs = require("fs")
-const path = require("path")
-const crypto = require("crypto")
-const axios = require("axios")
-const { Compilation } = require("webpack")
-const { generateAtlasViewsFromReferences, createDirectoriesForFile } = require("./utils.js")
-
-
-class MaterialSymbolsDownloader {
- static validStyls = [ "outlined", "rounded", "sharp" ]
- static validWghts = [ 100, 200, 300, 400, 500, 600, 700 ]
- static validGrads = [ -25, 0, 200 ]
- static validFills = [ false, true ]
- static validOpszs = [ 20, 24, 40, 48 ]
-
- constructor(ref) {
- this.icon = ref.symbol
- this.styl = ref.style ?? "outlined"
- this.wght = ref.wght ?? 400
- this.grad = ref.grad ?? 0
- this.fill = ref.fill ?? false
- this.opsz = ref.opsz ?? 24
- this.validateProperties()
- }
-
- validateProperties() {
- // TODO validate icons
- if (!MaterialSymbolsDownloader.validStyls.includes(this.styl)) throw new Error(`Styl ${this.styl} is not valid, must be one of ${this.validStyls}`)
- if (!MaterialSymbolsDownloader.validWghts.includes(this.wght)) throw new Error(`Wght ${this.wght} is not valid, must be one of ${this.validWghts}`)
- if (!MaterialSymbolsDownloader.validGrads.includes(this.grad)) throw new Error(`Grad ${this.grad} is not valid, must be one of ${this.validGrads}`)
- if (!MaterialSymbolsDownloader.validFills.includes(this.fill)) throw new Error(`Fill ${this.fill} is not valid, must be one of ${this.validFills}`)
- if (!MaterialSymbolsDownloader.validOpszs.includes(this.opsz)) throw new Error(`Opsz ${this.opsz} is not valid, must be one of ${this.validOpszs}`)
- }
-
- get axes() {
- const wght = this.wght == 400 ? "" : `wght${this.wght}`
- const grad = this.grad == 0 ? "" : `grad${this.grad}`
- const fill = !this.fill ? "" : "fill1"
- return wght + grad + fill || "default"
- }
-
- get svgDownloadUrl() {
- return `https://fonts.gstatic.com/s/i/short-term/release/materialsymbols${this.styl}/${this.icon}/${this.axes}/${this.opsz}px.svg`
- }
-
- async downloadSvg(cache) {
- const url = this.svgDownloadUrl
- const cached = await cache.getPromise(url, null)
- if (cached)
- return cached
-
- try {
- const res = await axios.get(url)
- const svg = res.data
- await cache.storePromise(url, null, svg)
- return svg
- } catch (err) {
- throw new Error(`Symbol ${this.icon} could not be downloaded. Error: ${err}`)
- }
- }
-}
-
-
-class MaterialSymbolsAtlasPlugin {
- constructor({ referenceFile, filename }) {
- this.referenceFile = path.resolve(referenceFile)
- this.filename = filename ?? "icons.svg"
- }
-
- readReferences() {
- const ext = path.extname(this.referenceFile)
-
- if (ext !== ".json")
- throw new Error(`Unsupported reference file extension: ${ext}. Only .json files are supported at this time`)
-
- const content = fs.readFileSync(this.referenceFile, "utf8")
- return JSON.parse(content)
- }
-
- async resolveRefs(refs, cache) {
- const root = path.dirname(this.referenceFile) // Relative to referenceFile
-
- for (const ref of refs) {
- if (ref.path) {
- // Local files
- const filePath = path.join(root, ref.path)
- if (!fs.existsSync(filePath))
- throw new Error(`SVG asset at ${filePath} does not exist`)
- ref.svg = fs.readFileSync(filePath, "utf8" )
- } else if (ref.symbol) {
- // Material symbol icon refs
- const symbolDl = new MaterialSymbolsDownloader(ref)
- ref.svg = await symbolDl.downloadSvg(cache)
- } else {
- throw new Error(`Ref does not provide a symbol name or path:\n${ref}`)
- }
- }
- return refs
- }
-
- apply(compiler) {
- compiler.hooks.thisCompilation.tap("MaterialSymbolsAtlasPlugin", (compilation) => {
- compilation.hooks.processAssets.tapPromise(
- {
- name: "MaterialSymbolsAtlasPlugin",
- stage: Compilation.PROCESS_ASSETS_STAGE_ADDITIONS,
- },
- async () => {
- try {
- // Handle cache
- const cache = compilation.getCache("MaterialSymbolsAtlasPlugin")
-
- const content = this.readReferences()
- const cacheKey = crypto.createHash("sha256")
- .update(JSON.stringify(content))
- .digest("hex")
-
- const cached = await cache.getPromise(cacheKey, null)
-
- // Create asset if not existing
- let atlas = cached
- if (!cached) {
- const refs = content.refs
- const svgRefs = await this.resolveRefs(refs, cache)
- atlas = await generateAtlasViewsFromReferences(svgRefs)
- await cache.storePromise(cacheKey, null, atlas)
- }
-
- createDirectoriesForFile(this.filename)
-
- compilation.emitAsset(
- this.filename,
- new compiler.webpack.sources.RawSource(atlas)
- )
- } catch (err) {
- compilation.errors.push(err)
- }
- }
- )
- })
-
- compiler.hooks.afterCompile.tap("MaterialSymbolsAtlasPlugin", (compilation) => {
- // Watch the reference file for changes
- compilation.fileDependencies.add(this.referenceFile)
- })
- }
-}
-
-module.exports = MaterialSymbolsAtlasPlugin