Files
yoga/enums.py
Joe Vilches 06c26d7d46 Remove static-behaves-like-relative errata (#1556)
Summary:
Pull Request resolved: https://github.com/facebook/yoga/pull/1556

X-link: https://github.com/facebook/react-native/pull/42315

Since we aim to ship static to all users of yoga (not just XPR), we need to remove the errata that is gating most of the features. This should be a non breaking change. To ensure that, I added a new errata which, if on, will use the inner size of the containing node as the containing block. This is how it has been for a while and resolving this is risky and time consuming so for the time being we will stick with that.

Reviewed By: NickGerleman

Differential Revision: D52706161

fbshipit-source-id: 30a93f29cb0d97b20b2947eaa21f36cdc78c4961
2024-01-18 21:22:05 -08:00

290 lines
9.7 KiB
Python
Executable File

#!/usr/bin/env python3
# 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.
import math
import os
ENUMS = {
"Direction": ["Inherit", "LTR", "RTL"],
"Unit": ["Undefined", "Point", "Percent", "Auto"],
"FlexDirection": ["Column", "ColumnReverse", "Row", "RowReverse"],
"Justify": [
"FlexStart",
"Center",
"FlexEnd",
"SpaceBetween",
"SpaceAround",
"SpaceEvenly",
],
"Overflow": ["Visible", "Hidden", "Scroll"],
"Align": [
"Auto",
"FlexStart",
"Center",
"FlexEnd",
"Stretch",
"Baseline",
"SpaceBetween",
"SpaceAround",
"SpaceEvenly",
],
"PositionType": ["Static", "Relative", "Absolute"],
"Display": ["Flex", "None"],
"Wrap": ["NoWrap", "Wrap", "WrapReverse"],
"MeasureMode": ["Undefined", "Exactly", "AtMost"],
"Dimension": ["Width", "Height"],
"Edge": [
"Left",
"Top",
"Right",
"Bottom",
"Start",
"End",
"Horizontal",
"Vertical",
"All",
],
"NodeType": ["Default", "Text"],
"LogLevel": ["Error", "Warn", "Info", "Debug", "Verbose", "Fatal"],
"ExperimentalFeature": [
# Mimic web flex-basis behavior (experiment may be broken)
"WebFlexBasis",
],
"PrintOptions": [
("Layout", 1 << 0),
("Style", 1 << 1),
("Children", 1 << 2),
],
"Gutter": ["Column", "Row", "All"],
# Known incorrect behavior which can be enabled for compatibility
"Errata": [
# Default: Standards conformant mode
("None", 0),
# Allows main-axis flex basis to be stretched without flexGrow being
# set (previously referred to as "UseLegacyStretchBehaviour")
("StretchFlexBasis", 1 << 0),
# Positioning of absolute nodes will have various bugs related to
# justification, alignment, and insets
("AbsolutePositioning", 1 << 1),
# Absolute nodes will resolve percentages against the inner size of
# their containing node, not the padding box
("AbsolutePercentAgainstInnerSize", 1 << 2),
# Enable all incorrect behavior (preserve compatibility)
("All", 0x7FFFFFFF),
# Enable all errata except for "StretchFlexBasis" (Defaults behavior
# before Yoga 2.0)
("Classic", 0x7FFFFFFF & (~(1 << 0))),
],
}
DO_NOT_STRIP = ["LogLevel"]
BITSET_ENUMS = ["PrintOptions", "Errata"]
def get_license(ext):
return f"""{"/**" if ext == "js" else "/*"}
* 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.
*/
// @{"generated"} by enums.py
{"// clang-format off" if ext == "cpp" else ""}
"""
def _format_name(symbol, delimiter=None, transform=None):
symbol = str(symbol)
out = ""
for i in range(0, len(symbol)):
c = symbol[i]
if str.istitle(c) and i != 0 and not str.istitle(symbol[i - 1]):
out += delimiter or ""
if transform is None:
out += c
else:
out += getattr(c, transform)()
return out
def to_java_upper(symbol):
return _format_name(symbol, "_", "upper")
def to_hyphenated_lower(symbol):
return _format_name(symbol, "-", "lower")
root = os.path.dirname(os.path.abspath(__file__))
# write out C & Objective-C headers
with open(root + "/yoga/YGEnums.h", "w") as f:
f.write(get_license("cpp"))
f.write("#pragma once\n")
f.write("#include <yoga/YGMacros.h>\n\n")
f.write("YG_EXTERN_C_BEGIN\n\n")
items = sorted(ENUMS.items())
for name, values in items:
f.write("YG_ENUM_DECL(\n")
f.write(" YG%s,\n" % name)
for value in values:
if isinstance(value, tuple):
f.write(" YG%s%s = %d" % (name, value[0], value[1]))
else:
f.write(" YG%s%s" % (name, value))
if value == values[-1]:
f.write(")\n")
else:
f.write(",\n")
if name in BITSET_ENUMS:
f.write("YG_DEFINE_ENUM_FLAG_OPERATORS(YG%s)\n" % name)
f.write("\n")
f.write("YG_EXTERN_C_END\n")
# Write out C++ scoped enums
for name, values in sorted(ENUMS.items()):
with open(f"{root}/yoga/enums/{name}.h", "w") as f:
f.write(get_license("cpp"))
f.write("#pragma once\n\n")
f.write("#include <cstdint>\n")
f.write("#include <yoga/YGEnums.h>\n")
f.write("#include <yoga/enums/YogaEnums.h>\n\n")
f.write("namespace facebook::yoga {\n\n")
width = "uint32_t" if name in BITSET_ENUMS else "uint8_t"
f.write(f"enum class {name} : {width} {{\n")
for value in values:
ordinal = value[0] if isinstance(value, tuple) else value
f.write(f" {ordinal} = YG{name}{ordinal},\n")
f.write("};\n\n")
if name in BITSET_ENUMS:
f.write(f"YG_DEFINE_ENUM_FLAG_OPERATORS({name})\n\n")
else:
f.write("template <>\n")
f.write(f"constexpr int32_t ordinalCount<{name}>() {{\n")
f.write(f" return {len(values)};\n")
f.write("}\n\n")
f.write(f"constexpr {name} scopedEnum(YG{name} unscoped) {{\n")
f.write(f" return static_cast<{name}>(unscoped);\n")
f.write("}\n\n")
f.write(f"constexpr YG{name} unscopedEnum({name} scoped) {{\n")
f.write(f" return static_cast<YG{name}>(scoped);\n")
f.write("}\n\n")
f.write(f"inline const char* toString({name} e) {{\n")
f.write(f" return YG{name}ToString(unscopedEnum(e));\n")
f.write("}\n\n")
f.write("} // namespace facebook::yoga\n")
# write out C body for printing
with open(root + "/yoga/YGEnums.cpp", "w") as f:
f.write(get_license("cpp"))
f.write("#include <yoga/YGEnums.h>\n\n")
items = sorted(ENUMS.items())
for name, values in items:
f.write("const char* YG%sToString(const YG%s value) {\n" % (name, name))
f.write(" switch (value) {\n")
for value in values:
if isinstance(value, tuple):
f.write(" case YG%s%s:\n" % (name, value[0]))
f.write(' return "%s";\n' % to_hyphenated_lower(value[0]))
else:
f.write(" case YG%s%s:\n" % (name, value))
f.write(' return "%s";\n' % to_hyphenated_lower(value))
f.write(" }\n")
f.write(' return "unknown";\n')
f.write("}\n")
if name != items[-1][0]:
f.write("\n")
# write out java files
for name, values in sorted(ENUMS.items()):
with open(root + "/java/com/facebook/yoga/Yoga%s.java" % name, "w") as f:
f.write(get_license("java"))
f.write("package com.facebook.yoga;\n\n")
if name in DO_NOT_STRIP:
f.write("import com.facebook.yoga.annotations.DoNotStrip;\n\n")
f.write("@DoNotStrip\n")
f.write("public enum Yoga%s {\n" % name)
if len(values) > 0:
for value in values:
if isinstance(value, tuple):
f.write(" %s(%d)" % (to_java_upper(value[0]), value[1]))
else:
f.write(" %s(%d)" % (to_java_upper(value), values.index(value)))
if values.index(value) is len(values) - 1:
f.write(";\n")
else:
f.write(",\n")
else:
f.write("__EMPTY(-1);")
f.write("\n")
f.write(" private final int mIntValue;\n")
f.write("\n")
f.write(" Yoga%s(int intValue) {\n" % name)
f.write(" mIntValue = intValue;\n")
f.write(" }\n")
f.write("\n")
f.write(" public int intValue() {\n")
f.write(" return mIntValue;\n")
f.write(" }\n")
f.write("\n")
if name in DO_NOT_STRIP:
f.write(" @DoNotStrip\n")
f.write(" public static Yoga%s fromInt(int value) {\n" % name)
f.write(" switch (value) {\n")
for value in values:
if isinstance(value, tuple):
f.write(
" case %d: return %s;\n" % (value[1], to_java_upper(value[0]))
)
else:
f.write(
" case %d: return %s;\n"
% (values.index(value), to_java_upper(value))
)
f.write(
' default: throw new IllegalArgumentException("Unknown enum value: " + value);\n'
)
f.write(" }\n")
f.write(" }\n")
f.write("}\n")
# write out TypeScript file
with open(root + "/javascript/src/generated/YGEnums.ts", "w") as f:
f.write(get_license("js"))
enums = sorted(ENUMS.items())
for enum_name, ordinals in enums:
f.write(f"export enum {enum_name} {{\n")
for ordinal_index, ordinal in enumerate(ordinals):
ordinal_name = ordinal[0] if isinstance(ordinal, tuple) else ordinal
ordinal_value = ordinal[1] if isinstance(ordinal, tuple) else ordinal_index
f.write(f" {ordinal_name} = {ordinal_value},\n")
f.write("}\n\n")
f.write("const constants = {\n")
for enum_name, ordinals in enums:
for ordinal in ordinals:
ordinal_name = ordinal[0] if isinstance(ordinal, tuple) else ordinal
ordinal_value = ordinal[1] if isinstance(ordinal, tuple) else ordinal_index
f.write(
f" {to_java_upper(enum_name)}_{to_java_upper(ordinal_name)}: {enum_name}.{ordinal_name},\n"
)
f.write("}\n")
f.write("export default constants")