Найти тему
Николай Сталин

E. Флексить в космосе. Yandex Cup 2020: Фронтенд — Финал

Эдвин разрабатывает свой собственный браузер HubbleBrowser для использования в межгалактических кораблях, но пока его браузер умеет рисовать только абсолютно спозиционированные элементы <div>.

Эдвин знает, что в интернете уже давно широко распространена и используется система компоновки контента Flexbox. Он хочет добавить в свой браузер возможность правильно отображать интерфейсы, описанные в спецификации Flexbox. Для этого ему требуется разработать алгоритм, который сможет позиционировать элементы согласно заданным свойствам.

Помогите написать Эдвину алгоритм, который сможет располагать элементы друг относительно друга согласно поднабору правил и свойств из спецификации Flexbox. Эдвин понимает, что лучшее – враг хорошего, поэтому вы будете разрабатывать упрощенную «наивную» версию алгоритма, который для начала сможет корректно обрабатывать только простые макеты.

Эдвин выбрал из спецификации Flexbox несколько основных CSS-свойств, которые должен поддерживать алгоритм. Их можно описать следующим интерфейсом:

interface SupportedCSSProperties {
width?: number;
height?: number;
flexGrow?: number;
flexDirection?: "row" | "column";
alignItems?: "stretch" | "baseline" | "center" | "flex-start" | "flex-end";
justifyContent?: "center" | "flex-start" | "flex-end" | "space-between"
| "space-evenly";
}

Значения по умолчанию заданы следующим образом:

const defaultValues = {
flexDirection: "row",
alignItems: "stretch",
justifyContent: "flex-start"
}

Алгоритм будет получать на вход AST-разметки и должен высчитать координаты и размеры всех элементов в соответствии с поддерживаемым набором правил Flexbox. Ноды AST имеют следующую структуру:

interface Node {
style: SupportedCSSProperties;
children?: Node[];
}

Каждая нода AST (не только корневая) может содержать дочерние ноды.На выходе, в качестве результата работы алгоритма, ожидается массив объектов описывающих координаты и размер элементов после их позиционирования алгоритмом.

interface NodeDimensionObject {
x: number;
y: number;
width: number;
height: number;
}

Чем точнее вы запрограммируете алгоритм и чем больше свойств он будет поддерживать, тем больше тестов вы сможете пройти и более высокий балл получить.

К упрощенной реализации алгоритма применяются следующие договоренности:

  • все элементы по умолчанию считаются flex-контейнерами (display: flex;)
  • корневая нода всегда будет иметь явно заданные свойства width и height;
  • корневая нода имеет координаты x и y, равные нулю (верхний левый угол);
  • все значения width и height целочисленные и измеряются в пикселях;
  • порядок объектов в результирующем массиве не учитывается;
  • все координаты должны быть заданы относительно корневой ноды;
  • суммарный размер дочерних элементов никогда не превышает размер родителя;
  • за дополнительной информацией о системе Flexbox вы можете обращаться к официальной спецификации (учтите, что от вас не требуется полного соответствия: итоговый алгоритм, проходящий все тесты, действительно будет «наивным»);
  • эталонной реализацией Flexbox-алгоритма считаем реализацию в последней версии браузера Google Chrome, при тестировании алгоритма мы будем ориентироваться на него.

Пример входных данных

{
"style": {
"width": 400,
"height": 400,
"flexDirection": "column",
"alignItems": "center"
},
"children": [{
"style": {
"width": 200,
"flexGrow": 1
}
}, {
"style": {
"width": 150,
"flexGrow": 1
}
}, {
"style": {
"width": 100,
"height": 100
}
}]
}

Ожидаемый результат

[{
"x": 0,
"y": 0,
"width": 400,
"height": 400
}, {
"x": 100,
"y": 0,
"width": 200,
"height": 150
}, {
"x": 125,
"y": 150,
"width": 150,
"height": 150
}, {
"x": 150,
"y": 300,
"width": 100,
"height": 100
}]

Решение должно быть оформлено в виде модуля

СommonJS:module.exports = function(root) {
// ваш код
return [];
}

Для отладки вашего решения и визуализации работы алгоритма вы можете использовать специально приготовленную песочницу.

Скачать условие задачи