-
-
Notifications
You must be signed in to change notification settings - Fork 37
/
preprocess.js
118 lines (107 loc) · 2.82 KB
/
preprocess.js
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
function indentError(input, l, p) {
throw input.error('Mixed tabs and spaces are not allowed', l, p + 1)
}
module.exports = function preprocess(input, lines) {
let indentType
let prevNumber = 0
let parts = lines.map(line => {
let lastComma = false
let comment = false
let number = prevNumber + 1
let atrule = false
let indent = ''
let tokens = []
let colon = false
if (line.length > 0) {
if (line[0][0] === 'space') {
indent = line[0][1]
tokens = line.slice(1)
} else {
indent = ''
tokens = line
}
if (!indentType && indent.length) {
indentType = indent[0] === ' ' ? 'space' : 'tab'
}
if (indentType === 'space') {
if (indent.includes('\t')) {
indentError(input, number, indent.indexOf('\t'))
}
} else if (indentType === 'tab') {
if (indent.includes(' ')) {
indentError(input, number, indent.indexOf(' '))
}
}
if (tokens.length) {
for (let i = tokens.length - 1; i >= 0; i--) {
let type = tokens[i][0]
if (type === ',') {
lastComma = true
break
} else if (type === 'space') {
continue
} else if (type === 'comment') {
continue
} else if (type === 'newline') {
continue
} else {
break
}
}
comment = tokens[0][0] === 'comment'
atrule = tokens[0][0] === 'at-word'
let brackets = 0
for (let i = 0; i < tokens.length - 1; i++) {
let type = tokens[i][0]
let next = tokens[i + 1][0]
if (type === '(') {
brackets += 1
} else if (type === ')') {
brackets -= 1
} else if (
type === ':' &&
brackets === 0 &&
(next === 'space' || next === 'newline')
) {
colon = true
}
}
}
let last = tokens[tokens.length - 1]
if (last && last[0] === 'newline') prevNumber = last[2]
}
return {
atrule,
before: '',
colon,
comment,
indent,
lastComma,
number,
tokens
}
})
parts = parts.reduceRight(
(all, i) => {
if (!i.tokens.length || i.tokens.every(j => j[0] === 'newline')) {
let prev = all[0]
let before = i.indent + i.tokens.map(j => j[1]).join('')
prev.before = before + prev.before
} else {
all.unshift(i)
}
return all
},
[{ before: '', end: true }]
)
parts.forEach((part, i) => {
if (i === 0) return
let prev = parts[i - 1]
let last = prev.tokens[prev.tokens.length - 1]
if (last && last[0] === 'newline') {
part.before = last[1] + part.before
prev.tokens.pop()
}
})
return parts
}