Blame view

node_modules/postcss-modules-values/src/index.js 3.16 KB
2a09d1a4   liuqimichale   添加宜春 天水 宣化
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
  import postcss from 'postcss'
  import replaceSymbols, {replaceAll} from 'icss-replace-symbols'
  
  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++}`)
  
  export default postcss.plugin('postcss-modules-values', () => (css, result) => {
    let importAliases = []
    let 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] = replaceAll(definitions, value)
        atRule.remove()
      }
    }
  
    const addImport = atRule => {
      let 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]
        let imports = aliases.replace(/^\(\s*([\s\S]+)\s*\)$/, '$1').split(/\s*,\s*/).map(alias => {
          let tokens = matchImport.exec(alias)
          if (tokens) {
            let [/*match*/, theirName, myName = theirName] = tokens
            let 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 */
    let 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 */
    replaceSymbols(css, definitions)
  
    /* Add export rules if any */
    if (exportDeclarations.length > 0) {
      let exportRule = postcss.rule({
        selector: `:export`,
        raws: { after: "\n" }
      })
      exportRule.append(exportDeclarations)
      css.prepend(exportRule)
    }
  
    /* Add import rules */
    importAliases.reverse().forEach(({ path, imports }) => {
      let 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)
    })
  })