@dazl/shorthands-opener 4.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 (237) hide show
  1. package/README.md +3 -0
  2. package/dist/compounds/compound-css-data.d.ts +22 -0
  3. package/dist/compounds/compound-css-data.d.ts.map +1 -0
  4. package/dist/compounds/compound-css-data.js +2 -0
  5. package/dist/compounds/compound-css-data.js.map +1 -0
  6. package/dist/compounds/compound-mapper.d.ts +4 -0
  7. package/dist/compounds/compound-mapper.d.ts.map +1 -0
  8. package/dist/compounds/compound-mapper.js +10 -0
  9. package/dist/compounds/compound-mapper.js.map +1 -0
  10. package/dist/compounds/compound-parser-utils.d.ts +3 -0
  11. package/dist/compounds/compound-parser-utils.d.ts.map +1 -0
  12. package/dist/compounds/compound-parser-utils.js +33 -0
  13. package/dist/compounds/compound-parser-utils.js.map +1 -0
  14. package/dist/compounds/compound-types.d.ts +26 -0
  15. package/dist/compounds/compound-types.d.ts.map +1 -0
  16. package/dist/compounds/compound-types.js +2 -0
  17. package/dist/compounds/compound-types.js.map +1 -0
  18. package/dist/compounds/compound-value-parsers.d.ts +6 -0
  19. package/dist/compounds/compound-value-parsers.d.ts.map +1 -0
  20. package/dist/compounds/compound-value-parsers.js +5 -0
  21. package/dist/compounds/compound-value-parsers.js.map +1 -0
  22. package/dist/compounds/index.d.ts +6 -0
  23. package/dist/compounds/index.d.ts.map +1 -0
  24. package/dist/compounds/index.js +6 -0
  25. package/dist/compounds/index.js.map +1 -0
  26. package/dist/compounds/parsers/index.d.ts +2 -0
  27. package/dist/compounds/parsers/index.d.ts.map +1 -0
  28. package/dist/compounds/parsers/index.js +2 -0
  29. package/dist/compounds/parsers/index.js.map +1 -0
  30. package/dist/compounds/parsers/shadow-compound.d.ts +5 -0
  31. package/dist/compounds/parsers/shadow-compound.d.ts.map +1 -0
  32. package/dist/compounds/parsers/shadow-compound.js +39 -0
  33. package/dist/compounds/parsers/shadow-compound.js.map +1 -0
  34. package/dist/css-data-types/data-types-consts.d.ts +212 -0
  35. package/dist/css-data-types/data-types-consts.d.ts.map +1 -0
  36. package/dist/css-data-types/data-types-consts.js +790 -0
  37. package/dist/css-data-types/data-types-consts.js.map +1 -0
  38. package/dist/css-data-types/data-types-predicates.d.ts +32 -0
  39. package/dist/css-data-types/data-types-predicates.d.ts.map +1 -0
  40. package/dist/css-data-types/data-types-predicates.js +353 -0
  41. package/dist/css-data-types/data-types-predicates.js.map +1 -0
  42. package/dist/css-data-types/data-types-state-machines.d.ts +14 -0
  43. package/dist/css-data-types/data-types-state-machines.d.ts.map +1 -0
  44. package/dist/css-data-types/data-types-state-machines.js +129 -0
  45. package/dist/css-data-types/data-types-state-machines.js.map +1 -0
  46. package/dist/css-data-types/data-types-types.d.ts +26 -0
  47. package/dist/css-data-types/data-types-types.d.ts.map +1 -0
  48. package/dist/css-data-types/data-types-types.js +2 -0
  49. package/dist/css-data-types/data-types-types.js.map +1 -0
  50. package/dist/css-data-types/data-types-utils.d.ts +31 -0
  51. package/dist/css-data-types/data-types-utils.d.ts.map +1 -0
  52. package/dist/css-data-types/data-types-utils.js +176 -0
  53. package/dist/css-data-types/data-types-utils.js.map +1 -0
  54. package/dist/css-data-types/data-types.d.ts +64 -0
  55. package/dist/css-data-types/data-types.d.ts.map +1 -0
  56. package/dist/css-data-types/data-types.js +304 -0
  57. package/dist/css-data-types/data-types.js.map +1 -0
  58. package/dist/css-data-types/index.d.ts +7 -0
  59. package/dist/css-data-types/index.d.ts.map +1 -0
  60. package/dist/css-data-types/index.js +7 -0
  61. package/dist/css-data-types/index.js.map +1 -0
  62. package/dist/index.d.ts +5 -0
  63. package/dist/index.d.ts.map +1 -0
  64. package/dist/index.js +5 -0
  65. package/dist/index.js.map +1 -0
  66. package/dist/shorthands/index.d.ts +8 -0
  67. package/dist/shorthands/index.d.ts.map +1 -0
  68. package/dist/shorthands/index.js +8 -0
  69. package/dist/shorthands/index.js.map +1 -0
  70. package/dist/shorthands/openers/background-position-shorthand.d.ts +5 -0
  71. package/dist/shorthands/openers/background-position-shorthand.d.ts.map +1 -0
  72. package/dist/shorthands/openers/background-position-shorthand.js +173 -0
  73. package/dist/shorthands/openers/background-position-shorthand.js.map +1 -0
  74. package/dist/shorthands/openers/background-shorthand.d.ts +5 -0
  75. package/dist/shorthands/openers/background-shorthand.d.ts.map +1 -0
  76. package/dist/shorthands/openers/background-shorthand.js +88 -0
  77. package/dist/shorthands/openers/background-shorthand.js.map +1 -0
  78. package/dist/shorthands/openers/border-image-shorthand.d.ts +5 -0
  79. package/dist/shorthands/openers/border-image-shorthand.d.ts.map +1 -0
  80. package/dist/shorthands/openers/border-image-shorthand.js +16 -0
  81. package/dist/shorthands/openers/border-image-shorthand.js.map +1 -0
  82. package/dist/shorthands/openers/border-radius-shorthand.d.ts +5 -0
  83. package/dist/shorthands/openers/border-radius-shorthand.d.ts.map +1 -0
  84. package/dist/shorthands/openers/border-radius-shorthand.js +61 -0
  85. package/dist/shorthands/openers/border-radius-shorthand.js.map +1 -0
  86. package/dist/shorthands/openers/border-shorthand.d.ts +20 -0
  87. package/dist/shorthands/openers/border-shorthand.d.ts.map +1 -0
  88. package/dist/shorthands/openers/border-shorthand.js +90 -0
  89. package/dist/shorthands/openers/border-shorthand.js.map +1 -0
  90. package/dist/shorthands/openers/flex-flow-shorthand.d.ts +5 -0
  91. package/dist/shorthands/openers/flex-flow-shorthand.d.ts.map +1 -0
  92. package/dist/shorthands/openers/flex-flow-shorthand.js +13 -0
  93. package/dist/shorthands/openers/flex-flow-shorthand.js.map +1 -0
  94. package/dist/shorthands/openers/flex-shorthand.d.ts +5 -0
  95. package/dist/shorthands/openers/flex-shorthand.d.ts.map +1 -0
  96. package/dist/shorthands/openers/flex-shorthand.js +55 -0
  97. package/dist/shorthands/openers/flex-shorthand.js.map +1 -0
  98. package/dist/shorthands/openers/font-shorthand.d.ts +5 -0
  99. package/dist/shorthands/openers/font-shorthand.d.ts.map +1 -0
  100. package/dist/shorthands/openers/font-shorthand.js +60 -0
  101. package/dist/shorthands/openers/font-shorthand.js.map +1 -0
  102. package/dist/shorthands/openers/gap-shorthand.d.ts +5 -0
  103. package/dist/shorthands/openers/gap-shorthand.d.ts.map +1 -0
  104. package/dist/shorthands/openers/gap-shorthand.js +28 -0
  105. package/dist/shorthands/openers/gap-shorthand.js.map +1 -0
  106. package/dist/shorthands/openers/grid-axis-shorthand.d.ts +6 -0
  107. package/dist/shorthands/openers/grid-axis-shorthand.d.ts.map +1 -0
  108. package/dist/shorthands/openers/grid-axis-shorthand.js +36 -0
  109. package/dist/shorthands/openers/grid-axis-shorthand.js.map +1 -0
  110. package/dist/shorthands/openers/grid-gap-shorthand.d.ts +5 -0
  111. package/dist/shorthands/openers/grid-gap-shorthand.d.ts.map +1 -0
  112. package/dist/shorthands/openers/grid-gap-shorthand.js +21 -0
  113. package/dist/shorthands/openers/grid-gap-shorthand.js.map +1 -0
  114. package/dist/shorthands/openers/grid-shorthand.d.ts +8 -0
  115. package/dist/shorthands/openers/grid-shorthand.d.ts.map +1 -0
  116. package/dist/shorthands/openers/grid-shorthand.js +145 -0
  117. package/dist/shorthands/openers/grid-shorthand.js.map +1 -0
  118. package/dist/shorthands/openers/grid-template-shorthand.d.ts +10 -0
  119. package/dist/shorthands/openers/grid-template-shorthand.d.ts.map +1 -0
  120. package/dist/shorthands/openers/grid-template-shorthand.js +113 -0
  121. package/dist/shorthands/openers/grid-template-shorthand.js.map +1 -0
  122. package/dist/shorthands/openers/index.d.ts +22 -0
  123. package/dist/shorthands/openers/index.d.ts.map +1 -0
  124. package/dist/shorthands/openers/index.js +22 -0
  125. package/dist/shorthands/openers/index.js.map +1 -0
  126. package/dist/shorthands/openers/list-style-shorthand.d.ts +5 -0
  127. package/dist/shorthands/openers/list-style-shorthand.d.ts.map +1 -0
  128. package/dist/shorthands/openers/list-style-shorthand.js +15 -0
  129. package/dist/shorthands/openers/list-style-shorthand.js.map +1 -0
  130. package/dist/shorthands/openers/margin-shorthand.d.ts +5 -0
  131. package/dist/shorthands/openers/margin-shorthand.d.ts.map +1 -0
  132. package/dist/shorthands/openers/margin-shorthand.js +11 -0
  133. package/dist/shorthands/openers/margin-shorthand.js.map +1 -0
  134. package/dist/shorthands/openers/outline-shorthand.d.ts +5 -0
  135. package/dist/shorthands/openers/outline-shorthand.d.ts.map +1 -0
  136. package/dist/shorthands/openers/outline-shorthand.js +14 -0
  137. package/dist/shorthands/openers/outline-shorthand.js.map +1 -0
  138. package/dist/shorthands/openers/overflow-shorthand.d.ts +5 -0
  139. package/dist/shorthands/openers/overflow-shorthand.d.ts.map +1 -0
  140. package/dist/shorthands/openers/overflow-shorthand.js +21 -0
  141. package/dist/shorthands/openers/overflow-shorthand.js.map +1 -0
  142. package/dist/shorthands/openers/padding-shorthand.d.ts +5 -0
  143. package/dist/shorthands/openers/padding-shorthand.d.ts.map +1 -0
  144. package/dist/shorthands/openers/padding-shorthand.js +11 -0
  145. package/dist/shorthands/openers/padding-shorthand.js.map +1 -0
  146. package/dist/shorthands/openers/place-content-shorthand.d.ts +5 -0
  147. package/dist/shorthands/openers/place-content-shorthand.d.ts.map +1 -0
  148. package/dist/shorthands/openers/place-content-shorthand.js +29 -0
  149. package/dist/shorthands/openers/place-content-shorthand.js.map +1 -0
  150. package/dist/shorthands/openers/place-items-shorthand.d.ts +5 -0
  151. package/dist/shorthands/openers/place-items-shorthand.d.ts.map +1 -0
  152. package/dist/shorthands/openers/place-items-shorthand.js +23 -0
  153. package/dist/shorthands/openers/place-items-shorthand.js.map +1 -0
  154. package/dist/shorthands/openers/text-decoration-shorthand.d.ts +5 -0
  155. package/dist/shorthands/openers/text-decoration-shorthand.d.ts.map +1 -0
  156. package/dist/shorthands/openers/text-decoration-shorthand.js +14 -0
  157. package/dist/shorthands/openers/text-decoration-shorthand.js.map +1 -0
  158. package/dist/shorthands/shorthand-css-data.d.ts +120 -0
  159. package/dist/shorthands/shorthand-css-data.d.ts.map +1 -0
  160. package/dist/shorthands/shorthand-css-data.js +48 -0
  161. package/dist/shorthands/shorthand-css-data.js.map +1 -0
  162. package/dist/shorthands/shorthand-mapper.d.ts +6 -0
  163. package/dist/shorthands/shorthand-mapper.d.ts.map +1 -0
  164. package/dist/shorthands/shorthand-mapper.js +72 -0
  165. package/dist/shorthands/shorthand-mapper.js.map +1 -0
  166. package/dist/shorthands/shorthand-parser-errors.d.ts +25 -0
  167. package/dist/shorthands/shorthand-parser-errors.d.ts.map +1 -0
  168. package/dist/shorthands/shorthand-parser-errors.js +41 -0
  169. package/dist/shorthands/shorthand-parser-errors.js.map +1 -0
  170. package/dist/shorthands/shorthand-parser-utils.d.ts +24 -0
  171. package/dist/shorthands/shorthand-parser-utils.d.ts.map +1 -0
  172. package/dist/shorthands/shorthand-parser-utils.js +398 -0
  173. package/dist/shorthands/shorthand-parser-utils.js.map +1 -0
  174. package/dist/shorthands/shorthand-types.d.ts +64 -0
  175. package/dist/shorthands/shorthand-types.d.ts.map +1 -0
  176. package/dist/shorthands/shorthand-types.js +2 -0
  177. package/dist/shorthands/shorthand-types.js.map +1 -0
  178. package/dist/shorthands/shorthands-ast-evaluation.d.ts +5 -0
  179. package/dist/shorthands/shorthands-ast-evaluation.d.ts.map +1 -0
  180. package/dist/shorthands/shorthands-ast-evaluation.js +19 -0
  181. package/dist/shorthands/shorthands-ast-evaluation.js.map +1 -0
  182. package/dist/tokenizers/css-value-tokenizer.d.ts +43 -0
  183. package/dist/tokenizers/css-value-tokenizer.d.ts.map +1 -0
  184. package/dist/tokenizers/css-value-tokenizer.js +154 -0
  185. package/dist/tokenizers/css-value-tokenizer.js.map +1 -0
  186. package/dist/tokenizers/index.d.ts +2 -0
  187. package/dist/tokenizers/index.d.ts.map +1 -0
  188. package/dist/tokenizers/index.js +2 -0
  189. package/dist/tokenizers/index.js.map +1 -0
  190. package/package.json +54 -0
  191. package/src/compounds/compound-css-data.ts +24 -0
  192. package/src/compounds/compound-mapper.ts +21 -0
  193. package/src/compounds/compound-parser-utils.ts +47 -0
  194. package/src/compounds/compound-types.ts +35 -0
  195. package/src/compounds/compound-value-parsers.ts +12 -0
  196. package/src/compounds/index.ts +5 -0
  197. package/src/compounds/parsers/index.ts +1 -0
  198. package/src/compounds/parsers/shadow-compound.ts +56 -0
  199. package/src/css-data-types/data-types-consts.ts +877 -0
  200. package/src/css-data-types/data-types-predicates.ts +477 -0
  201. package/src/css-data-types/data-types-state-machines.ts +169 -0
  202. package/src/css-data-types/data-types-types.ts +43 -0
  203. package/src/css-data-types/data-types-utils.ts +258 -0
  204. package/src/css-data-types/data-types.ts +435 -0
  205. package/src/css-data-types/index.ts +6 -0
  206. package/src/index.ts +4 -0
  207. package/src/shorthands/index.ts +7 -0
  208. package/src/shorthands/openers/background-position-shorthand.ts +180 -0
  209. package/src/shorthands/openers/background-shorthand.ts +161 -0
  210. package/src/shorthands/openers/border-image-shorthand.ts +35 -0
  211. package/src/shorthands/openers/border-radius-shorthand.ts +93 -0
  212. package/src/shorthands/openers/border-shorthand.ts +198 -0
  213. package/src/shorthands/openers/flex-flow-shorthand.ts +24 -0
  214. package/src/shorthands/openers/flex-shorthand.ts +79 -0
  215. package/src/shorthands/openers/font-shorthand.ts +85 -0
  216. package/src/shorthands/openers/gap-shorthand.ts +47 -0
  217. package/src/shorthands/openers/grid-axis-shorthand.ts +61 -0
  218. package/src/shorthands/openers/grid-gap-shorthand.ts +40 -0
  219. package/src/shorthands/openers/grid-shorthand.ts +260 -0
  220. package/src/shorthands/openers/grid-template-shorthand.ts +176 -0
  221. package/src/shorthands/openers/index.ts +21 -0
  222. package/src/shorthands/openers/list-style-shorthand.ts +33 -0
  223. package/src/shorthands/openers/margin-shorthand.ts +20 -0
  224. package/src/shorthands/openers/outline-shorthand.ts +27 -0
  225. package/src/shorthands/openers/overflow-shorthand.ts +40 -0
  226. package/src/shorthands/openers/padding-shorthand.ts +21 -0
  227. package/src/shorthands/openers/place-content-shorthand.ts +49 -0
  228. package/src/shorthands/openers/place-items-shorthand.ts +43 -0
  229. package/src/shorthands/openers/text-decoration-shorthand.ts +27 -0
  230. package/src/shorthands/shorthand-css-data.ts +210 -0
  231. package/src/shorthands/shorthand-mapper.ts +157 -0
  232. package/src/shorthands/shorthand-parser-errors.ts +47 -0
  233. package/src/shorthands/shorthand-parser-utils.ts +602 -0
  234. package/src/shorthands/shorthand-types.ts +107 -0
  235. package/src/shorthands/shorthands-ast-evaluation.ts +38 -0
  236. package/src/tokenizers/css-value-tokenizer.ts +220 -0
  237. package/src/tokenizers/index.ts +1 -0
@@ -0,0 +1,477 @@
1
+ import type {
2
+ AstItem,
3
+ PredicateMatch,
4
+ ParsedPredicateMatch,
5
+ DataTypePredicate,
6
+ ParsedDataTypePredicate,
7
+ } from './data-types-types.js';
8
+
9
+ import { type MethodCall, valueTextNode } from '../tokenizers/index.js';
10
+ import {
11
+ AUTO_KEYWORD,
12
+ LENGTH_UNITS_MAP,
13
+ PERCENTAGE_UNIT,
14
+ LENGTH_PERCENTAGE_UNITS,
15
+ ANGLE_UNITS,
16
+ FLEX_UNIT,
17
+ FLEX_NUMBER_RANGE_MIN,
18
+ FONT_STYLE_OBLIQUE_KEYWORD,
19
+ TEXT_DECORATION_LINE_KEYWORDS,
20
+ BORDER_IMAGE_SLICE_FILL_KEYWORD,
21
+ GRID_LINE_SPAN_KEYWORD,
22
+ BREADTH_KEYWORDS,
23
+ LINE_NAMES_EXCLUDE_KEYWORDS,
24
+ MINMAX_FUNCTION,
25
+ REPEAT_FUNCTION,
26
+ TRACK_SIZE_FUNCTIONS,
27
+ INITIAL_TRACK_SIZE,
28
+ AUTO_REPEAT_FIRST_ARGUMENT_KEYWORDS,
29
+ GRID_AUTO_FLOW_KEYWORD,
30
+ GRID_AUTO_FLOW_DENSE_KEYWORD,
31
+ BASIC_MATH_FUNCTIONS,
32
+ } from './data-types-consts.js';
33
+ import {
34
+ unorderedListPredicate,
35
+ functionPredicate,
36
+ dimensionPredicate,
37
+ customIdentPredicate,
38
+ typePredicate,
39
+ predicateUnion,
40
+ } from './data-types-utils.js';
41
+
42
+ // <number>
43
+ export const numberPredicate = dimensionPredicate();
44
+
45
+ // <length>
46
+ export const lengthPredicate = dimensionPredicate({ units: LENGTH_UNITS_MAP });
47
+
48
+ // <percentage>
49
+ export const percentagePredicate = dimensionPredicate({ units: PERCENTAGE_UNIT });
50
+
51
+ // <length-percentage>
52
+ export const lengthPercentagePredicate = dimensionPredicate({ units: LENGTH_PERCENTAGE_UNITS });
53
+
54
+ export const basicMathFunctionPredicate = functionPredicate(BASIC_MATH_FUNCTIONS);
55
+
56
+ // <angle>
57
+ export const anglePredicate = dimensionPredicate({ units: ANGLE_UNITS });
58
+
59
+ // <flex>
60
+ const flexPredicate = dimensionPredicate({ units: FLEX_UNIT, min: FLEX_NUMBER_RANGE_MIN });
61
+
62
+ // 'auto'
63
+ export const autoKeywordPredicate = unorderedListPredicate(AUTO_KEYWORD);
64
+
65
+ // <font-style>
66
+ // syntax: normal | italic | oblique <angle>?
67
+ export const fontStylePredicate: DataTypePredicate = (ast, index, items) => {
68
+ if (index === undefined || !items) {
69
+ return false;
70
+ }
71
+
72
+ const obliquePredicate = unorderedListPredicate(FONT_STYLE_OBLIQUE_KEYWORD);
73
+
74
+ let matchAmount = 0;
75
+ if (obliquePredicate(ast)) {
76
+ matchAmount++;
77
+ const next = items[index + 1];
78
+ if (next && anglePredicate(next.value)) {
79
+ matchAmount++;
80
+ }
81
+ }
82
+
83
+ return matchAmount;
84
+ };
85
+
86
+ // <font-family>
87
+ export const fontFamilyStringPredicate = typePredicate(['text', 'string', ',']);
88
+
89
+ // <grid-line>
90
+ // syntax: <custom-ident> | [ <integer> && <custom-ident>? ] | [ span && [ <integer> || <custom-ident> ] ]
91
+ export const gridLinePredicate: DataTypePredicate = (ast, index, items) => {
92
+ const startIndex = index ?? 0;
93
+ const astItems = items ?? [{ value: ast }];
94
+
95
+ const nonZeroIntegerPredicate = dimensionPredicate({ nonZero: true, integer: true });
96
+ const gridLineCustomIdentPredicate = customIdentPredicate(GRID_LINE_SPAN_KEYWORD);
97
+ const spanPredicate = unorderedListPredicate(GRID_LINE_SPAN_KEYWORD);
98
+
99
+ let hasSpan = false;
100
+ let hasCustomIdent = false;
101
+ let hasInteger = false;
102
+
103
+ let item: AstItem | undefined;
104
+ let i = startIndex;
105
+ while ((item = astItems[i++])) {
106
+ if (gridLineCustomIdentPredicate(item.value)) {
107
+ if (hasCustomIdent) {
108
+ break;
109
+ }
110
+ hasCustomIdent = true;
111
+ } else if (nonZeroIntegerPredicate(item.value)) {
112
+ if (hasInteger) {
113
+ break;
114
+ }
115
+ hasInteger = true;
116
+ } else if (spanPredicate(item.value)) {
117
+ if (hasSpan) {
118
+ break;
119
+ }
120
+ hasSpan = true;
121
+ } else {
122
+ break;
123
+ }
124
+ }
125
+
126
+ return !hasSpan || hasCustomIdent || hasInteger ? +hasSpan + +hasCustomIdent + +hasInteger : false;
127
+ };
128
+
129
+ // <track-breadth>
130
+ // syntax: <length-percentage> | <flex> | min-content | max-content | auto
131
+ const trackBreadthPredicate = predicateUnion([
132
+ lengthPercentagePredicate,
133
+ flexPredicate,
134
+ unorderedListPredicate(BREADTH_KEYWORDS),
135
+ ]);
136
+
137
+ // <line-names>
138
+ // syntax: '[' <custom-ident>* ']'
139
+ interface ParseLineNamesMatch extends ParsedPredicateMatch {
140
+ names: string[];
141
+ }
142
+
143
+ const INVALID_LINE_NAMES_MATCH: ParseLineNamesMatch = { names: [], match: false };
144
+ const parseLineNames: ParsedDataTypePredicate<ParseLineNamesMatch> = (ast, index, items) => {
145
+ const startIndex = index ?? 0;
146
+ const astItems = items ?? [{ value: ast }];
147
+
148
+ const lineNamesCustomIdentPredicate = customIdentPredicate(LINE_NAMES_EXCLUDE_KEYWORDS);
149
+
150
+ const names: string[] = [];
151
+ let matchAmount = 0;
152
+ let hasClosingBracket = false;
153
+ for (let i = startIndex; i < astItems.length; i++) {
154
+ const value = astItems[i]!.value;
155
+ let currText = value.text;
156
+
157
+ const isStart = i === startIndex;
158
+ const hasOpeningBracket = currText.startsWith('[');
159
+ hasClosingBracket = currText.endsWith(']');
160
+ if (value.type !== 'text' || (isStart && !hasOpeningBracket) || (!isStart && hasOpeningBracket)) {
161
+ return { ...INVALID_LINE_NAMES_MATCH };
162
+ }
163
+
164
+ currText = currText.slice(hasOpeningBracket ? 1 : 0, currText.length - (hasClosingBracket ? 1 : 0));
165
+ if (
166
+ currText !== '' &&
167
+ (currText.includes('[') ||
168
+ currText.includes(']') ||
169
+ !lineNamesCustomIdentPredicate(valueTextNode(currText)))
170
+ ) {
171
+ return { ...INVALID_LINE_NAMES_MATCH };
172
+ }
173
+
174
+ if (currText !== '') {
175
+ names.push(currText);
176
+ }
177
+ matchAmount++;
178
+ if (hasClosingBracket) {
179
+ break;
180
+ }
181
+ }
182
+
183
+ return hasClosingBracket ? { names, match: matchAmount } : { ...INVALID_LINE_NAMES_MATCH };
184
+ };
185
+
186
+ export const lineNamesPredicate: DataTypePredicate = (ast, index, items) => parseLineNames(ast, index, items).match;
187
+
188
+ // <track-size>
189
+ // syntax: <track-breadth> | minmax( <inflexible-breadth> , <track-breadth> ) | fit-content( [ <length> | <percentage> ] )
190
+ export const trackSizePredicate = predicateUnion([trackBreadthPredicate, functionPredicate(TRACK_SIZE_FUNCTIONS)]);
191
+
192
+ // <track-repeat> / <fixed-repeat> / <auto-repeat>
193
+ const repeatPredicate = functionPredicate(REPEAT_FUNCTION);
194
+
195
+ // <auto-repeat>
196
+ // syntax: repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )
197
+ const autoRepeatPredicate: DataTypePredicate = (ast) => {
198
+ if (repeatPredicate(ast)) {
199
+ const firstArgPredicate = unorderedListPredicate(AUTO_REPEAT_FIRST_ARGUMENT_KEYWORDS);
200
+ const firstArg = (ast as MethodCall).args[0];
201
+ if (firstArg) {
202
+ return firstArgPredicate(firstArg);
203
+ }
204
+ }
205
+
206
+ return false;
207
+ };
208
+
209
+ // <fixed-size>
210
+ // syntax: <fixed-breadth> | minmax( <fixed-breadth> , <track-breadth> ) | minmax( <inflexible-breadth> , <fixed-breadth> )
211
+ const fixedSizePredicate = predicateUnion([lengthPercentagePredicate, functionPredicate(MINMAX_FUNCTION)]);
212
+
213
+ const singleTrackPredicate =
214
+ (trackPredicates: DataTypePredicate[], asterisk = false): DataTypePredicate =>
215
+ (ast, index, items) => {
216
+ const startIndex = index ?? 0;
217
+ const astItems = items ?? [{ value: ast }];
218
+
219
+ let item: AstItem | undefined;
220
+ let i = startIndex;
221
+ let hasPrevNames = false;
222
+ let isValid = asterisk;
223
+ let matchAmount = 0;
224
+ while ((item = astItems[i])) {
225
+ const lineNamesMatch = parseLineNames(item.value, i, astItems).match;
226
+ if (lineNamesMatch) {
227
+ if (hasPrevNames) {
228
+ break;
229
+ }
230
+ i += Number(lineNamesMatch);
231
+ matchAmount += Number(lineNamesMatch);
232
+ hasPrevNames = true;
233
+ } else if (trackPredicates.some((predicate) => predicate(item!.value))) {
234
+ isValid = true;
235
+ hasPrevNames = false;
236
+ i++;
237
+ matchAmount++;
238
+ } else {
239
+ break;
240
+ }
241
+ }
242
+
243
+ return isValid ? matchAmount : false;
244
+ };
245
+
246
+ // <track-list>
247
+ // syntax: [ <line-names>? [ <track-size> | <track-repeat> ] ]+ <line-names>?
248
+ export const trackListPredicate = singleTrackPredicate([trackSizePredicate, repeatPredicate]);
249
+
250
+ // <explicit-track-list>
251
+ // syntax: [ <line-names>? <track-size> ]+ <line-names>?
252
+ export const explicitTrackListPredicate = singleTrackPredicate([trackSizePredicate]);
253
+
254
+ // <track-list-with-strings>
255
+ // syntax: [ <line-names>? <string> <track-size>? <line-names>? ]+
256
+ export interface ParsedTrackWithString {
257
+ string: string;
258
+ trackSize: string;
259
+ lineNamesBefore?: string[];
260
+ lineNamesAfter?: string[];
261
+ }
262
+
263
+ export interface ParseTrackListWithStringsMatch extends ParsedPredicateMatch {
264
+ tracks: ParsedTrackWithString[];
265
+ }
266
+
267
+ const EMPTY_TRACK: ParsedTrackWithString = { string: '', trackSize: INITIAL_TRACK_SIZE };
268
+ const INVALID_TRACK_MATCH: ParseTrackListWithStringsMatch = { tracks: [], match: false };
269
+ export const parseTrackListWithStrings: ParsedDataTypePredicate<ParseTrackListWithStringsMatch> = (
270
+ ast,
271
+ index,
272
+ items,
273
+ ) => {
274
+ const startIndex = index ?? 0;
275
+ const astItems = items ?? [{ value: ast }];
276
+
277
+ const tracks: ParsedTrackWithString[] = [{ ...EMPTY_TRACK }];
278
+ let item: AstItem | undefined;
279
+ let i = startIndex;
280
+ let isValid = false;
281
+ let matchAmount = 0;
282
+ while ((item = astItems[i])) {
283
+ if (item.value.type === 'string') {
284
+ tracks[tracks.length - 1]!.string = item.value.text;
285
+ isValid = true;
286
+ } else {
287
+ const hasString = tracks[tracks.length - 1]!.string === '';
288
+ const lineNames = parseLineNames(item.value, i, astItems);
289
+ if (lineNames.match) {
290
+ if (hasString) {
291
+ if (tracks[tracks.length - 1]!.lineNamesBefore) {
292
+ return { ...INVALID_TRACK_MATCH };
293
+ }
294
+ tracks[tracks.length - 1]!.lineNamesBefore = lineNames.names;
295
+ isValid = false;
296
+ } else {
297
+ tracks[tracks.length - 1]!.lineNamesAfter = lineNames.names;
298
+ tracks.push({ ...EMPTY_TRACK });
299
+ }
300
+ i += Number(lineNames.match) - 1;
301
+ matchAmount += Number(lineNames.match) - 1;
302
+ } else if (trackSizePredicate(item.value, i, astItems)) {
303
+ if (hasString) {
304
+ return { ...INVALID_TRACK_MATCH };
305
+ }
306
+ tracks[tracks.length - 1]!.trackSize = item.value.text;
307
+ } else {
308
+ break;
309
+ }
310
+ }
311
+ i++;
312
+ matchAmount++;
313
+ }
314
+
315
+ if (isValid && tracks[tracks.length - 1]!.string === '') {
316
+ tracks.pop();
317
+ }
318
+
319
+ return isValid ? { tracks, match: matchAmount } : { ...INVALID_TRACK_MATCH };
320
+ };
321
+
322
+ export const trackListWithStringsPredicate: DataTypePredicate = (ast, index, items) =>
323
+ parseTrackListWithStrings(ast, index, items).match;
324
+
325
+ // <auto-track-list>
326
+ // syntax: [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>? <auto-repeat> [ <line-names>? [ <fixed-size> | <fixed-repeat> ] ]* <line-names>?
327
+ export const autoTrackListPredicate: DataTypePredicate = (ast, index, items) => {
328
+ const startIndex = index ?? 0;
329
+ const astItems = items ?? [{ value: ast }];
330
+
331
+ let item: AstItem | undefined;
332
+ let i = startIndex;
333
+ let autoRepeatIndex = -1;
334
+ while ((item = astItems[i])) {
335
+ if (autoRepeatPredicate(item.value)) {
336
+ autoRepeatIndex = i;
337
+ break;
338
+ }
339
+ i++;
340
+ }
341
+
342
+ if (autoRepeatIndex === -1) {
343
+ return false;
344
+ }
345
+
346
+ const prefixSuffixTrackListPredicate = singleTrackPredicate([fixedSizePredicate, repeatPredicate], true);
347
+ let matchAmount = 1;
348
+
349
+ if (autoRepeatIndex > startIndex) {
350
+ const prefixMatch = prefixSuffixTrackListPredicate(
351
+ astItems[startIndex]!.value,
352
+ 0,
353
+ astItems.slice(startIndex, autoRepeatIndex),
354
+ );
355
+ if (!prefixMatch || Number(prefixMatch) !== autoRepeatIndex - startIndex) {
356
+ return false;
357
+ }
358
+ matchAmount += autoRepeatIndex - startIndex;
359
+ }
360
+
361
+ if (astItems[autoRepeatIndex + 1]) {
362
+ matchAmount += Number(
363
+ prefixSuffixTrackListPredicate(
364
+ astItems[autoRepeatIndex + 1]!.value,
365
+ 0,
366
+ astItems.slice(autoRepeatIndex + 1),
367
+ ),
368
+ );
369
+ }
370
+
371
+ return matchAmount;
372
+ };
373
+
374
+ // <grid-template-areas>
375
+ // syntax: none | <string>+
376
+ export const gridTemplateAreasStringPredicate = typePredicate(['string']);
377
+
378
+ // <grid-auto-flow>
379
+ // syntax: auto-flow && dense?
380
+ export const gridAutoFlowPredicate: DataTypePredicate = (ast, index, items) => {
381
+ const startIndex = index ?? 0;
382
+ const astItems = items ?? [{ value: ast }];
383
+
384
+ const autoFlowPredicate = unorderedListPredicate(GRID_AUTO_FLOW_KEYWORD);
385
+ const densePredicate = unorderedListPredicate(GRID_AUTO_FLOW_DENSE_KEYWORD);
386
+
387
+ let hasAutoFlow = false;
388
+ let hasDense = false;
389
+
390
+ let item: AstItem | undefined;
391
+ let i = startIndex;
392
+ while ((item = astItems[i++])) {
393
+ if (autoFlowPredicate(item.value)) {
394
+ if (hasAutoFlow) {
395
+ break;
396
+ }
397
+ hasAutoFlow = true;
398
+ } else if (densePredicate(item.value)) {
399
+ if (hasDense) {
400
+ break;
401
+ }
402
+ hasDense = true;
403
+ } else {
404
+ break;
405
+ }
406
+ }
407
+
408
+ return hasAutoFlow ? +hasAutoFlow + +hasDense : false;
409
+ };
410
+
411
+ // <text-decoration-line>
412
+ // syntax: none | [ underline || overline || line-through ]
413
+ export const textDecorationLinePredicate: DataTypePredicate = (ast, index, items) => {
414
+ const startIndex = index ?? 0;
415
+ const astItems = items ?? [{ value: ast }];
416
+
417
+ const currKeywords = new Map(TEXT_DECORATION_LINE_KEYWORDS);
418
+ let currPredicate = unorderedListPredicate(currKeywords);
419
+ let item: AstItem | undefined;
420
+ let i = startIndex;
421
+ let matchAmount = 0;
422
+ while (currKeywords.size > 0 && (item = astItems[i++])) {
423
+ if (currPredicate(item.value, i - 1, astItems)) {
424
+ matchAmount++;
425
+ currKeywords.delete(item.value.text);
426
+ currPredicate = unorderedListPredicate(currKeywords);
427
+ } else {
428
+ break;
429
+ }
430
+ }
431
+
432
+ return matchAmount;
433
+ };
434
+
435
+ // <border-image-slice>
436
+ // syntax: <number-percentage>{1,4} && fill?
437
+ export const borderImageSlicePredicate: DataTypePredicate = (ast, index, items) => {
438
+ const startIndex = index ?? 0;
439
+ const astItems = items ?? [{ value: ast }];
440
+
441
+ const numberPercentagePredicates = [numberPredicate, percentagePredicate];
442
+ const fillPredicate = unorderedListPredicate(BORDER_IMAGE_SLICE_FILL_KEYWORD);
443
+
444
+ let item: AstItem | undefined;
445
+ let i = startIndex;
446
+ let matchAmount = 0;
447
+ let matchedFill = false;
448
+ let match: PredicateMatch | undefined;
449
+ while ((item = astItems[i++])) {
450
+ match = undefined;
451
+ const fillMatch = fillPredicate(item.value, i - 1, astItems);
452
+ if (fillMatch) {
453
+ if (matchedFill) {
454
+ break;
455
+ }
456
+ match = fillMatch;
457
+ matchedFill = true;
458
+ } else {
459
+ for (const predicate of numberPercentagePredicates) {
460
+ const numberPercentageMatch = predicate(item.value, i - 1, astItems);
461
+ if (numberPercentageMatch) {
462
+ match = numberPercentageMatch;
463
+ break;
464
+ }
465
+ }
466
+ }
467
+ if (!match || ++matchAmount === (matchedFill ? 5 : 4)) {
468
+ break;
469
+ }
470
+ }
471
+
472
+ if (matchAmount === 4 && match && (item = astItems[i])) {
473
+ return fillPredicate(item.value, i - 1, astItems) ? 5 : 4;
474
+ }
475
+
476
+ return matchAmount >= 1 ? (!matchedFill || matchAmount > 1 ? matchAmount : false) : false;
477
+ };
@@ -0,0 +1,169 @@
1
+ import type { AstItem, DataTypePredicate } from './data-types-types.js';
2
+
3
+ import {
4
+ BG_POSITION_CENTER_KEYWORD,
5
+ BG_POSITION_HORIZONTAL_KEYWORDS_MAP,
6
+ BG_POSITION_VERTICAL_KEYWORDS_MAP,
7
+ BG_POSITION_ALL_EDGES_KEYWORDS,
8
+ } from './data-types-consts.js';
9
+ import { unorderedListPredicate } from './data-types-utils.js';
10
+
11
+ const PREDICATE_STATE_START = 'start';
12
+
13
+ type StateMachineKey<T extends string> = typeof PREDICATE_STATE_START | T;
14
+
15
+ interface PredicateStateMatch<T extends string> {
16
+ predicate: DataTypePredicate;
17
+ nextKey?: StateMachineKey<T>;
18
+ mustContinue?: boolean;
19
+ }
20
+
21
+ export type StateMachine<T extends string> = Array<Partial<Record<StateMachineKey<T>, PredicateStateMatch<T>[]>>>;
22
+
23
+ export const stateMachineDataTypeMatch = <T extends string>(
24
+ items: AstItem[],
25
+ index: number,
26
+ stateMachine: StateMachine<T>,
27
+ ): number => {
28
+ let returnMatch = 0;
29
+
30
+ let valueIndex = 0;
31
+ let currKey: StateMachineKey<T> | undefined = PREDICATE_STATE_START;
32
+
33
+ if (!currKey || !stateMachine[valueIndex]) {
34
+ return returnMatch;
35
+ }
36
+
37
+ let match: PredicateStateMatch<T> | undefined;
38
+ do {
39
+ let newMatch: PredicateStateMatch<T> | undefined;
40
+ const currItem = items[index + valueIndex];
41
+ if (currItem) {
42
+ const possibleMatches: PredicateStateMatch<T>[] | undefined = stateMachine[valueIndex]![currKey];
43
+ if (possibleMatches) {
44
+ for (let i = 0; i < possibleMatches.length; i++) {
45
+ const stateMatch = possibleMatches[i]!;
46
+ if (stateMatch.predicate(currItem.value)) {
47
+ newMatch = stateMatch;
48
+ break;
49
+ }
50
+ }
51
+ if (newMatch) {
52
+ returnMatch++;
53
+ currKey = newMatch.nextKey;
54
+ }
55
+ }
56
+ }
57
+ if (!newMatch && match && match.mustContinue) {
58
+ returnMatch--;
59
+ }
60
+ match = newMatch;
61
+ } while (match && currKey && stateMachine[++valueIndex]);
62
+
63
+ return returnMatch;
64
+ };
65
+
66
+ // <bg-position>
67
+ type BgPositionStateMachineKey =
68
+ | '<length-percentage>'
69
+ | 'center'
70
+ | 'left | right'
71
+ | 'top | bottom'
72
+ | '3-value'
73
+ | '[ left | right ] <length-percentage>'
74
+ | '[ top | bottom ] <length-percentage>'
75
+ | '4-value';
76
+ export const bgPositionStateMachine = (
77
+ lengthPercentagePredicate: DataTypePredicate,
78
+ ): StateMachine<BgPositionStateMachineKey> => {
79
+ const centerPredicate = unorderedListPredicate(BG_POSITION_CENTER_KEYWORD);
80
+ const horizontalPredicate = unorderedListPredicate(BG_POSITION_HORIZONTAL_KEYWORDS_MAP);
81
+ const verticalPredicate = unorderedListPredicate(BG_POSITION_VERTICAL_KEYWORDS_MAP);
82
+ const allEdgesPredicate = unorderedListPredicate(BG_POSITION_ALL_EDGES_KEYWORDS);
83
+
84
+ /*
85
+ syntax: [
86
+ [ left | center | right | top | bottom | <length-percentage> ] |
87
+ [ left | center | right | <length-percentage> ] [ top | center | bottom | <length-percentage> ] |
88
+ [ center | [ left | right ] <length-percentage>? ]
89
+ && [ center | [ top | bottom] <length-percentage>? ]
90
+ ]
91
+ */
92
+ return [
93
+ {
94
+ [PREDICATE_STATE_START]: [
95
+ // <length-percentage>
96
+ { predicate: lengthPercentagePredicate, nextKey: '<length-percentage>' },
97
+ // center
98
+ { predicate: centerPredicate, nextKey: 'center' },
99
+ // left | right
100
+ { predicate: horizontalPredicate, nextKey: 'left | right' },
101
+ // top | bottom
102
+ { predicate: verticalPredicate, nextKey: 'top | bottom' },
103
+ ],
104
+ },
105
+ {
106
+ '<length-percentage>': [
107
+ // <length-percentage> <length-percentage> $
108
+ { predicate: lengthPercentagePredicate },
109
+ // <length-percentage> center $
110
+ { predicate: centerPredicate },
111
+ // <length-percentage> [ top | bottom ] $
112
+ { predicate: verticalPredicate },
113
+ ],
114
+ center: [
115
+ // center <length-percentage> $
116
+ { predicate: lengthPercentagePredicate },
117
+ // center center $
118
+ { predicate: centerPredicate },
119
+ // center [ left | right | top | bottom ]
120
+ { predicate: allEdgesPredicate, nextKey: '3-value' },
121
+ ],
122
+ 'left | right': [
123
+ // [ left | right ] <length-percentage>
124
+ { predicate: lengthPercentagePredicate, nextKey: '[ left | right ] <length-percentage>' },
125
+ // [ left | right ] center $
126
+ { predicate: centerPredicate },
127
+ // [ left |right ] [ top | bottom ]
128
+ { predicate: verticalPredicate, nextKey: '3-value' },
129
+ ],
130
+ 'top | bottom': [
131
+ // [ top | bottom ] <length-percentage>
132
+ {
133
+ predicate: lengthPercentagePredicate,
134
+ nextKey: '[ top | bottom ] <length-percentage>',
135
+ mustContinue: true,
136
+ },
137
+ // [ top | bottom ] center $
138
+ { predicate: centerPredicate },
139
+ // [ top | bottom ] [ left |right ]
140
+ { predicate: horizontalPredicate, nextKey: '3-value' },
141
+ ],
142
+ },
143
+ {
144
+ '3-value': [
145
+ // center [ left | right | top | bottom ] <length-percentage> $
146
+ { predicate: lengthPercentagePredicate },
147
+ ],
148
+ '[ left | right ] <length-percentage>': [
149
+ // [ left | right ] <length-percentage> center $
150
+ { predicate: centerPredicate },
151
+ // [ left | right ] <length-percentage> [ top | bottom ]
152
+ { predicate: verticalPredicate, nextKey: '4-value' },
153
+ ],
154
+ '[ top | bottom ] <length-percentage>': [
155
+ // [ top | bottom ] <length-percentage> center $
156
+ { predicate: centerPredicate },
157
+ // [ top | bottom ] <length-percentage> [ left | right ]
158
+ { predicate: horizontalPredicate, nextKey: '4-value' },
159
+ ],
160
+ },
161
+ {
162
+ '4-value': [
163
+ // [ left | right ] <length-percentage> [ top | bottom ] <length-percentage> $
164
+ // [ top | bottom ] <length-percentage> [ left | right ] <length-percentage> $
165
+ { predicate: lengthPercentagePredicate },
166
+ ],
167
+ },
168
+ ];
169
+ };
@@ -0,0 +1,43 @@
1
+ import type { CSSCodeAst } from '../tokenizers/index.js';
2
+ import type { DataTypeType } from './data-types-consts.js';
3
+
4
+ export interface AstItem {
5
+ value: CSSCodeAst;
6
+ }
7
+
8
+ export type PredicateMatch = number | boolean;
9
+
10
+ export interface ParsedPredicateMatch {
11
+ match: PredicateMatch;
12
+ }
13
+
14
+ export interface PredicateIndexMatch {
15
+ index: number;
16
+ length: number;
17
+ }
18
+
19
+ export type DataTypePredicate = (
20
+ ast: CSSCodeAst,
21
+ index?: number,
22
+ items?: AstItem[],
23
+ prev?: DataTypeType,
24
+ ) => PredicateMatch;
25
+
26
+ export type ParsedDataTypePredicate<T extends ParsedPredicateMatch> = (
27
+ ast: CSSCodeAst,
28
+ index?: number,
29
+ items?: AstItem[],
30
+ prev?: DataTypeType,
31
+ ) => T;
32
+
33
+ export interface PredicatePrefix {
34
+ dataType: DataTypeType;
35
+ prefixChar: string;
36
+ }
37
+
38
+ export interface DataType {
39
+ dataType: DataTypeType;
40
+ predicate: DataTypePredicate;
41
+ initial: string;
42
+ prefix?: PredicatePrefix;
43
+ }