diff --git a/test/other/embind_tsgen.cpp b/test/other/embind_tsgen.cpp index 8687f8e5dc49a..66bfe440d86ac 100644 --- a/test/other/embind_tsgen.cpp +++ b/test/other/embind_tsgen.cpp @@ -58,12 +58,19 @@ struct ValArr { EMSCRIPTEN_DECLARE_VAL_TYPE(CallbackType); struct ValObj { - Foo foo; Bar bar; + std::string string; CallbackType callback; ValObj() : callback(val::undefined()) {} }; +ValObj getValObj() { + ValObj o; + return o; +} + +void setValObj(ValObj v) {} + class ClassWithConstructor { public: ClassWithConstructor(int, const ValArr&) {} @@ -190,9 +197,11 @@ EMSCRIPTEN_BINDINGS(Test) { .element(emscripten::index<3>()); value_object("ValObj") - .field("foo", &ValObj::foo) + .field("string", &ValObj::string) .field("bar", &ValObj::bar) .field("callback", &ValObj::callback); + function("getValObj", &getValObj); + function("setValObj", &setValObj); register_vector("IntVec"); diff --git a/test/other/embind_tsgen.d.ts b/test/other/embind_tsgen.d.ts index 367232ae5f178..df88531793f07 100644 --- a/test/other/embind_tsgen.d.ts +++ b/test/other/embind_tsgen.d.ts @@ -84,12 +84,6 @@ export interface ClassWithSmartPtrConstructor extends ClassHandle { fn(_0: number): number; } -export type ValObj = { - foo: Foo, - bar: Bar, - callback: (message: string) => void -}; - export interface BaseClass extends ClassHandle { fn(_0: number): number; } @@ -108,6 +102,12 @@ export interface InterfaceWrapper extends Interface { export type ValArr = [ number, number, number ]; +export type ValObj = { + string: EmbindString, + bar: Bar, + callback: (message: string) => void +}; + interface EmbindModule { Test: { staticFunction(_0: number): number; @@ -158,6 +158,8 @@ interface EmbindModule { smart_ptr_function(_0: ClassWithSmartPtrConstructor | null): number; smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor | null): number; function_with_callback_param(_0: (message: string) => void): number; + getValObj(): ValObj; + setValObj(_0: ValObj): void; string_test(_0: EmbindString): string; wstring_test(_0: string): string; } diff --git a/test/other/embind_tsgen_ignore_1.d.ts b/test/other/embind_tsgen_ignore_1.d.ts index d7a513215c143..a3526282d6aa2 100644 --- a/test/other/embind_tsgen_ignore_1.d.ts +++ b/test/other/embind_tsgen_ignore_1.d.ts @@ -93,12 +93,6 @@ export interface ClassWithSmartPtrConstructor extends ClassHandle { fn(_0: number): number; } -export type ValObj = { - foo: Foo, - bar: Bar, - callback: (message: string) => void -}; - export interface BaseClass extends ClassHandle { fn(_0: number): number; } @@ -117,6 +111,12 @@ export interface InterfaceWrapper extends Interface { export type ValArr = [ number, number, number ]; +export type ValObj = { + string: EmbindString, + bar: Bar, + callback: (message: string) => void +}; + interface EmbindModule { Test: { staticFunction(_0: number): number; @@ -167,6 +167,8 @@ interface EmbindModule { smart_ptr_function(_0: ClassWithSmartPtrConstructor | null): number; smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor | null): number; function_with_callback_param(_0: (message: string) => void): number; + getValObj(): ValObj; + setValObj(_0: ValObj): void; string_test(_0: EmbindString): string; wstring_test(_0: string): string; } diff --git a/test/other/embind_tsgen_ignore_2.d.ts b/test/other/embind_tsgen_ignore_2.d.ts index 7e2923be3c762..f56a1d323f526 100644 --- a/test/other/embind_tsgen_ignore_2.d.ts +++ b/test/other/embind_tsgen_ignore_2.d.ts @@ -70,12 +70,6 @@ export interface ClassWithSmartPtrConstructor extends ClassHandle { fn(_0: number): number; } -export type ValObj = { - foo: Foo, - bar: Bar, - callback: (message: string) => void -}; - export interface BaseClass extends ClassHandle { fn(_0: number): number; } @@ -94,6 +88,12 @@ export interface InterfaceWrapper extends Interface { export type ValArr = [ number, number, number ]; +export type ValObj = { + string: EmbindString, + bar: Bar, + callback: (message: string) => void +}; + interface EmbindModule { Test: { staticFunction(_0: number): number; @@ -144,6 +144,8 @@ interface EmbindModule { smart_ptr_function(_0: ClassWithSmartPtrConstructor | null): number; smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor | null): number; function_with_callback_param(_0: (message: string) => void): number; + getValObj(): ValObj; + setValObj(_0: ValObj): void; string_test(_0: EmbindString): string; wstring_test(_0: string): string; } diff --git a/test/other/embind_tsgen_ignore_3.d.ts b/test/other/embind_tsgen_ignore_3.d.ts index 367232ae5f178..df88531793f07 100644 --- a/test/other/embind_tsgen_ignore_3.d.ts +++ b/test/other/embind_tsgen_ignore_3.d.ts @@ -84,12 +84,6 @@ export interface ClassWithSmartPtrConstructor extends ClassHandle { fn(_0: number): number; } -export type ValObj = { - foo: Foo, - bar: Bar, - callback: (message: string) => void -}; - export interface BaseClass extends ClassHandle { fn(_0: number): number; } @@ -108,6 +102,12 @@ export interface InterfaceWrapper extends Interface { export type ValArr = [ number, number, number ]; +export type ValObj = { + string: EmbindString, + bar: Bar, + callback: (message: string) => void +}; + interface EmbindModule { Test: { staticFunction(_0: number): number; @@ -158,6 +158,8 @@ interface EmbindModule { smart_ptr_function(_0: ClassWithSmartPtrConstructor | null): number; smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor | null): number; function_with_callback_param(_0: (message: string) => void): number; + getValObj(): ValObj; + setValObj(_0: ValObj): void; string_test(_0: EmbindString): string; wstring_test(_0: string): string; } diff --git a/test/other/embind_tsgen_main.ts b/test/other/embind_tsgen_main.ts new file mode 100644 index 0000000000000..a3a39683245af --- /dev/null +++ b/test/other/embind_tsgen_main.ts @@ -0,0 +1,30 @@ +// Example TS program that consumes the emscripten-generated module to to +// illustrate how the type definitions are used and test they are workings as +// expected. +import moduleFactory from './embind_tsgen.mjs'; + +const module = await moduleFactory(); + +// Test a few variations of passing value_objects with strings. +module.setValObj({ + bar: module.Bar.valueOne, + string: "ABCD", + callback: () => {} +}); + +module.setValObj({ + bar: module.Bar.valueOne, + string: new Int8Array([65, 66, 67, 68]), + callback: () => {} +}); + +const valObj = module.getValObj(); +// TODO: remove the cast below when better definitions are generated for value +// objects. +const valString : string = valObj.string as string; + +// Ensure nonnull pointers do no need a cast or nullptr check to use. +const obj = module.getNonnullPointer(); +obj.delete(); + +console.log('ts ran'); diff --git a/test/other/embind_tsgen_module.d.ts b/test/other/embind_tsgen_module.d.ts new file mode 100644 index 0000000000000..1631d67bcde96 --- /dev/null +++ b/test/other/embind_tsgen_module.d.ts @@ -0,0 +1,168 @@ +// TypeScript bindings for emscripten-generated code. Automatically generated at compile time. +declare namespace RuntimeExports { + let HEAPF32: any; + let HEAPF64: any; + let HEAP_DATA_VIEW: any; + let HEAP8: any; + let HEAPU8: any; + let HEAP16: any; + let HEAPU16: any; + let HEAP32: any; + let HEAPU32: any; + let HEAP64: any; + let HEAPU64: any; +} +interface WasmModule { + _main(_0: number, _1: number): number; +} + +type EmbindString = ArrayBuffer|Uint8Array|Uint8ClampedArray|Int8Array|string; +export interface ClassHandle { + isAliasOf(other: ClassHandle): boolean; + delete(): void; + deleteLater(): this; + isDeleted(): boolean; + clone(): this; +} +export interface Test extends ClassHandle { + x: number; + readonly y: number; + get stringProperty(): string; + set stringProperty(value: EmbindString); + functionOne(_0: number, _1: number): number; + functionTwo(_0: number, _1: number): number; + functionFour(_0: boolean): number; + functionFive(x: number, y: number): number; + constFn(): number; + longFn(_0: number): number; + functionThree(_0: EmbindString): number; + functionSix(str: EmbindString): number; +} + +export interface Obj extends ClassHandle { +} + +export interface BarValue { + value: T; +} +export type Bar = BarValue<0>|BarValue<1>|BarValue<2>; + +export interface EmptyEnumValue { + value: T; +} +export type EmptyEnum = never/* Empty Enumerator */; + +export type ValArrIx = [ Bar, Bar, Bar, Bar ]; + +export interface IntVec extends ClassHandle { + push_back(_0: number): void; + resize(_0: number, _1: number): void; + size(): number; + get(_0: number): number | undefined; + set(_0: number, _1: number): boolean; +} + +export interface MapIntInt extends ClassHandle { + keys(): IntVec; + get(_0: number): number | undefined; + set(_0: number, _1: number): void; + size(): number; +} + +export interface Foo extends ClassHandle { + process(_0: Test): void; +} + +export interface ClassWithConstructor extends ClassHandle { + fn(_0: number): number; +} + +export interface ClassWithTwoConstructors extends ClassHandle { +} + +export interface ClassWithSmartPtrConstructor extends ClassHandle { + fn(_0: number): number; +} + +export interface BaseClass extends ClassHandle { + fn(_0: number): number; +} + +export interface DerivedClass extends BaseClass { + fn2(_0: number): number; +} + +export interface Interface extends ClassHandle { + invoke(_0: EmbindString): void; +} + +export interface InterfaceWrapper extends Interface { + notifyOnDestruction(): void; +} + +export type ValArr = [ number, number, number ]; + +export type ValObj = { + string: EmbindString, + bar: Bar, + callback: (message: string) => void +}; + +interface EmbindModule { + Test: { + staticFunction(_0: number): number; + staticFunctionWithParam(x: number): number; + staticProperty: number; + get staticStringProperty(): string; + set staticStringProperty(value: EmbindString); + }; + class_returning_fn(): Test; + class_unique_ptr_returning_fn(): Test; + Obj: {}; + getPointer(_0: Obj | null): Obj | null; + getNonnullPointer(): Obj; + a_class_instance: Test; + an_enum: Bar; + Bar: {valueOne: BarValue<0>, valueTwo: BarValue<1>, valueThree: BarValue<2>}; + EmptyEnum: {}; + enum_returning_fn(): Bar; + IntVec: { + new(): IntVec; + }; + MapIntInt: { + new(): MapIntInt; + }; + Foo: {}; + ClassWithConstructor: { + new(_0: number, _1: ValArr): ClassWithConstructor; + }; + ClassWithTwoConstructors: { + new(): ClassWithTwoConstructors; + new(_0: number): ClassWithTwoConstructors; + }; + ClassWithSmartPtrConstructor: { + new(_0: number, _1: ValArr): ClassWithSmartPtrConstructor; + }; + BaseClass: {}; + DerivedClass: {}; + Interface: { + implement(_0: any): InterfaceWrapper; + extend(_0: EmbindString, _1: any): any; + }; + InterfaceWrapper: {}; + a_bool: boolean; + an_int: number; + optional_test(_0?: Foo): number | undefined; + global_fn(_0: number, _1: number): number; + optional_and_nonoptional_test(_0: Foo | undefined, _1: number): number | undefined; + smart_ptr_function(_0: ClassWithSmartPtrConstructor | null): number; + smart_ptr_function_with_params(foo: ClassWithSmartPtrConstructor | null): number; + function_with_callback_param(_0: (message: string) => void): number; + getValObj(): ValObj; + setValObj(_0: ValObj): void; + string_test(_0: EmbindString): string; + wstring_test(_0: string): string; +} + +export type MainModule = WasmModule & typeof RuntimeExports & EmbindModule; +export default function MainModuleFactory (options?: unknown): Promise; diff --git a/test/other/embind_tsgen_package.json b/test/other/embind_tsgen_package.json new file mode 100644 index 0000000000000..3dbc1ca591c05 --- /dev/null +++ b/test/other/embind_tsgen_package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} diff --git a/test/test_other.py b/test/test_other.py index db997372b2d0a..ece2fc6ab9dbe 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3386,15 +3386,19 @@ def test_jspi_add_function(self): def test_embind_tsgen(self, opts): # Check that TypeScript generation works and that the program is runs as # expected. - self.do_runf('other/embind_tsgen.cpp', 'main ran', - emcc_args=['-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] + opts) + self.emcc(test_file('other/embind_tsgen.cpp'), + ['-o', 'embind_tsgen.mjs', '-lembind', '--emit-tsd', 'embind_tsgen.d.ts'] + opts) # Test that the output compiles with a TS file that uses the defintions. - cmd = shared.get_npm_cmd('tsc') + ['embind_tsgen.d.ts', '--noEmit'] + shutil.copyfile(test_file('other/embind_tsgen_main.ts'), 'main.ts') + # A package file with type=module is needed to enabled ES modules in TSC and + # also run the output JS file as a module in node. + shutil.copyfile(test_file('other/embind_tsgen_package.json'), 'package.json') + cmd = shared.get_npm_cmd('tsc') + ['embind_tsgen.d.ts', 'main.ts', '--module', 'NodeNext', '--moduleResolution', 'nodenext'] shared.check_call(cmd) - actual = read_file('embind_tsgen.d.ts') - self.assertFileContents(test_file('other/embind_tsgen.d.ts'), actual) + self.assertFileContents(test_file('other/embind_tsgen_module.d.ts'), actual) + self.assertContained('main ran\nts ran', self.run_js('main.js')) def test_embind_tsgen_ignore(self): create_file('fail.js', 'assert(false);')