@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
package/lib/index.js ADDED
@@ -0,0 +1,30 @@
1
+ import syntax from './syntax/index.js';
2
+
3
+ export * from './version.js';
4
+ export { default as createSyntax } from './syntax/create.js';
5
+ export { List } from './utils/List.js';
6
+ export { Lexer } from './lexer/Lexer.js';
7
+ export { tokenTypes, tokenNames, TokenStream, OffsetToLocation } from './tokenizer/index.js';
8
+ export * as definitionSyntax from './definition-syntax/index.js';
9
+ export { clone } from './utils/clone.js';
10
+ export * from './utils/names.js';
11
+ export * as ident from './utils/ident.js';
12
+ export * as string from './utils/string.js';
13
+ export * as url from './utils/url.js';
14
+ export const {
15
+ tokenize,
16
+ parse,
17
+ generate,
18
+ lexer,
19
+ createLexer,
20
+
21
+ walk,
22
+ find,
23
+ findLast,
24
+ findAll,
25
+
26
+ toPlainObject,
27
+ fromPlainObject,
28
+
29
+ fork
30
+ } = syntax;
@@ -0,0 +1,511 @@
1
+ import { SyntaxReferenceError, SyntaxMatchError } from './error.js';
2
+ import * as names from '../utils/names.js';
3
+ import { cssWideKeywords } from './generic-const.js';
4
+ import { createGenericTypes } from './generic.js';
5
+ import * as units from './units.js';
6
+ import { parse, generate, walk } from '../definition-syntax/index.js';
7
+ import prepareTokens from './prepare-tokens.js';
8
+ import { buildMatchGraph } from './match-graph.js';
9
+ import { matchAsTree } from './match.js';
10
+ import * as trace from './trace.js';
11
+ import { matchFragments } from './search.js';
12
+ import { getStructureFromConfig } from './structure.js';
13
+
14
+ function dumpMapSyntax(map, compact, syntaxAsAst) {
15
+ const result = {};
16
+
17
+ for (const name in map) {
18
+ if (map[name].syntax) {
19
+ result[name] = syntaxAsAst
20
+ ? map[name].syntax
21
+ : generate(map[name].syntax, { compact });
22
+ }
23
+ }
24
+
25
+ return result;
26
+ }
27
+
28
+ function dumpAtruleMapSyntax(map, compact, syntaxAsAst) {
29
+ const result = {};
30
+
31
+ for (const [name, atrule] of Object.entries(map)) {
32
+ result[name] = {
33
+ prelude: atrule.prelude && (
34
+ syntaxAsAst
35
+ ? atrule.prelude.syntax
36
+ : generate(atrule.prelude.syntax, { compact })
37
+ ),
38
+ descriptors: atrule.descriptors && dumpMapSyntax(atrule.descriptors, compact, syntaxAsAst)
39
+ };
40
+ }
41
+
42
+ return result;
43
+ }
44
+
45
+ function valueHasVar(tokens) {
46
+ for (let i = 0; i < tokens.length; i++) {
47
+ if (tokens[i].value.toLowerCase() === 'var(') {
48
+ return true;
49
+ }
50
+ }
51
+
52
+ return false;
53
+ }
54
+
55
+ function syntaxHasTopLevelCommaMultiplier(syntax) {
56
+ const singleTerm = syntax.terms[0];
57
+
58
+ return (
59
+ syntax.explicit === false &&
60
+ syntax.terms.length === 1 &&
61
+ singleTerm.type === 'Multiplier' &&
62
+ singleTerm.comma === true
63
+ );
64
+ }
65
+
66
+ function buildMatchResult(matched, error, iterations) {
67
+ return {
68
+ matched,
69
+ iterations,
70
+ error,
71
+ ...trace
72
+ };
73
+ }
74
+
75
+ function matchSyntax(lexer, syntax, value, useCssWideKeywords) {
76
+ const tokens = prepareTokens(value, lexer.syntax);
77
+ let result;
78
+
79
+ if (valueHasVar(tokens)) {
80
+ return buildMatchResult(null, new Error('Matching for a tree with var() is not supported'));
81
+ }
82
+
83
+ if (useCssWideKeywords) {
84
+ result = matchAsTree(tokens, lexer.cssWideKeywordsSyntax, lexer);
85
+ }
86
+
87
+ if (!useCssWideKeywords || !result.match) {
88
+ result = matchAsTree(tokens, syntax.match, lexer);
89
+ if (!result.match) {
90
+ return buildMatchResult(
91
+ null,
92
+ new SyntaxMatchError(result.reason, syntax.syntax, value, result),
93
+ result.iterations
94
+ );
95
+ }
96
+ }
97
+
98
+ return buildMatchResult(result.match, null, result.iterations);
99
+ }
100
+
101
+ export class Lexer {
102
+ constructor(config, syntax, structure) {
103
+ this.cssWideKeywords = cssWideKeywords;
104
+ this.syntax = syntax;
105
+ this.generic = false;
106
+ this.units = { ...units };
107
+ this.atrules = Object.create(null);
108
+ this.properties = Object.create(null);
109
+ this.types = Object.create(null);
110
+ this.structure = structure || getStructureFromConfig(config);
111
+
112
+ if (config) {
113
+ if (config.cssWideKeywords) {
114
+ this.cssWideKeywords = config.cssWideKeywords;
115
+ }
116
+
117
+ if (config.units) {
118
+ for (const group of Object.keys(units)) {
119
+ if (Array.isArray(config.units[group])) {
120
+ this.units[group] = config.units[group];
121
+ }
122
+ }
123
+ }
124
+
125
+ if (config.types) {
126
+ for (const [name, type] of Object.entries(config.types)) {
127
+ this.addType_(name, type);
128
+ }
129
+ }
130
+
131
+ if (config.generic) {
132
+ this.generic = true;
133
+ for (const [name, value] of Object.entries(createGenericTypes(this.units))) {
134
+ this.addType_(name, value);
135
+ }
136
+ }
137
+
138
+ if (config.atrules) {
139
+ for (const [name, atrule] of Object.entries(config.atrules)) {
140
+ this.addAtrule_(name, atrule);
141
+ }
142
+ }
143
+
144
+ if (config.properties) {
145
+ for (const [name, property] of Object.entries(config.properties)) {
146
+ this.addProperty_(name, property);
147
+ }
148
+ }
149
+ }
150
+
151
+ this.cssWideKeywordsSyntax = buildMatchGraph(this.cssWideKeywords.join(' | '));
152
+ }
153
+
154
+ checkStructure(ast) {
155
+ function collectWarning(node, message) {
156
+ warns.push({ node, message });
157
+ }
158
+
159
+ const structure = this.structure;
160
+ const warns = [];
161
+
162
+ this.syntax.walk(ast, function(node) {
163
+ if (structure.hasOwnProperty(node.type)) {
164
+ structure[node.type].check(node, collectWarning);
165
+ } else {
166
+ collectWarning(node, 'Unknown node type `' + node.type + '`');
167
+ }
168
+ });
169
+
170
+ return warns.length ? warns : false;
171
+ }
172
+
173
+ createDescriptor(syntax, type, name, parent = null) {
174
+ const ref = {
175
+ type,
176
+ name
177
+ };
178
+ const descriptor = {
179
+ type,
180
+ name,
181
+ parent,
182
+ serializable: typeof syntax === 'string' || (syntax && typeof syntax.type === 'string'),
183
+ syntax: null,
184
+ match: null,
185
+ matchRef: null // used for properties when a syntax referenced as <'property'> in other syntax definitions
186
+ };
187
+
188
+ if (typeof syntax === 'function') {
189
+ descriptor.match = buildMatchGraph(syntax, ref);
190
+ } else {
191
+ if (typeof syntax === 'string') {
192
+ // lazy parsing on first access
193
+ Object.defineProperty(descriptor, 'syntax', {
194
+ get() {
195
+ Object.defineProperty(descriptor, 'syntax', {
196
+ value: parse(syntax)
197
+ });
198
+
199
+ return descriptor.syntax;
200
+ }
201
+ });
202
+ } else {
203
+ descriptor.syntax = syntax;
204
+ }
205
+
206
+ // lazy graph build on first access
207
+ Object.defineProperty(descriptor, 'match', {
208
+ get() {
209
+ Object.defineProperty(descriptor, 'match', {
210
+ value: buildMatchGraph(descriptor.syntax, ref)
211
+ });
212
+
213
+ return descriptor.match;
214
+ }
215
+ });
216
+
217
+ if (type === 'Property') {
218
+ Object.defineProperty(descriptor, 'matchRef', {
219
+ get() {
220
+ const syntax = descriptor.syntax;
221
+ const value = syntaxHasTopLevelCommaMultiplier(syntax)
222
+ ? buildMatchGraph({
223
+ ...syntax,
224
+ terms: [syntax.terms[0].term]
225
+ }, ref)
226
+ : null;
227
+
228
+ Object.defineProperty(descriptor, 'matchRef', {
229
+ value
230
+ });
231
+
232
+ return value;
233
+ }
234
+ });
235
+ }
236
+ }
237
+
238
+ return descriptor;
239
+ }
240
+ addAtrule_(name, syntax) {
241
+ if (!syntax) {
242
+ return;
243
+ }
244
+
245
+ this.atrules[name] = {
246
+ type: 'Atrule',
247
+ name: name,
248
+ prelude: syntax.prelude ? this.createDescriptor(syntax.prelude, 'AtrulePrelude', name) : null,
249
+ descriptors: syntax.descriptors
250
+ ? Object.keys(syntax.descriptors).reduce(
251
+ (map, descName) => {
252
+ map[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name);
253
+ return map;
254
+ },
255
+ Object.create(null)
256
+ )
257
+ : null
258
+ };
259
+ }
260
+ addProperty_(name, syntax) {
261
+ if (!syntax) {
262
+ return;
263
+ }
264
+
265
+ this.properties[name] = this.createDescriptor(syntax, 'Property', name);
266
+ }
267
+ addType_(name, syntax) {
268
+ if (!syntax) {
269
+ return;
270
+ }
271
+
272
+ this.types[name] = this.createDescriptor(syntax, 'Type', name);
273
+ }
274
+
275
+ checkAtruleName(atruleName) {
276
+ if (!this.getAtrule(atruleName)) {
277
+ return new SyntaxReferenceError('Unknown at-rule', '@' + atruleName);
278
+ }
279
+ }
280
+ checkAtrulePrelude(atruleName, prelude) {
281
+ const error = this.checkAtruleName(atruleName);
282
+
283
+ if (error) {
284
+ return error;
285
+ }
286
+
287
+ const atrule = this.getAtrule(atruleName);
288
+
289
+ if (!atrule.prelude && prelude) {
290
+ return new SyntaxError('At-rule `@' + atruleName + '` should not contain a prelude');
291
+ }
292
+
293
+ if (atrule.prelude && !prelude) {
294
+ if (!matchSyntax(this, atrule.prelude, '', false).matched) {
295
+ return new SyntaxError('At-rule `@' + atruleName + '` should contain a prelude');
296
+ }
297
+ }
298
+ }
299
+ checkAtruleDescriptorName(atruleName, descriptorName) {
300
+ const error = this.checkAtruleName(atruleName);
301
+
302
+ if (error) {
303
+ return error;
304
+ }
305
+
306
+ const atrule = this.getAtrule(atruleName);
307
+ const descriptor = names.keyword(descriptorName);
308
+
309
+ if (!atrule.descriptors) {
310
+ return new SyntaxError('At-rule `@' + atruleName + '` has no known descriptors');
311
+ }
312
+
313
+ if (!atrule.descriptors[descriptor.name] &&
314
+ !atrule.descriptors[descriptor.basename]) {
315
+ return new SyntaxReferenceError('Unknown at-rule descriptor', descriptorName);
316
+ }
317
+ }
318
+ checkPropertyName(propertyName) {
319
+ if (!this.getProperty(propertyName)) {
320
+ return new SyntaxReferenceError('Unknown property', propertyName);
321
+ }
322
+ }
323
+
324
+ matchAtrulePrelude(atruleName, prelude) {
325
+ const error = this.checkAtrulePrelude(atruleName, prelude);
326
+
327
+ if (error) {
328
+ return buildMatchResult(null, error);
329
+ }
330
+
331
+ const atrule = this.getAtrule(atruleName);
332
+
333
+ if (!atrule.prelude) {
334
+ return buildMatchResult(null, null);
335
+ }
336
+
337
+ return matchSyntax(this, atrule.prelude, prelude || '', false);
338
+ }
339
+ matchAtruleDescriptor(atruleName, descriptorName, value) {
340
+ const error = this.checkAtruleDescriptorName(atruleName, descriptorName);
341
+
342
+ if (error) {
343
+ return buildMatchResult(null, error);
344
+ }
345
+
346
+ const atrule = this.getAtrule(atruleName);
347
+ const descriptor = names.keyword(descriptorName);
348
+
349
+ return matchSyntax(this, atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename], value, false);
350
+ }
351
+ matchDeclaration(node) {
352
+ if (node.type !== 'Declaration') {
353
+ return buildMatchResult(null, new Error('Not a Declaration node'));
354
+ }
355
+
356
+ return this.matchProperty(node.property, node.value);
357
+ }
358
+ matchProperty(propertyName, value) {
359
+ // don't match syntax for a custom property at the moment
360
+ if (names.property(propertyName).custom) {
361
+ return buildMatchResult(null, new Error('Lexer matching doesn\'t applicable for custom properties'));
362
+ }
363
+
364
+ const error = this.checkPropertyName(propertyName);
365
+
366
+ if (error) {
367
+ return buildMatchResult(null, error);
368
+ }
369
+
370
+ return matchSyntax(this, this.getProperty(propertyName), value, true);
371
+ }
372
+ matchType(typeName, value) {
373
+ const typeSyntax = this.getType(typeName);
374
+
375
+ if (!typeSyntax) {
376
+ return buildMatchResult(null, new SyntaxReferenceError('Unknown type', typeName));
377
+ }
378
+
379
+ return matchSyntax(this, typeSyntax, value, false);
380
+ }
381
+ match(syntax, value) {
382
+ if (typeof syntax !== 'string' && (!syntax || !syntax.type)) {
383
+ return buildMatchResult(null, new SyntaxReferenceError('Bad syntax'));
384
+ }
385
+
386
+ if (typeof syntax === 'string' || !syntax.match) {
387
+ syntax = this.createDescriptor(syntax, 'Type', 'anonymous');
388
+ }
389
+
390
+ return matchSyntax(this, syntax, value, false);
391
+ }
392
+
393
+ findValueFragments(propertyName, value, type, name) {
394
+ return matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
395
+ }
396
+ findDeclarationValueFragments(declaration, type, name) {
397
+ return matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
398
+ }
399
+ findAllFragments(ast, type, name) {
400
+ const result = [];
401
+
402
+ this.syntax.walk(ast, {
403
+ visit: 'Declaration',
404
+ enter: (declaration) => {
405
+ result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name));
406
+ }
407
+ });
408
+
409
+ return result;
410
+ }
411
+
412
+ getAtrule(atruleName, fallbackBasename = true) {
413
+ const atrule = names.keyword(atruleName);
414
+ const atruleEntry = atrule.vendor && fallbackBasename
415
+ ? this.atrules[atrule.name] || this.atrules[atrule.basename]
416
+ : this.atrules[atrule.name];
417
+
418
+ return atruleEntry || null;
419
+ }
420
+ getAtrulePrelude(atruleName, fallbackBasename = true) {
421
+ const atrule = this.getAtrule(atruleName, fallbackBasename);
422
+
423
+ return atrule && atrule.prelude || null;
424
+ }
425
+ getAtruleDescriptor(atruleName, name) {
426
+ return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators
427
+ ? this.atrules[atruleName].declarators[name] || null
428
+ : null;
429
+ }
430
+ getProperty(propertyName, fallbackBasename = true) {
431
+ const property = names.property(propertyName);
432
+ const propertyEntry = property.vendor && fallbackBasename
433
+ ? this.properties[property.name] || this.properties[property.basename]
434
+ : this.properties[property.name];
435
+
436
+ return propertyEntry || null;
437
+ }
438
+ getType(name) {
439
+ return hasOwnProperty.call(this.types, name) ? this.types[name] : null;
440
+ }
441
+
442
+ validate() {
443
+ function syntaxRef(name, isType) {
444
+ return isType ? `<${name}>` : `<'${name}'>`;
445
+ }
446
+
447
+ function validate(syntax, name, broken, descriptor) {
448
+ if (broken.has(name)) {
449
+ return broken.get(name);
450
+ }
451
+
452
+ broken.set(name, false);
453
+ if (descriptor.syntax !== null) {
454
+ walk(descriptor.syntax, function(node) {
455
+ if (node.type !== 'Type' && node.type !== 'Property') {
456
+ return;
457
+ }
458
+
459
+ const map = node.type === 'Type' ? syntax.types : syntax.properties;
460
+ const brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
461
+
462
+ if (!hasOwnProperty.call(map, node.name)) {
463
+ errors.push(`${syntaxRef(name, broken === brokenTypes)} used missed syntax definition ${syntaxRef(node.name, node.type === 'Type')}`);
464
+ broken.set(name, true);
465
+ } else if (validate(syntax, node.name, brokenMap, map[node.name])) {
466
+ errors.push(`${syntaxRef(name, broken === brokenTypes)} used broken syntax definition ${syntaxRef(node.name, node.type === 'Type')}`);
467
+ broken.set(name, true);
468
+ }
469
+ }, this);
470
+ }
471
+ }
472
+
473
+ const errors = [];
474
+ let brokenTypes = new Map();
475
+ let brokenProperties = new Map();
476
+
477
+ for (const key in this.types) {
478
+ validate(this, key, brokenTypes, this.types[key]);
479
+ }
480
+
481
+ for (const key in this.properties) {
482
+ validate(this, key, brokenProperties, this.properties[key]);
483
+ }
484
+
485
+ const brokenTypesArray = [...brokenTypes.keys()].filter(name => brokenTypes.get(name));
486
+ const brokenPropertiesArray = [...brokenProperties.keys()].filter(name => brokenProperties.get(name));
487
+
488
+ if (brokenTypesArray.length || brokenPropertiesArray.length) {
489
+ return {
490
+ errors,
491
+ types: brokenTypesArray,
492
+ properties: brokenPropertiesArray
493
+ };
494
+ }
495
+
496
+ return null;
497
+ }
498
+ dump(syntaxAsAst, pretty) {
499
+ return {
500
+ generic: this.generic,
501
+ cssWideKeywords: this.cssWideKeywords,
502
+ units: this.units,
503
+ types: dumpMapSyntax(this.types, !pretty, syntaxAsAst),
504
+ properties: dumpMapSyntax(this.properties, !pretty, syntaxAsAst),
505
+ atrules: dumpAtruleMapSyntax(this.atrules, !pretty, syntaxAsAst)
506
+ };
507
+ }
508
+ toString() {
509
+ return JSON.stringify(this.dump());
510
+ }
511
+ };
@@ -0,0 +1,123 @@
1
+ import { createCustomError } from '../utils/create-custom-error.js';
2
+ import { generate } from '../definition-syntax/generate.js';
3
+
4
+ const defaultLoc = { offset: 0, line: 1, column: 1 };
5
+
6
+ function locateMismatch(matchResult, node) {
7
+ const tokens = matchResult.tokens;
8
+ const longestMatch = matchResult.longestMatch;
9
+ const mismatchNode = longestMatch < tokens.length ? tokens[longestMatch].node || null : null;
10
+ const badNode = mismatchNode !== node ? mismatchNode : null;
11
+ let mismatchOffset = 0;
12
+ let mismatchLength = 0;
13
+ let entries = 0;
14
+ let css = '';
15
+ let start;
16
+ let end;
17
+
18
+ for (let i = 0; i < tokens.length; i++) {
19
+ const token = tokens[i].value;
20
+
21
+ if (i === longestMatch) {
22
+ mismatchLength = token.length;
23
+ mismatchOffset = css.length;
24
+ }
25
+
26
+ if (badNode !== null && tokens[i].node === badNode) {
27
+ if (i <= longestMatch) {
28
+ entries++;
29
+ } else {
30
+ entries = 0;
31
+ }
32
+ }
33
+
34
+ css += token;
35
+ }
36
+
37
+ if (longestMatch === tokens.length || entries > 1) { // last
38
+ start = fromLoc(badNode || node, 'end') || buildLoc(defaultLoc, css);
39
+ end = buildLoc(start);
40
+ } else {
41
+ start = fromLoc(badNode, 'start') ||
42
+ buildLoc(fromLoc(node, 'start') || defaultLoc, css.slice(0, mismatchOffset));
43
+ end = fromLoc(badNode, 'end') ||
44
+ buildLoc(start, css.substr(mismatchOffset, mismatchLength));
45
+ }
46
+
47
+ return {
48
+ css,
49
+ mismatchOffset,
50
+ mismatchLength,
51
+ start,
52
+ end
53
+ };
54
+ }
55
+
56
+ function fromLoc(node, point) {
57
+ const value = node && node.loc && node.loc[point];
58
+
59
+ if (value) {
60
+ return 'line' in value ? buildLoc(value) : value;
61
+ }
62
+
63
+ return null;
64
+ }
65
+
66
+ function buildLoc({ offset, line, column }, extra) {
67
+ const loc = {
68
+ offset,
69
+ line,
70
+ column
71
+ };
72
+
73
+ if (extra) {
74
+ const lines = extra.split(/\n|\r\n?|\f/);
75
+
76
+ loc.offset += extra.length;
77
+ loc.line += lines.length - 1;
78
+ loc.column = lines.length === 1 ? loc.column + extra.length : lines.pop().length + 1;
79
+ }
80
+
81
+ return loc;
82
+ }
83
+
84
+ export const SyntaxReferenceError = function(type, referenceName) {
85
+ const error = createCustomError(
86
+ 'SyntaxReferenceError',
87
+ type + (referenceName ? ' `' + referenceName + '`' : '')
88
+ );
89
+
90
+ error.reference = referenceName;
91
+
92
+ return error;
93
+ };
94
+
95
+ export const SyntaxMatchError = function(message, syntax, node, matchResult) {
96
+ const error = createCustomError('SyntaxMatchError', message);
97
+ const {
98
+ css,
99
+ mismatchOffset,
100
+ mismatchLength,
101
+ start,
102
+ end
103
+ } = locateMismatch(matchResult, node);
104
+
105
+ error.rawMessage = message;
106
+ error.syntax = syntax ? generate(syntax) : '<generic>';
107
+ error.css = css;
108
+ error.mismatchOffset = mismatchOffset;
109
+ error.mismatchLength = mismatchLength;
110
+ error.message = message + '\n' +
111
+ ' syntax: ' + error.syntax + '\n' +
112
+ ' value: ' + (css || '<empty string>') + '\n' +
113
+ ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
114
+
115
+ Object.assign(error, start);
116
+ error.loc = {
117
+ source: (node && node.loc && node.loc.source) || '<unknown>',
118
+ start,
119
+ end
120
+ };
121
+
122
+ return error;
123
+ };