From 9bb6ba7c7a4f36f4bbb289f66c2ad232769972e7 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Mon, 3 Feb 2025 14:35:49 -0800 Subject: [PATCH] CSSCommaSeparatedList (#48987) Summary: Adds a data type parser for a variable number of values of a given single data type (at least 1). E.g. `CSSCommaSeparatedList` will represent the syntax of `#` (ie the value produced by box-shadow). Changelog: [internal] Reviewed By: lenaic Differential Revision: D68738165 --- .../renderer/css/CSSCommaSeparatedList.h | 45 +++++++++ .../css/tests/CSSCommaSeparatedListTest.cpp | 92 +++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 packages/react-native/ReactCommon/react/renderer/css/CSSCommaSeparatedList.h create mode 100644 packages/react-native/ReactCommon/react/renderer/css/tests/CSSCommaSeparatedListTest.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/css/CSSCommaSeparatedList.h b/packages/react-native/ReactCommon/react/renderer/css/CSSCommaSeparatedList.h new file mode 100644 index 00000000000000..ee640e65e9d3ef --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/CSSCommaSeparatedList.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace facebook::react { + +/** + * Represents a comma-separated repetition of a given single type. + * https://www.w3.org/TR/css-values-4/#mult-comma + */ +template +struct CSSCommaSeparatedList : public std::vector {}; + +template +struct CSSDataTypeParser> { + static inline auto consume(CSSSyntaxParser& parser) + -> std::optional> { + CSSCommaSeparatedList result; + for (auto nextValue = parseNextCSSValue(parser); + !std::holds_alternative(nextValue); + nextValue = + parseNextCSSValue(parser, CSSDelimiter::Comma)) { + result.push_back(std::move(std::get(nextValue))); + } + + if (result.empty()) { + return {}; + } + + return result; + } +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/css/tests/CSSCommaSeparatedListTest.cpp b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSCommaSeparatedListTest.cpp new file mode 100644 index 00000000000000..d96ef2f2073d7c --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/css/tests/CSSCommaSeparatedListTest.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include +#include + +namespace facebook::react { + +TEST(CSSCommaSeparatedList, empty_values) { + auto emptyValue = parseCSSProperty>(""); + EXPECT_TRUE(std::holds_alternative(emptyValue)); + + auto whitespaceValue = + parseCSSProperty>(" "); + EXPECT_TRUE(std::holds_alternative(whitespaceValue)); + + auto commaValue = parseCSSProperty>(","); +} + +TEST(CSSCommaSeparatedList, single_value) { + auto simpleValue = parseCSSProperty>("20"); + EXPECT_TRUE( + std::holds_alternative>(simpleValue)); + EXPECT_EQ(std::get>(simpleValue).size(), 1); + EXPECT_EQ( + std::get>(simpleValue)[0].value, 20); + + auto whitespaceValue = + parseCSSProperty>(" 20 "); + EXPECT_TRUE(std::holds_alternative>( + whitespaceValue)); + EXPECT_EQ( + std::get>(whitespaceValue).size(), 1); + EXPECT_EQ( + std::get>(whitespaceValue)[0].value, 20); +} + +TEST(CSSCommaSeparatedList, wrong_type) { + auto simpleValue = parseCSSProperty>("20px"); + EXPECT_TRUE(std::holds_alternative(simpleValue)); +} + +TEST(CSSCommaSeparatedList, multiple_values) { + auto simpleValue = + parseCSSProperty>("20, 30, 40"); + EXPECT_TRUE( + std::holds_alternative>(simpleValue)); + EXPECT_EQ(std::get>(simpleValue).size(), 3); + EXPECT_EQ( + std::get>(simpleValue)[0].value, 20); + EXPECT_EQ( + std::get>(simpleValue)[1].value, 30); + EXPECT_EQ( + std::get>(simpleValue)[2].value, 40); + + auto whitespaceValue = + parseCSSProperty>(" 20 , 30 , 40 "); + EXPECT_TRUE(std::holds_alternative>( + whitespaceValue)); + EXPECT_EQ( + std::get>(whitespaceValue).size(), 3); + EXPECT_EQ( + std::get>(whitespaceValue)[0].value, 20); + EXPECT_EQ( + std::get>(whitespaceValue)[1].value, 30); + EXPECT_EQ( + std::get>(whitespaceValue)[2].value, 40); +} + +TEST(CSSCommaSeparatedList, extra_tokens) { + auto extraTokensValue = + parseCSSProperty>("20, 30, 40 50"); + EXPECT_TRUE(std::holds_alternative(extraTokensValue)); +} + +TEST(CSSCommaSeparatedList, extra_commas) { + auto prefixCommaValue = + parseCSSProperty>(",20"); + EXPECT_TRUE(std::holds_alternative(prefixCommaValue)); + + auto suffixCommaValue = + parseCSSProperty>("20,"); + EXPECT_TRUE(std::holds_alternative(suffixCommaValue)); +} + +} // namespace facebook::react