Skip to content

Commit 31b38ba

Browse files
j-piaseckimeta-codesync[bot]
authored andcommitted
Update sorting and grouping behavior (#55647)
Summary: Pull Request resolved: #55647 Changelog: [Internal] Updates sorting and grouping behavior of C++ API snapshot. Reviewed By: cipolleschi Differential Revision: D93407634
1 parent 7e5b2bf commit 31b38ba

File tree

6 files changed

+118
-20
lines changed

6 files changed

+118
-20
lines changed

scripts/cxx-api/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ ReactCommon:
55
exclude_patterns:
66
- "*/test_utils/*"
77
- "*/jni/*"
8-
- "*/platform/cxx/*"
8+
- "*/platform/cxx/*" # Should this be included in ReactCommon?
99
- "*/platform/windows/*"
1010
- "*/platform/macos/*"
1111
- "*/platform/ios/*"

scripts/cxx-api/parser/member.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from __future__ import annotations
77

88
from abc import ABC, abstractmethod
9+
from enum import IntEnum
910
from typing import TYPE_CHECKING
1011

1112
from .template import Template, TemplateList
@@ -25,12 +26,31 @@
2526
from .scope import Scope
2627

2728

29+
class MemberKind(IntEnum):
30+
"""
31+
Classification of member kinds for grouping in output.
32+
The order here determines the output order within namespace scopes.
33+
"""
34+
35+
CONSTANT = 0
36+
TYPE_ALIAS = 1
37+
CONCEPT = 2
38+
FUNCTION = 3
39+
OPERATOR = 4
40+
VARIABLE = 5
41+
42+
2843
class Member(ABC):
2944
def __init__(self, name: str, visibility: str) -> None:
3045
self.name: str = name
3146
self.visibility: str = visibility
3247
self.template_list: TemplateList | None = None
3348

49+
@property
50+
@abstractmethod
51+
def member_kind(self) -> MemberKind:
52+
pass
53+
3454
@abstractmethod
3555
def to_string(
3656
self,
@@ -62,6 +82,10 @@ def __init__(self, name: str, value: str | None) -> None:
6282
super().__init__(name, "public")
6383
self.value: str | None = value
6484

85+
@property
86+
def member_kind(self) -> MemberKind:
87+
return MemberKind.CONSTANT
88+
6589
def to_string(
6690
self,
6791
indent: int = 0,
@@ -104,6 +128,12 @@ def __init__(
104128
)
105129
self._parsed_type: list[str | list[Argument]] = parse_type_with_argstrings(type)
106130

131+
@property
132+
def member_kind(self) -> MemberKind:
133+
if self.is_const or self.is_constexpr:
134+
return MemberKind.CONSTANT
135+
return MemberKind.VARIABLE
136+
107137
def close(self, scope: Scope):
108138
self._fp_arguments = qualify_arguments(self._fp_arguments, scope)
109139
self._parsed_type = qualify_parsed_type(self._parsed_type, scope)
@@ -188,6 +218,12 @@ def __init__(
188218
self.is_const = self.modifiers.is_const
189219
self.is_override = self.modifiers.is_override
190220

221+
@property
222+
def member_kind(self) -> MemberKind:
223+
if self.name.startswith("operator"):
224+
return MemberKind.OPERATOR
225+
return MemberKind.FUNCTION
226+
191227
def close(self, scope: Scope):
192228
self.type = qualify_type_str(self.type, scope)
193229
self.arguments = qualify_arguments(self.arguments, scope)
@@ -264,6 +300,10 @@ def __init__(
264300
self._parsed_type: list[str | list[Argument]] = parse_type_with_argstrings(type)
265301
self.type: str = type
266302

303+
@property
304+
def member_kind(self) -> MemberKind:
305+
return MemberKind.TYPE_ALIAS
306+
267307
def close(self, scope: Scope):
268308
self._fp_arguments = qualify_arguments(self._fp_arguments, scope)
269309
self._parsed_type = qualify_parsed_type(self._parsed_type, scope)
@@ -315,6 +355,10 @@ def __init__(
315355
super().__init__(name, "public")
316356
self.constraint: str = self._normalize_constraint(constraint)
317357

358+
@property
359+
def member_kind(self) -> MemberKind:
360+
return MemberKind.CONCEPT
361+
318362
@staticmethod
319363
def _normalize_constraint(constraint: str) -> str:
320364
"""

scripts/cxx-api/parser/scope.py

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@
99
from enum import Enum
1010
from typing import Generic, TypeVar
1111

12-
from natsort import natsorted
12+
from natsort import natsort_keygen, natsorted
1313

14-
from .member import Member
14+
from .member import Member, MemberKind
1515
from .template import Template, TemplateList
1616
from .utils import parse_qualified_path
1717

1818

19+
# Pre-create natsort key function for efficiency
20+
_natsort_key = natsort_keygen()
21+
22+
1923
class ScopeKind(ABC):
2024
def __init__(self, name) -> None:
2125
self.name: str = name
@@ -105,11 +109,20 @@ def __init__(self) -> None:
105109
def to_string(self, scope: Scope) -> str:
106110
qualification = scope.get_qualified_name()
107111

108-
result = []
112+
# Group members by kind
113+
groups: dict[MemberKind, list[str]] = {kind: [] for kind in MemberKind}
114+
109115
for member in scope.get_members():
110-
result.append(member.to_string(0, qualification, hide_visibility=True))
116+
kind = member.member_kind
117+
stringified = member.to_string(0, qualification, hide_visibility=True)
118+
groups[kind].append(stringified)
119+
120+
# Sort within each group and combine in kind order
121+
result = []
122+
for kind in MemberKind:
123+
sorted_group = natsorted(groups[kind])
124+
result.extend(sorted_group)
111125

112-
result = natsorted(result)
113126
return "\n".join(result)
114127

115128

@@ -264,16 +277,56 @@ def to_string(self) -> str:
264277
"""
265278
Get the string representation of the scope.
266279
"""
267-
result = [self.kind.to_string(self)]
280+
# Get this scope's content (e.g., class members, free functions, ...)
281+
this_content = self.kind.to_string(self)
268282

269-
for _, inner_scope in sorted(
270-
filter(lambda x: x[0] is not None, self.inner_scopes.items()),
271-
key=lambda x: x[0],
272-
):
273-
result.append(inner_scope.to_string())
283+
# Separate inner scopes into namespaces and non-namespaces
284+
# Keep (scope, string) tuples to sort by scope properties
285+
namespace_scope_items: list[tuple[Scope, str]] = []
286+
non_namespace_scope_items: list[tuple[Scope, str]] = []
274287

275-
result = natsorted(result)
276-
return "\n\n".join(result).strip()
288+
for _, inner_scope in self.inner_scopes.items():
289+
if inner_scope.name is None:
290+
continue
291+
inner_str = inner_scope.to_string()
292+
if not inner_str.strip():
293+
continue
294+
295+
if isinstance(inner_scope.kind, NamespaceScopeKind):
296+
namespace_scope_items.append((inner_scope, inner_str))
297+
else:
298+
non_namespace_scope_items.append((inner_scope, inner_str))
299+
300+
# Sort non-namespace scopes by depth (fewer :: first) then by string
301+
def scope_sort_key(item: tuple[Scope, str]) -> tuple:
302+
scope, string = item
303+
depth = scope.get_qualified_name().count("::")
304+
return (depth, _natsort_key(string))
305+
306+
non_namespace_scope_items.sort(key=scope_sort_key)
307+
non_namespace_scope_strings = [s for _, s in non_namespace_scope_items]
308+
namespace_scope_strings = [s for _, s in namespace_scope_items]
309+
310+
# Build result:
311+
# 1. Free members / this scope's content first
312+
# 2. Non-namespace inner scopes (classes, structs, enums), sorted by depth
313+
# 3. Namespace inner scopes, each separated by "\n\n\n" (two blank lines)
314+
315+
local_parts = []
316+
if this_content.strip():
317+
local_parts.append(this_content)
318+
local_parts.extend(non_namespace_scope_strings)
319+
320+
# NOTE: Don't sort local_parts together - free members should come first
321+
local_block = "\n\n".join(local_parts)
322+
323+
# Combine with namespace scopes using one more blank line for clearer separation
324+
all_blocks = []
325+
if local_block.strip():
326+
all_blocks.append(local_block)
327+
all_blocks.extend(natsorted(namespace_scope_strings))
328+
329+
return "\n\n\n".join(all_blocks).strip()
277330

278331
def print(self):
279332
"""
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1+
struct test::TestStruct {
2+
}
3+
14
enum test::TestStruct::Enum {
25
Value1,
36
Value2,
47
}
5-
6-
struct test::TestStruct {
7-
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
struct test::Param {
2-
}
3-
41
typedef void(*test::FreeFnPtr)(test::Param);
52
using test::FreeCallback = void(test::Param);
63
void test::freeFunction(test::Param p);
4+
5+
struct test::Param {
6+
}

scripts/cxx-api/tests/snapshots/should_qualify_partially_qualified_args/snapshot.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
facebook::yoga::Result facebook::react::getResult(facebook::yoga::Node node, int flags);
22
void facebook::react::processNode(facebook::yoga::Node node);
33

4+
45
struct facebook::yoga::Node {
56
}
67

0 commit comments

Comments
 (0)