保誠-保戶業務員媒合平台
HelenHuang
2022-06-09 9bdb95c9e34cef640534e5e5a1e2225a80442000
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
109
110
111
112
113
114
115
116
117
118
'use strict';
 
const postcss = require('postcss');
const ICSSUtils = require('icss-utils');
 
const matchImports = /^(.+?|\([\s\S]+?\))\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/;
const matchValueDefinition = /(?:\s+|^)([\w-]+):?\s+(.+?)\s*$/g;
const matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/;
 
let options = {};
let importIndex = 0;
let createImportedName =
  (options && options.createImportedName) ||
  ((importName /*, path*/) =>
    `i__const_${importName.replace(/\W/g, '_')}_${importIndex++}`);
 
module.exports = postcss.plugin(
  'postcss-modules-values',
  () => (css, result) => {
    const importAliases = [];
    const definitions = {};
 
    const addDefinition = atRule => {
      let matches;
      while ((matches = matchValueDefinition.exec(atRule.params))) {
        let [, /*match*/ key, value] = matches;
        // Add to the definitions, knowing that values can refer to each other
        definitions[key] = ICSSUtils.replaceValueSymbols(value, definitions);
        atRule.remove();
      }
    };
 
    const addImport = atRule => {
      const matches = matchImports.exec(atRule.params);
      if (matches) {
        let [, /*match*/ aliases, path] = matches;
        // We can use constants for path names
        if (definitions[path]) {
          path = definitions[path];
        }
        const imports = aliases
          .replace(/^\(\s*([\s\S]+)\s*\)$/, '$1')
          .split(/\s*,\s*/)
          .map(alias => {
            const tokens = matchImport.exec(alias);
            if (tokens) {
              const [, /*match*/ theirName, myName = theirName] = tokens;
              const importedName = createImportedName(myName);
              definitions[myName] = importedName;
              return { theirName, importedName };
            } else {
              throw new Error(`@import statement "${alias}" is invalid!`);
            }
          });
        importAliases.push({ path, imports });
        atRule.remove();
      }
    };
 
    /* Look at all the @value statements and treat them as locals or as imports */
    css.walkAtRules('value', atRule => {
      if (matchImports.exec(atRule.params)) {
        addImport(atRule);
      } else {
        if (atRule.params.indexOf('@value') !== -1) {
          result.warn('Invalid value definition: ' + atRule.params);
        }
 
        addDefinition(atRule);
      }
    });
 
    /* We want to export anything defined by now, but don't add it to the CSS yet or
   it well get picked up by the replacement stuff */
    const exportDeclarations = Object.keys(definitions).map(key =>
      postcss.decl({
        value: definitions[key],
        prop: key,
        raws: { before: '\n  ' }
      })
    );
 
    /* If we have no definitions, don't continue */
    if (!Object.keys(definitions).length) {
      return;
    }
 
    /* Perform replacements */
    ICSSUtils.replaceSymbols(css, definitions);
 
    /* Add export rules if any */
    if (exportDeclarations.length > 0) {
      const exportRule = postcss.rule({
        selector: ':export',
        raws: { after: '\n' }
      });
      exportRule.append(exportDeclarations);
      css.prepend(exportRule);
    }
 
    /* Add import rules */
    importAliases.reverse().forEach(({ path, imports }) => {
      const importRule = postcss.rule({
        selector: `:import(${path})`,
        raws: { after: '\n' }
      });
      imports.forEach(({ theirName, importedName }) => {
        importRule.append({
          value: theirName,
          prop: importedName,
          raws: { before: '\n  ' }
        });
      });
 
      css.prepend(importRule);
    });
  }
);