1 | import postcss from 'postcss'
|
2 | import replaceSymbols, { replaceAll } from 'icss-replace-symbols'
|
3 |
|
4 | const matchImports = /^(.+?)\s+from\s+("[^"]*"|'[^']*'|[\w-]+)$/
|
5 | const matchValueDefinition = /(?:,\s+|^)([\w-]+):?\s+("[^"]*"|'[^']*'|\w+\([^\)]+\)|[^,]+)\s?/g
|
6 | const matchImport = /^([\w-]+)(?:\s+as\s+([\w-]+))?/
|
7 | let options = {}
|
8 | let importIndex = 0
|
9 | let createImportedName = options && options.createImportedName || ((importName/*, path*/) => `i__const_${importName.replace(/\W/g, '_')}_${importIndex++}`)
|
10 |
|
11 | export default (css, result) => {
|
12 | let importAliases = []
|
13 | let definitions = {}
|
14 |
|
15 | const addDefinition = atRule => {
|
16 | let matches
|
17 | while (matches = matchValueDefinition.exec(atRule.params)) {
|
18 | let [, key, value] = matches
|
19 |
|
20 | definitions[key] = replaceAll(definitions, value)
|
21 | atRule.remove()
|
22 | }
|
23 | }
|
24 |
|
25 | const addImport = atRule => {
|
26 | let matches = matchImports.exec(atRule.params)
|
27 | if (matches) {
|
28 | let [, aliases, path] = matches
|
29 |
|
30 | if (definitions[path]) path = definitions[path]
|
31 | let imports = aliases.split(/\s*,\s*/).map(alias => {
|
32 | let tokens = matchImport.exec(alias)
|
33 | if (tokens) {
|
34 | let [, theirName, myName = theirName] = tokens
|
35 | let importedName = createImportedName(myName)
|
36 | definitions[myName] = importedName
|
37 | return {theirName, importedName}
|
38 | } else {
|
39 | throw new Error(`@import statement "${alias}" is invalid!`)
|
40 | }
|
41 | })
|
42 | importAliases.push({path, imports})
|
43 | atRule.remove()
|
44 | }
|
45 | }
|
46 |
|
47 |
|
48 | css.walkAtRules('value', atRule => {
|
49 | if (matchImports.exec(atRule.params)) {
|
50 | addImport(atRule)
|
51 | } else {
|
52 | if (atRule.params.indexOf('@value') !== -1) {
|
53 | result.warn('Invalid value definition: ' + atRule.params)
|
54 | }
|
55 |
|
56 | addDefinition(atRule)
|
57 | }
|
58 | })
|
59 |
|
60 | |
61 |
|
62 | let exportDeclarations = Object.keys(definitions).map(key => postcss.decl({
|
63 | value: definitions[key],
|
64 | prop: key,
|
65 | raws: { before: "\n " },
|
66 | _autoprefixerDisabled: true
|
67 | }))
|
68 |
|
69 |
|
70 | if (!Object.keys(definitions).length) return
|
71 |
|
72 |
|
73 | replaceSymbols(css, definitions)
|
74 |
|
75 |
|
76 | if (exportDeclarations.length > 0) {
|
77 | css.prepend(postcss.rule({
|
78 | selector: `:export`,
|
79 | raws: { after: "\n" },
|
80 | nodes: exportDeclarations
|
81 | }))
|
82 | }
|
83 |
|
84 |
|
85 | importAliases.reverse().forEach(({path, imports}) => {
|
86 | css.prepend(postcss.rule({
|
87 | selector: `:import(${path})`,
|
88 | raws: { after: "\n" },
|
89 | nodes: imports.map(({theirName, importedName}) => postcss.decl({
|
90 | value: theirName,
|
91 | prop: importedName,
|
92 | raws: { before: "\n " },
|
93 | _autoprefixerDisabled: true
|
94 | }))
|
95 | }))
|
96 | })
|
97 | }
|