objc-js 0.0.6 → 0.0.8
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/build/Release/nobjc_native.node +0 -0
- package/dist/index.js +51 -18
- package/package.json +1 -1
|
Binary file
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LoadLibrary, GetClassObject, ObjcObject, GetPointer, FromPointer, CreateProtocolImplementation } from "./native.js";
|
|
2
|
+
const customInspectSymbol = Symbol.for("nodejs.util.inspect.custom");
|
|
2
3
|
const NATIVE_OBJC_OBJECT = Symbol("nativeObjcObject");
|
|
3
4
|
class NobjcLibrary {
|
|
4
5
|
constructor(library) {
|
|
@@ -24,6 +25,7 @@ function ObjcSelectorToNobjcMethodName(selector) {
|
|
|
24
25
|
}
|
|
25
26
|
class NobjcObject {
|
|
26
27
|
constructor(object) {
|
|
28
|
+
// Create the proxy handler
|
|
27
29
|
const handler = {
|
|
28
30
|
has(target, p) {
|
|
29
31
|
// Return true for the special Symbol to enable unwrapping
|
|
@@ -36,7 +38,12 @@ class NobjcObject {
|
|
|
36
38
|
if (p === "toString")
|
|
37
39
|
return true;
|
|
38
40
|
// check if the object responds to the selector
|
|
39
|
-
|
|
41
|
+
try {
|
|
42
|
+
return target.$msgSend("respondsToSelector:", NobjcMethodNameToObjcSelector(p.toString()));
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
40
47
|
},
|
|
41
48
|
get(target, methodName, receiver) {
|
|
42
49
|
// Return the underlying native object when Symbol is accessed
|
|
@@ -49,7 +56,29 @@ class NobjcObject {
|
|
|
49
56
|
}
|
|
50
57
|
// handle toString separately
|
|
51
58
|
if (methodName === "toString") {
|
|
52
|
-
|
|
59
|
+
// if the receiver has a UTF8String method, use it to get the string representation
|
|
60
|
+
if ("UTF8String" in receiver) {
|
|
61
|
+
return () => String(object.$msgSend("UTF8String"));
|
|
62
|
+
}
|
|
63
|
+
// Otherwise, use the description method
|
|
64
|
+
return () => String(wrapObjCObjectIfNeeded(object.$msgSend("description")));
|
|
65
|
+
}
|
|
66
|
+
// handle other built-in Object.prototype properties
|
|
67
|
+
const builtInProps = [
|
|
68
|
+
"constructor",
|
|
69
|
+
"valueOf",
|
|
70
|
+
"hasOwnProperty",
|
|
71
|
+
"isPrototypeOf",
|
|
72
|
+
"propertyIsEnumerable",
|
|
73
|
+
"toLocaleString",
|
|
74
|
+
"__proto__",
|
|
75
|
+
"__defineGetter__",
|
|
76
|
+
"__defineSetter__",
|
|
77
|
+
"__lookupGetter__",
|
|
78
|
+
"__lookupSetter__"
|
|
79
|
+
];
|
|
80
|
+
if (builtInProps.includes(methodName)) {
|
|
81
|
+
return Reflect.get(target, methodName);
|
|
53
82
|
}
|
|
54
83
|
if (!(methodName in receiver)) {
|
|
55
84
|
throw new Error(`Method ${methodName} not found on object ${receiver}`);
|
|
@@ -57,7 +86,12 @@ class NobjcObject {
|
|
|
57
86
|
return NobjcMethod(object, methodName);
|
|
58
87
|
}
|
|
59
88
|
};
|
|
60
|
-
|
|
89
|
+
// Create the proxy
|
|
90
|
+
const proxy = new Proxy(object, handler);
|
|
91
|
+
// This is used to override the default inspect behavior for the object. (console.log)
|
|
92
|
+
object[customInspectSymbol] = () => proxy.toString();
|
|
93
|
+
// Return the proxy
|
|
94
|
+
return proxy;
|
|
61
95
|
}
|
|
62
96
|
}
|
|
63
97
|
function unwrapArg(arg) {
|
|
@@ -66,6 +100,12 @@ function unwrapArg(arg) {
|
|
|
66
100
|
}
|
|
67
101
|
return arg;
|
|
68
102
|
}
|
|
103
|
+
function wrapObjCObjectIfNeeded(result) {
|
|
104
|
+
if (typeof result == "object" && result instanceof ObjcObject) {
|
|
105
|
+
return new NobjcObject(result);
|
|
106
|
+
}
|
|
107
|
+
return result;
|
|
108
|
+
}
|
|
69
109
|
// Note: This is actually a factory function that returns a callable Proxy
|
|
70
110
|
const NobjcMethod = function (object, methodName) {
|
|
71
111
|
const selector = NobjcMethodNameToObjcSelector(methodName);
|
|
@@ -73,10 +113,7 @@ const NobjcMethod = function (object, methodName) {
|
|
|
73
113
|
function methodFunc() {
|
|
74
114
|
const unwrappedArgs = Array.from(arguments).map(unwrapArg);
|
|
75
115
|
const result = object.$msgSend(selector, ...unwrappedArgs);
|
|
76
|
-
|
|
77
|
-
return new NobjcObject(result);
|
|
78
|
-
}
|
|
79
|
-
return result;
|
|
116
|
+
return wrapObjCObjectIfNeeded(result);
|
|
80
117
|
}
|
|
81
118
|
const handler = {};
|
|
82
119
|
return new Proxy(methodFunc, handler);
|
|
@@ -87,19 +124,15 @@ class NobjcProtocol {
|
|
|
87
124
|
const convertedMethods = {};
|
|
88
125
|
for (const [methodName, impl] of Object.entries(methodImplementations)) {
|
|
89
126
|
const selector = NobjcMethodNameToObjcSelector(methodName);
|
|
90
|
-
// Wrap the implementation to
|
|
127
|
+
// Wrap the implementation to wrap args and unwrap return values
|
|
91
128
|
convertedMethods[selector] = function (...args) {
|
|
92
|
-
|
|
93
|
-
const
|
|
129
|
+
// Wrap native ObjcObject arguments in NobjcObject proxies
|
|
130
|
+
const wrappedArgs = args.map((arg) => {
|
|
131
|
+
return wrapObjCObjectIfNeeded(arg);
|
|
132
|
+
});
|
|
133
|
+
const result = impl(...wrappedArgs);
|
|
94
134
|
// If the result is already a NobjcObject, unwrap it to get the native object
|
|
95
|
-
|
|
96
|
-
return result[NATIVE_OBJC_OBJECT];
|
|
97
|
-
}
|
|
98
|
-
// If the result is a native ObjcObject, return it as-is
|
|
99
|
-
if (typeof result === "object" && result instanceof ObjcObject) {
|
|
100
|
-
return result;
|
|
101
|
-
}
|
|
102
|
-
return result;
|
|
135
|
+
return unwrapArg(result);
|
|
103
136
|
};
|
|
104
137
|
}
|
|
105
138
|
// Call native implementation
|
package/package.json
CHANGED
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"format": "prettier --write \"**/*.{ts,js,json,md}\"",
|
|
37
37
|
"preinstall-disabled": "npm run build-scripts && npm run make-clangd-config"
|
|
38
38
|
},
|
|
39
|
-
"version": "0.0.
|
|
39
|
+
"version": "0.0.8",
|
|
40
40
|
"description": "Objective-C bridge for Node.js",
|
|
41
41
|
"main": "dist/index.js",
|
|
42
42
|
"devDependencies": {
|