@ansight/react-native 1.3.0-preview.9 → 1.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ansight/react-native",
3
- "version": "1.3.0-preview.9",
3
+ "version": "1.4.0-preview.3",
4
4
  "description": "React Native bridge for the Ansight mobile SDK.",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -25,6 +25,11 @@
25
25
  "README.md",
26
26
  "index.js",
27
27
  "index.d.ts",
28
+ "react-inspection-hook.js",
29
+ "react-tree-geometry.js",
30
+ "react-tree-semantics.js",
31
+ "network.js",
32
+ "session-properties.js",
28
33
  "app.plugin.js",
29
34
  "expo-plugin.js",
30
35
  "tsconfig.json",
@@ -44,7 +49,8 @@
44
49
  "react-native": ">=0.72"
45
50
  },
46
51
  "scripts": {
47
- "check": "node --check index.js && node --check app.plugin.js && node --check expo-plugin.js && tsc --noEmit",
52
+ "check": "node --check index.js && node --check session-properties.js && node --check app.plugin.js && node --check expo-plugin.js && tsc --noEmit && npm test",
53
+ "test": "node --test test/*.test.js",
48
54
  "typecheck": "tsc --noEmit"
49
55
  },
50
56
  "devDependencies": {
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+
3
+ const ANSIGHT_HOOK_MARKER = "__ansightReactInspectionHook";
4
+
5
+ function hasElementState(current) {
6
+ const state = current && current.memoizedState;
7
+ if (!state || typeof state !== "object") {
8
+ return true;
9
+ }
10
+ if (!Object.prototype.hasOwnProperty.call(state, "element")) {
11
+ return true;
12
+ }
13
+ return state.element != null;
14
+ }
15
+
16
+ function createReactInspectionHook() {
17
+ const renderers = new Map();
18
+ const fiberRoots = new Map();
19
+ let nextRendererId = 1;
20
+
21
+ function rootsForRenderer(rendererId) {
22
+ let roots = fiberRoots.get(rendererId);
23
+ if (!roots) {
24
+ roots = new Set();
25
+ fiberRoots.set(rendererId, roots);
26
+ }
27
+ return roots;
28
+ }
29
+
30
+ return {
31
+ [ANSIGHT_HOOK_MARKER]: true,
32
+ supportsFiber: true,
33
+ isDisabled: false,
34
+ renderers,
35
+ _fiberRoots: fiberRoots,
36
+ inject(renderer) {
37
+ const rendererId = nextRendererId++;
38
+ renderers.set(rendererId, renderer);
39
+ rootsForRenderer(rendererId);
40
+ return rendererId;
41
+ },
42
+ getFiberRoots(rendererId) {
43
+ return rootsForRenderer(rendererId);
44
+ },
45
+ onCommitFiberRoot(rendererId, root) {
46
+ const roots = rootsForRenderer(rendererId);
47
+ if (root && root.current && hasElementState(root.current)) {
48
+ roots.add(root);
49
+ } else {
50
+ roots.delete(root);
51
+ }
52
+ },
53
+ onCommitFiberUnmount() {},
54
+ };
55
+ }
56
+
57
+ function ensureReactInspectionHook(runtimeGlobal) {
58
+ if (!runtimeGlobal || typeof runtimeGlobal !== "object") {
59
+ return undefined;
60
+ }
61
+
62
+ const existing = runtimeGlobal.__REACT_DEVTOOLS_GLOBAL_HOOK__;
63
+ if (existing) {
64
+ return existing;
65
+ }
66
+
67
+ const hook = createReactInspectionHook();
68
+ runtimeGlobal.__REACT_DEVTOOLS_GLOBAL_HOOK__ = hook;
69
+ return hook;
70
+ }
71
+
72
+ module.exports = {
73
+ ANSIGHT_HOOK_MARKER,
74
+ createReactInspectionHook,
75
+ ensureReactInspectionHook,
76
+ };
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+
3
+ function readDimensionSize(dimensions, name) {
4
+ if (!dimensions || typeof dimensions.get !== "function") {
5
+ return null;
6
+ }
7
+ try {
8
+ const value = dimensions.get(name);
9
+ const width = Number(value && value.width);
10
+ const height = Number(value && value.height);
11
+ if (Number.isFinite(width) && width > 0 && Number.isFinite(height) && height > 0) {
12
+ return { width, height };
13
+ }
14
+ } catch (_) {
15
+ // Some non-native React renderers do not expose screen dimensions.
16
+ }
17
+ return null;
18
+ }
19
+
20
+ function viewportHostBounds(nodes, screenSize) {
21
+ const candidates = (nodes || [])
22
+ .map((node) => node && node.bounds)
23
+ .filter((bounds) => bounds
24
+ && Number.isFinite(Number(bounds.x))
25
+ && Number.isFinite(Number(bounds.y))
26
+ && Number.isFinite(Number(bounds.width))
27
+ && Number.isFinite(Number(bounds.height))
28
+ && Number(bounds.width) >= screenSize.width * 0.85
29
+ && Number(bounds.height) >= screenSize.height * 0.5);
30
+ if (candidates.length === 0) {
31
+ return null;
32
+ }
33
+ return candidates.reduce((largest, candidate) => (
34
+ Number(candidate.width) * Number(candidate.height)
35
+ > Number(largest.width) * Number(largest.height)
36
+ ? candidate
37
+ : largest
38
+ ));
39
+ }
40
+
41
+ function createReactCoordinateSpace(dimensions, measuredNodes = []) {
42
+ const screenSize = readDimensionSize(dimensions, "screen");
43
+ const windowSize = readDimensionSize(dimensions, "window");
44
+ const size = screenSize || windowSize;
45
+ if (!size) {
46
+ return undefined;
47
+ }
48
+
49
+ const hostBounds = viewportHostBounds(measuredNodes, size);
50
+ return {
51
+ x: hostBounds ? Math.min(0, Number(hostBounds.x)) : 0,
52
+ y: hostBounds ? Math.min(0, Number(hostBounds.y)) : 0,
53
+ width: size.width,
54
+ height: size.height,
55
+ source: screenSize ? "react-native.screen" : "react-native.window",
56
+ };
57
+ }
58
+
59
+ module.exports = {
60
+ createReactCoordinateSpace,
61
+ };
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ function reactSemanticRole(type, props, fiberTag) {
4
+ const declared = props && (props.accessibilityRole || props.role);
5
+ if (declared) return String(declared).toLowerCase();
6
+ if (fiberTag === 6 || /text/i.test(type)) return "text";
7
+ if (/button|pressable|touchable/i.test(type)) return "button";
8
+ if (/textinput/i.test(type)) return "textbox";
9
+ if (/switch/i.test(type)) return "switch";
10
+ if (/scrollview|flatlist|sectionlist/i.test(type)) return "scrollview";
11
+ return "view";
12
+ }
13
+
14
+ function reactSupportedActions(type, props) {
15
+ const actions = [];
16
+ if (props && (
17
+ typeof props.onPress === "function"
18
+ || typeof props.onClick === "function"
19
+ || typeof props.onResponderRelease === "function"
20
+ )) actions.push("tap");
21
+ if (props && (typeof props.onChangeText === "function" || /textinput/i.test(type))) {
22
+ actions.push("typeText", "focus");
23
+ }
24
+ if (/scrollview|flatlist|sectionlist/i.test(type) || (props && typeof props.onScroll === "function")) {
25
+ actions.push("scroll", "swipe");
26
+ }
27
+ return actions;
28
+ }
29
+
30
+ module.exports = {
31
+ reactSemanticRole,
32
+ reactSupportedActions,
33
+ };
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+
3
+ const { version: sdkVersion } = require("./package.json");
4
+
5
+ const REACT_NATIVE_GROUP = "reactNative";
6
+ const LOCALIZATION_GROUP = "localization";
7
+
8
+ function formatBoolean(value) {
9
+ return value ? "true" : "false";
10
+ }
11
+
12
+ function normalizeString(value) {
13
+ if (value == null) {
14
+ return undefined;
15
+ }
16
+ const normalized = String(value).trim();
17
+ return normalized || undefined;
18
+ }
19
+
20
+ function formatReactNativeVersion(version) {
21
+ if (!version || typeof version !== "object") {
22
+ return undefined;
23
+ }
24
+ const major = normalizeString(version.major);
25
+ const minor = normalizeString(version.minor);
26
+ const patch = normalizeString(version.patch);
27
+ if (major == null || minor == null || patch == null) {
28
+ return undefined;
29
+ }
30
+ const prerelease = normalizeString(version.prerelease);
31
+ return `${major}.${minor}.${patch}${prerelease ? `-${prerelease}` : ""}`;
32
+ }
33
+
34
+ function resolveJavaScriptEngine(runtimeGlobal) {
35
+ if (runtimeGlobal && runtimeGlobal.HermesInternal) {
36
+ return "hermes";
37
+ }
38
+ if (runtimeGlobal && runtimeGlobal._v8runtime) {
39
+ return "v8";
40
+ }
41
+ return "javascriptCore";
42
+ }
43
+
44
+ function readHermesProperties(runtimeGlobal) {
45
+ try {
46
+ return runtimeGlobal?.HermesInternal?.getRuntimeProperties?.() || {};
47
+ } catch (_) {
48
+ return {};
49
+ }
50
+ }
51
+
52
+ function canonicalizeLocale(value) {
53
+ const normalized = normalizeString(value)?.replace(/_/g, "-");
54
+ if (!normalized) {
55
+ return undefined;
56
+ }
57
+ try {
58
+ return Intl.getCanonicalLocales(normalized)[0] || normalized;
59
+ } catch (_) {
60
+ return normalized;
61
+ }
62
+ }
63
+
64
+ function parseLocale(locale) {
65
+ const parts = (locale || "").split("-").filter(Boolean);
66
+ const language = parts[0]?.toLowerCase();
67
+ const region = parts.find(
68
+ (part, index) => index > 0 && (/^[A-Za-z]{2}$/.test(part) || /^\d{3}$/.test(part))
69
+ );
70
+ return {
71
+ language,
72
+ region: region ? region.toUpperCase() : undefined,
73
+ };
74
+ }
75
+
76
+ function createLocalizationProperties() {
77
+ let resolved = {};
78
+ try {
79
+ resolved = Intl.DateTimeFormat().resolvedOptions();
80
+ } catch (_) {
81
+ // Older JavaScript runtimes may not provide Intl data.
82
+ }
83
+
84
+ const locale = canonicalizeLocale(resolved.locale);
85
+ const parsed = parseLocale(locale);
86
+ const properties = {
87
+ utcOffsetMinutes: String(-new Date().getTimezoneOffset()),
88
+ };
89
+ if (locale) properties.locale = locale;
90
+ if (parsed.language) properties.language = parsed.language;
91
+ if (parsed.region) properties.region = parsed.region;
92
+ if (normalizeString(resolved.timeZone)) properties.timeZone = resolved.timeZone;
93
+ return properties;
94
+ }
95
+
96
+ function createAutomaticSessionProperties({
97
+ platform,
98
+ reactVersion,
99
+ runtimeGlobal,
100
+ developmentMode,
101
+ } = {}) {
102
+ const reactNativeVersion = formatReactNativeVersion(platform?.constants?.reactNativeVersion);
103
+ const newArchitectureEnabled = Boolean(
104
+ runtimeGlobal?.nativeFabricUIManager || runtimeGlobal?.__turboModuleProxy
105
+ );
106
+ const hermesProperties = readHermesProperties(runtimeGlobal);
107
+ const engineVersion = normalizeString(
108
+ hermesProperties["OSS Release Version"] || hermesProperties["Release Version"]
109
+ );
110
+ const bytecodeVersion = normalizeString(hermesProperties["Bytecode Version"]);
111
+
112
+ const properties = {
113
+ sdkVersion,
114
+ platform: normalizeString(platform?.OS) || "unknown",
115
+ runtimeLanguage: "javascript",
116
+ javascriptEngine: resolveJavaScriptEngine(runtimeGlobal),
117
+ architecture: newArchitectureEnabled ? "new" : "legacy",
118
+ newArchitectureEnabled: formatBoolean(newArchitectureEnabled),
119
+ bridgelessEnabled: formatBoolean(Boolean(runtimeGlobal?.RN$Bridgeless)),
120
+ developmentMode: formatBoolean(Boolean(developmentMode)),
121
+ };
122
+ if (reactNativeVersion) properties.reactNativeVersion = reactNativeVersion;
123
+ if (normalizeString(reactVersion)) properties.reactVersion = String(reactVersion).trim();
124
+ if (engineVersion) properties.javascriptEngineVersion = engineVersion;
125
+ if (bytecodeVersion) properties.hermesBytecodeVersion = bytecodeVersion;
126
+
127
+ return {
128
+ [REACT_NATIVE_GROUP]: properties,
129
+ [LOCALIZATION_GROUP]: createLocalizationProperties(),
130
+ };
131
+ }
132
+
133
+ function mergeSessionProperties(automaticProperties, customProperties) {
134
+ const merged = {};
135
+ for (const [group, properties] of Object.entries(automaticProperties || {})) {
136
+ merged[group] = { ...(properties || {}) };
137
+ }
138
+ for (const [group, properties] of Object.entries(customProperties || {})) {
139
+ merged[group] = { ...(merged[group] || {}), ...(properties || {}) };
140
+ }
141
+ return merged;
142
+ }
143
+
144
+ module.exports = {
145
+ LOCALIZATION_GROUP,
146
+ REACT_NATIVE_GROUP,
147
+ createAutomaticSessionProperties,
148
+ createLocalizationProperties,
149
+ formatReactNativeVersion,
150
+ mergeSessionProperties,
151
+ };