All files / lib avdo.ts

91.49% Statements 43/47
66.67% Branches 8/12
84.62% Functions 11/13
92.86% Lines 39/42
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104        1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x     1x                                       1x 9x   9x 9x 4x   5x   9x       9x                 1x   72x             36x 36x 36x 36x 36x 36x 36x 36x 36x       36x     36x       36x         36x     36x 36x         1x  
// Plugin code based off of svgo v1.0.3.
 
import { JsApi } from './jsapi';
import { Plugin } from '../plugins/_types';
import { bakeGroupTransforms } from '../plugins/bakeGroupTransforms';
import { collapseGroups } from '../plugins/collapseGroups';
import { convertPathData } from '../plugins/convertPathData';
import { js2xml } from './js2xml';
import { mergePaths } from '../plugins/mergePaths';
import { processPlugins } from '../plugins/_plugins';
import { removeComments } from '../plugins/removeComments';
import { removeDefaults } from '../plugins/removeDefaults';
import { removeEmptyGroups } from '../plugins/removeEmptyGroups';
import { removeHiddenElems } from '../plugins/removeHiddenElems';
import { removeXMLProcInst } from '../plugins/removeXMLProcInst';
import { xml2js } from './xml2js';
 
// The order is from https://github.com/svg/svgo/blob/master/.svgo.yml
export const plugins: { [name: string]: Plugin } = {
  removeXMLProcInst,
  removeComments,
  // cleanupAttrs,
  // cleanupIDs,
  // cleanupNumericValues,
  // convertColors,
  removeDefaults,
  // removeUselessStrokeAndFill,
  removeHiddenElems,
  bakeGroupTransforms,
  collapseGroups,
  convertPathData,
  // convertTransform,
  removeEmptyGroups,
  mergePaths,
  // removeUnusedNS,
  // sortAttrs,
};
 
const batchedPlugins = (function(ps: Plugin[]) {
  return ps.map(item => [item]).reduce(
    (arr, item) => {
      const last = arr[arr.length - 1];
      if (last && item[0].type === last[0].type) {
        last.push(item[0]);
      } else {
        arr.push(item);
      }
      return arr;
    },
    [] as Plugin[][]
  );
})(Object.keys(plugins).map(k => plugins[k]));
 
// TODO: make it possible to configure indentation too?
export interface Options {
  plugins: Plugin[][];
  multipass?: boolean;
  pretty?: boolean;
}
 
export class Avdo {
  constructor(
    private readonly Ioptions: Options = {
      plugins: batchedPlugins,
      multipass: true,
      pretty: true,
    },
  ) {}
 
  optimize(xml: string) {
    return new Promise<string>((resolve, reject) => {
      const maxPassCount = this.options.multipass ? 10 : 1;
      let numPasses = 0;
      let prevResultSize = Number.POSITIVE_INFINITY;
      const onFail = (error: string) => reject(error);
      const onSuccess = (result: string) => {
        numPasses++;
        Iif (numPasses < maxPassCount && result.length < prevResultSize) {
          prevResultSize = result.length;
          this.optimizeOnce(result, onSuccess, onFail);
        } else {
          resolve(result);
        }
      };
      this.optimizeOnce(xml, onSuccess, onFail);
    });
  }
 
  private optimizeOnce(
    xml: string,
    onSuccess: (result: string) => void,
    onFail: (error: string) => void,
  ) {
    xml2js(
      xml,
      jsApi => {
        jsApi = processPlugins(jsApi, this.options.plugins);
        onSuccess(js2xml(jsApi, { pretty: this.options.pretty }));
      },
      error => onFail(error),
    );
  }
}