sugar-high 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,9 @@
1
1
  // @ts-check
2
+ import {
3
+ T_BREAK, T_CLASS, T_COMMENT, T_IDENTIFIER, T_PROPERTY, T_SIGN, T_SPACE,
4
+ } from '../../shared.js'
5
+ import { tokenize as tokenizePlain } from '../../core.js'
6
+
2
7
  export const keywords = new Set([
3
8
  // css keywords like @media, @import, @keyframes, etc.
4
9
  '@media', '@import', '@keyframes', '@font-face', '@supports', '@page', '@counter-style',
@@ -17,3 +22,121 @@ export const onLiteral = (curr, index, code) => {
17
22
  if (curr !== '#') return 0
18
23
  return code.slice(index).match(/^#(?:[\da-f]{8}|[\da-f]{6}|[\da-f]{4}|[\da-f]{3})(?![\w-])/i)?.[0].length || 0
19
24
  }
25
+
26
+ const isIgnored = (type) => type === T_SPACE || type === T_BREAK || type === T_COMMENT
27
+ const isPropertyPart = ([type, value]) =>
28
+ type === T_IDENTIFIER || type === T_CLASS || (type === T_SIGN && value === '-')
29
+ const isNamePart = ([type]) =>
30
+ type === T_IDENTIFIER || type === T_CLASS || type === T_PROPERTY
31
+ const isNameStart = (token) => isNamePart(token) && !/^\d/.test(token[1])
32
+ const isHyphen = ([type, value]) => type === T_SIGN && value === '-'
33
+
34
+ /**
35
+ * Rejoin CSS dashed identifiers split by the shared punctuation lexer.
36
+ * @param {Array<[number, string]>} tokens
37
+ */
38
+ const mergeDashedNames = (tokens) => {
39
+ for (let index = 0; index < tokens.length; index++) {
40
+ let firstWord = index
41
+ let end = index
42
+
43
+ if (isHyphen(tokens[end])) {
44
+ while (isHyphen(tokens[end])) end++
45
+ if (!tokens[end] || !isNameStart(tokens[end])) continue
46
+ firstWord = end++
47
+ } else if (isNameStart(tokens[end])) {
48
+ end++
49
+ } else {
50
+ continue
51
+ }
52
+
53
+ let dashed = firstWord > index
54
+ while (tokens[end] && isHyphen(tokens[end])) {
55
+ const hyphenStart = end
56
+ while (tokens[end] && isHyphen(tokens[end])) end++
57
+ if (!tokens[end] || !isNamePart(tokens[end])) {
58
+ end = hyphenStart
59
+ break
60
+ }
61
+ dashed = true
62
+ end++
63
+ }
64
+
65
+ if (!dashed) continue
66
+ const name = tokens.slice(index, end).map(([, value]) => value).join('')
67
+ tokens.splice(index, end - index, [tokens[firstWord][0], name])
68
+ }
69
+ }
70
+
71
+ /** Return true when a colon belongs to a nested selector instead of a declaration. */
72
+ const opensBlock = (tokens, start) => {
73
+ let parentheses = 0
74
+ let brackets = 0
75
+ for (let index = start; index < tokens.length; index++) {
76
+ const [type, value] = tokens[index]
77
+ if (type !== T_SIGN) continue
78
+ if (value === '(') parentheses++
79
+ else if (value === ')') parentheses--
80
+ else if (value === '[') brackets++
81
+ else if (value === ']') brackets--
82
+ else if (!parentheses && !brackets && value === '{') return true
83
+ else if (!parentheses && !brackets && (value === ';' || value === '}')) return false
84
+ }
85
+ return false
86
+ }
87
+
88
+ /**
89
+ * Add CSS declaration context after the shared plain lexer runs.
90
+ * @param {string} code
91
+ * @param {import('../../core.js').ParseOptions} options
92
+ */
93
+ export const tokenize = (code, options) => {
94
+ const tokens = tokenizePlain(code, { ...options, tokenize: undefined })
95
+ mergeDashedNames(tokens)
96
+ let blockDepth = 0
97
+ let declarationStart = false
98
+
99
+ for (let index = 0; index < tokens.length; index++) {
100
+ const [type, value] = tokens[index]
101
+
102
+ if (type === T_SIGN && value === '{') {
103
+ blockDepth++
104
+ declarationStart = true
105
+ continue
106
+ }
107
+ if (type === T_SIGN && value === '}') {
108
+ blockDepth--
109
+ declarationStart = false
110
+ continue
111
+ }
112
+ if (type === T_SIGN && value === ';') {
113
+ declarationStart = blockDepth > 0
114
+ continue
115
+ }
116
+ if (!declarationStart || isIgnored(type)) continue
117
+
118
+ const propertyStart = index
119
+ let propertyEnd = index
120
+ while (propertyEnd < tokens.length && isPropertyPart(tokens[propertyEnd])) {
121
+ propertyEnd++
122
+ }
123
+ let colon = propertyEnd
124
+ while (colon < tokens.length && isIgnored(tokens[colon][0])) colon++
125
+
126
+ if (
127
+ propertyEnd > propertyStart &&
128
+ tokens[colon]?.[0] === T_SIGN &&
129
+ tokens[colon][1] === ':' &&
130
+ !opensBlock(tokens, colon + 1)
131
+ ) {
132
+ const property = tokens
133
+ .slice(propertyStart, propertyEnd)
134
+ .map(([, part]) => part)
135
+ .join('')
136
+ tokens.splice(propertyStart, propertyEnd - propertyStart, [T_PROPERTY, property])
137
+ }
138
+ declarationStart = false
139
+ }
140
+
141
+ return tokens
142
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sugar-high",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/huozhi/sugar-high.git",