All files / src avdo.ts

90.7% Statements 39/43
64.29% Branches 9/14
83.33% Functions 10/12
92.31% Lines 36/39
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 105 106 107 108        1x 1x 1x 1x 1x 1x 1x 1x 1x                           1x                                       1x 6x   6x 6x 1x   5x   6x                         1x 48x 24x     24x 24x 24x 24x 24x 24x 24x       24x     24x 24x       1x         24x 24x     24x 24x         1x  
// Code forked and modified from svgo v1.0.3.
 
import { JsApi } from './jsapi';
import { Plugin } from './plugins/_types';
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 { removeEmptyGroups } from './plugins/removeEmptyGroups';
import { removeXMLProcInst } from './plugins/removeXMLProcInst';
import { xml2js } from './xml2js';
 
// import * as cleanupAttrs from './plugins/cleanupAttrs';
// import * as cleanupIDs from './plugins/cleanupIDs';
// import * as cleanupNumericValues from './plugins/cleanupNumericValues';
// import * as convertColors from './plugins/convertColors';
// import * as removeUnknownsAndDefaults from './plugins/removeUnknownsAndDefaults';
// import * as removeUselessStrokeAndFill from './plugins/removeUselessStrokeAndFill';
// import * as removeHiddenElems from './plugins/removeHiddenElems';
// import * as convertTransform from './plugins/convertTransform';
// import * as removeUnusedNS from './plugins/removeUnusedNS';
// import * as sortAttrs from './plugins/sortAttrs';
 
// 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,
  // removeUnknownsAndDefaults,
  // removeUselessStrokeAndFill,
  // removeHiddenElems,
  collapseGroups,
  convertPathData,
  // convertTransform,
  removeEmptyGroups,
  mergePaths,
  // removeUnusedNS,
  // sortAttrs,
};
 
// Arrange plugins by type - this is what plugins() expects.
const optimizedPluginsData = (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[][]
  );
})(Array.from(Object.values(plugins)));
 
export interface Options {
  plugins?: Plugin[][];
  multipass?: boolean;
  // TODO: make it possible to configure indentation too
  pretty?: boolean;
}
 
export class Avdo {
  constructor(private readonly Ioptions: Options = {}) {
    options.plugins = options.plugins || optimizedPluginsData;
  }
 
  optimize(xml: string): Promise<string> {
    return new Promise((resolve, reject) => {
      const maxPassCount = this.options.multipass ? 10 : 1;
      let counter = 0;
      let prevResultSize = Number.POSITIVE_INFINITY;
      const onSuccess = (result: string) => {
        Iif (++counter < maxPassCount && result.length < prevResultSize) {
          prevResultSize = result.length;
          this.optimizeOnce(result, onSuccess, onFail);
        } else {
          resolve(result);
        }
      };
      const onFail = (error: any) => reject(error);
      this.optimizeOnce(xml, onSuccess, onFail);
    });
  }
 
  private optimizeOnce(
    xml: string,
    onSuccess: (result: string) => void,
    onFail: (error: string) => void,
  ) {
    const { options } = this;
    xml2js(
      xml,
      jsApi => {
        jsApi = processPlugins(jsApi, options.plugins);
        onSuccess(js2xml(jsApi, { pretty: options.pretty }));
      },
      error => onFail(error),
    );
  }
}