@iamevan/nobjc 0.0.1

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 ADDED
@@ -0,0 +1,10 @@
1
+ # nobjc
2
+
3
+ > [!WARNING]
4
+ > Don't use this in production.
5
+
6
+ **nobjc** is an Objective-C bridge for Node.js. [Don't use it.](https://wts.dev/posts/nobjc/)
7
+
8
+ ## Usage
9
+
10
+ You shouldn't use this, but if you want to, check back here later for when I actually add documentation.
Binary file
@@ -0,0 +1,13 @@
1
+ import { NobjcNative } from './native.js';
2
+ declare class NobjcLibrary {
3
+ [key: string]: NobjcObject;
4
+ constructor(library: string);
5
+ }
6
+ declare class NobjcObject {
7
+ [key: string]: NobjcMethod;
8
+ constructor(object: NobjcNative.ObjcObject);
9
+ }
10
+ declare class NobjcMethod {
11
+ constructor(object: NobjcNative.ObjcObject, methodName: string);
12
+ }
13
+ export { NobjcLibrary, NobjcObject, NobjcMethod };
package/dist/index.js ADDED
@@ -0,0 +1,70 @@
1
+ import { LoadLibrary, GetClassObject, ObjcObject } from './native.js';
2
+ class NobjcLibrary {
3
+ constructor(library) {
4
+ const handler = {
5
+ wasLoaded: false,
6
+ get(_, className) {
7
+ if (!this.wasLoaded) {
8
+ LoadLibrary(library);
9
+ this.wasLoaded = true;
10
+ }
11
+ return new NobjcObject(GetClassObject(className));
12
+ }
13
+ };
14
+ return new Proxy({}, handler);
15
+ }
16
+ }
17
+ function NobjcMethodNameToObjcSelector(methodName) {
18
+ return methodName.replace(/\$/g, ':');
19
+ }
20
+ // unused, might be useful for codegen later
21
+ function ObjcSelectorToNobjcMethodName(selector) {
22
+ return selector.replace(/:/g, '$');
23
+ }
24
+ class NobjcObject {
25
+ constructor(object) {
26
+ const handler = {
27
+ has(target, p) {
28
+ // guard against symbols
29
+ if (typeof p === 'symbol')
30
+ return Reflect.has(target, p);
31
+ // toString is always present
32
+ if (p === 'toString')
33
+ return true;
34
+ // check if the object responds to the selector
35
+ return target.$msgSend('respondsToSelector:', NobjcMethodNameToObjcSelector(p.toString()));
36
+ },
37
+ get(_, methodName, receiver) {
38
+ // guard against symbols
39
+ if (typeof methodName === 'symbol') {
40
+ return Reflect.get(object, methodName, receiver);
41
+ }
42
+ // handle toString separately
43
+ if (methodName === 'toString') {
44
+ return () => String(object.$msgSend('description'));
45
+ }
46
+ if (!(methodName in receiver)) {
47
+ throw new Error(`Method ${methodName} not found on object ${receiver}`);
48
+ }
49
+ return new NobjcMethod(object, methodName);
50
+ }
51
+ };
52
+ return new Proxy(object, handler);
53
+ }
54
+ }
55
+ class NobjcMethod {
56
+ constructor(object, methodName) {
57
+ const selector = NobjcMethodNameToObjcSelector(methodName);
58
+ // This cannot be an arrow function because we need to access `arguments`.
59
+ function methodFunc() {
60
+ const result = object.$msgSend(selector, ...arguments);
61
+ if (typeof result == 'object' && result instanceof ObjcObject) {
62
+ return new NobjcObject(result);
63
+ }
64
+ return result;
65
+ }
66
+ const handler = {};
67
+ return new Proxy(methodFunc, handler);
68
+ }
69
+ }
70
+ export { NobjcLibrary, NobjcObject, NobjcMethod };
@@ -0,0 +1,4 @@
1
+ import * as _binding from '#nobjc_native';
2
+ declare const LoadLibrary: typeof _binding.LoadLibrary, GetClassObject: typeof _binding.GetClassObject, ObjcObject: typeof _binding.ObjcObject;
3
+ export { LoadLibrary, GetClassObject, ObjcObject };
4
+ export type { _binding as NobjcNative };
package/dist/native.js ADDED
@@ -0,0 +1,5 @@
1
+ import { createRequire } from 'node:module';
2
+ const require = createRequire(import.meta.url);
3
+ const binding = require('#nobjc_native');
4
+ const { LoadLibrary, GetClassObject, ObjcObject } = binding;
5
+ export { LoadLibrary, GetClassObject, ObjcObject };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@iamevan/nobjc",
3
+ "private": false,
4
+ "access": "public",
5
+ "type": "module",
6
+ "os": [
7
+ "darwin"
8
+ ],
9
+ "repository": "github:nmggithub/nobjc",
10
+ "author": {
11
+ "name": "Noah Gregory",
12
+ "email": "noah@wts.dev",
13
+ "url": "https://wts.dev"
14
+ },
15
+ "imports": {
16
+ "#nobjc_native": "./build/Release/nobjc_native.node"
17
+ },
18
+ "exports": {
19
+ ".": "./dist/index.js",
20
+ "./native": "./build/Release/nobjc_native.node"
21
+ },
22
+ "files": [
23
+ "dist/",
24
+ "build/Release/nobjc_native.node"
25
+ ],
26
+ "scripts": {
27
+ "build-native": "node-gyp build",
28
+ "build-scripts": "tsc --project scripts/tsconfig.json",
29
+ "build-source": "tsc --project src/ts/tsconfig.json",
30
+ "prebuild": "node-gyp clean && node-gyp configure",
31
+ "build": "npm run build-native && npm run build-scripts && npm run build-source",
32
+ "pretest": "npm run build",
33
+ "test-native": "node ./scripts/test-native-code.js",
34
+ "test-js": "node ./scripts/test-js-code.js",
35
+ "test": "npm run test-native && npm run test-js",
36
+ "make-clangd-config": "node ./scripts/make-clangd-config.js",
37
+ "preinstall": "npm run build-scripts && npm run make-clangd-config"
38
+ },
39
+ "version": "0.0.1",
40
+ "description": "Objective-C bridge for Node.js",
41
+ "main": "dist/index.js",
42
+ "devDependencies": {
43
+ "@types/node": "^20.0.0",
44
+ "typescript": "^5.9.3",
45
+ "node-addon-api": "^8.5.0",
46
+ "node-gyp": "^11.4.2"
47
+ },
48
+ "gypfile": true
49
+ }