-
Notifications
You must be signed in to change notification settings - Fork 580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactored binding wrapper #6820
Conversation
5c817dd
to
23ebc3a
Compare
I rebased this on |
23ebc3a
to
348ab11
Compare
@@ -0,0 +1,405 @@ | |||
import { TemplateContext } from "@realm/bindgen/context"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The removal of the platform specific wrappers and the addition of this file are the biggest part of the changes proposed here. Originally we had the thought that keeping these separate could allow for platform specific optimizations but in reality we haven't relied on that and the separation gives rise to extra unneeded complexity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice refactor 🙂 LGTM after addressing the comments 👌
@@ -0,0 +1,405 @@ | |||
import { TemplateContext } from "@realm/bindgen/context"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import { TemplateContext } from "@realm/bindgen/context"; | |
//////////////////////////////////////////////////////////////////////////// | |
// | |
// Copyright 2024 Realm Inc. | |
// | |
// Licensed under the Apache License, Version 2.0 (the "License"); | |
// you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at | |
// | |
// http://www.apache.org/licenses/LICENSE-2.0 | |
// | |
// Unless required by applicable law or agreed to in writing, software | |
// distributed under the License is distributed on an "AS IS" BASIS, | |
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
// See the License for the specific language governing permissions and | |
// limitations under the License. | |
// | |
//////////////////////////////////////////////////////////////////////////// | |
import { TemplateContext } from "@realm/bindgen/context"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is missing because the eslint config is different for these files: https://github.com/realm/realm-js/blob/nh/wasm/emscripten_target/packages/realm/bindgen/.eslintrc.json
We could probably delete that .eslintrc.json
and commit the --fix
but I'll defer that to another PR.
return `export const enum ${e.jsName} { ${e.enumerators.map(({ jsName, value }) => `${jsName} = ${value}`)} };`; | ||
} | ||
|
||
const PRIMITIVES_MAPPING: Record<string, string | undefined> = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was there a reason for including undefined
here?
const PRIMITIVES_MAPPING: Record<string, string | undefined> = { | |
const PRIMITIVES_MAPPING: Record<string, string> = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because not all possible string properties result in a string
upon lookup.
If omitted PRIMITIVES_MAPPING["invalid"]
would have the type string
when in fact it'll be undefined
. I often forget this myself (and should probably add it to TEMPLATE_MAPPING
as well 🤔)
} | ||
} | ||
|
||
function generateRecordDeclaration(spec: BoundSpec, record: Struct) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice that generateXDeclaration
logic has been pulled out 👍
// Check the support for primitives used | ||
for (const primitive of rawSpec.primitives) { | ||
if (primitive === "Mixed") continue; | ||
assert( | ||
Object.keys(PRIMITIVES_MAPPING).includes(primitive), | ||
`Spec declares an unsupported primitive: "${primitive}"`, | ||
); | ||
} | ||
|
||
// Check the support for template instances used | ||
for (const template of Object.keys(rawSpec.templates)) { | ||
assert( | ||
Object.keys(TEMPLATE_MAPPING).includes(template), | ||
`Spec declares an unsupported template instance: "${template}"`, | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Alternatively, this could be refactored into some assertSupportedTypes()
(or the like) function (with the rawSpec
param), and let generate()
only focus on generating output.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this could be simplified, but I think I'll let it pass for now as it's a copy-paste from the former typescript.ts
template:
realm-js/packages/realm/bindgen/src/templates/typescript.ts
Lines 135 to 150 in ff3d889
// Check the support for primitives used | |
for (const primitive of rawSpec.primitives) { | |
if (primitive === "Mixed") continue; | |
assert( | |
Object.keys(PRIMITIVES_MAPPING).includes(primitive), | |
`Spec declares an unsupported primitive: "${primitive}"`, | |
); | |
} | |
// Check the support for template instances used | |
for (const template of Object.keys(rawSpec.templates)) { | |
assert( | |
Object.keys(TEMPLATE_MAPPING).includes(template), | |
`Spec declares an unsupported template instance: "${template}"`, | |
); | |
} |
packages/realm/package.json
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice simplification here
import type { binding } from "./wrapper.generated"; | ||
import { assert } from "../assert"; | ||
|
||
export const PolyfilledBigInt: typeof binding.Int64 = Object.freeze({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting solution for the RN issue 🙂
WeakRef: class WeakRef { | ||
private native: unknown; | ||
constructor(obj: unknown) { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- See "createWeakRef" protocol in the jsi bindgen template | ||
this.native = (nativeModule as any).createWeakRef(obj); | ||
} | ||
deref() { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- See "createWeakRef" protocol in the jsi bindgen template | ||
return (nativeModule as any).lockWeakRef(this.native); | ||
} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this also a polyfill? If so, perhaps we could declare and define it PolyfillWeakRef
similar to the bigint polyfill.
Co-authored-by: LJ <81748770+elle-j@users.noreply.github.com>
What, How & Why?
As a prerequisite for the rebase of the WASM / browser binding, I had to rework the generated code that wraps the native module and expose it in a TypeScript friendlier way than free functions. Instead of having platform specific wrappers that implement platform specific code to load the native module I suggest exporting an
injectNativeModule
function which takes the native module (from somewhere) and wraps it into thebinding
namespace / object.This has multiple benefits:
src/platform
files, which enables us to leverage TypeScript to achieve type-safety.injectNativeModule
once the native module has loaded (possibly asynchronously as in the case of the WASM module).any
type at the point of injection. This has the added benefit that we can get rid of a lot of the complexity in the./binding
directory as well as the babel transpile step require to get a CommonJS variant of the wrappers.☑️ ToDos
Compatibility
label is updated or copied from previous entryCOMPATIBILITY.md
package.json
s (if updating internal packages)Breaking
label has been applied or is not necessary@realm/devdocs
if documentation changes are needed