/ build.ts
build.ts
1 #!/usr/bin/env -S node -r ts-node/register/transpile-only 2 3 // Imports 4 import { mkdir, writeFile } from 'fs/promises'; 5 import path from 'path'; 6 import pMap from 'p-map'; 7 import { PathLike, existsSync, readdirSync, statSync, readFile } from 'fs'; 8 import { optimize, loadConfig } from 'svgo'; 9 import { camelCase, kebabCase, upperFirst} from 'lodash' 10 11 const dist = path.resolve(__dirname, 'dist'); 12 13 function renderTemplate(title: string, tData: {path: string | null, vbox: string | null}, name: string) { 14 return `<template> 15 <span v-bind="$attrs" 16 :aria-hidden="!title" 17 :aria-label="title" 18 class="princple-icon ${title}-icon" 19 role="img" 20 @click="$emit('click', $event)"> 21 <svg :fill="fillColor" 22 class="principle-icon__svg" 23 :width="size" 24 :height="size" 25 viewBox="${tData.vbox}"> 26 <path d="${tData.path}"> 27 <title v-if="title">{{ title }}</title> 28 </path> 29 </svg> 30 </span> 31 </template> 32 33 <script> 34 export default { 35 name: "${name}Icon", 36 emits: ['click'], 37 props: { 38 title: { 39 type: String, 40 }, 41 fillColor: { 42 type: String, 43 default: "currentColor" 44 }, 45 size: { 46 type: Number, 47 default: 24 48 } 49 } 50 } 51 </script>`; 52 } 53 54 function getTemplateData(svg: string) { 55 const vboxMatch = svg.match(/viewBox="(?<vbox>[0-9. ]*)"/) 56 const pathMatch = svg.match(/d="(?<path>.*)"/); 57 58 // if (!vboxMatch?.groups || !pathMatch?.groups) {console.error("No match!", vboxMatch, pathMatch); return;} 59 // This is a hacky way to remove the 'mdi' prefix, so "mdiAndroid" becomes 60 // "android", for example 61 62 return { 63 vbox: vboxMatch?.groups ? vboxMatch.groups.vbox : null, 64 path: pathMatch?.groups ? pathMatch.groups.path : null, 65 }; 66 } 67 68 const getAllFiles = function(dirPath: string, arrayOfFiles: Array<string>): Array<string> { 69 let files = readdirSync(dirPath) 70 71 arrayOfFiles = arrayOfFiles || [] 72 73 files.forEach(function(file) { 74 if (statSync(dirPath + "/" + file).isDirectory()) { 75 arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles) 76 } else if(file.endsWith(".svg")) { 77 arrayOfFiles.push(dirPath + "/" + file) 78 } else ( 79 console.log("skipped" , file) 80 ) 81 }) 82 83 return arrayOfFiles 84 } 85 86 87 async function build() { 88 const svgFiles = getAllFiles(__dirname + "/principles", []) 89 // const config = await loadConfig(); 90 91 svgFiles.forEach(fName => { 92 console.log(fName) 93 readFile(fName, 'utf-8', (err, data) => { 94 if (err) { 95 console.error(err) 96 return 97 } else { 98 let svgString = optimize(data, {floatPrecision: 2, multipass:true, plugins:[ 99 'preset-default', 100 'convertStyleToAttrs', 101 'convertPathData', 102 'removeComments', 103 { 104 name: 'preset-default', 105 params: { 106 'overrides': { 107 // viewBox is required to resize SVGs with CSS. 108 // @see https://github.com/svg/svgo/issues/1128 109 removeViewBox: false, 110 } 111 }, 112 }, 113 { 114 name: 'mergePaths', 115 params: { 116 force: true 117 } 118 }, 119 { 120 name: 'removeAttrs', 121 params: { 122 attrs: [ 123 '(stroke|fill)', 124 'style', 125 'color', 126 'aria-label', // This and the following were present in text-converted-to-paths 127 'direction', 128 'font-family', 129 'font-size', 130 'text-anchor', 131 'baseline-shift' 132 ] 133 } 134 }, 135 136 ]}).data 137 const fBase = path.basename(fName,".svg") 138 const title = kebabCase(fBase) 139 const name = upperFirst(camelCase(fBase)) 140 const tData = getTemplateData(svgString) 141 const component = renderTemplate(title, tData, name) 142 const filename = `${name}.vue`; 143 writeFile(path.resolve(dist, filename), component); 144 // console.log( 145 146 // ) 147 return; 148 } 149 } 150 ) 151 }); 152 // console.log(config) 153 if (!existsSync(dist)) { 154 await mkdir(dist); 155 } 156 // // Batch process promises to avoid overloading memory 157 // await pMap( 158 // templateData, 159 // async ({ name, title, svgPathData }) => { 160 // const component = renderTemplate(title, svgPathData, name); 161 // const filename = `${name}.vue`; 162 163 // return writeFile(path.resolve(dist, filename), component); 164 // }, 165 // { concurrency: 20 }, 166 // ); 167 } 168 169 build().catch((err: unknown) => { 170 console.log(err); 171 });