⎇ 4f43428b5e387dafa19cbcc0c5217fc8e61d0ce6
scripts/gentest/test_helper.js
Historia
Quién tocó qué
crudo
Grid/width depends on height tests (#300)
1
2class TrackSizingParser {
3 static INITIAL_CHAR_REGEX = /[a-z-A-Z0-9]/;
4 static TOKEN_CHAR_REGEX = /[-\.a-z-A-Z0-9%]/;
5
6 constructor(input, options = { allowFrUnits: true }) {
7 this.input = input;
8 this.index = 0;
9 this.options = options;
10 }
11
12 parseList() {
13 return this._parseItemList(' ', null);
14 }
15
16 parseSingleItem() {
17 return this.parseItem();
18 }
19
20 _parseItemList(separator, terminator = null) {
21 if (!separator) throw new Error('No terminator passed');
22 let tokenList = [];
23 // console.debug('Parse List', this.index, this.input.slice(this.index));
24
25 while (this.index < this.input.length) {
26 const char = this.input[this.index];
27 // console.debug(this.index, char);
28
29 // Skip whitespace
30 if (char === ' ') { this.index++; continue;}
31
32 if (TrackSizingParser.INITIAL_CHAR_REGEX.test(char)) {
33 const token = this._parseItem();
34 tokenList.push(token);
35
36 const nextChar = this.input[this.index];
37 if ((terminator && nextChar === terminator) || !terminator && !nextChar) {
38 return tokenList;
39 } else {
40 this.index++;
41 continue;
42 }
43 }
44
45 throw new Error (`Invalid start of token ${char}`);
46 }
47 }
48
49 _parseItem() {
50 let token = '';
51 // console.debug('Parse Item', this.index, this.input.slice(this.index));
52
53 while (this.index < this.input.length) {
54 const char = this.input[this.index];
55 // console.debug(this.index, char);
56
57 if (TrackSizingParser.TOKEN_CHAR_REGEX.test(char)) {
58 token += char;
59 this.index++;
60 continue;
61 }
62
63 if (char === '(') {
64 this.index++;
65 const args = this._parseItemList(',', ')');
66 this.index++;
67 return { kind: 'function', name: token, arguments: args };
68 }
69
70 return { kind: 'scalar', ...this._parseScalarItem(token) };
71 }
72 return { kind: 'scalar', ...this._parseScalarItem(token) };
73
74 }
75
76 _parseScalarItem(item) {
77 const res = parseRepetition(item) || parseDimension(item, { allowFrUnits: this.options.allowFrUnits });
78 if (!res) throw new Error(`Invalid scalar grid track sizing function ${item}`);
79 return res;
80 }
81
82}
83
84function parseRepetition(input) {
85 if (input === "auto-fill") return { unit: 'auto-fill' };
86 if (input === "auto-fit") return { unit: 'auto-fit' };
87 if (/^[0-9]*$/.test(input)) return { 'unit': 'integer', value: parseInt(input, 10) };
88 return undefined;
89}
90
91function parseDimension(input, options = { allowFrUnits: false }) {
92 if (options.allowFrUnits && input.endsWith('fr')) return { unit: 'fraction', value: parseFloat(input.replace('fr','')) };
93 if (input.endsWith('px')) return { unit: 'points', value: parseFloat(input.replace('px','')) };
94 if (input.endsWith('%')) return { unit: 'percent', value: parseFloat(input.replace('%','')) / 100 };
95 if (input === 'auto') return { unit: 'auto' };
96 if (input === 'min-content') return { unit: 'min-content' };
97 if (input === 'max-content') return { unit: 'max-content' };
98 return undefined;
99}
100
101function parseNumber(input) {
102 if (input === '' || isNaN(input)) return undefined;
103 return Number(input);
104}
105
106function parseEnum(input) {
107 if (input) return input;
108 return undefined;
109}
110
111function parseEdges(edges) {
112 const left = parseDimension(edges.left);
113 const right = parseDimension(edges.right);
114 const top = parseDimension(edges.top);
115 const bottom = parseDimension(edges.bottom);
116
117 if (!left && !right && !top && !bottom) return undefined;
118 return { left, right, top, bottom };
119}
120
121function parseSize(size) {
122 const width = parseDimension(size.width);
123 const height = parseDimension(size.height);
124
125 if (!width && !height) return undefined;
126 return { width, height };
127}
128
129function parseGaps(style) {
130 if (style.gap) {
131 const gaps = style.gap.trim().split(/\s+/).map(part => parseDimension(part));
132 return { row: gaps[0], column: gaps[1] ?? gaps[0] };
133 }
134 if (style.rowGap || style.columnGap) {
135 return { row: parseDimension(style.rowGap), column: parseDimension(style.columnGap) }
136 }
137 return undefined;
138}
139
140
141function parseGridTrackDefinitions(input) {
142 if (input === '') return undefined;
143 return new TrackSizingParser(input).parseList();
144}
145
146function parseGridAutoFlow(input) {
147 if (!/column/.test(input) && !/row/.test(input) && !/dense/.test(input)) return undefined;
148 const direction = /column/.test(input) ? 'column' : 'row';
149 const algorithm = /dense/.test(input) ? 'dense' : 'sparse';
150 return { direction, algorithm };
151}
152
153function parseGridPosition(input) {
154 if (input === 'auto') return { kind: 'auto' }
155 if (/^span +\d+$/.test(input)) return { kind: 'span', value: parseInt(input.replace(/[^\d]/g, ''), 10)}
156 if (/^-?\d+$/.test(input)) return { kind: 'line', value: parseInt(input, 10)}
157 return undefined;
158}
159
160function describeElement(e) {
161
162 return {
163 style: {
164 display: parseEnum(e.style.display),
165
166 position: parseEnum(e.style.position),
167 direction: parseEnum(e.style.direction),
168 flexDirection: parseEnum(e.style.flexDirection),
169
170 writingMode: parseEnum(e.style.writingMode),
171
172 flexWrap: parseEnum(e.style.flexWrap),
173 overflow: parseEnum(e.style.overflow),
174
175 alignItems: parseEnum(e.style.alignItems),
176 alignSelf: parseEnum(e.style.alignSelf),
177 justifyItems: parseEnum(e.style.justifyItems),
178 justifySelf: parseEnum(e.style.justifySelf),
179
180 alignContent: parseEnum(e.style.alignContent),
181 justifyContent: parseEnum(e.style.justifyContent),
182
183 flexGrow: parseNumber(e.style.flexGrow),
184 flexShrink: parseNumber(e.style.flexShrink),
185 flexBasis: parseDimension(e.style.flexBasis),
186
187 gridTemplateRows: parseGridTrackDefinitions(e.style.gridTemplateRows),
188 gridTemplateColumns: parseGridTrackDefinitions(e.style.gridTemplateColumns),
189 gridAutoRows: parseGridTrackDefinitions(e.style.gridAutoRows),
190 gridAutoColumns: parseGridTrackDefinitions(e.style.gridAutoColumns),
191 gridAutoFlow: parseGridAutoFlow(e.style.gridAutoFlow),
192
193 gridRowStart: parseGridPosition(e.style.gridRowStart),
194 gridRowEnd: parseGridPosition(e.style.gridRowEnd),
195 gridColumnStart: parseGridPosition(e.style.gridColumnStart),
196 gridColumnEnd: parseGridPosition(e.style.gridColumnEnd),
197
198 gap: parseGaps(e.style),
199
200 size: parseSize({width: e.style.width, height: e.style.height}),
201 minSize: parseSize({width: e.style.minWidth, height: e.style.minHeight}),
202 maxSize: parseSize({width: e.style.maxWidth, height: e.style.maxHeight}),
203
204 margin: parseEdges({
205 left: e.style.marginLeft,
206 right: e.style.marginRight,
207 top: e.style.marginTop,
208 bottom: e.style.marginBottom,
209 }),
210
211 padding: parseEdges({
212 left: e.style.paddingLeft,
213 right: e.style.paddingRight,
214 top: e.style.paddingTop,
215 bottom: e.style.paddingBottom,
216 }),
217
218 border: parseEdges({
219 left: e.style.borderLeftWidth,
220 right: e.style.borderRightWidth,
221 top: e.style.borderTopWidth,
222 bottom: e.style.borderBottomWidth,
223 }),
224
225 inset: parseEdges({
226 left: e.style.left,
227 right: e.style.right,
228 top: e.style.top,
229 bottom: e.style.bottom,
230 }),
231 },
232
233 // The textContent is used for generating intrinsic sizing measure funcs
234 // So we're only interested in the text content of leaf nodes
235 textContent: e.childElementCount === 0 && e.textContent.length && e.textContent !== "\n" ? e.textContent : undefined,
236
237 layout: {
238 width: e.offsetWidth,
239 height: e.offsetHeight,
240 x: e.offsetLeft + e.parentNode.clientLeft,
241 y: e.offsetTop + e.parentNode.clientTop,
242 },
243
244 children: Array.from(e.children).map(c => describeElement(c)),
245 }
246}
247
248// Useful when developing this script. Logs the parsed style to the console when any test fixture is opened in a browser.
249window.onload = function () {
250 try {
251 console.log(describeElement(document.getElementById('test-root')));
252 } catch (e) {
253 console.error(e);
254 }
255}