liusuyi
2023-04-24 4737f1e038743ced243c9e52423404d9034d6107
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
const Promise = require('bluebird');
const merge = require('merge-options');
const FileRequest = require('./request');
const RuleSet = require('./rules');
const Sprite = require('./sprite');
const SpriteSymbol = require('./symbol');
const symbolFactory = require('./symbol-factory');
const spriteFactory = require('./sprite-factory');
 
const defaultConfig = {
  rules: [
    { test: /\.svg$/, value: 'sprite.svg' }
  ],
  symbolFactory,
  spriteFactory
};
 
class Compiler {
  static sortSymbols(symbols) {
    symbols.sort((leftSymbol, rightSymbol) => {
      const leftId = leftSymbol.id;
      const rightId = rightSymbol.id;
 
      if (leftId === rightId) {
        return 0;
      }
      return leftId < rightId ? -1 : 1;
    });
 
    return symbols;
  }
 
  constructor(cfg = {}) {
    const config = this.config = merge(defaultConfig, cfg);
    this.rules = new RuleSet(config.rules);
    this.symbols = [];
  }
 
  /**
   * @param {string} content
   * @param {string} path
   * @param {string} [id]
   * @return {Promise<SpriteSymbol>}
   */
  addSymbol({ path, content, id }) {
    const symbols = this.symbols;
    const factory = this.config.symbolFactory;
    const request = new FileRequest(path);
    const options = { id, request, content, factory };
 
    return SpriteSymbol.create(options).then((newSymbol) => {
      const existing = symbols.find(s => s.request.equals(request));
 
      if (!existing) {
        symbols.push(newSymbol);
        Compiler.sortSymbols(symbols);
        return newSymbol;
      }
 
      const existingIndex = existing ? symbols.indexOf(existing) : -1;
      const allExceptCurrent = symbols
        .filter(s => s.request.fileEquals(request) && !s.request.queryEquals(request))
        .map(symbol => ({ symbol, index: symbols.indexOf(symbol) }));
 
      symbols[existingIndex] = newSymbol;
      Compiler.sortSymbols(symbols);
 
      return Promise.map(allExceptCurrent, ({ symbol, index }) => {
        const opts = { id: symbol.id, request: symbol.request, content, factory };
        return SpriteSymbol.create(opts).then(created => symbols[index] = created);
      }).then(() => newSymbol);
    });
  }
 
  /**
   * @return {Promise<Array<Sprite>>}
   */
  compile() {
    const symbols = this.symbols;
    const rules = this.rules.rules;
    const factory = this.config.spriteFactory;
 
    return Promise.map(rules, (rule) => {
      const spriteSymbols = [];
      const filename = rule.uri;
 
      symbols.forEach((symbol) => {
        const isMatch = rule.match(symbol.request.file);
        if (isMatch) {
          spriteSymbols.push(symbol);
        }
      });
 
      return spriteSymbols.length > 0 ?
        Sprite.create({ symbols: spriteSymbols, filename, factory }) :
        null;
    }).filter(result => result !== null);
  }
}
 
module.exports = Compiler;
module.exports.defaultConfig = defaultConfig;