Skip to content

Commit

Permalink
Add support for parsing grid style properties to test_helper.js
Browse files Browse the repository at this point in the history
  • Loading branch information
nicoburns committed Jul 30, 2022
1 parent 1ed932a commit 842db83
Showing 1 changed file with 153 additions and 56 deletions.
209 changes: 153 additions & 56 deletions scripts/gentest/test_helper.js
Original file line number Diff line number Diff line change
@@ -1,79 +1,153 @@
function define_element_prop(property, getter) {
if (!(property in Element.prototype)) {
Object.defineProperty(Element.prototype, property, {
get: function() {
return getter(this);

class TrackSizingParser {
static INITIAL_CHAR_REGEX = /[a-z-A-Z0-9]/;
static TOKEN_CHAR_REGEX = /[-\.a-z-A-Z0-9%]/;

constructor(input, options = { allowFrUnits: true }) {
this.input = input;
this.index = 0;
this.options = options;
}

parseList() {
return this._parseItemList(' ', null);
}

parseSingleItem() {
return this.parseItem();
}

_parseItemList(separator, terminator = null) {
if (!separator) throw new Error('No terminator passed');
let tokenList = [];
// console.debug('Parse List', this.index, this.input.slice(this.index));

while (this.index < this.input.length) {
const char = this.input[this.index];
// console.debug(this.index, char);

// Skip whitespace
if (char === ' ') { this.index++; continue;}

if (TrackSizingParser.INITIAL_CHAR_REGEX.test(char)) {
const token = this._parseItem();
tokenList.push(token);

const nextChar = this.input[this.index];
if ((terminator && nextChar === terminator) || !terminator && !nextChar) {
return tokenList;
} else {
this.index++;
continue;
}
}
});

throw new Error (`Invalid start of token ${char}`);
}
}
}

define_element_prop("__stretch_description__", (e) => {
return JSON.stringify(describeElement(e));
});

function parseDimension(input) {
if (input.endsWith("px")) {
return {
unit: 'points',
value: Number(input.replace('px',''))
};
} else if (input.endsWith("%")) {
return {
unit: 'percent',
value: Number(input.replace('%','')) / 100
};
} else {
return input == "auto" ? {unit: "auto"} : undefined;
_parseItem() {
let token = '';
// console.debug('Parse Item', this.index, this.input.slice(this.index));

while (this.index < this.input.length) {
const char = this.input[this.index];
// console.debug(this.index, char);

if (TrackSizingParser.TOKEN_CHAR_REGEX.test(char)) {
token += char;
this.index++;
continue;
}

if (char === '(') {
this.index++;
const args = this._parseItemList(',', ')');
this.index++;
return { type: 'function', name: token, arguments: args };
}

return { type: 'scalar', ...this._parseScalarItem(token) };
}
return { type: 'scalar', ...this._parseScalarItem(token) };

}

_parseScalarItem(item) {
const res = parseDimension(item, { allowFrUnits: this.options.allowFrUnits });
if (!res) throw new Error(`Invalid scalar grid track sizing function ${item}`);
return res;
}

}

function parseDimension(input, options = { allowFrUnits: false }) {
if (options.allowFrUnits && input.endsWith('fr')) return { unit: 'fraction', value: parseFloat(input.replace('fr','')) };
if (input.endsWith('px')) return { unit: 'points', value: parseFloat(input.replace('px','')) };
if (input.endsWith('%')) return { unit: 'percent', value: parseFloat(input.replace('%','')) / 100 };
if (input === 'auto') return { unit: 'auto' };
if (input === 'min-content') return { unit: 'min-content' };
if (input === 'max-content') return { unit: 'max-content' };
return undefined;
}

function parseNumber(input) {
if (input === "" || isNaN(input)) {
return undefined;
} else {
return Number(input);
}
if (input === '' || isNaN(input)) return undefined;
return Number(input);
}

function parseEnum(input) {
if (input) {
return input;
} else {
return undefined;
}
if (input) return input;
return undefined;
}

function parseEdges(edges) {
var start = parseDimension(edges.start);
var end = parseDimension(edges.end);
var top = parseDimension(edges.top);
var bottom = parseDimension(edges.bottom);
const start = parseDimension(edges.start);
const end = parseDimension(edges.end);
const top = parseDimension(edges.top);
const bottom = parseDimension(edges.bottom);

if (start === undefined && end === undefined && top === undefined && bottom === undefined) {
return undefined;
}

return {
start: start,
end: end,
top: top,
bottom: bottom
};
if (!start && !end && !top && !bottom) return undefined;
return { start, end, top, bottom };
}

function parseSize(size) {
var width = parseDimension(size.width);
var height = parseDimension(size.height);
const width = parseDimension(size.width);
const height = parseDimension(size.height);

if (width === undefined && height === undefined) {
return undefined;
if (!width && !height) return undefined;
return { width, height };
}

function parseGaps(style) {
if (style.gap) {
const gaps = style.gap.trim().split(/\s+/).map(part => parseDimension(part));
return { row: gaps[0], column: gaps[1] ?? gaps[0] };
}
if (style.rowGap || style.columnGap) {
return { row: parseDimension(style.rowGap), column: parseDimension(style.columnGap) }
}
return undefined;
}

return {
width: width,
height: height,
};

function parseGridTrackDefinitions(input) {
if (input === '') return undefined;
return new TrackSizingParser(input).parseList();
}

function parseGridAutoFlow(input) {
if (!/column/.test(input) && !/row/.test(input) && !/dense/.test(input)) return undefined;
const direction = /column/.test(input) ? 'column' : 'row';
const algorithm = /dense/.test(input) ? 'dense' : 'sparse';
return { direction, algorithm };
}

function parseGridPosition(input) {
if (input === 'auto') return { kind: 'auto' }
if (/^span +\d+$/.test(input)) return { kind: 'span', value: parseInt(input.replace(/[^\d]/g, ''), 10)}
if (/^-?\d+$/.test(input)) return { kind: 'track', value: parseInt(input, 10)}
return undefined;
}

function describeElement(e) {
Expand All @@ -98,6 +172,20 @@ function describeElement(e) {
flexShrink: parseNumber(e.style.flexShrink),
flexBasis: parseDimension(e.style.flexBasis),

gridTemplateRows: parseGridTrackDefinitions(e.style.gridTemplateRows),
gridTemplateColumns: parseGridTrackDefinitions(e.style.gridTemplateColumns),

gridAutoRows: parseGridTrackDefinitions(e.style.gridAutoRows),
gridAutoColumns: parseGridTrackDefinitions(e.style.gridAutoColumns),
gridAutoFlow: parseGridAutoFlow(e.style.gridAutoFlow),

gridRowStart: parseGridPosition(e.style.gridRowStart),
gridRowEnd: parseGridPosition(e.style.gridRowEnd),
gridColumnStart: parseGridPosition(e.style.gridColumnStart),
gridColumnEnd: parseGridPosition(e.style.gridColumnEnd),

gap: parseGaps(e.style),

size: parseSize({width: e.style.width, height: e.style.height}),
minSize: parseSize({width: e.style.minWidth, height: e.style.minHeight}),
maxSize: parseSize({width: e.style.maxWidth, height: e.style.maxHeight}),
Expand Down Expand Up @@ -141,3 +229,12 @@ function describeElement(e) {
children: Array.from(e.children).map(c => describeElement(c)),
}
}

// Useful when developing this script. Logs the parsed style to the console when any test fixture is opened in a browser.
window.onload = function () {
try {
console.log(describeElement(document.getElementById('test-root')));
} catch (e) {
console.error(e);
}
}

0 comments on commit 842db83

Please sign in to comment.