@eslint/css-tree 3.2.0

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.
Files changed (279) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +194 -0
  3. package/cjs/convertor/create.cjs +32 -0
  4. package/cjs/convertor/index.cjs +8 -0
  5. package/cjs/data-patch.cjs +7 -0
  6. package/cjs/data.cjs +120 -0
  7. package/cjs/definition-syntax/SyntaxError.cjs +16 -0
  8. package/cjs/definition-syntax/generate.cjs +139 -0
  9. package/cjs/definition-syntax/index.cjs +13 -0
  10. package/cjs/definition-syntax/parse.cjs +556 -0
  11. package/cjs/definition-syntax/scanner.cjs +113 -0
  12. package/cjs/definition-syntax/walk.cjs +57 -0
  13. package/cjs/generator/create.cjs +102 -0
  14. package/cjs/generator/index.cjs +8 -0
  15. package/cjs/generator/sourceMap.cjs +96 -0
  16. package/cjs/generator/token-before.cjs +170 -0
  17. package/cjs/index.cjs +65 -0
  18. package/cjs/lexer/Lexer.cjs +517 -0
  19. package/cjs/lexer/error.cjs +128 -0
  20. package/cjs/lexer/generic-an-plus-b.cjs +235 -0
  21. package/cjs/lexer/generic-const.cjs +12 -0
  22. package/cjs/lexer/generic-urange.cjs +149 -0
  23. package/cjs/lexer/generic.cjs +589 -0
  24. package/cjs/lexer/index.cjs +7 -0
  25. package/cjs/lexer/match-graph.cjs +530 -0
  26. package/cjs/lexer/match.cjs +632 -0
  27. package/cjs/lexer/prepare-tokens.cjs +54 -0
  28. package/cjs/lexer/search.cjs +65 -0
  29. package/cjs/lexer/structure.cjs +173 -0
  30. package/cjs/lexer/trace.cjs +73 -0
  31. package/cjs/lexer/units.cjs +38 -0
  32. package/cjs/parser/SyntaxError.cjs +74 -0
  33. package/cjs/parser/create.cjs +378 -0
  34. package/cjs/parser/index.cjs +8 -0
  35. package/cjs/parser/parse-selector.cjs +8 -0
  36. package/cjs/parser/sequence.cjs +47 -0
  37. package/cjs/syntax/atrule/container.cjs +32 -0
  38. package/cjs/syntax/atrule/font-face.cjs +12 -0
  39. package/cjs/syntax/atrule/import.cjs +101 -0
  40. package/cjs/syntax/atrule/index.cjs +27 -0
  41. package/cjs/syntax/atrule/layer.cjs +16 -0
  42. package/cjs/syntax/atrule/media.cjs +16 -0
  43. package/cjs/syntax/atrule/nest.cjs +16 -0
  44. package/cjs/syntax/atrule/page.cjs +16 -0
  45. package/cjs/syntax/atrule/scope.cjs +16 -0
  46. package/cjs/syntax/atrule/starting-style.cjs +12 -0
  47. package/cjs/syntax/atrule/supports.cjs +16 -0
  48. package/cjs/syntax/config/generator.cjs +9 -0
  49. package/cjs/syntax/config/lexer.cjs +14 -0
  50. package/cjs/syntax/config/mix.cjs +126 -0
  51. package/cjs/syntax/config/parser-selector.cjs +19 -0
  52. package/cjs/syntax/config/parser.cjs +49 -0
  53. package/cjs/syntax/config/walker.cjs +9 -0
  54. package/cjs/syntax/create.cjs +58 -0
  55. package/cjs/syntax/function/expression.cjs +11 -0
  56. package/cjs/syntax/function/var.cjs +43 -0
  57. package/cjs/syntax/index.cjs +14 -0
  58. package/cjs/syntax/node/AnPlusB.cjs +293 -0
  59. package/cjs/syntax/node/Atrule.cjs +103 -0
  60. package/cjs/syntax/node/AtrulePrelude.cjs +52 -0
  61. package/cjs/syntax/node/AttributeSelector.cjs +148 -0
  62. package/cjs/syntax/node/Block.cjs +96 -0
  63. package/cjs/syntax/node/Brackets.cjs +38 -0
  64. package/cjs/syntax/node/CDC.cjs +26 -0
  65. package/cjs/syntax/node/CDO.cjs +26 -0
  66. package/cjs/syntax/node/ClassSelector.cjs +31 -0
  67. package/cjs/syntax/node/Combinator.cjs +61 -0
  68. package/cjs/syntax/node/Comment.cjs +40 -0
  69. package/cjs/syntax/node/Condition.cjs +120 -0
  70. package/cjs/syntax/node/Declaration.cjs +166 -0
  71. package/cjs/syntax/node/DeclarationList.cjs +62 -0
  72. package/cjs/syntax/node/Dimension.cjs +30 -0
  73. package/cjs/syntax/node/Feature.cjs +101 -0
  74. package/cjs/syntax/node/FeatureFunction.cjs +67 -0
  75. package/cjs/syntax/node/FeatureRange.cjs +133 -0
  76. package/cjs/syntax/node/Function.cjs +45 -0
  77. package/cjs/syntax/node/GeneralEnclosed.cjs +68 -0
  78. package/cjs/syntax/node/Hash.cjs +30 -0
  79. package/cjs/syntax/node/IdSelector.cjs +33 -0
  80. package/cjs/syntax/node/Identifier.cjs +25 -0
  81. package/cjs/syntax/node/Layer.cjs +35 -0
  82. package/cjs/syntax/node/LayerList.cjs +43 -0
  83. package/cjs/syntax/node/MediaQuery.cjs +100 -0
  84. package/cjs/syntax/node/MediaQueryList.cjs +41 -0
  85. package/cjs/syntax/node/NestingSelector.cjs +29 -0
  86. package/cjs/syntax/node/Nth.cjs +54 -0
  87. package/cjs/syntax/node/Number.cjs +25 -0
  88. package/cjs/syntax/node/Operator.cjs +28 -0
  89. package/cjs/syntax/node/Parentheses.cjs +38 -0
  90. package/cjs/syntax/node/Percentage.cjs +25 -0
  91. package/cjs/syntax/node/PseudoClassSelector.cjs +67 -0
  92. package/cjs/syntax/node/PseudoElementSelector.cjs +69 -0
  93. package/cjs/syntax/node/Ratio.cjs +71 -0
  94. package/cjs/syntax/node/Raw.cjs +48 -0
  95. package/cjs/syntax/node/Rule.cjs +58 -0
  96. package/cjs/syntax/node/Scope.cjs +69 -0
  97. package/cjs/syntax/node/Selector.cjs +38 -0
  98. package/cjs/syntax/node/SelectorList.cjs +43 -0
  99. package/cjs/syntax/node/String.cjs +26 -0
  100. package/cjs/syntax/node/StyleSheet.cjs +83 -0
  101. package/cjs/syntax/node/SupportsDeclaration.cjs +38 -0
  102. package/cjs/syntax/node/TypeSelector.cjs +59 -0
  103. package/cjs/syntax/node/UnicodeRange.cjs +158 -0
  104. package/cjs/syntax/node/Url.cjs +54 -0
  105. package/cjs/syntax/node/Value.cjs +26 -0
  106. package/cjs/syntax/node/WhiteSpace.cjs +34 -0
  107. package/cjs/syntax/node/index-generate.cjs +103 -0
  108. package/cjs/syntax/node/index-parse-selector.cjs +39 -0
  109. package/cjs/syntax/node/index-parse.cjs +103 -0
  110. package/cjs/syntax/node/index.cjs +103 -0
  111. package/cjs/syntax/pseudo/index.cjs +60 -0
  112. package/cjs/syntax/pseudo/lang.cjs +37 -0
  113. package/cjs/syntax/scope/atrulePrelude.cjs +9 -0
  114. package/cjs/syntax/scope/default.cjs +76 -0
  115. package/cjs/syntax/scope/index.cjs +11 -0
  116. package/cjs/syntax/scope/selector.cjs +88 -0
  117. package/cjs/syntax/scope/value.cjs +29 -0
  118. package/cjs/tokenizer/OffsetToLocation.cjs +91 -0
  119. package/cjs/tokenizer/TokenStream.cjs +358 -0
  120. package/cjs/tokenizer/adopt-buffer.cjs +13 -0
  121. package/cjs/tokenizer/char-code-definitions.cjs +236 -0
  122. package/cjs/tokenizer/index.cjs +554 -0
  123. package/cjs/tokenizer/names.cjs +32 -0
  124. package/cjs/tokenizer/types.cjs +57 -0
  125. package/cjs/tokenizer/utils.cjs +261 -0
  126. package/cjs/utils/List.cjs +473 -0
  127. package/cjs/utils/clone.cjs +25 -0
  128. package/cjs/utils/create-custom-error.cjs +18 -0
  129. package/cjs/utils/ident.cjs +102 -0
  130. package/cjs/utils/index.cjs +20 -0
  131. package/cjs/utils/names.cjs +113 -0
  132. package/cjs/utils/string.cjs +99 -0
  133. package/cjs/utils/url.cjs +108 -0
  134. package/cjs/version.cjs +5 -0
  135. package/cjs/walker/create.cjs +291 -0
  136. package/cjs/walker/index.cjs +8 -0
  137. package/data/patch.json +874 -0
  138. package/dist/csstree.esm.js +12 -0
  139. package/dist/csstree.js +12 -0
  140. package/dist/data.cjs +1341 -0
  141. package/dist/data.js +1341 -0
  142. package/dist/version.cjs +1 -0
  143. package/dist/version.js +1 -0
  144. package/lib/convertor/create.js +28 -0
  145. package/lib/convertor/index.js +4 -0
  146. package/lib/data-patch.js +6 -0
  147. package/lib/data.js +118 -0
  148. package/lib/definition-syntax/SyntaxError.js +12 -0
  149. package/lib/definition-syntax/generate.js +135 -0
  150. package/lib/definition-syntax/index.js +4 -0
  151. package/lib/definition-syntax/parse.js +552 -0
  152. package/lib/definition-syntax/scanner.js +109 -0
  153. package/lib/definition-syntax/walk.js +53 -0
  154. package/lib/generator/create.js +97 -0
  155. package/lib/generator/index.js +4 -0
  156. package/lib/generator/sourceMap.js +92 -0
  157. package/lib/generator/token-before.js +182 -0
  158. package/lib/index.d.ts +3016 -0
  159. package/lib/index.js +30 -0
  160. package/lib/lexer/Lexer.js +511 -0
  161. package/lib/lexer/error.js +123 -0
  162. package/lib/lexer/generic-an-plus-b.js +238 -0
  163. package/lib/lexer/generic-const.js +8 -0
  164. package/lib/lexer/generic-urange.js +151 -0
  165. package/lib/lexer/generic.js +622 -0
  166. package/lib/lexer/index.js +1 -0
  167. package/lib/lexer/match-graph.js +527 -0
  168. package/lib/lexer/match.js +630 -0
  169. package/lib/lexer/prepare-tokens.js +50 -0
  170. package/lib/lexer/search.js +61 -0
  171. package/lib/lexer/structure.js +169 -0
  172. package/lib/lexer/trace.js +66 -0
  173. package/lib/lexer/units.js +27 -0
  174. package/lib/parser/SyntaxError.js +70 -0
  175. package/lib/parser/create.js +388 -0
  176. package/lib/parser/index.js +4 -0
  177. package/lib/parser/parse-selector.js +4 -0
  178. package/lib/parser/sequence.js +43 -0
  179. package/lib/syntax/atrule/container.js +28 -0
  180. package/lib/syntax/atrule/font-face.js +8 -0
  181. package/lib/syntax/atrule/import.js +104 -0
  182. package/lib/syntax/atrule/index.js +23 -0
  183. package/lib/syntax/atrule/layer.js +12 -0
  184. package/lib/syntax/atrule/media.js +12 -0
  185. package/lib/syntax/atrule/nest.js +12 -0
  186. package/lib/syntax/atrule/page.js +12 -0
  187. package/lib/syntax/atrule/scope.js +12 -0
  188. package/lib/syntax/atrule/starting-style.js +8 -0
  189. package/lib/syntax/atrule/supports.js +12 -0
  190. package/lib/syntax/config/generator.js +5 -0
  191. package/lib/syntax/config/lexer.js +10 -0
  192. package/lib/syntax/config/mix.js +122 -0
  193. package/lib/syntax/config/parser-selector.js +15 -0
  194. package/lib/syntax/config/parser.js +45 -0
  195. package/lib/syntax/config/walker.js +5 -0
  196. package/lib/syntax/create.js +55 -0
  197. package/lib/syntax/function/expression.js +7 -0
  198. package/lib/syntax/function/var.js +39 -0
  199. package/lib/syntax/index.js +10 -0
  200. package/lib/syntax/node/AnPlusB.js +292 -0
  201. package/lib/syntax/node/Atrule.js +100 -0
  202. package/lib/syntax/node/AtrulePrelude.js +47 -0
  203. package/lib/syntax/node/AttributeSelector.js +147 -0
  204. package/lib/syntax/node/Block.js +95 -0
  205. package/lib/syntax/node/Brackets.js +35 -0
  206. package/lib/syntax/node/CDC.js +19 -0
  207. package/lib/syntax/node/CDO.js +19 -0
  208. package/lib/syntax/node/ClassSelector.js +24 -0
  209. package/lib/syntax/node/Combinator.js +54 -0
  210. package/lib/syntax/node/Comment.js +33 -0
  211. package/lib/syntax/node/Condition.js +123 -0
  212. package/lib/syntax/node/Declaration.js +165 -0
  213. package/lib/syntax/node/DeclarationList.js +62 -0
  214. package/lib/syntax/node/Dimension.js +23 -0
  215. package/lib/syntax/node/Feature.js +103 -0
  216. package/lib/syntax/node/FeatureFunction.js +63 -0
  217. package/lib/syntax/node/FeatureRange.js +133 -0
  218. package/lib/syntax/node/Function.js +41 -0
  219. package/lib/syntax/node/GeneralEnclosed.js +66 -0
  220. package/lib/syntax/node/Hash.js +23 -0
  221. package/lib/syntax/node/IdSelector.js +26 -0
  222. package/lib/syntax/node/Identifier.js +18 -0
  223. package/lib/syntax/node/Layer.js +28 -0
  224. package/lib/syntax/node/LayerList.js +36 -0
  225. package/lib/syntax/node/MediaQuery.js +102 -0
  226. package/lib/syntax/node/MediaQueryList.js +34 -0
  227. package/lib/syntax/node/NestingSelector.js +22 -0
  228. package/lib/syntax/node/Nth.js +47 -0
  229. package/lib/syntax/node/Number.js +18 -0
  230. package/lib/syntax/node/Operator.js +21 -0
  231. package/lib/syntax/node/Parentheses.js +34 -0
  232. package/lib/syntax/node/Percentage.js +18 -0
  233. package/lib/syntax/node/PseudoClassSelector.js +65 -0
  234. package/lib/syntax/node/PseudoElementSelector.js +66 -0
  235. package/lib/syntax/node/Ratio.js +68 -0
  236. package/lib/syntax/node/Raw.js +41 -0
  237. package/lib/syntax/node/Rule.js +51 -0
  238. package/lib/syntax/node/Scope.js +66 -0
  239. package/lib/syntax/node/Selector.js +31 -0
  240. package/lib/syntax/node/SelectorList.js +35 -0
  241. package/lib/syntax/node/String.js +19 -0
  242. package/lib/syntax/node/StyleSheet.js +82 -0
  243. package/lib/syntax/node/SupportsDeclaration.js +34 -0
  244. package/lib/syntax/node/TypeSelector.js +52 -0
  245. package/lib/syntax/node/UnicodeRange.js +156 -0
  246. package/lib/syntax/node/Url.js +52 -0
  247. package/lib/syntax/node/Value.js +19 -0
  248. package/lib/syntax/node/WhiteSpace.js +27 -0
  249. package/lib/syntax/node/index-generate.js +49 -0
  250. package/lib/syntax/node/index-parse-selector.js +17 -0
  251. package/lib/syntax/node/index-parse.js +49 -0
  252. package/lib/syntax/node/index.js +49 -0
  253. package/lib/syntax/pseudo/index.js +56 -0
  254. package/lib/syntax/pseudo/lang.js +33 -0
  255. package/lib/syntax/scope/atrulePrelude.js +5 -0
  256. package/lib/syntax/scope/default.js +85 -0
  257. package/lib/syntax/scope/index.js +3 -0
  258. package/lib/syntax/scope/selector.js +94 -0
  259. package/lib/syntax/scope/value.js +25 -0
  260. package/lib/tokenizer/OffsetToLocation.js +87 -0
  261. package/lib/tokenizer/TokenStream.js +366 -0
  262. package/lib/tokenizer/adopt-buffer.js +9 -0
  263. package/lib/tokenizer/char-code-definitions.js +212 -0
  264. package/lib/tokenizer/index.js +513 -0
  265. package/lib/tokenizer/names.js +28 -0
  266. package/lib/tokenizer/types.js +28 -0
  267. package/lib/tokenizer/utils.js +254 -0
  268. package/lib/utils/List.js +469 -0
  269. package/lib/utils/clone.js +21 -0
  270. package/lib/utils/create-custom-error.js +14 -0
  271. package/lib/utils/ident.js +101 -0
  272. package/lib/utils/index.js +6 -0
  273. package/lib/utils/names.js +106 -0
  274. package/lib/utils/string.js +99 -0
  275. package/lib/utils/url.js +108 -0
  276. package/lib/version.js +5 -0
  277. package/lib/walker/create.js +287 -0
  278. package/lib/walker/index.js +4 -0
  279. package/package.json +133 -0
@@ -0,0 +1,530 @@
1
+ 'use strict';
2
+
3
+ const parse = require('../definition-syntax/parse.cjs');
4
+
5
+ const MATCH = { type: 'Match' };
6
+ const MISMATCH = { type: 'Mismatch' };
7
+ const DISALLOW_EMPTY = { type: 'DisallowEmpty' };
8
+
9
+ const LEFTPARENTHESIS = 40; // (
10
+ const RIGHTPARENTHESIS = 41; // )
11
+
12
+ function createCondition(match, thenBranch, elseBranch) {
13
+ // reduce node count
14
+ if (thenBranch === MATCH && elseBranch === MISMATCH) {
15
+ return match;
16
+ }
17
+
18
+ if (match === MATCH && thenBranch === MATCH && elseBranch === MATCH) {
19
+ return match;
20
+ }
21
+
22
+ if (match.type === 'If' && match.else === MISMATCH && thenBranch === MATCH) {
23
+ thenBranch = match.then;
24
+ match = match.match;
25
+ }
26
+
27
+ return {
28
+ type: 'If',
29
+ match,
30
+ then: thenBranch,
31
+ else: elseBranch
32
+ };
33
+ }
34
+
35
+ function isFunctionType(name) {
36
+ return (
37
+ name.length > 2 &&
38
+ name.charCodeAt(name.length - 2) === LEFTPARENTHESIS &&
39
+ name.charCodeAt(name.length - 1) === RIGHTPARENTHESIS
40
+ );
41
+ }
42
+
43
+ function isEnumCapatible(term) {
44
+ return (
45
+ term.type === 'Keyword' ||
46
+ term.type === 'AtKeyword' ||
47
+ term.type === 'Function' ||
48
+ term.type === 'Type' && isFunctionType(term.name)
49
+ );
50
+ }
51
+
52
+ function groupNode(terms, combinator = ' ', explicit = false) {
53
+ return {
54
+ type: 'Group',
55
+ terms,
56
+ combinator,
57
+ disallowEmpty: false,
58
+ explicit
59
+ };
60
+ }
61
+
62
+ function replaceTypeInGraph(node, replacements, visited = new Set()) {
63
+ if (!visited.has(node)) {
64
+ visited.add(node);
65
+
66
+ switch (node.type) {
67
+ case 'If':
68
+ node.match = replaceTypeInGraph(node.match, replacements, visited);
69
+ node.then = replaceTypeInGraph(node.then, replacements, visited);
70
+ node.else = replaceTypeInGraph(node.else, replacements, visited);
71
+ break;
72
+
73
+ case 'Type':
74
+ return replacements[node.name] || node;
75
+ }
76
+ }
77
+
78
+ return node;
79
+ }
80
+
81
+ function buildGroupMatchGraph(combinator, terms, atLeastOneTermMatched) {
82
+ switch (combinator) {
83
+ case ' ': {
84
+ // Juxtaposing components means that all of them must occur, in the given order.
85
+ //
86
+ // a b c
87
+ // =
88
+ // match a
89
+ // then match b
90
+ // then match c
91
+ // then MATCH
92
+ // else MISMATCH
93
+ // else MISMATCH
94
+ // else MISMATCH
95
+ let result = MATCH;
96
+
97
+ for (let i = terms.length - 1; i >= 0; i--) {
98
+ const term = terms[i];
99
+
100
+ result = createCondition(
101
+ term,
102
+ result,
103
+ MISMATCH
104
+ );
105
+ }
106
+ return result;
107
+ }
108
+
109
+ case '|': {
110
+ // A bar (|) separates two or more alternatives: exactly one of them must occur.
111
+ //
112
+ // a | b | c
113
+ // =
114
+ // match a
115
+ // then MATCH
116
+ // else match b
117
+ // then MATCH
118
+ // else match c
119
+ // then MATCH
120
+ // else MISMATCH
121
+
122
+ let result = MISMATCH;
123
+ let map = null;
124
+
125
+ for (let i = terms.length - 1; i >= 0; i--) {
126
+ let term = terms[i];
127
+
128
+ // reduce sequence of keywords into a Enum
129
+ if (isEnumCapatible(term)) {
130
+ if (map === null && i > 0 && isEnumCapatible(terms[i - 1])) {
131
+ map = Object.create(null);
132
+ result = createCondition(
133
+ {
134
+ type: 'Enum',
135
+ map
136
+ },
137
+ MATCH,
138
+ result
139
+ );
140
+ }
141
+
142
+ if (map !== null) {
143
+ const key = (isFunctionType(term.name) ? term.name.slice(0, -1) : term.name).toLowerCase();
144
+ if (key in map === false) {
145
+ map[key] = term;
146
+ continue;
147
+ }
148
+ }
149
+ }
150
+
151
+ map = null;
152
+
153
+ // create a new conditonal node
154
+ result = createCondition(
155
+ term,
156
+ MATCH,
157
+ result
158
+ );
159
+ }
160
+ return result;
161
+ }
162
+
163
+ case '&&': {
164
+ // A double ampersand (&&) separates two or more components,
165
+ // all of which must occur, in any order.
166
+
167
+ // Use MatchOnce for groups with a large number of terms,
168
+ // since &&-groups produces at least N!-node trees
169
+ if (terms.length > 5) {
170
+ return {
171
+ type: 'MatchOnce',
172
+ terms,
173
+ all: true
174
+ };
175
+ }
176
+
177
+ // Use a combination tree for groups with small number of terms
178
+ //
179
+ // a && b && c
180
+ // =
181
+ // match a
182
+ // then [b && c]
183
+ // else match b
184
+ // then [a && c]
185
+ // else match c
186
+ // then [a && b]
187
+ // else MISMATCH
188
+ //
189
+ // a && b
190
+ // =
191
+ // match a
192
+ // then match b
193
+ // then MATCH
194
+ // else MISMATCH
195
+ // else match b
196
+ // then match a
197
+ // then MATCH
198
+ // else MISMATCH
199
+ // else MISMATCH
200
+ let result = MISMATCH;
201
+
202
+ for (let i = terms.length - 1; i >= 0; i--) {
203
+ const term = terms[i];
204
+ let thenClause;
205
+
206
+ if (terms.length > 1) {
207
+ thenClause = buildGroupMatchGraph(
208
+ combinator,
209
+ terms.filter(function(newGroupTerm) {
210
+ return newGroupTerm !== term;
211
+ }),
212
+ false
213
+ );
214
+ } else {
215
+ thenClause = MATCH;
216
+ }
217
+
218
+ result = createCondition(
219
+ term,
220
+ thenClause,
221
+ result
222
+ );
223
+ }
224
+ return result;
225
+ }
226
+
227
+ case '||': {
228
+ // A double bar (||) separates two or more options:
229
+ // one or more of them must occur, in any order.
230
+
231
+ // Use MatchOnce for groups with a large number of terms,
232
+ // since ||-groups produces at least N!-node trees
233
+ if (terms.length > 5) {
234
+ return {
235
+ type: 'MatchOnce',
236
+ terms,
237
+ all: false
238
+ };
239
+ }
240
+
241
+ // Use a combination tree for groups with small number of terms
242
+ //
243
+ // a || b || c
244
+ // =
245
+ // match a
246
+ // then [b || c]
247
+ // else match b
248
+ // then [a || c]
249
+ // else match c
250
+ // then [a || b]
251
+ // else MISMATCH
252
+ //
253
+ // a || b
254
+ // =
255
+ // match a
256
+ // then match b
257
+ // then MATCH
258
+ // else MATCH
259
+ // else match b
260
+ // then match a
261
+ // then MATCH
262
+ // else MATCH
263
+ // else MISMATCH
264
+ let result = atLeastOneTermMatched ? MATCH : MISMATCH;
265
+
266
+ for (let i = terms.length - 1; i >= 0; i--) {
267
+ const term = terms[i];
268
+ let thenClause;
269
+
270
+ if (terms.length > 1) {
271
+ thenClause = buildGroupMatchGraph(
272
+ combinator,
273
+ terms.filter(function(newGroupTerm) {
274
+ return newGroupTerm !== term;
275
+ }),
276
+ true
277
+ );
278
+ } else {
279
+ thenClause = MATCH;
280
+ }
281
+
282
+ result = createCondition(
283
+ term,
284
+ thenClause,
285
+ result
286
+ );
287
+ }
288
+ return result;
289
+ }
290
+ }
291
+ }
292
+
293
+ function buildMultiplierMatchGraph(node) {
294
+ let result = MATCH;
295
+ let matchTerm = buildMatchGraphInternal(node.term);
296
+
297
+ if (node.max === 0) {
298
+ // disable repeating of empty match to prevent infinite loop
299
+ matchTerm = createCondition(
300
+ matchTerm,
301
+ DISALLOW_EMPTY,
302
+ MISMATCH
303
+ );
304
+
305
+ // an occurrence count is not limited, make a cycle;
306
+ // to collect more terms on each following matching mismatch
307
+ result = createCondition(
308
+ matchTerm,
309
+ null, // will be a loop
310
+ MISMATCH
311
+ );
312
+
313
+ result.then = createCondition(
314
+ MATCH,
315
+ MATCH,
316
+ result // make a loop
317
+ );
318
+
319
+ if (node.comma) {
320
+ result.then.else = createCondition(
321
+ { type: 'Comma', syntax: node },
322
+ result,
323
+ MISMATCH
324
+ );
325
+ }
326
+ } else {
327
+ // create a match node chain for [min .. max] interval with optional matches
328
+ for (let i = node.min || 1; i <= node.max; i++) {
329
+ if (node.comma && result !== MATCH) {
330
+ result = createCondition(
331
+ { type: 'Comma', syntax: node },
332
+ result,
333
+ MISMATCH
334
+ );
335
+ }
336
+
337
+ result = createCondition(
338
+ matchTerm,
339
+ createCondition(
340
+ MATCH,
341
+ MATCH,
342
+ result
343
+ ),
344
+ MISMATCH
345
+ );
346
+ }
347
+ }
348
+
349
+ if (node.min === 0) {
350
+ // allow zero match
351
+ result = createCondition(
352
+ MATCH,
353
+ MATCH,
354
+ result
355
+ );
356
+ } else {
357
+ // create a match node chain to collect [0 ... min - 1] required matches
358
+ for (let i = 0; i < node.min - 1; i++) {
359
+ if (node.comma && result !== MATCH) {
360
+ result = createCondition(
361
+ { type: 'Comma', syntax: node },
362
+ result,
363
+ MISMATCH
364
+ );
365
+ }
366
+
367
+ result = createCondition(
368
+ matchTerm,
369
+ result,
370
+ MISMATCH
371
+ );
372
+ }
373
+ }
374
+
375
+ return result;
376
+ }
377
+
378
+ function buildMatchGraphInternal(node) {
379
+ if (typeof node === 'function') {
380
+ return {
381
+ type: 'Generic',
382
+ fn: node
383
+ };
384
+ }
385
+
386
+ switch (node.type) {
387
+ case 'Group': {
388
+ let result = buildGroupMatchGraph(
389
+ node.combinator,
390
+ node.terms.map(buildMatchGraphInternal),
391
+ false
392
+ );
393
+
394
+ if (node.disallowEmpty) {
395
+ result = createCondition(
396
+ result,
397
+ DISALLOW_EMPTY,
398
+ MISMATCH
399
+ );
400
+ }
401
+
402
+ return result;
403
+ }
404
+
405
+ case 'Multiplier':
406
+ return buildMultiplierMatchGraph(node);
407
+
408
+ // https://drafts.csswg.org/css-values-5/#boolean
409
+ case 'Boolean': {
410
+ const term = buildMatchGraphInternal(node.term);
411
+ // <boolean-expr[ <test> ]> = not <boolean-expr-group> | <boolean-expr-group> [ [ and <boolean-expr-group> ]* | [ or <boolean-expr-group> ]* ]
412
+ const matchNode = buildMatchGraphInternal(groupNode([
413
+ groupNode([
414
+ { type: 'Keyword', name: 'not' },
415
+ { type: 'Type', name: '!boolean-group' }
416
+ ]),
417
+ groupNode([
418
+ { type: 'Type', name: '!boolean-group' },
419
+ groupNode([
420
+ { type: 'Multiplier', comma: false, min: 0, max: 0, term: groupNode([
421
+ { type: 'Keyword', name: 'and' },
422
+ { type: 'Type', name: '!boolean-group' }
423
+ ]) },
424
+ { type: 'Multiplier', comma: false, min: 0, max: 0, term: groupNode([
425
+ { type: 'Keyword', name: 'or' },
426
+ { type: 'Type', name: '!boolean-group' }
427
+ ]) }
428
+ ], '|')
429
+ ])
430
+ ], '|'));
431
+ // <boolean-expr-group> = <test> | ( <boolean-expr[ <test> ]> ) | <general-enclosed>
432
+ const booleanGroup = buildMatchGraphInternal(
433
+ groupNode([
434
+ { type: 'Type', name: '!term' },
435
+ groupNode([
436
+ { type: 'Token', value: '(' },
437
+ { type: 'Type', name: '!self' },
438
+ { type: 'Token', value: ')' }
439
+ ]),
440
+ { type: 'Type', name: 'general-enclosed' }
441
+ ], '|')
442
+ );
443
+
444
+ replaceTypeInGraph(booleanGroup, { '!term': term, '!self': matchNode });
445
+ replaceTypeInGraph(matchNode, { '!boolean-group': booleanGroup });
446
+
447
+ return matchNode;
448
+ }
449
+
450
+ case 'Type':
451
+ case 'Property':
452
+ return {
453
+ type: node.type,
454
+ name: node.name,
455
+ syntax: node
456
+ };
457
+
458
+ case 'Keyword':
459
+ return {
460
+ type: node.type,
461
+ name: node.name.toLowerCase(),
462
+ syntax: node
463
+ };
464
+
465
+ case 'AtKeyword':
466
+ return {
467
+ type: node.type,
468
+ name: '@' + node.name.toLowerCase(),
469
+ syntax: node
470
+ };
471
+
472
+ case 'Function':
473
+ return {
474
+ type: node.type,
475
+ name: node.name.toLowerCase() + '(',
476
+ syntax: node
477
+ };
478
+
479
+ case 'String':
480
+ // convert a one char length String to a Token
481
+ if (node.value.length === 3) {
482
+ return {
483
+ type: 'Token',
484
+ value: node.value.charAt(1),
485
+ syntax: node
486
+ };
487
+ }
488
+
489
+ // otherwise use it as is
490
+ return {
491
+ type: node.type,
492
+ value: node.value.substr(1, node.value.length - 2).replace(/\\'/g, '\''),
493
+ syntax: node
494
+ };
495
+
496
+ case 'Token':
497
+ return {
498
+ type: node.type,
499
+ value: node.value,
500
+ syntax: node
501
+ };
502
+
503
+ case 'Comma':
504
+ return {
505
+ type: node.type,
506
+ syntax: node
507
+ };
508
+
509
+ default:
510
+ throw new Error('Unknown node type:', node.type);
511
+ }
512
+ }
513
+
514
+ function buildMatchGraph(syntaxTree, ref) {
515
+ if (typeof syntaxTree === 'string') {
516
+ syntaxTree = parse.parse(syntaxTree);
517
+ }
518
+
519
+ return {
520
+ type: 'MatchGraph',
521
+ match: buildMatchGraphInternal(syntaxTree),
522
+ syntax: ref || null,
523
+ source: syntaxTree
524
+ };
525
+ }
526
+
527
+ exports.DISALLOW_EMPTY = DISALLOW_EMPTY;
528
+ exports.MATCH = MATCH;
529
+ exports.MISMATCH = MISMATCH;
530
+ exports.buildMatchGraph = buildMatchGraph;