@colbymchenry/codegraph-darwin-x64 0.9.4 → 0.9.5
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/lib/dist/bin/codegraph.js +12 -0
- package/lib/dist/bin/codegraph.js.map +1 -1
- package/lib/dist/extraction/grammars.d.ts.map +1 -1
- package/lib/dist/extraction/grammars.js +14 -1
- package/lib/dist/extraction/grammars.js.map +1 -1
- package/lib/dist/extraction/index.d.ts +15 -2
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +170 -78
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/index.d.ts.map +1 -1
- package/lib/dist/extraction/languages/index.js +2 -0
- package/lib/dist/extraction/languages/index.js.map +1 -1
- package/lib/dist/extraction/languages/objc.d.ts +3 -0
- package/lib/dist/extraction/languages/objc.d.ts.map +1 -0
- package/lib/dist/extraction/languages/objc.js +133 -0
- package/lib/dist/extraction/languages/objc.js.map +1 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts +4 -0
- package/lib/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/lib/dist/extraction/tree-sitter.js +82 -5
- package/lib/dist/extraction/tree-sitter.js.map +1 -1
- package/lib/dist/index.d.ts +21 -2
- package/lib/dist/index.d.ts.map +1 -1
- package/lib/dist/index.js +33 -0
- package/lib/dist/index.js.map +1 -1
- package/lib/dist/installer/instructions-template.d.ts +2 -2
- package/lib/dist/installer/instructions-template.d.ts.map +1 -1
- package/lib/dist/installer/instructions-template.js +1 -1
- package/lib/dist/mcp/daemon-paths.d.ts +46 -0
- package/lib/dist/mcp/daemon-paths.d.ts.map +1 -0
- package/lib/dist/mcp/daemon-paths.js +125 -0
- package/lib/dist/mcp/daemon-paths.js.map +1 -0
- package/lib/dist/mcp/daemon.d.ts +161 -0
- package/lib/dist/mcp/daemon.d.ts.map +1 -0
- package/lib/dist/mcp/daemon.js +403 -0
- package/lib/dist/mcp/daemon.js.map +1 -0
- package/lib/dist/mcp/engine.d.ts +100 -0
- package/lib/dist/mcp/engine.d.ts.map +1 -0
- package/lib/dist/mcp/engine.js +291 -0
- package/lib/dist/mcp/engine.js.map +1 -0
- package/lib/dist/mcp/index.d.ts +64 -53
- package/lib/dist/mcp/index.d.ts.map +1 -1
- package/lib/dist/mcp/index.js +307 -387
- package/lib/dist/mcp/index.js.map +1 -1
- package/lib/dist/mcp/proxy.d.ts +46 -0
- package/lib/dist/mcp/proxy.d.ts.map +1 -0
- package/lib/dist/mcp/proxy.js +276 -0
- package/lib/dist/mcp/proxy.js.map +1 -0
- package/lib/dist/mcp/server-instructions.d.ts +1 -1
- package/lib/dist/mcp/server-instructions.d.ts.map +1 -1
- package/lib/dist/mcp/server-instructions.js +1 -1
- package/lib/dist/mcp/session.d.ts +67 -0
- package/lib/dist/mcp/session.d.ts.map +1 -0
- package/lib/dist/mcp/session.js +276 -0
- package/lib/dist/mcp/session.js.map +1 -0
- package/lib/dist/mcp/tools.d.ts +49 -0
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +239 -14
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/dist/mcp/transport.d.ts +111 -29
- package/lib/dist/mcp/transport.d.ts.map +1 -1
- package/lib/dist/mcp/transport.js +181 -71
- package/lib/dist/mcp/transport.js.map +1 -1
- package/lib/dist/mcp/version.d.ts +19 -0
- package/lib/dist/mcp/version.d.ts.map +1 -0
- package/lib/dist/mcp/version.js +71 -0
- package/lib/dist/mcp/version.js.map +1 -0
- package/lib/dist/resolution/callback-synthesizer.d.ts +3 -2
- package/lib/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/lib/dist/resolution/callback-synthesizer.js +274 -3
- package/lib/dist/resolution/callback-synthesizer.js.map +1 -1
- package/lib/dist/resolution/frameworks/expo-modules.d.ts +3 -0
- package/lib/dist/resolution/frameworks/expo-modules.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/expo-modules.js +143 -0
- package/lib/dist/resolution/frameworks/expo-modules.js.map +1 -0
- package/lib/dist/resolution/frameworks/fabric.d.ts +3 -0
- package/lib/dist/resolution/frameworks/fabric.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/fabric.js +354 -0
- package/lib/dist/resolution/frameworks/fabric.js.map +1 -0
- package/lib/dist/resolution/frameworks/index.d.ts +4 -0
- package/lib/dist/resolution/frameworks/index.d.ts.map +1 -1
- package/lib/dist/resolution/frameworks/index.js +21 -1
- package/lib/dist/resolution/frameworks/index.js.map +1 -1
- package/lib/dist/resolution/frameworks/react-native.d.ts +3 -0
- package/lib/dist/resolution/frameworks/react-native.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/react-native.js +360 -0
- package/lib/dist/resolution/frameworks/react-native.js.map +1 -0
- package/lib/dist/resolution/frameworks/swift-objc.d.ts +37 -0
- package/lib/dist/resolution/frameworks/swift-objc.d.ts.map +1 -0
- package/lib/dist/resolution/frameworks/swift-objc.js +252 -0
- package/lib/dist/resolution/frameworks/swift-objc.js.map +1 -0
- package/lib/dist/resolution/import-resolver.d.ts.map +1 -1
- package/lib/dist/resolution/import-resolver.js +1 -0
- package/lib/dist/resolution/import-resolver.js.map +1 -1
- package/lib/dist/resolution/swift-objc-bridge.d.ts +134 -0
- package/lib/dist/resolution/swift-objc-bridge.d.ts.map +1 -0
- package/lib/dist/resolution/swift-objc-bridge.js +256 -0
- package/lib/dist/resolution/swift-objc-bridge.js.map +1 -0
- package/lib/dist/sync/index.d.ts +3 -1
- package/lib/dist/sync/index.d.ts.map +1 -1
- package/lib/dist/sync/index.js +7 -1
- package/lib/dist/sync/index.js.map +1 -1
- package/lib/dist/sync/watcher.d.ts +109 -7
- package/lib/dist/sync/watcher.d.ts.map +1 -1
- package/lib/dist/sync/watcher.js +215 -33
- package/lib/dist/sync/watcher.js.map +1 -1
- package/lib/dist/sync/worktree.d.ts +54 -0
- package/lib/dist/sync/worktree.d.ts.map +1 -0
- package/lib/dist/sync/worktree.js +136 -0
- package/lib/dist/sync/worktree.js.map +1 -0
- package/lib/dist/types.d.ts +1 -1
- package/lib/dist/types.d.ts.map +1 -1
- package/lib/dist/types.js +1 -0
- package/lib/dist/types.js.map +1 -1
- package/lib/node_modules/.package-lock.json +29 -1
- package/lib/node_modules/chokidar/LICENSE +21 -0
- package/lib/node_modules/chokidar/README.md +305 -0
- package/lib/node_modules/chokidar/esm/handler.d.ts +90 -0
- package/lib/node_modules/chokidar/esm/handler.js +629 -0
- package/lib/node_modules/chokidar/esm/index.d.ts +215 -0
- package/lib/node_modules/chokidar/esm/index.js +798 -0
- package/lib/node_modules/chokidar/esm/package.json +1 -0
- package/lib/node_modules/chokidar/handler.d.ts +90 -0
- package/lib/node_modules/chokidar/handler.js +635 -0
- package/lib/node_modules/chokidar/index.d.ts +215 -0
- package/lib/node_modules/chokidar/index.js +804 -0
- package/lib/node_modules/chokidar/package.json +69 -0
- package/lib/node_modules/readdirp/LICENSE +21 -0
- package/lib/node_modules/readdirp/README.md +120 -0
- package/lib/node_modules/readdirp/esm/index.d.ts +108 -0
- package/lib/node_modules/readdirp/esm/index.js +257 -0
- package/lib/node_modules/readdirp/esm/package.json +1 -0
- package/lib/node_modules/readdirp/index.d.ts +108 -0
- package/lib/node_modules/readdirp/index.js +263 -0
- package/lib/node_modules/readdirp/package.json +70 -0
- package/lib/package.json +2 -1
- package/package.json +1 -1
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reactNativeBridgeResolver = void 0;
|
|
4
|
+
/** Per-context lazy map cache. */
|
|
5
|
+
const nativeMethodMaps = new WeakMap();
|
|
6
|
+
// ─── Native-side extraction ─────────────────────────────────────────────────
|
|
7
|
+
/**
|
|
8
|
+
* Default ObjC module name when `RCT_EXPORT_MODULE()` has no argument:
|
|
9
|
+
* strip a leading `RCT` prefix from the class name (Apple's convention)
|
|
10
|
+
* and treat the rest as the JS-visible module name. `RCTGeolocation` →
|
|
11
|
+
* `Geolocation`. Class names without an `RCT` prefix are returned
|
|
12
|
+
* unchanged.
|
|
13
|
+
*/
|
|
14
|
+
function defaultObjcModuleName(className) {
|
|
15
|
+
return className.startsWith('RCT') && className.length > 3
|
|
16
|
+
? className.slice(3)
|
|
17
|
+
: className;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse an ObjC `.m`/`.mm` file's source for `RCT_EXPORT_MODULE` and
|
|
21
|
+
* `RCT_EXPORT_METHOD` / `RCT_REMAP_METHOD` declarations, returning the
|
|
22
|
+
* inferred (moduleName, jsMethodName) pairs.
|
|
23
|
+
*
|
|
24
|
+
* The macro forms (a single `RCT_EXPORT_MODULE` per file conventionally
|
|
25
|
+
* matched to a single `@implementation`):
|
|
26
|
+
* - `RCT_EXPORT_MODULE()` — module name = class name with `RCT` prefix
|
|
27
|
+
* stripped
|
|
28
|
+
* - `RCT_EXPORT_MODULE(jsName)` — explicit name
|
|
29
|
+
* - `RCT_EXPORT_METHOD(selector:(arg1)label1:(arg2)label2)` — JS name =
|
|
30
|
+
* `selector` (the first keyword)
|
|
31
|
+
* - `RCT_REMAP_METHOD(jsName, selector:(arg1)label1:(arg2)label2)` —
|
|
32
|
+
* JS name = literal `jsName`
|
|
33
|
+
*
|
|
34
|
+
* Regex-based scan is sufficient — these macros are highly stylized and
|
|
35
|
+
* appear at top level. Pulling them out of the full AST would require a
|
|
36
|
+
* macro-aware ObjC parse the tree-sitter grammar doesn't provide.
|
|
37
|
+
*/
|
|
38
|
+
function parseObjcRNExports(source, className) {
|
|
39
|
+
const results = [];
|
|
40
|
+
// RCT_EXPORT_MODULE — one per file by convention. Capture the optional arg.
|
|
41
|
+
const moduleMatch = source.match(/RCT_EXPORT_MODULE\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)?\s*\)/);
|
|
42
|
+
// Need a module name to attribute methods. Prefer the explicit macro arg,
|
|
43
|
+
// then the class name, then bail (no module = nothing useful to register).
|
|
44
|
+
const moduleName = moduleMatch?.[1] ??
|
|
45
|
+
(className ? defaultObjcModuleName(className) : null);
|
|
46
|
+
if (!moduleName)
|
|
47
|
+
return results;
|
|
48
|
+
// RCT_EXPORT_METHOD(selectorFirstKw:(args)…)
|
|
49
|
+
// The first keyword (everything up to the first `:` or open paren) is the
|
|
50
|
+
// JS-visible name. We don't try to parse full multi-keyword selectors —
|
|
51
|
+
// RN's JS view of the method uses only the first keyword.
|
|
52
|
+
const exportRegex = /RCT_EXPORT_METHOD\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
53
|
+
let m;
|
|
54
|
+
while ((m = exportRegex.exec(source)) !== null) {
|
|
55
|
+
const kw = m[1];
|
|
56
|
+
if (kw)
|
|
57
|
+
results.push({ moduleName, jsName: kw, nativeSelectorFirstKw: kw });
|
|
58
|
+
}
|
|
59
|
+
// RCT_REMAP_METHOD(jsName, nativeSelectorFirstKw:(args)…)
|
|
60
|
+
const remapRegex = /RCT_REMAP_METHOD\s*\(\s*([A-Za-z_][A-Za-z0-9_]*)\s*,\s*([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
61
|
+
while ((m = remapRegex.exec(source)) !== null) {
|
|
62
|
+
const jsName = m[1];
|
|
63
|
+
const nativeKw = m[2];
|
|
64
|
+
if (jsName && nativeKw) {
|
|
65
|
+
results.push({ moduleName, jsName, nativeSelectorFirstKw: nativeKw });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return results;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Find the `@implementation` class name in an ObjC file — used as the
|
|
72
|
+
* fallback module name when `RCT_EXPORT_MODULE()` has no argument.
|
|
73
|
+
* (Categories of the form `@implementation Foo (Bar)` are correctly
|
|
74
|
+
* captured here as `Foo`, but a category file probably isn't where a
|
|
75
|
+
* fresh `RCT_EXPORT_MODULE` lives anyway.)
|
|
76
|
+
*/
|
|
77
|
+
function findObjcClassName(source) {
|
|
78
|
+
const m = source.match(/@implementation\s+([A-Za-z_][A-Za-z0-9_]*)/);
|
|
79
|
+
return m?.[1] ?? null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Parse a Java/Kotlin source file for `@ReactMethod` annotated methods
|
|
83
|
+
* and the surrounding class's `getName()` return value (the JS-visible
|
|
84
|
+
* module name).
|
|
85
|
+
*
|
|
86
|
+
* Java: `@ReactMethod public void getCurrentPosition(Callback cb) { … }`
|
|
87
|
+
* Kotlin: `@ReactMethod fun getCurrentPosition(cb: Callback) { … }`
|
|
88
|
+
*
|
|
89
|
+
* Class name comes from `class XxxModule extends ReactContextBaseJavaModule`
|
|
90
|
+
* (Java) or `class XxxModule : ReactContextBaseJavaModule(...)` (Kotlin).
|
|
91
|
+
* The JS-visible module name comes from `getName()` returning a literal
|
|
92
|
+
* string — fall back to the class name with a `Module` suffix stripped
|
|
93
|
+
* when the literal isn't present.
|
|
94
|
+
*/
|
|
95
|
+
function parseJvmRNExports(source) {
|
|
96
|
+
const results = [];
|
|
97
|
+
// getName() literal — Java + Kotlin both look something like:
|
|
98
|
+
// public String getName() { return "Geolocation"; }
|
|
99
|
+
// fun getName(): String = "Geolocation"
|
|
100
|
+
// fun getName() = "Geolocation"
|
|
101
|
+
const getName = source.match(/\bgetName\s*\([^)]*\)\s*(?::\s*String)?\s*(?:=\s*|\{[^}]*return\s*)"([^"]+)"/);
|
|
102
|
+
// Class name fallback.
|
|
103
|
+
const classMatch = source.match(/\bclass\s+([A-Za-z_][A-Za-z0-9_]*)\b[^{]*ReactContextBaseJavaModule/) ??
|
|
104
|
+
source.match(/\bclass\s+([A-Za-z_][A-Za-z0-9_]*)\b[^{]*ReactPackage/);
|
|
105
|
+
const moduleName = getName?.[1] ?? (classMatch?.[1] ? classMatch[1].replace(/Module$/, '') : null);
|
|
106
|
+
if (!moduleName)
|
|
107
|
+
return results;
|
|
108
|
+
// @ReactMethod annotations — followed (after optional modifiers / args /
|
|
109
|
+
// newlines) by either `void <name>(` (Java) or `fun <name>(` (Kotlin).
|
|
110
|
+
const methodRegex = /@ReactMethod\b[^{]*?(?:\bfun\s+|\bvoid\s+|\bpublic\s+\w[\w<>\[\]]*\s+)([A-Za-z_][A-Za-z0-9_]*)\s*\(/g;
|
|
111
|
+
let m;
|
|
112
|
+
while ((m = methodRegex.exec(source)) !== null) {
|
|
113
|
+
const jsName = m[1];
|
|
114
|
+
if (jsName)
|
|
115
|
+
results.push({ moduleName, jsName });
|
|
116
|
+
}
|
|
117
|
+
return results;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Parse a TS file for a TurboModule spec declaration. The spec file is
|
|
121
|
+
* the JS↔native source-of-truth in the new architecture — its interface
|
|
122
|
+
* lists every JS-visible method, and a `TurboModuleRegistry.get*<Spec>(...)`
|
|
123
|
+
* default export pins the module name.
|
|
124
|
+
*
|
|
125
|
+
* Returns `null` when the file isn't a TurboModule spec.
|
|
126
|
+
*/
|
|
127
|
+
function parseTurboModuleSpec(source) {
|
|
128
|
+
// `TurboModuleRegistry.getEnforcing<Spec>('ModuleName')` or
|
|
129
|
+
// `TurboModuleRegistry.get<Spec>('ModuleName')`. The literal must be a
|
|
130
|
+
// single-or-double-quoted string.
|
|
131
|
+
const regMatch = source.match(/TurboModuleRegistry\.(?:getEnforcing|get)\s*<[^>]*>\s*\(\s*['"]([^'"]+)['"]\s*\)/);
|
|
132
|
+
if (!regMatch || !regMatch[1])
|
|
133
|
+
return null;
|
|
134
|
+
const moduleName = regMatch[1];
|
|
135
|
+
// Find `export interface Spec extends TurboModule { … }` and pull each
|
|
136
|
+
// method declaration's name. We don't need types — just names.
|
|
137
|
+
const ifaceMatch = source.match(/export\s+interface\s+Spec\b[^{]*\{([\s\S]*?)\n\}/);
|
|
138
|
+
if (!ifaceMatch || !ifaceMatch[1])
|
|
139
|
+
return null;
|
|
140
|
+
const body = ifaceMatch[1];
|
|
141
|
+
const methods = [];
|
|
142
|
+
// Method shape: `name(args): ReturnType;` or `name(): void;`. Skip
|
|
143
|
+
// properties (no parens before colon).
|
|
144
|
+
const methodRegex = /^\s*([A-Za-z_][A-Za-z0-9_]*)\s*\(/gm;
|
|
145
|
+
let m;
|
|
146
|
+
while ((m = methodRegex.exec(body)) !== null) {
|
|
147
|
+
const name = m[1];
|
|
148
|
+
if (name)
|
|
149
|
+
methods.push(name);
|
|
150
|
+
}
|
|
151
|
+
return { moduleName, methods };
|
|
152
|
+
}
|
|
153
|
+
// ─── Map building ───────────────────────────────────────────────────────────
|
|
154
|
+
/**
|
|
155
|
+
* RCTEventEmitter built-ins that every emitter subclass inherits. JS code
|
|
156
|
+
* doesn't directly call these — they're internal plumbing for the
|
|
157
|
+
* `NativeEventEmitter` abstraction. If we leave them in the bridge map,
|
|
158
|
+
* every JS `addListener` / `remove` call (Firestore subscribers, RxJS
|
|
159
|
+
* pipelines, plain Array.remove, etc.) gets mis-bridged to whichever
|
|
160
|
+
* emitter happens to define them. Skip during map building.
|
|
161
|
+
*/
|
|
162
|
+
const RN_EMITTER_BUILTINS = new Set([
|
|
163
|
+
'addListener',
|
|
164
|
+
'removeListeners',
|
|
165
|
+
'remove',
|
|
166
|
+
'invalidate',
|
|
167
|
+
'startObserving',
|
|
168
|
+
'stopObserving',
|
|
169
|
+
]);
|
|
170
|
+
function buildRNMaps(context) {
|
|
171
|
+
const cached = nativeMethodMaps.get(context);
|
|
172
|
+
if (cached)
|
|
173
|
+
return cached;
|
|
174
|
+
const byJsName = new Map();
|
|
175
|
+
const allFiles = context.getAllFiles();
|
|
176
|
+
// Pre-index native methods by name for fast lookup when matching to
|
|
177
|
+
// their bridge exports.
|
|
178
|
+
const objcMethodsByFirstKw = new Map();
|
|
179
|
+
const jvmMethodsByName = new Map();
|
|
180
|
+
for (const node of context.getNodesByKind('method')) {
|
|
181
|
+
if (node.language === 'objc') {
|
|
182
|
+
const firstKw = node.name.includes(':') ? node.name.split(':')[0] : node.name;
|
|
183
|
+
if (firstKw) {
|
|
184
|
+
const arr = objcMethodsByFirstKw.get(firstKw);
|
|
185
|
+
if (arr)
|
|
186
|
+
arr.push(node);
|
|
187
|
+
else
|
|
188
|
+
objcMethodsByFirstKw.set(firstKw, [node]);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else if (node.language === 'java' || node.language === 'kotlin') {
|
|
192
|
+
const arr = jvmMethodsByName.get(node.name);
|
|
193
|
+
if (arr)
|
|
194
|
+
arr.push(node);
|
|
195
|
+
else
|
|
196
|
+
jvmMethodsByName.set(node.name, [node]);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const file of allFiles) {
|
|
200
|
+
// Legacy bridge — ObjC side.
|
|
201
|
+
if (file.endsWith('.m') || file.endsWith('.mm')) {
|
|
202
|
+
const source = context.readFile(file);
|
|
203
|
+
if (!source)
|
|
204
|
+
continue;
|
|
205
|
+
const className = findObjcClassName(source);
|
|
206
|
+
const exports = parseObjcRNExports(source, className);
|
|
207
|
+
for (const exp of exports) {
|
|
208
|
+
if (RN_EMITTER_BUILTINS.has(exp.jsName))
|
|
209
|
+
continue;
|
|
210
|
+
// Resolve to the native node by selector first-keyword. Multiple
|
|
211
|
+
// ObjC methods may share a first keyword across modules; filter by
|
|
212
|
+
// file path to attribute the export to this module's
|
|
213
|
+
// implementation file.
|
|
214
|
+
const candidates = objcMethodsByFirstKw.get(exp.nativeSelectorFirstKw) ?? [];
|
|
215
|
+
const node = candidates.find((c) => c.filePath === file) ?? candidates[0];
|
|
216
|
+
if (!node)
|
|
217
|
+
continue;
|
|
218
|
+
const entry = { moduleName: exp.moduleName, jsName: exp.jsName, node };
|
|
219
|
+
const arr = byJsName.get(exp.jsName);
|
|
220
|
+
if (arr)
|
|
221
|
+
arr.push(entry);
|
|
222
|
+
else
|
|
223
|
+
byJsName.set(exp.jsName, [entry]);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Legacy bridge — Java/Kotlin side.
|
|
227
|
+
if (file.endsWith('.java') || file.endsWith('.kt')) {
|
|
228
|
+
const source = context.readFile(file);
|
|
229
|
+
if (!source)
|
|
230
|
+
continue;
|
|
231
|
+
const exports = parseJvmRNExports(source);
|
|
232
|
+
for (const exp of exports) {
|
|
233
|
+
if (RN_EMITTER_BUILTINS.has(exp.jsName))
|
|
234
|
+
continue;
|
|
235
|
+
const candidates = jvmMethodsByName.get(exp.jsName) ?? [];
|
|
236
|
+
const node = candidates.find((c) => c.filePath === file) ?? candidates[0];
|
|
237
|
+
if (!node)
|
|
238
|
+
continue;
|
|
239
|
+
const entry = { moduleName: exp.moduleName, jsName: exp.jsName, node };
|
|
240
|
+
const arr = byJsName.get(exp.jsName);
|
|
241
|
+
if (arr)
|
|
242
|
+
arr.push(entry);
|
|
243
|
+
else
|
|
244
|
+
byJsName.set(exp.jsName, [entry]);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// TurboModule spec — TS side.
|
|
248
|
+
if (file.endsWith('.ts') || file.endsWith('.tsx')) {
|
|
249
|
+
const source = context.readFile(file);
|
|
250
|
+
if (!source)
|
|
251
|
+
continue;
|
|
252
|
+
const spec = parseTurboModuleSpec(source);
|
|
253
|
+
if (!spec)
|
|
254
|
+
continue;
|
|
255
|
+
// For each spec method, find a matching native implementation by
|
|
256
|
+
// name. The spec's module name doesn't determine the native file
|
|
257
|
+
// path (Codegen wires it via name convention), so we match across
|
|
258
|
+
// all native methods of the right name.
|
|
259
|
+
for (const methodName of spec.methods) {
|
|
260
|
+
if (RN_EMITTER_BUILTINS.has(methodName))
|
|
261
|
+
continue;
|
|
262
|
+
// ObjC first-keyword match, then JVM bare-name match. Don't
|
|
263
|
+
// require module-name match for ObjC because the native side may
|
|
264
|
+
// have stripped a prefix.
|
|
265
|
+
const objcCands = objcMethodsByFirstKw.get(methodName) ?? [];
|
|
266
|
+
const jvmCands = jvmMethodsByName.get(methodName) ?? [];
|
|
267
|
+
for (const node of [...objcCands, ...jvmCands]) {
|
|
268
|
+
const entry = { moduleName: spec.moduleName, jsName: methodName, node };
|
|
269
|
+
const arr = byJsName.get(methodName);
|
|
270
|
+
if (arr)
|
|
271
|
+
arr.push(entry);
|
|
272
|
+
else
|
|
273
|
+
byJsName.set(methodName, [entry]);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
const result = { byJsName };
|
|
279
|
+
nativeMethodMaps.set(context, result);
|
|
280
|
+
return result;
|
|
281
|
+
}
|
|
282
|
+
// ─── Resolver ───────────────────────────────────────────────────────────────
|
|
283
|
+
exports.reactNativeBridgeResolver = {
|
|
284
|
+
name: 'react-native-bridge',
|
|
285
|
+
languages: ['javascript', 'typescript', 'tsx', 'jsx'],
|
|
286
|
+
/**
|
|
287
|
+
* Detect: package.json depends on `react-native`, OR any source file
|
|
288
|
+
* uses the `RCT_EXPORT_MODULE` / `RCT_EXPORT_METHOD` /
|
|
289
|
+
* `TurboModuleRegistry` markers. Either signal is enough — different
|
|
290
|
+
* libraries split the JS package from the native code (`react-native-svg`'s
|
|
291
|
+
* apple/ + android/ directories vs its src/), so we don't require both.
|
|
292
|
+
*/
|
|
293
|
+
detect(context) {
|
|
294
|
+
const pkg = context.readFile('package.json');
|
|
295
|
+
if (pkg && /["']react-native["']\s*:/.test(pkg))
|
|
296
|
+
return true;
|
|
297
|
+
// Fallback: scan a small number of files for the macro markers — only
|
|
298
|
+
// looking at the first ones returned by getAllFiles to keep detect()
|
|
299
|
+
// fast on huge repos.
|
|
300
|
+
const files = context.getAllFiles();
|
|
301
|
+
for (let i = 0; i < Math.min(files.length, 200); i++) {
|
|
302
|
+
const f = files[i];
|
|
303
|
+
if (!f)
|
|
304
|
+
continue;
|
|
305
|
+
if (f.endsWith('.mm') || f.endsWith('.m')) {
|
|
306
|
+
const src = context.readFile(f);
|
|
307
|
+
if (src && /RCT_EXPORT_MODULE\b/.test(src))
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
if (f.endsWith('.ts') || f.endsWith('.tsx')) {
|
|
311
|
+
const src = context.readFile(f);
|
|
312
|
+
if (src && /TurboModuleRegistry\.(?:get|getEnforcing)\s*</.test(src))
|
|
313
|
+
return true;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return false;
|
|
317
|
+
},
|
|
318
|
+
claimsReference(_name) {
|
|
319
|
+
// JS-visible method names are ordinary identifiers and are typically
|
|
320
|
+
// already in `knownNames` (every TurboModule spec method, every
|
|
321
|
+
// RCT_EXPORT_METHOD, has a node somewhere). So we don't need to
|
|
322
|
+
// claim through the pre-filter — the ref reaches us via the normal
|
|
323
|
+
// hasAnyPossibleMatch path.
|
|
324
|
+
return false;
|
|
325
|
+
},
|
|
326
|
+
resolve(ref, context) {
|
|
327
|
+
// We only redirect JS callers — native callers don't need this resolver.
|
|
328
|
+
if (ref.language !== 'javascript' &&
|
|
329
|
+
ref.language !== 'typescript' &&
|
|
330
|
+
ref.language !== 'tsx' &&
|
|
331
|
+
ref.language !== 'jsx') {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
// JS callsites of `obj.method()` reach the resolver as either
|
|
335
|
+
// `obj.method` (qualified) or `method` (bare). Strip a single dot
|
|
336
|
+
// prefix to get the JS-visible method name.
|
|
337
|
+
const name = ref.referenceName.includes('.')
|
|
338
|
+
? ref.referenceName.slice(ref.referenceName.lastIndexOf('.') + 1)
|
|
339
|
+
: ref.referenceName;
|
|
340
|
+
const maps = buildRNMaps(context);
|
|
341
|
+
const entries = maps.byJsName.get(name);
|
|
342
|
+
if (!entries || entries.length === 0)
|
|
343
|
+
return null;
|
|
344
|
+
// Prefer the iOS (ObjC) target over Android when both exist — iOS is
|
|
345
|
+
// the conventional first-class platform for RN library docs and most
|
|
346
|
+
// graph queries. We still record only one edge; a JVM-only resolution
|
|
347
|
+
// is fine when no ObjC target exists.
|
|
348
|
+
const objc = entries.find((e) => e.node.language === 'objc');
|
|
349
|
+
const target = objc ?? entries[0];
|
|
350
|
+
if (!target)
|
|
351
|
+
return null;
|
|
352
|
+
return {
|
|
353
|
+
original: ref,
|
|
354
|
+
targetNodeId: target.node.id,
|
|
355
|
+
confidence: 0.6,
|
|
356
|
+
resolvedBy: 'framework',
|
|
357
|
+
};
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
//# sourceMappingURL=react-native.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react-native.js","sourceRoot":"","sources":["../../../src/resolution/frameworks/react-native.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swift ↔ Objective-C bridge resolver.
|
|
3
|
+
*
|
|
4
|
+
* Closes the cross-language flow gap in mixed iOS codebases. The pure
|
|
5
|
+
* bridging name math lives in `../swift-objc-bridge.ts`; this file wires
|
|
6
|
+
* it into the resolution pipeline.
|
|
7
|
+
*
|
|
8
|
+
* **Two directions to close:**
|
|
9
|
+
*
|
|
10
|
+
* 1. **Swift call → ObjC method** — A Swift caller writes
|
|
11
|
+
* `imageDownloader.download(url:completion:)`. Tree-sitter-swift parses
|
|
12
|
+
* this as a call_expression whose callee identifier is `download`
|
|
13
|
+
* (parameter labels live in the argument list, not the callee). The
|
|
14
|
+
* name-matcher tries to find any node named `download` and fails (no
|
|
15
|
+
* Swift method by that name in this project; the ObjC implementation is
|
|
16
|
+
* `-downloadURL:completion:`). We catch it here: from the bare Swift
|
|
17
|
+
* name `download`, look up ObjC methods whose bridged Swift base name
|
|
18
|
+
* would be `download` (using `swiftBaseNamesForObjcSelector`'s reverse
|
|
19
|
+
* map, precomputed once per session).
|
|
20
|
+
*
|
|
21
|
+
* 2. **ObjC call → Swift method** — An ObjC caller writes
|
|
22
|
+
* `[swiftThing fooWithBar:42]`. Tree-sitter-objc parses this as a
|
|
23
|
+
* message_expression with selector `fooWithBar:` (after the multi-
|
|
24
|
+
* keyword fix in this branch). The name-matcher tries to find a node
|
|
25
|
+
* named `fooWithBar:` — no Swift node has colons in its name, so it
|
|
26
|
+
* fails. We catch it: from the ObjC selector, derive candidate Swift
|
|
27
|
+
* base names (`['fooWithBar', 'foo']`), and look up Swift methods
|
|
28
|
+
* named those.
|
|
29
|
+
*
|
|
30
|
+
* **Provenance:** every edge produced here is recorded as a framework-
|
|
31
|
+
* resolved reference (`resolvedBy: 'framework'`) with `confidence: 0.7`
|
|
32
|
+
* (matches the django ORM dynamic-dispatch precedent — not exact, but
|
|
33
|
+
* deterministic from the bridging rule).
|
|
34
|
+
*/
|
|
35
|
+
import { FrameworkResolver } from '../types';
|
|
36
|
+
export declare const swiftObjcBridgeResolver: FrameworkResolver;
|
|
37
|
+
//# sourceMappingURL=swift-objc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swift-objc.d.ts","sourceRoot":"","sources":["../../../src/resolution/frameworks/swift-objc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,OAAO,EAAE,iBAAiB,EAAiD,MAAM,UAAU,CAAC;AAqN5F,eAAO,MAAM,uBAAuB,EAAE,iBAmDrC,CAAC"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.swiftObjcBridgeResolver = void 0;
|
|
4
|
+
const swift_objc_bridge_1 = require("../swift-objc-bridge");
|
|
5
|
+
/**
|
|
6
|
+
* Memoized "Swift base name → ObjC method nodes" map.
|
|
7
|
+
*
|
|
8
|
+
* Built lazily on first `resolve()` per resolver instance — the resolver is
|
|
9
|
+
* recreated when the index is rebuilt, so this naturally invalidates with
|
|
10
|
+
* the graph. Keyed by ResolutionContext identity so multiple projects sharing
|
|
11
|
+
* a process (the daemon) don't bleed maps between them.
|
|
12
|
+
*/
|
|
13
|
+
const objcByCandidateSwiftBase = new WeakMap();
|
|
14
|
+
/**
|
|
15
|
+
* Build the reverse-bridge map: for every ObjC method node in the graph,
|
|
16
|
+
* compute the Swift base names that would auto-bridge to its selector and
|
|
17
|
+
* record the node under each.
|
|
18
|
+
*
|
|
19
|
+
* Runs once per resolver lifetime; the cost scales linearly with the count
|
|
20
|
+
* of ObjC method nodes. On Wikipedia-iOS (~2500 files, ~25k ObjC methods)
|
|
21
|
+
* this is a few hundred ms — much cheaper than re-parsing source on each
|
|
22
|
+
* unresolved ref.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Names that are too generic to bridge with any precision. These are common
|
|
26
|
+
* Cocoa / NSObject conventions that almost every ObjC class implements; if a
|
|
27
|
+
* Swift caller writes `init()` or `description`, mapping it to an arbitrary
|
|
28
|
+
* project-local ObjC method of the same name produces noise, not signal.
|
|
29
|
+
*
|
|
30
|
+
* Critically, refs of these names virtually always resolve via the regular
|
|
31
|
+
* name-matcher (every project has many `init` nodes) — skipping them here
|
|
32
|
+
* just keeps the bridge from competing with name-match on already-handled
|
|
33
|
+
* refs.
|
|
34
|
+
*/
|
|
35
|
+
const GENERIC_NAMES = new Set([
|
|
36
|
+
'init',
|
|
37
|
+
'description',
|
|
38
|
+
'debugDescription',
|
|
39
|
+
'hash',
|
|
40
|
+
'isEqual',
|
|
41
|
+
'isEqualTo',
|
|
42
|
+
'copy',
|
|
43
|
+
'mutableCopy',
|
|
44
|
+
'class',
|
|
45
|
+
'self',
|
|
46
|
+
'count',
|
|
47
|
+
'length',
|
|
48
|
+
'value',
|
|
49
|
+
'name',
|
|
50
|
+
'data',
|
|
51
|
+
'string',
|
|
52
|
+
'object',
|
|
53
|
+
'add',
|
|
54
|
+
'remove',
|
|
55
|
+
'update',
|
|
56
|
+
'load',
|
|
57
|
+
'save',
|
|
58
|
+
'reload',
|
|
59
|
+
'cancel',
|
|
60
|
+
'start',
|
|
61
|
+
'stop',
|
|
62
|
+
'pause',
|
|
63
|
+
'resume',
|
|
64
|
+
'close',
|
|
65
|
+
'open',
|
|
66
|
+
'show',
|
|
67
|
+
'hide',
|
|
68
|
+
'toString',
|
|
69
|
+
'dealloc',
|
|
70
|
+
'release',
|
|
71
|
+
'retain',
|
|
72
|
+
'autorelease',
|
|
73
|
+
]);
|
|
74
|
+
function buildObjcMap(context) {
|
|
75
|
+
const cached = objcByCandidateSwiftBase.get(context);
|
|
76
|
+
if (cached)
|
|
77
|
+
return cached;
|
|
78
|
+
const map = new Map();
|
|
79
|
+
const objcMethods = context
|
|
80
|
+
.getNodesByKind('method')
|
|
81
|
+
.filter((n) => n.language === 'objc');
|
|
82
|
+
for (const node of objcMethods) {
|
|
83
|
+
const candidates = (0, swift_objc_bridge_1.swiftBaseNamesForObjcSelector)(node.name);
|
|
84
|
+
for (const c of candidates) {
|
|
85
|
+
// Skip the trivial case where the Swift base name equals the ObjC
|
|
86
|
+
// method name verbatim (no colons) — the regular name-matcher
|
|
87
|
+
// already handles that and our map would just duplicate the work.
|
|
88
|
+
if (c === node.name && !node.name.includes(':'))
|
|
89
|
+
continue;
|
|
90
|
+
// Skip generic Cocoa names (init, description, etc.) — they would
|
|
91
|
+
// false-positive against any project-local ObjC method of the same
|
|
92
|
+
// name. The regular name-matcher handles them.
|
|
93
|
+
if (GENERIC_NAMES.has(c))
|
|
94
|
+
continue;
|
|
95
|
+
const arr = map.get(c);
|
|
96
|
+
if (arr)
|
|
97
|
+
arr.push(node);
|
|
98
|
+
else
|
|
99
|
+
map.set(c, [node]);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
objcByCandidateSwiftBase.set(context, map);
|
|
103
|
+
return map;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Window of source text around a Swift declaration used by `isObjcExposed`
|
|
107
|
+
* to spot `@objc` / `@nonobjc` annotations. Read line above + the
|
|
108
|
+
* declaration line — Swift attributes typically sit on the preceding line
|
|
109
|
+
* (`@objc` on a line of its own) or inline.
|
|
110
|
+
*/
|
|
111
|
+
const SOURCE_PROBE_LINES = 3;
|
|
112
|
+
/**
|
|
113
|
+
* Read a small window of source ending at `node.startLine`, used to
|
|
114
|
+
* inspect Swift attribute annotations attached to a declaration. Returns
|
|
115
|
+
* an empty string if the source can't be read.
|
|
116
|
+
*/
|
|
117
|
+
function declarationSourceWindow(node, context) {
|
|
118
|
+
const content = context.readFile(node.filePath);
|
|
119
|
+
if (!content)
|
|
120
|
+
return '';
|
|
121
|
+
const lines = content.split(/\r?\n/);
|
|
122
|
+
const startIdx = Math.max(0, node.startLine - 1 - SOURCE_PROBE_LINES);
|
|
123
|
+
const endIdx = Math.min(lines.length, node.startLine);
|
|
124
|
+
return lines.slice(startIdx, endIdx).join('\n');
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Try to resolve a Swift caller's bare reference to an ObjC implementation.
|
|
128
|
+
*
|
|
129
|
+
* Strategy: look up the ObjC reverse-bridge map for nodes whose Swift base
|
|
130
|
+
* name would match. Return the first match (matches the existing
|
|
131
|
+
* single-target resolution contract).
|
|
132
|
+
*/
|
|
133
|
+
function resolveSwiftCallToObjc(ref, context) {
|
|
134
|
+
// Swift call sites of `obj.foo(bar:)` reach the resolver as either bare
|
|
135
|
+
// name `foo` (tree-sitter-swift) or qualified `obj.foo` — strip prefix.
|
|
136
|
+
const rawName = ref.referenceName.includes('.')
|
|
137
|
+
? ref.referenceName.slice(ref.referenceName.lastIndexOf('.') + 1)
|
|
138
|
+
: ref.referenceName;
|
|
139
|
+
const map = buildObjcMap(context);
|
|
140
|
+
const candidates = map.get(rawName);
|
|
141
|
+
if (!candidates || candidates.length === 0)
|
|
142
|
+
return null;
|
|
143
|
+
// Prefer ObjC methods whose corresponding Swift declaration isn't itself
|
|
144
|
+
// present (so we don't wrongly redirect a Swift call to ObjC when a Swift
|
|
145
|
+
// method of the same name is the real target — that's the in-language case
|
|
146
|
+
// and should already be resolved by the name-matcher). Since this resolver
|
|
147
|
+
// runs AFTER exact-match, any matching Swift node would already have won;
|
|
148
|
+
// so a candidate reaching us is a legitimate cross-language hit.
|
|
149
|
+
const target = candidates[0];
|
|
150
|
+
if (!target)
|
|
151
|
+
return null;
|
|
152
|
+
return {
|
|
153
|
+
original: ref,
|
|
154
|
+
targetNodeId: target.id,
|
|
155
|
+
confidence: 0.6,
|
|
156
|
+
resolvedBy: 'framework',
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Try to resolve an ObjC caller's selector reference to a Swift `@objc`
|
|
161
|
+
* implementation.
|
|
162
|
+
*
|
|
163
|
+
* Strategy: derive candidate Swift base names from the selector via
|
|
164
|
+
* `swiftBaseNamesForObjcSelector`. For each, look up Swift methods named
|
|
165
|
+
* that and verify with a source-window check that the declaration is
|
|
166
|
+
* `@objc`-exposed (filters out false matches where a Swift function
|
|
167
|
+
* happens to share the name but isn't bridged).
|
|
168
|
+
*/
|
|
169
|
+
function resolveObjcCallToSwift(ref, context) {
|
|
170
|
+
// ObjC call sites get receiver-prefixed when the receiver isn't self/super
|
|
171
|
+
// (see tree-sitter.ts message_expression handling): `[obj foo:bar:]`
|
|
172
|
+
// becomes `obj.foo:bar:`. Strip the receiver prefix to recover the raw
|
|
173
|
+
// selector for the bridge math.
|
|
174
|
+
const rawSelector = ref.referenceName.includes('.')
|
|
175
|
+
? ref.referenceName.slice(ref.referenceName.lastIndexOf('.') + 1)
|
|
176
|
+
: ref.referenceName;
|
|
177
|
+
// Bridge math only applies to selector-shape names (contain `:`).
|
|
178
|
+
if (!rawSelector.includes(':'))
|
|
179
|
+
return null;
|
|
180
|
+
const candidates = (0, swift_objc_bridge_1.swiftBaseNamesForObjcSelector)(rawSelector);
|
|
181
|
+
for (const candidate of candidates) {
|
|
182
|
+
const matches = context
|
|
183
|
+
.getNodesByName(candidate)
|
|
184
|
+
.filter((n) => n.language === 'swift' && (n.kind === 'method' || n.kind === 'function'));
|
|
185
|
+
for (const match of matches) {
|
|
186
|
+
const window = declarationSourceWindow(match, context);
|
|
187
|
+
if ((0, swift_objc_bridge_1.isObjcExposed)(window)) {
|
|
188
|
+
return {
|
|
189
|
+
original: ref,
|
|
190
|
+
targetNodeId: match.id,
|
|
191
|
+
confidence: 0.6,
|
|
192
|
+
resolvedBy: 'framework',
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
exports.swiftObjcBridgeResolver = {
|
|
200
|
+
name: 'swift-objc-bridge',
|
|
201
|
+
// Applies to both languages — bridging crosses the boundary.
|
|
202
|
+
languages: ['swift', 'objc'],
|
|
203
|
+
/**
|
|
204
|
+
* Detect: this resolver is relevant when the project has both Swift and
|
|
205
|
+
* Objective-C source. Either-side-only projects don't need bridging
|
|
206
|
+
* (and the empty reverse-map would be a no-op anyway).
|
|
207
|
+
*/
|
|
208
|
+
detect(context) {
|
|
209
|
+
const files = context.getAllFiles();
|
|
210
|
+
let hasSwift = false;
|
|
211
|
+
let hasObjc = false;
|
|
212
|
+
for (const f of files) {
|
|
213
|
+
if (f.endsWith('.swift'))
|
|
214
|
+
hasSwift = true;
|
|
215
|
+
else if (f.endsWith('.m') || f.endsWith('.mm'))
|
|
216
|
+
hasObjc = true;
|
|
217
|
+
if (hasSwift && hasObjc)
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
return false;
|
|
221
|
+
},
|
|
222
|
+
/**
|
|
223
|
+
* Let selector-shape references (anything containing a `:`) through the
|
|
224
|
+
* resolver's name-exists pre-filter — no Swift node has a colon in its
|
|
225
|
+
* name, so without this opt-in those refs would be dropped before
|
|
226
|
+
* `resolve()` sees them. Also opt-in `setX:`-style names that aren't
|
|
227
|
+
* otherwise declared symbols, in case the Swift side is a property.
|
|
228
|
+
*/
|
|
229
|
+
claimsReference(name) {
|
|
230
|
+
if (name.includes(':'))
|
|
231
|
+
return true;
|
|
232
|
+
// Bare names without colons are handled by the regular name-exists
|
|
233
|
+
// pre-filter — no need to opt them in here.
|
|
234
|
+
return false;
|
|
235
|
+
},
|
|
236
|
+
/**
|
|
237
|
+
* Route based on which language the caller is in. The two directions are
|
|
238
|
+
* symmetric in shape but very different in implementation (forward
|
|
239
|
+
* direction uses the precomputed reverse-bridge map; reverse direction
|
|
240
|
+
* uses the deterministic name-derivation).
|
|
241
|
+
*/
|
|
242
|
+
resolve(ref, context) {
|
|
243
|
+
if (ref.language === 'swift') {
|
|
244
|
+
return resolveSwiftCallToObjc(ref, context);
|
|
245
|
+
}
|
|
246
|
+
if (ref.language === 'objc') {
|
|
247
|
+
return resolveObjcCallToSwift(ref, context);
|
|
248
|
+
}
|
|
249
|
+
return null;
|
|
250
|
+
},
|
|
251
|
+
};
|
|
252
|
+
//# sourceMappingURL=swift-objc.js.map
|