@ansight/react-native 1.3.0-preview.1 → 1.3.0-preview.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/android/build.gradle +2 -2
- package/index.js +109 -28
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,8 +77,8 @@ bundle; its API requires the native Ansight module.
|
|
|
77
77
|
|
|
78
78
|
This package version expects matching native SDK packages:
|
|
79
79
|
|
|
80
|
-
- CocoaPods: `Ansight`, `AnsightObjC` version `1.3.0-preview.
|
|
81
|
-
- Maven: `ai.ansight:ansight-android:1.3.0-preview.
|
|
80
|
+
- CocoaPods: `Ansight`, `AnsightObjC` version `1.3.0-preview.3`
|
|
81
|
+
- Maven: `ai.ansight:ansight-android:1.3.0-preview.3`
|
|
82
82
|
|
|
83
83
|
## Quickstart
|
|
84
84
|
|
package/android/build.gradle
CHANGED
|
@@ -67,6 +67,6 @@ repositories {
|
|
|
67
67
|
dependencies {
|
|
68
68
|
implementation("com.facebook.react:react-android")
|
|
69
69
|
def ansightAndroidVersion =
|
|
70
|
-
findProperty("ansightAndroidVersion") ?: "1.3.0-preview.
|
|
71
|
-
implementation("ai.ansight:ansight-android:1.3.0-preview.
|
|
70
|
+
findProperty("ansightAndroidVersion") ?: "1.3.0-preview.3"
|
|
71
|
+
implementation("ai.ansight:ansight-android:1.3.0-preview.3")
|
|
72
72
|
}
|
package/index.js
CHANGED
|
@@ -1391,7 +1391,7 @@ function summarizeProps(props) {
|
|
|
1391
1391
|
}
|
|
1392
1392
|
const keys = Object.keys(props).filter((key) => key !== "children");
|
|
1393
1393
|
const summary = { keys };
|
|
1394
|
-
["testID", "nativeID", "accessibilityLabel", "role"].forEach((key) => {
|
|
1394
|
+
["testID", "nativeID", "accessibilityLabel", "accessibilityRole", "role"].forEach((key) => {
|
|
1395
1395
|
if (props[key] != null && !isSensitiveKey(key)) {
|
|
1396
1396
|
summary[key] = String(props[key]);
|
|
1397
1397
|
}
|
|
@@ -1403,6 +1403,42 @@ function summarizeProps(props) {
|
|
|
1403
1403
|
return summary;
|
|
1404
1404
|
}
|
|
1405
1405
|
|
|
1406
|
+
function reactSemanticRole(type, props, fiberTag) {
|
|
1407
|
+
const declared = props && (props.accessibilityRole || props.role);
|
|
1408
|
+
if (declared) return String(declared).toLowerCase();
|
|
1409
|
+
if (fiberTag === 6 || /text/i.test(type)) return "text";
|
|
1410
|
+
if (/button|pressable|touchable/i.test(type)) return "button";
|
|
1411
|
+
if (/textinput/i.test(type)) return "textbox";
|
|
1412
|
+
if (/switch/i.test(type)) return "switch";
|
|
1413
|
+
if (/scrollview|flatlist|sectionlist/i.test(type)) return "scrollview";
|
|
1414
|
+
return "view";
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
function reactSupportedActions(type, props) {
|
|
1418
|
+
const actions = [];
|
|
1419
|
+
if (props && typeof props.onPress === "function") actions.push("tap");
|
|
1420
|
+
if (props && (typeof props.onChangeText === "function" || /textinput/i.test(type))) {
|
|
1421
|
+
actions.push("typeText", "focus");
|
|
1422
|
+
}
|
|
1423
|
+
if (/scrollview|flatlist|sectionlist/i.test(type) || (props && typeof props.onScroll === "function")) {
|
|
1424
|
+
actions.push("scroll", "swipe");
|
|
1425
|
+
}
|
|
1426
|
+
return actions;
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
function applyReactTargetability(node, fiber, props, type) {
|
|
1430
|
+
const style = StyleSheet && typeof StyleSheet.flatten === "function"
|
|
1431
|
+
? StyleSheet.flatten(props && props.style)
|
|
1432
|
+
: props && props.style;
|
|
1433
|
+
node.text = node.label || (node.visual && node.visual.text) || null;
|
|
1434
|
+
node.role = reactSemanticRole(type, props, fiber.tag);
|
|
1435
|
+
node.supportedActions = reactSupportedActions(type, props);
|
|
1436
|
+
node.visible = !(style && style.display === "none") && !(props && props.accessibilityElementsHidden);
|
|
1437
|
+
node.enabled = !(props && (props.disabled === true || props.accessibilityState && props.accessibilityState.disabled === true));
|
|
1438
|
+
node.focusable = !!(props && props.focusable) || node.supportedActions.includes("focus");
|
|
1439
|
+
node.interactable = node.visible && node.enabled && node.supportedActions.length > 0;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1406
1442
|
function reactColorToArgbHex(value) {
|
|
1407
1443
|
if (value == null) {
|
|
1408
1444
|
return undefined;
|
|
@@ -1453,6 +1489,28 @@ function createReactVisual(fiber, props, maxStringLength) {
|
|
|
1453
1489
|
return visual;
|
|
1454
1490
|
}
|
|
1455
1491
|
|
|
1492
|
+
function createReactZIndex(props) {
|
|
1493
|
+
const style = StyleSheet && typeof StyleSheet.flatten === "function"
|
|
1494
|
+
? StyleSheet.flatten(props && props.style)
|
|
1495
|
+
: props && props.style;
|
|
1496
|
+
const zIndex = style && style.zIndex != null ? Number(style.zIndex) : NaN;
|
|
1497
|
+
const elevation = style && style.elevation != null ? Number(style.elevation) : NaN;
|
|
1498
|
+
if (Number.isFinite(zIndex) && zIndex !== 0) return zIndex;
|
|
1499
|
+
if (Number.isFinite(elevation) && elevation !== 0) return elevation;
|
|
1500
|
+
return null;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
function registerReactType(context, typeName) {
|
|
1504
|
+
const normalizedTypeName = String(typeName || "UnknownComponent").trim() || "UnknownComponent";
|
|
1505
|
+
const existingTypeId = context.typeIdsByName.get(normalizedTypeName);
|
|
1506
|
+
if (existingTypeId != null) return existingTypeId;
|
|
1507
|
+
|
|
1508
|
+
const typeId = context.types.length;
|
|
1509
|
+
context.types.push(normalizedTypeName);
|
|
1510
|
+
context.typeIdsByName.set(normalizedTypeName, typeId);
|
|
1511
|
+
return typeId;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1456
1514
|
function nativeTagForFiber(fiber) {
|
|
1457
1515
|
const stateNode = fiber && fiber.stateNode;
|
|
1458
1516
|
if (!stateNode) {
|
|
@@ -1524,17 +1582,17 @@ function serializeFiber(fiber, context, depth) {
|
|
|
1524
1582
|
|
|
1525
1583
|
const props = fiber.memoizedProps || fiber.pendingProps || {};
|
|
1526
1584
|
const type = reactFiberTypeName(fiber);
|
|
1527
|
-
const kind = reactFiberKind(fiber.tag);
|
|
1528
1585
|
const node = {
|
|
1529
1586
|
id: reactFiberId(fiber),
|
|
1530
|
-
type,
|
|
1531
|
-
kind,
|
|
1587
|
+
typeId: registerReactType(context, type),
|
|
1532
1588
|
tag: fiber.tag,
|
|
1533
1589
|
key: fiber.key == null ? null : String(fiber.key),
|
|
1534
1590
|
depth,
|
|
1535
1591
|
visual: createReactVisual(fiber, props, context.maxStringLength),
|
|
1536
1592
|
children: [],
|
|
1537
1593
|
};
|
|
1594
|
+
const zIndex = createReactZIndex(props);
|
|
1595
|
+
if (zIndex != null) node.z = zIndex;
|
|
1538
1596
|
|
|
1539
1597
|
if (fiber._debugSource) {
|
|
1540
1598
|
node.source = {
|
|
@@ -1546,7 +1604,7 @@ function serializeFiber(fiber, context, depth) {
|
|
|
1546
1604
|
|
|
1547
1605
|
const owner = fiber._debugOwner && reactFiberTypeName(fiber._debugOwner);
|
|
1548
1606
|
if (owner) {
|
|
1549
|
-
node.
|
|
1607
|
+
node.ownerTypeId = registerReactType(context, owner);
|
|
1550
1608
|
}
|
|
1551
1609
|
|
|
1552
1610
|
const nativeTag = nativeTagForFiber(fiber);
|
|
@@ -1577,6 +1635,8 @@ function serializeFiber(fiber, context, depth) {
|
|
|
1577
1635
|
node.state = sanitizeValue(fiber.memoizedState, context);
|
|
1578
1636
|
}
|
|
1579
1637
|
|
|
1638
|
+
applyReactTargetability(node, fiber, props, type);
|
|
1639
|
+
|
|
1580
1640
|
if (depth < context.maxDepth) {
|
|
1581
1641
|
let child = fiber.child;
|
|
1582
1642
|
while (child) {
|
|
@@ -1600,16 +1660,18 @@ function isShadowTreeFiber(fiber) {
|
|
|
1600
1660
|
|
|
1601
1661
|
function createShadowTreeNode(fiber, context, depth) {
|
|
1602
1662
|
const props = fiber.memoizedProps || fiber.pendingProps || {};
|
|
1663
|
+
const type = reactFiberTypeName(fiber);
|
|
1603
1664
|
const node = {
|
|
1604
1665
|
id: reactFiberId(fiber),
|
|
1605
|
-
|
|
1606
|
-
kind: fiber.tag === 3 ? "root" : fiber.tag === 6 ? "text" : "host",
|
|
1666
|
+
typeId: registerReactType(context, type),
|
|
1607
1667
|
tag: fiber.tag,
|
|
1608
1668
|
key: fiber.key == null ? null : String(fiber.key),
|
|
1609
1669
|
depth,
|
|
1610
1670
|
visual: createReactVisual(fiber, props, context.maxStringLength),
|
|
1611
1671
|
children: [],
|
|
1612
1672
|
};
|
|
1673
|
+
const zIndex = createReactZIndex(props);
|
|
1674
|
+
if (zIndex != null) node.z = zIndex;
|
|
1613
1675
|
|
|
1614
1676
|
const nativeTag = nativeTagForFiber(fiber);
|
|
1615
1677
|
if (nativeTag != null) {
|
|
@@ -1635,6 +1697,8 @@ function createShadowTreeNode(fiber, context, depth) {
|
|
|
1635
1697
|
}
|
|
1636
1698
|
}
|
|
1637
1699
|
|
|
1700
|
+
applyReactTargetability(node, fiber, props, type);
|
|
1701
|
+
|
|
1638
1702
|
return node;
|
|
1639
1703
|
}
|
|
1640
1704
|
|
|
@@ -1691,19 +1755,21 @@ async function captureReactVisualTree(rawOptions = {}) {
|
|
|
1691
1755
|
maxStringLength: rawOptions.maxStringLength || 180,
|
|
1692
1756
|
maxValueDepth: rawOptions.maxValueDepth || 2,
|
|
1693
1757
|
nodesWithNativeTags: [],
|
|
1758
|
+
typeIdsByName: new Map(),
|
|
1759
|
+
types: [],
|
|
1694
1760
|
count: 0,
|
|
1695
1761
|
truncated: false,
|
|
1696
1762
|
visited: new Set(),
|
|
1697
1763
|
};
|
|
1698
1764
|
const roots = getReactRoots();
|
|
1699
|
-
const rootNodes = roots.roots.map((root
|
|
1765
|
+
const rootNodes = roots.roots.map((root) => {
|
|
1700
1766
|
const node = serializeFiber(root.fiber, context, 0);
|
|
1701
1767
|
if (node) {
|
|
1702
1768
|
node.rendererId = root.rendererId;
|
|
1703
|
-
node.rootIndex = index;
|
|
1704
1769
|
}
|
|
1705
1770
|
return node;
|
|
1706
1771
|
}).filter(Boolean);
|
|
1772
|
+
const rootTypeId = registerReactType(context, "ReactRoots");
|
|
1707
1773
|
|
|
1708
1774
|
if (includeBounds && context.nodesWithNativeTags.length > 0) {
|
|
1709
1775
|
await Promise.all(context.nodesWithNativeTags.slice(0, 300).map(async (node) => {
|
|
@@ -1715,6 +1781,7 @@ async function captureReactVisualTree(rawOptions = {}) {
|
|
|
1715
1781
|
}
|
|
1716
1782
|
|
|
1717
1783
|
return {
|
|
1784
|
+
format: "ansight.react.visual-tree.compact.v2",
|
|
1718
1785
|
platform: Platform.OS,
|
|
1719
1786
|
source: "react",
|
|
1720
1787
|
adapter: "react.fiber",
|
|
@@ -1724,11 +1791,11 @@ async function captureReactVisualTree(rawOptions = {}) {
|
|
|
1724
1791
|
renderers: roots.renderers,
|
|
1725
1792
|
root: {
|
|
1726
1793
|
id: "react:roots",
|
|
1727
|
-
|
|
1728
|
-
|
|
1794
|
+
typeId: rootTypeId,
|
|
1795
|
+
childCount: rootNodes.length,
|
|
1729
1796
|
children: rootNodes,
|
|
1730
1797
|
},
|
|
1731
|
-
|
|
1798
|
+
types: context.types,
|
|
1732
1799
|
nodeCount: context.count,
|
|
1733
1800
|
truncated: context.truncated,
|
|
1734
1801
|
unavailableReason: roots.hookAvailable ? undefined : "React DevTools global hook is not available in this runtime.",
|
|
@@ -1748,19 +1815,21 @@ async function captureReactShadowTree(rawOptions = {}) {
|
|
|
1748
1815
|
maxStringLength: rawOptions.maxStringLength || 180,
|
|
1749
1816
|
maxValueDepth: rawOptions.maxValueDepth || 2,
|
|
1750
1817
|
nodesWithNativeTags: [],
|
|
1818
|
+
typeIdsByName: new Map(),
|
|
1819
|
+
types: [],
|
|
1751
1820
|
count: 0,
|
|
1752
1821
|
truncated: false,
|
|
1753
1822
|
visited: new Set(),
|
|
1754
1823
|
};
|
|
1755
1824
|
const roots = getReactRoots();
|
|
1756
|
-
const rootNodes = roots.roots.flatMap((root
|
|
1825
|
+
const rootNodes = roots.roots.flatMap((root) => {
|
|
1757
1826
|
const nodes = serializeShadowFiber(root.fiber, context, 0);
|
|
1758
1827
|
nodes.forEach((node) => {
|
|
1759
1828
|
node.rendererId = root.rendererId;
|
|
1760
|
-
node.rootIndex = index;
|
|
1761
1829
|
});
|
|
1762
1830
|
return nodes;
|
|
1763
1831
|
});
|
|
1832
|
+
const rootTypeId = registerReactType(context, "ReactNativeShadowRoots");
|
|
1764
1833
|
|
|
1765
1834
|
if (includeBounds && context.nodesWithNativeTags.length > 0) {
|
|
1766
1835
|
await Promise.all(context.nodesWithNativeTags.slice(0, 300).map(async (node) => {
|
|
@@ -1772,6 +1841,7 @@ async function captureReactShadowTree(rawOptions = {}) {
|
|
|
1772
1841
|
}
|
|
1773
1842
|
|
|
1774
1843
|
return {
|
|
1844
|
+
format: "ansight.react.visual-tree.compact.v2",
|
|
1775
1845
|
platform: Platform.OS,
|
|
1776
1846
|
source: "react-native",
|
|
1777
1847
|
adapter: "react-native.host-fiber",
|
|
@@ -1781,11 +1851,11 @@ async function captureReactShadowTree(rawOptions = {}) {
|
|
|
1781
1851
|
renderers: roots.renderers,
|
|
1782
1852
|
root: {
|
|
1783
1853
|
id: "react:shadow-roots",
|
|
1784
|
-
|
|
1785
|
-
|
|
1854
|
+
typeId: rootTypeId,
|
|
1855
|
+
childCount: rootNodes.length,
|
|
1786
1856
|
children: rootNodes,
|
|
1787
1857
|
},
|
|
1788
|
-
|
|
1858
|
+
types: context.types,
|
|
1789
1859
|
nodeCount: context.count,
|
|
1790
1860
|
truncated: context.truncated,
|
|
1791
1861
|
unavailableReason: roots.hookAvailable ? undefined : "React DevTools global hook is not available in this runtime.",
|
|
@@ -1801,13 +1871,18 @@ function flattenReactTree(node, output = []) {
|
|
|
1801
1871
|
return output;
|
|
1802
1872
|
}
|
|
1803
1873
|
|
|
1804
|
-
function
|
|
1874
|
+
function createReactNodeSnapshot(node) {
|
|
1875
|
+
const snapshot = { ...node };
|
|
1876
|
+
delete snapshot.children;
|
|
1877
|
+
return snapshot;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
function nodeSearchText(node, types) {
|
|
1805
1881
|
return [
|
|
1806
1882
|
node.id,
|
|
1807
|
-
node.
|
|
1808
|
-
node.kind,
|
|
1883
|
+
types[node.typeId],
|
|
1809
1884
|
node.label,
|
|
1810
|
-
node.
|
|
1885
|
+
types[node.ownerTypeId],
|
|
1811
1886
|
node.propsSummary && node.propsSummary.testID,
|
|
1812
1887
|
node.propsSummary && node.propsSummary.nativeID,
|
|
1813
1888
|
node.propsSummary && node.propsSummary.accessibilityLabel,
|
|
@@ -1815,14 +1890,14 @@ function nodeSearchText(node) {
|
|
|
1815
1890
|
].filter(Boolean).join(" ").toLowerCase();
|
|
1816
1891
|
}
|
|
1817
1892
|
|
|
1818
|
-
function matchesReactNode(node, args) {
|
|
1893
|
+
function matchesReactNode(node, args, types) {
|
|
1819
1894
|
const query = args.query ? String(args.query).toLowerCase() : null;
|
|
1820
1895
|
const type = args.type ? String(args.type).toLowerCase() : null;
|
|
1821
1896
|
const testID = args.testID ? String(args.testID).toLowerCase() : null;
|
|
1822
1897
|
const text = args.text ? String(args.text).toLowerCase() : null;
|
|
1823
|
-
const searchText = nodeSearchText(node);
|
|
1898
|
+
const searchText = nodeSearchText(node, types);
|
|
1824
1899
|
return (!query || searchText.includes(query)) &&
|
|
1825
|
-
(!type || String(node.
|
|
1900
|
+
(!type || String(types[node.typeId] || "").toLowerCase().includes(type)) &&
|
|
1826
1901
|
(!testID || String((node.propsSummary && node.propsSummary.testID) || "").toLowerCase() === testID) &&
|
|
1827
1902
|
(!text || searchText.includes(text));
|
|
1828
1903
|
}
|
|
@@ -2043,12 +2118,14 @@ function installReactTools(options = {}) {
|
|
|
2043
2118
|
});
|
|
2044
2119
|
const maxResults = parseInteger(args.maxResults, 50, 1, 500);
|
|
2045
2120
|
const matches = flattenReactTree(tree.root)
|
|
2046
|
-
.filter((node) => node.id !== "react:roots" && matchesReactNode(node, args))
|
|
2047
|
-
.slice(0, maxResults)
|
|
2121
|
+
.filter((node) => node.id !== "react:roots" && matchesReactNode(node, args, tree.types))
|
|
2122
|
+
.slice(0, maxResults)
|
|
2123
|
+
.map(createReactNodeSnapshot);
|
|
2048
2124
|
return {
|
|
2049
2125
|
success: tree.hookAvailable,
|
|
2050
2126
|
message: `Found ${matches.length} React component(s).`,
|
|
2051
2127
|
result: {
|
|
2128
|
+
types: tree.types,
|
|
2052
2129
|
matches,
|
|
2053
2130
|
count: matches.length,
|
|
2054
2131
|
truncated: matches.length === maxResults,
|
|
@@ -2060,7 +2137,11 @@ function installReactTools(options = {}) {
|
|
|
2060
2137
|
const tree = await captureReactVisualTree(reactToolOptions(options, args));
|
|
2061
2138
|
const node = flattenReactTree(tree.root).find((candidate) => candidate.id === args.nodeId);
|
|
2062
2139
|
return node
|
|
2063
|
-
? {
|
|
2140
|
+
? {
|
|
2141
|
+
success: true,
|
|
2142
|
+
message: "React component captured.",
|
|
2143
|
+
result: { types: tree.types, node: createReactNodeSnapshot(node) },
|
|
2144
|
+
}
|
|
2064
2145
|
: { success: false, message: `React component '${args.nodeId}' was not found.`, errorCode: "react_component_not_found" };
|
|
2065
2146
|
}
|
|
2066
2147
|
|
|
@@ -2101,7 +2182,7 @@ function installReactTools(options = {}) {
|
|
|
2101
2182
|
result: {
|
|
2102
2183
|
nodeId: args.nodeId,
|
|
2103
2184
|
prop,
|
|
2104
|
-
type: node.
|
|
2185
|
+
type: tree.types[node.typeId],
|
|
2105
2186
|
},
|
|
2106
2187
|
};
|
|
2107
2188
|
}
|