/ 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  });