diff options
Diffstat (limited to 'material-symbols-plugin.js')
| -rw-r--r-- | material-symbols-plugin.js | 149 |
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 |
