├── .ado ├── publish.yml └── release.yml ├── .editorconfig ├── .github └── workflows │ ├── build.yml │ ├── codeql.yml │ ├── docs.yml │ └── test-report.yml ├── .gitignore ├── .npmrc ├── .vscode ├── extensions.json ├── settings.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── Directory.Build.props ├── Directory.Build.targets ├── Directory.Packages.props ├── LICENSE ├── NodeApi.sln ├── NuGet.config ├── README-DEV.md ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── bench ├── .gitignore ├── Benchmarks.cs ├── Directory.Build.props ├── NodeApi.Bench.csproj └── README.md ├── docs ├── .gitignore ├── .vitepress │ ├── config.mts │ └── theme │ │ ├── custom.css │ │ └── index.ts ├── DotnetToJS.drawio.svg ├── JStoDotnet.drawio.svg ├── NodeApi-Layers.drawio.svg ├── NodeApi-Layers.md ├── contributing.md ├── examples.md ├── features │ ├── dotnet-native-aot.md │ ├── js-dotnet-marshalling.md │ ├── js-references.md │ ├── js-threading-async.md │ ├── js-types-in-dotnet.md │ ├── js-value-scopes.md │ ├── node-workers.md │ ├── performance.md │ └── type-definitions.md ├── images │ ├── dark │ │ └── ts.svg │ ├── dotnet-bot_scene_coffee-shop.png │ ├── light │ │ └── ts.svg │ └── node-api-dotnet-logo.svg ├── index.md ├── overview.md ├── package-lock.json ├── package.json ├── presentation.html ├── presentation.md ├── presentation2.html ├── presentation2.md ├── reference │ ├── arrays-collections.md │ ├── async-promises.md │ ├── basic-types.md │ ├── classes-interfaces.md │ ├── dates.md │ ├── delegates.md │ ├── enums.md │ ├── events.md │ ├── exceptions.md │ ├── extension-methods.md │ ├── generics.md │ ├── js-apis.md │ ├── js-dotnet-types.md │ ├── msbuild-props.md │ ├── namespaces.md │ ├── null-undefined.md │ ├── other-types.md │ ├── overloaded-methods.md │ ├── packages-releases.md │ ├── ref-out-params.md │ ├── streams.md │ └── structs-tuples.md ├── requirements.md ├── scenarios │ ├── dotnet-js.md │ ├── index.md │ ├── js-aot-module.md │ ├── js-dotnet-dynamic.md │ └── js-dotnet-module.md ├── support.md └── tools │ ├── XmlDocMarkdown.cs │ ├── XmlDocMarkdown.csproj │ ├── build-dotnet-api-docs.js │ └── build-js-api-docs.js ├── examples ├── Directory.Build.props ├── Directory.Packages.props ├── NuGet.config ├── aot-module │ ├── Example.cs │ ├── README.md │ ├── aot-module.csproj │ ├── example.js │ └── package.json ├── aot-npm-package │ ├── README.md │ ├── app │ │ ├── example.js │ │ └── package.json │ └── lib │ │ ├── .npmignore │ │ ├── Example.cs │ │ ├── aot-npm-package.csproj │ │ └── package.json ├── dotnet-dynamic-classlib │ ├── ClassLib │ │ ├── Class1.cs │ │ └── ClassLib.csproj │ ├── README.md │ ├── dotnet-dynamic-classlib.csproj │ ├── example.js │ └── package.json ├── dotnet-dynamic │ ├── README.md │ ├── example.js │ └── package.json ├── dotnet-module │ ├── Example.cs │ ├── README.md │ ├── dotnet-module.csproj │ ├── example.js │ └── package.json ├── electron │ ├── README.md │ ├── example.js │ ├── index.html │ ├── main.js │ ├── package.json │ └── preload.js ├── hermes-engine │ ├── HermesApi.Interop.cs │ ├── HermesConfig.cs │ ├── HermesRuntime.cs │ ├── NuGet.config │ ├── Program.cs │ ├── hermes-engine.csproj │ └── hermes-engine.sln ├── jsdom │ ├── Program.cs │ ├── README.md │ ├── jsdom.csproj │ ├── jsdom.sln │ └── package.json ├── semantic-kernel │ ├── .gitignore │ ├── README.md │ ├── example.js │ ├── package.json │ ├── semantic-kernel.csproj │ └── tsconfig.json ├── winui-fluid │ ├── App.xaml │ ├── App.xaml.cs │ ├── Assets │ │ ├── LockScreenLogo.scale-200.png │ │ ├── SplashScreen.scale-200.png │ │ ├── Square150x150Logo.scale-200.png │ │ ├── Square44x44Logo.scale-200.png │ │ ├── Square44x44Logo.targetsize-24_altform-unplated.png │ │ ├── StoreLogo.png │ │ └── Wide310x150Logo.scale-200.png │ ├── CollabEditBox.xaml │ ├── CollabEditBox.xaml.cs │ ├── Fluid │ │ ├── IFluidContainer.cs │ │ ├── ISequenceDeltaEvent.cs │ │ ├── ISharedMap.cs │ │ ├── ISharedString.cs │ │ └── ITinyliciousClient.cs │ ├── Imports.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Package.appxmanifest │ ├── Properties │ │ ├── PublishProfiles │ │ │ ├── win10-arm64.pubxml │ │ │ ├── win10-x64.pubxml │ │ │ └── win10-x86.pubxml │ │ └── launchSettings.json │ ├── README.md │ ├── app.manifest │ ├── index.js │ ├── package.json │ ├── winui-fluid.csproj │ └── winui-fluid.sln └── wpf │ ├── .gitignore │ ├── README.md │ ├── Window1.xaml │ ├── Window1.xaml.cs │ ├── WpfExample.csproj │ ├── example.js │ └── package.json ├── global.json ├── rid.props ├── src ├── Directory.Build.props ├── NodeApi.DotNetHost │ ├── DebugHelper.cs │ ├── JSInterfaceMarshaller.cs │ ├── JSMarshaller.cs │ ├── JSMarshallerDelegates.cs │ ├── JSMarshallerException.cs │ ├── JSRuntimeContextExtensions.cs │ ├── ManagedHost.cs │ ├── NamespaceProxy.cs │ ├── NodeApi.DotNetHost.csproj │ ├── TypeExporter.cs │ ├── TypeExtensions.cs │ └── TypeProxy.cs ├── NodeApi.Generator │ ├── ExpressionExtensions.cs │ ├── ModuleGenerator.cs │ ├── NodeApi.Generator.csproj │ ├── NodeApi.Generator.props │ ├── NodeApi.Generator.targets │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── SourceBuilder.cs │ ├── SourceGenerator.cs │ ├── StringExtensions.cs │ ├── SymbolExtensions.cs │ ├── TypeDefinitionsGenerator.cs │ └── TypeExtensions.cs ├── NodeApi │ ├── DotNetHost │ │ ├── HostFxr.cs │ │ ├── MSCorEE.cs │ │ └── NativeHost.cs │ ├── IJSValue.cs │ ├── Interop │ │ ├── EmptyAttributes.cs │ │ ├── JSAbortSignal.cs │ │ ├── JSAsyncScope.cs │ │ ├── JSCallbackDescriptor.cs │ │ ├── JSCallbackOverload.cs │ │ ├── JSClassBuilderOfT.cs │ │ ├── JSCollectionExtensions.cs │ │ ├── JSCollectionProxies.cs │ │ ├── JSInterface.cs │ │ ├── JSModuleAttribute.cs │ │ ├── JSModuleBuilderOfT.cs │ │ ├── JSModuleContext.cs │ │ ├── JSPropertyDescriptorListOfT.cs │ │ ├── JSRuntimeContext.cs │ │ ├── JSSynchronizationContext.cs │ │ ├── JSThreadSafeFunction.cs │ │ ├── NodeProcess.cs │ │ ├── NodeStream.Proxy.cs │ │ ├── NodeStream.cs │ │ ├── NodeWorker.cs │ │ └── TypeExtensions.cs │ ├── JSArray.Enumerator.cs │ ├── JSArray.cs │ ├── JSAsyncIterable.Enumerator.cs │ ├── JSAsyncIterable.cs │ ├── JSBigInt.cs │ ├── JSCallback.cs │ ├── JSCallbackArgs.cs │ ├── JSDate.cs │ ├── JSDispatcherQueue.cs │ ├── JSError.cs │ ├── JSEventEmitter.cs │ ├── JSException.cs │ ├── JSExportAttribute.cs │ ├── JSFunction.cs │ ├── JSImportAttribute.cs │ ├── JSInvalidThreadAccessException.cs │ ├── JSIterable.Enumerator.cs │ ├── JSIterable.cs │ ├── JSMap.Enumerator.cs │ ├── JSMap.cs │ ├── JSObject.Enumerator.cs │ ├── JSObject.cs │ ├── JSPromise.cs │ ├── JSPropertyAttributes.cs │ ├── JSPropertyDescriptor.cs │ ├── JSProxy.cs │ ├── JSReference.cs │ ├── JSSet.cs │ ├── JSSymbol.cs │ ├── JSTypedArray.cs │ ├── JSTypedArrayType.cs │ ├── JSValue.cs │ ├── JSValueScope.cs │ ├── JSValueScopeClosedException.cs │ ├── JSValueType.cs │ ├── NodeApi.csproj │ ├── NodeApi.targets │ ├── NodeApiStatusExtensions.cs │ ├── Runtime │ │ ├── JSRuntime.Types.cs │ │ ├── JSRuntime.cs │ │ ├── NativeLibrary.cs │ │ ├── NodeEmbedding.cs │ │ ├── NodeEmbeddingModuleInfo.cs │ │ ├── NodeEmbeddingNodeApiScope.cs │ │ ├── NodeEmbeddingPlatform.cs │ │ ├── NodeEmbeddingPlatformSettings.cs │ │ ├── NodeEmbeddingRuntime.cs │ │ ├── NodeEmbeddingRuntimeSettings.cs │ │ ├── NodeEmbeddingThreadRuntime.cs │ │ ├── NodeJSRuntime.cs │ │ ├── NodejsRuntime.Embedding.cs │ │ ├── NodejsRuntime.JS.cs │ │ ├── NodejsRuntime.Node.cs │ │ ├── NodejsRuntime.Types.cs │ │ ├── PooledBuffer.cs │ │ ├── TracingJSRuntime.cs │ │ └── Utf8StringArray.cs │ ├── TaskExtensions.cs │ └── import.cjs └── node-api-dotnet │ ├── generator │ ├── index.js │ └── package.json │ ├── index.d.ts │ ├── init.js │ ├── pack.js │ ├── package.json │ └── tsconfig.json ├── test ├── GCTests.cs ├── HostedClrTests.cs ├── JSProjectTests.cs ├── JSReferenceTests.cs ├── JSValueScopeTests.cs ├── MockJSRuntime.cs ├── NativeAotTests.cs ├── NodeApi.Test.csproj ├── NodejsEmbeddingTests.cs ├── TestBuilder.cs ├── TestCases │ ├── .gitignore │ ├── Directory.Build.props │ ├── Directory.Build.targets │ ├── NuGet.config │ ├── common │ │ └── index.js │ ├── edgejs-perf │ │ ├── Edge.Performance.cs │ │ └── measure-latency.js │ ├── napi-dotnet-init │ │ ├── ModuleInitializer.cs │ │ ├── custom_export.js │ │ └── custom_init.js │ ├── napi-dotnet │ │ ├── Another.cs │ │ ├── AsyncMethods.cs │ │ ├── Collections.cs │ │ ├── ComplexTypes.cs │ │ ├── Counter.cs │ │ ├── Delegates.cs │ │ ├── Errors.cs │ │ ├── ExtensionMethods.cs │ │ ├── Generics.cs │ │ ├── Hello.cs │ │ ├── JSValueCast.cs │ │ ├── ModuleClass.cs │ │ ├── ModuleExports.cs │ │ ├── NoNamespaceTypes.cs │ │ ├── OptionalParameters.cs │ │ ├── Overloads.cs │ │ ├── Streams.cs │ │ ├── ThreadSafety.cs │ │ ├── async_methods.js │ │ ├── collections.js │ │ ├── complex_types.js │ │ ├── delegates.js │ │ ├── dynamic_extensions.js │ │ ├── dynamic_generics.js │ │ ├── dynamic_invoke.js │ │ ├── dynamic_no_namespace_type.js │ │ ├── dynamic_optional_params.js │ │ ├── errors.js │ │ ├── hello.js │ │ ├── jsvalue_cast.js │ │ ├── module_class.js │ │ ├── multi_instance.js │ │ ├── object_map.js │ │ ├── overloads.js │ │ ├── streams.js │ │ ├── subclass.js │ │ └── thread_safety.js │ ├── node-addon-api │ │ ├── basic_types │ │ │ ├── array.cs │ │ │ ├── array.js │ │ │ ├── boolean.cs │ │ │ ├── boolean.js │ │ │ ├── number.cs │ │ │ ├── number.js │ │ │ ├── value.cs │ │ │ └── value.js │ │ ├── bigint.cs │ │ ├── bigint.js │ │ ├── binding.cs │ │ ├── object │ │ │ ├── delete_property.cs │ │ │ ├── delete_property.js │ │ │ ├── finalizer.cs │ │ │ ├── finalizer.js │ │ │ ├── get_property.cs │ │ │ ├── get_property.js │ │ │ ├── has_own_property.cs │ │ │ ├── has_own_property.js │ │ │ ├── has_property.cs │ │ │ ├── has_property.js │ │ │ ├── object.cs │ │ │ ├── object.js │ │ │ ├── object_freeze_seal.cs │ │ │ ├── object_freeze_seal.js │ │ │ ├── set_property.cs │ │ │ ├── set_property.js │ │ │ ├── subscript_operator.cs │ │ │ └── subscript_operator.js │ │ └── testUtil.js │ └── projects │ │ ├── .gitignore │ │ ├── Directory.Build.props │ │ ├── Module.cs │ │ ├── js-cjs-dynamic │ │ ├── js-cjs-dynamic.csproj │ │ ├── net472.js │ │ ├── net8.0.js │ │ ├── net9.0.js │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ ├── js-cjs-module │ │ ├── js-cjs-module.csproj │ │ ├── package.json │ │ ├── test.js │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ ├── js-esm-dynamic │ │ ├── js-esm-dynamic.csproj │ │ ├── net472.js │ │ ├── net8.0.js │ │ ├── net9.0.js │ │ ├── package.json │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ ├── js-esm-module │ │ ├── js-esm-module.csproj │ │ ├── package.json │ │ ├── test.js │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ ├── ts-cjs-dynamic │ │ ├── .gitignore │ │ ├── net472.ts │ │ ├── net8.0.ts │ │ ├── net9.0.ts │ │ ├── package.json │ │ ├── ts-cjs-dynamic.csproj │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ ├── ts-cjs-module │ │ ├── .gitignore │ │ ├── package.json │ │ ├── test.ts │ │ ├── ts-cjs-module.csproj │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ ├── ts-esm-dynamic │ │ ├── .gitignore │ │ ├── net472.ts │ │ ├── net8.0.ts │ │ ├── net9.0.ts │ │ ├── package.json │ │ ├── ts-esm-dynamic.csproj │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json │ │ └── ts-esm-module │ │ ├── .gitignore │ │ ├── package.json │ │ ├── test.ts │ │ ├── ts-esm-module.csproj │ │ ├── tsconfig.json │ │ └── tsconfig.net472.json ├── TestUtils.cs ├── TypeDefsGeneratorTests.cs ├── test-cjs-package │ ├── index.js │ └── package.json ├── test-esm-package │ ├── feature.js │ ├── index.js │ └── package.json ├── test-module.cjs └── test-module.mjs └── version.json /.github/workflows/test-report.yml: -------------------------------------------------------------------------------- 1 | # https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 2 | # https://github.com/dorny/test-reporter#recommended-setup-for-public-repositories 3 | 4 | name: Test Report 5 | on: 6 | workflow_run: 7 | workflows: ['PR Verification'] # runs after 'PR Verification' workflow 8 | types: 9 | - completed 10 | 11 | permissions: 12 | checks: write 13 | pull-requests: write 14 | statuses: write 15 | 16 | jobs: 17 | report: 18 | strategy: 19 | matrix: # This must be kept in sync with the PR build matrix. 20 | os: [ windows-latest, macos-latest, ubuntu-latest ] 21 | dotnet-version: [ net472, net8.0, net9.0] 22 | node-version: [ 18.x, 22.x ] 23 | configuration: [ Release ] 24 | exclude: 25 | # Exclude Node 18.x on .NET < 9, to thin the matrix. 26 | - dotnet-version: net8.0 27 | node-version: 18.x 28 | - dotnet-version: net472 29 | node-version: 18.x 30 | # Exclude .NET 4.x on non-Windows OS. 31 | - os: macos-latest 32 | dotnet-version: net472 33 | - os: ubuntu-latest 34 | dotnet-version: net472 35 | 36 | runs-on: ubuntu-latest 37 | 38 | steps: 39 | - name: Publish test results 40 | uses: dorny/test-reporter@v1 41 | with: 42 | artifact: test-logs-${{ matrix.os }}-${{matrix.dotnet-version}}-node${{matrix.node-version}}-${{matrix.configuration}} 43 | name: test results (${{ matrix.os }}, ${{matrix.dotnet-version}}, node${{ matrix.node-version }}, ${{ matrix.configuration }}) 44 | path: test/**/*.trx 45 | reporter: dotnet-trx 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out/ 2 | bin/ 3 | obj/ 4 | pkg/ 5 | 6 | *.suo 7 | *.user 8 | 9 | .vs/ 10 | 11 | node_modules/ 12 | examples/**/package-lock.json 13 | 14 | /src/**/*.xml 15 | 16 | *.log 17 | *.binlog 18 | 19 | cache/ 20 | dist/ 21 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # DO NOT SPECIFY AUTHENTICATION CREDENTIALS IN THIS FILE. 2 | # It should only be used to configure NPM registry sources. 3 | 4 | # Use ADO public NPM registry to be complient 5 | # Additional registries should be added as upstreams instead of being added here. 6 | 7 | registry=https://pkgs.dev.azure.com/ms/react-native/_packaging/react-native-public/npm/registry/ 8 | always-auth=true -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-dotnettools.csharp" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | // Don't show the "Required assets are missing..." dialog on startup. We'll manage tasks.json / launch.json manually. 3 | "csharp.suppressBuildAssetsNotification": true, 4 | 5 | // We try to limit the length of code lines to 100 columns. 6 | "editor.rulers": [ 7 | 100, 8 | ], 9 | "dotnet.preferRuntimeFromSDK": true 10 | } 11 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | 15 | 18 | 19 | %(PackageVersion.Version) 20 | 21 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | Copyright (c) 2022 Jason Ginchereau 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | For help and questions about using this project, please refer to the product documentation 10 | or use GitHub discussions for this project. 11 | 12 | ## Microsoft Support Policy 13 | 14 | Support for this **Node-API .Net** project is limited to the resources listed above. 15 | -------------------------------------------------------------------------------- /bench/.gitignore: -------------------------------------------------------------------------------- 1 | BenchmarkDotNet.Artifacts 2 | -------------------------------------------------------------------------------- /bench/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | net9.0;net8.0 6 | net9.0;net8.0;net472 7 | 12 8 | enable 9 | false 10 | true 11 | 12 | 13 | -------------------------------------------------------------------------------- /bench/NodeApi.Bench.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | exe 5 | Microsoft.JavaScript.NodeApi.Bench 6 | false 7 | false 8 | MSB3270 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /bench/README.md: -------------------------------------------------------------------------------- 1 | # Micro-benchmarks for node-api-dotnet APIs 2 | 3 | This project contains a set of micro-benchmarks for .NET + JS interop operations, driven by 4 | [BenchmarkDotNet](https://benchmarkdotnet.org/). Most benchmarks run in both CLR and AOT modes, 5 | though the "Dynamic" benchmarks are CLR-only. 6 | 7 | > :warning: The benchmarks currently depend on a special branch build of `libnode` being present at 8 | `../bin/`. This should be resolved with [#107](https://github.com/microsoft/node-api-dotnet/issues/107). 9 | 10 | ### Run all benchmarks 11 | ``` 12 | dotnet run -c Release -f net9.0 --filter * 13 | ``` 14 | 15 | ### Run only CLR or only AOT benchmarks 16 | ``` 17 | dotnet run -c Release -f net9.0 --filter *clr.* 18 | dotnet run -c Release -f net9.0 --filter *aot.* 19 | ``` 20 | 21 | ### Run a specific benchmark 22 | ``` 23 | dotnet run -c Release -f net9.0 --filter *clr.CallDotnetFunction 24 | ``` 25 | 26 | ### List benchmarks 27 | ``` 28 | dotnet run -c Release -f net9.0 --list flat 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # API doc files are generated by the XmlDocMarkdown tool. 2 | /reference/dotnet 3 | /reference/js 4 | 5 | # Temporary files generated by vitepress 6 | /.vitepress/.temp 7 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This file has customizations for the VitePress default theme. For a list of 3 | * variable defaults that can be overridden, see 4 | * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css 5 | */ 6 | 7 | :root { 8 | /* The default sidebar width is 272px. We need extra width for a deep API doc tree. */ 9 | --vp-sidebar-width: 400px; 10 | } 11 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | import DefaultTheme from 'vitepress/theme' 2 | import './custom.css' 3 | 4 | export default DefaultTheme 5 | -------------------------------------------------------------------------------- /docs/contributing.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: false 3 | next: false 4 | --- 5 | 6 | # Contributing 7 | 8 | For information about building, testing, and contributing changes to this project, see 9 | [README-DEV.md](https://github.com/microsoft/node-api-dotnet/blob/main/README-DEV.md). 10 | 11 | ## Contributor License Agreement 12 | 13 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 14 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 15 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 16 | 17 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 18 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the 19 | instructions provided by the bot. You will only need to do this once across all repos using our CLA. 20 | 21 | ## Code of Conduct 22 | 23 | This project has adopted the 24 | [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 25 | For more information see the 26 | [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact 27 | [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 28 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | # Example Projects 2 | 3 | See the [examples](https://github.com/microsoft/node-api-dotnet/tree/main/examples) directory in 4 | the repo. 5 | -------------------------------------------------------------------------------- /docs/features/performance.md: -------------------------------------------------------------------------------- 1 | # Performance 2 | 3 | .NET / JS interop is fast because: 4 | - Marshaling does not use JSON serialization. 5 | - Compile-time or runtime [code generation](./js-dotnet-marshalling#marshalling-code-generation) 6 | avoids reflection. 7 | - Use of shared memory and proxies minimizes data transfer. 8 | - Use of modern C# like `struct`, `Span`, and `stackalloc` minimizes heap allocation & copying. 9 | 10 | ## Performance comparison vs Edge.js 11 | Warm JS to .NET calls are nearly twice as fast when compared to 12 | [`edge-js`](https://github.com/agracio/edge-js) using 13 | [that project's benchmark](https://github.com/tjanczuk/edge/wiki/Performance). 14 | 15 | | | HTTP | Edge.js | Node API .NET | AOT | JS (baseline) | 16 | |-----:|------:|--------:|--------------:|----:|--------------:| 17 | | Cold | 32039 | 38761 | 9355 | 362 | 1680 | 18 | | Warm | 2003 | 87 | 54 | 47 | 23 | 19 | 20 | Numbers are _microseconds_. "Warm" is an average of 10000 .NET -> JS calls (passing a medium-size object). 21 | -------------------------------------------------------------------------------- /docs/images/dark/ts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/images/dotnet-bot_scene_coffee-shop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/docs/images/dotnet-bot_scene_coffee-shop.png -------------------------------------------------------------------------------- /docs/images/light/ts.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/overview.md: -------------------------------------------------------------------------------- 1 | # Project Overview 2 | 3 | This project enables advanced interoperability between .NET and JavaScript in the same process. 4 | 5 | - Load .NET assemblies and call .NET APIs in-proc from a JavaScript application. 6 | - Load JavaScript packages and call JS APIs in-proc from a .NET application. 7 | 8 | Interop is [high-performance](./features/performance) and supports [TypeScript type-definitions 9 | generation](./features/type-definitions), [async (tasks/promises)](./features/js-threading-async), 10 | [streams](./reference/streams), [exception propagation](./reference/exceptions), and more. It is 11 | built on [Node API](https://nodejs.org/api/n-api.html) so it is compatible with any Node.js version 12 | (without recompiling) or other JavaScript runtime that supports Node API, such as Deno. 13 | 14 | :warning: _**Status: Public Preview** - Most functionality works well, though there are some known 15 | limitations around the edges, and there may still be minor breaking API changes._ 16 | 17 | ### Minimal example - JS calling .NET 18 | ```JavaScript 19 | const Console = require('node-api-dotnet').System.Console; 20 | Console.WriteLine('Hello from .NET!'); // JS writes to the .NET console API 21 | ``` 22 | 23 | ### Minimal example - .NET calling JS 24 | ```C# 25 | interface IConsole { void Log(string message); } 26 | 27 | var nodejs = new NodejsPlatform(libnodePath).CreateEnvironment(); 28 | nodejs.Run(() => 29 | { 30 | var console = nodejs.Import("global", "console"); 31 | console.Log("Hello from JS!"); // C# writes to the JS console API 32 | }); 33 | ``` 34 | 35 | For more complete example projects, see the 36 | [examples directory in the repo](https://github.com/microsoft/node-api-dotnet/tree/main/examples). 37 | Or proceed to the next page to learn about the different supported scenarios and how to get started 38 | with your own project. 39 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-docs", 3 | "devDependencies": { 4 | "typedoc": "^0.25.13", 5 | "vitepress": "^1.2" 6 | }, 7 | "scripts": { 8 | "build-dotnet": "node ./tools/build-dotnet-api-docs.js", 9 | "build-js": "node ./tools/build-js-api-docs.js", 10 | "dev": "vitepress dev", 11 | "build": "vitepress build", 12 | "preview": "vitepress preview" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /docs/reference/async-promises.md: -------------------------------------------------------------------------------- 1 | # Async, Tasks, and Promises 2 | 3 | | C# Type | JS Type | 4 | |-----------|-----------------| 5 | | `Task` | `Promise` | 6 | | `Task` | `Promise` | 7 | 8 | ## Async methods 9 | 10 | A .NET method that returns a `Task` or `Task` can be awaited in JavaScript because the 11 | `Task` is automatically marshalled as a JS `Promise`: 12 | 13 | ```C# 14 | [JSExport] 15 | public static class AsyncExample 16 | { 17 | public async Task GetResultAsync(); 18 | } 19 | ``` 20 | 21 | ```JS 22 | const result = await AsyncExample.getResultAsync(); 23 | ``` 24 | 25 | A JavaScript method that returns a `Promise` can be awaited in C# by converting the `Promise` to a 26 | `Task`: 27 | 28 | ```C# 29 | JSFunction exampleAsyncJSFunc = … 30 | string result = await exampleAsyncJSFunc.CallAsStatic(arg).AsTask(); 31 | ``` 32 | 33 | ## `JSPromise` type 34 | 35 | The [`JSPromise`](./dotnet/Microsoft.JavaScript.NodeApi/JSPromise) type supports working directly 36 | with JavaScript `Promise` values, while the extension methods in the 37 | [`JSPromiseExtensions`](./dotnet/Microsoft.JavaScript.NodeApi/TaskExtensions) 38 | class enable converting between `JSPromise` and `Task` values. 39 | 40 | ## Async execution 41 | See [JS Threading and Async Continuations](../features/js-threading-async) for more about 42 | coordinating asynchronous .NET and JavaScript execution. 43 | -------------------------------------------------------------------------------- /docs/reference/delegates.md: -------------------------------------------------------------------------------- 1 | # Delegates 2 | 3 | An exported .NET delegate type is converted to a TypeScript function type definition: 4 | ```C# 5 | [JSExport] 6 | public delegate string ExampleCallback(int arg1, bool arg2); 7 | ``` 8 | ```TS 9 | export function ExampleCallback(arg1: number, arg2: boolean): string; 10 | ``` 11 | 12 | Then a JavaScript function can be passed to a .NET API that expects a delegate of that type, and 13 | the parameters and return value will be marshalled accordingly. 14 | 15 | ```C# 16 | [JSExport] 17 | public static class Example 18 | { 19 | public static void RegisterCallback(ExampleCallback cb) { … } 20 | } 21 | ``` 22 | ```JS 23 | Example.registerCallback((arg1, arg2) => 'ok'); 24 | ``` 25 | 26 | This is one way for .NET to call back into JavaScript. Another way is to 27 | [implement a .NET interface with a JavaScript class](./classes-interfaces#implement-a-net-interface-with-a-js-class). 28 | -------------------------------------------------------------------------------- /docs/reference/enums.md: -------------------------------------------------------------------------------- 1 | # Enums 2 | 3 | .NET `enum` types are marshalled as TypeScript-style 4 | [numeric enums](https://www.typescriptlang.org/docs/handbook/enums.html#numeric-enums) 5 | including [reverse mappings](https://www.typescriptlang.org/docs/handbook/enums.html#numeric-enums) 6 | of enum member values to names. 7 | 8 | ```C# 9 | [JSExport] 10 | public enum ExampleEnum 11 | { 12 | A = 1, 13 | } 14 | ``` 15 | 16 | ```JS 17 | const a = ExampleEnum.A; // 1 18 | const nameOfA = ExampleEnum[a]; // 'A' 19 | ``` 20 | 21 | (Enum members are not auto-camel-cased by the marshaller.) 22 | -------------------------------------------------------------------------------- /docs/reference/events.md: -------------------------------------------------------------------------------- 1 | # Events 2 | 3 | .NET Events are [not yet supported](https://github.com/microsoft/node-api-dotnet/issues/59). 4 | 5 | It is possible to work with JS events from .NET by calling the JS `addEventListener()` or similar 6 | method and passing a [`JSFunction`](./dotnet/Microsoft.JavaScript.NodeApi/JSFunction) callback. 7 | But there is no automatic marshalling yet to project a JS event as a .NET event. 8 | -------------------------------------------------------------------------------- /docs/reference/extension-methods.md: -------------------------------------------------------------------------------- 1 | # .NET Extension Methods in JavaScript 2 | 3 | Extension methods are important to the usability and discoverability of many .NET libraries, yet 4 | JavaScript has no built-in support for extension methods. Since the JavaScript type system is 5 | very dynamic, the JS marshaller can simulate extension methods by dynamically attaching the methods 6 | to the types they apply to. 7 | 8 | Extension methods are supported only in the 9 | [dynamic invocation scenario](../scenarios/js-dotnet-dynamic) 10 | since pre-built .NET APIs were most likely not designed with JavaScript in mind. But when developing 11 | a [Node.js addon module in C#](../scenarios/js-dotnet-module) the expectation is that the APIs 12 | specifically exported to JavaScript with `[JSExport]` should be designed without any need for 13 | extension methods. 14 | 15 | Extension methods may be provided by the same assembly as the target type, or a different assembly. 16 | When provided by a different assembly, it may be necessary to explicitly import the other assembly, 17 | otherwise the extension method will not be registered on the target type. 18 | 19 | Here is a snippet from the Semantic Kernel example. The Semantic Kernel library makes heavy use of 20 | extension methods. 21 | 22 | ```JS 23 | import dotnet from 'node-api-dotnet'; 24 | import './bin/Microsoft.SemanticKernel.Core.js'; 25 | import './bin/Microsoft.SemanticKernel.Connectors.OpenAI.js'; 26 | 27 | const kernelBuilder = dotnet.Microsoft.SemanticKernel.Kernel.CreateBuilder(); 28 | 29 | // Call an extension method provided by the MS.SK.Connectors.OpenAI assembly. 30 | kernelBuilder.AddAzureOpenAIChatCompletion(deployment, endpoint, key); 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/reference/js-apis.md: -------------------------------------------------------------------------------- 1 | --- 2 | outline: deep 3 | --- 4 | 5 | # Runtime API Examples 6 | 7 | This page demonstrates usage of some of the runtime APIs provided by VitePress. 8 | 9 | The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files: 10 | 11 | ```md 12 | 17 | 18 | ## Results 19 | 20 | ### Theme Data 21 |
{{ theme }}
22 | 23 | ### Page Data 24 |
{{ page }}
25 | 26 | ### Page Frontmatter 27 |
{{ frontmatter }}
28 | ``` 29 | 30 | 35 | 36 | ## Results 37 | 38 | ### Theme Data 39 |
{{ theme }}
40 | 41 | ### Page Data 42 |
{{ page }}
43 | 44 | ### Page Frontmatter 45 |
{{ frontmatter }}
46 | 47 | ## More 48 | 49 | Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata). 50 | -------------------------------------------------------------------------------- /docs/reference/other-types.md: -------------------------------------------------------------------------------- 1 | # Other Special Types 2 | 3 | ## BigInteger 4 | 5 | | C# Type | JS Type | 6 | |--------------|----------| 7 | | `BigInteger` | `BigInt` | 8 | 9 | .NET [`BigInteger`](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.biginteger) 10 | converts to and from JavaScript 11 | [`BigInt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) 12 | with no loss in precision. (Conversion internally allocates and copies memory for the number data.) 13 | The [`JSBigInt`](./dotnet/Microsoft.JavaScript.NodeApi/JSBigInt) class supports working directly 14 | with JS `BigInt` values, and converting to/from .NET `BigInteger`. 15 | 16 | ## Guid 17 | 18 | | C# Type | JS Type | 19 | |---------|----------| 20 | | `Guid` | `string` | 21 | 22 | A .NET `Guid` is marshalled to JS as a `string` in the default `"D"` format. Marshalling in the 23 | other direction supports any format accepted by 24 | [`Guid.Parse()`](https://learn.microsoft.com/en-us/dotnet/api/system.guid.parse). 25 | -------------------------------------------------------------------------------- /docs/reference/packages-releases.md: -------------------------------------------------------------------------------- 1 | # Packages & Releases 2 | 3 | ## NuGet packages 4 | 5 | [`Microsoft.JavaScript.NodeApi`](https://www.nuget.org/packages/Microsoft.JavaScript.NodeApi/) - 6 | Contains the core functionality for interop between .NET and JavaScript, including runtime 7 | code-generation for dynamic marshalling. See the [.NET API reference](../reference/dotnet/). 8 | 9 | [`Microsoft.JavaScript.NodeApi.Generator`](https://www.nuget.org/packages/Microsoft.JavaScript.NodeApi.Generator/) - 10 | Contains the MSBuild tasks and supporting assemblies for generating marshalling code at compile 11 | time, and for generating TypeScript type defintions for .NET APIs. 12 | 13 | ## NPM packages 14 | 15 | [`node-api-dotnet`](https://www.npmjs.com/package/node-api-dotnet) - Supports loading .NET 16 | assemblies into a Node.js process. Contains the native .NET hosting modules 17 | (`Microsoft.JavaScript.NodeApi.node`, built with .NET Native AOT) for all supported platforms, 18 | the runtime assemblies (`Microsoft.JavaScript.NodeApi.dll`) for all supported target frameworks, 19 | and loader scripts. See the [JavaScript API reference](../reference/js/). 20 | 21 | [`node-api-dotnet-generator`](https://www.npmjs.com/package/node-api-dotnet-generator) - A Node.js 22 | command-line tool that is a wrapper around the .NET generator assembly. It enables generating 23 | TypeScript type definitions without using MSBuild. See the CLI reference at 24 | [TypeScript Type Definitions](../features/type-definitions). 25 | 26 | ## Releases 27 | 28 | Packages are published to nuget and npm automatically, usually around an hour after any PR 29 | is merged. 30 | 31 | While the project is in pre-release phase, there may be occasional breaking API changes between 32 | versions less than 1.0. Starting with v1.0 (expected late 2024), it will follow 33 | [semantic versioning practices](https://semver.org/). 34 | -------------------------------------------------------------------------------- /docs/reference/streams.md: -------------------------------------------------------------------------------- 1 | # Streams 2 | 3 | | C# Type | JS Type | 4 | |-----------------------|------------| 5 | | `Stream` (read/write) | `Duplex` | 6 | | `Stream` (read-only) | `Readable` | 7 | | `Stream` (write-only) | `Writable` | 8 | 9 | A .NET `Stream` instance is marshalled to and from Node.js 10 | [`Duplex`](https://nodejs.org/api/stream.html#duplex-and-transform-streams), 11 | [`Readable`](https://nodejs.org/api/stream.html#readable-streams), or 12 | [`Writable`](https://nodejs.org/api/stream.html#writable-streams), 13 | depending whether the stream supports reading and/or writing. JS code can seamlessly read from 14 | or write to streams created by .NET, or .NET code can read from or write to streams created by JS. 15 | Streamed data is transferred using shared memory (without any additional sockets or pipes), so 16 | memory allocation and copying is minimized. 17 | 18 | ```C# 19 | [JSExport] 20 | public static class Example 21 | { 22 | public Stream GetContent() { … } 23 | } 24 | ``` 25 | 26 | ```JS 27 | const stream = Example.getContent(); 28 | stream.on('data', (chunk) => { console.log(chunk.toString()); }); 29 | ``` 30 | 31 | The [`NodeStream`](./dotnet/Microsoft.JavaScript.NodeApi.Interop/NodeStream) class provides the 32 | .NET `Stream` adapter over a Node.js `Duplex`, `Readable`, or `Writable` stream. 33 | -------------------------------------------------------------------------------- /docs/requirements.md: -------------------------------------------------------------------------------- 1 | # Requirements 2 | 3 | ## Runtime requirements 4 | #### OS 5 | - Windows: x64, arm64 6 | - Mac: x64, arm64 7 | - Linux: x64 ([arm64 coming soon](https://github.com/microsoft/node-api-dotnet/issues/80)) 8 | 9 | #### .NET 10 | - For .NET runtime-dependent applications, .NET 4.7.2 or later, .NET 6, or .NET 8 runtime 11 | must be installed. 12 | - For .NET Native AOT applications, .NET is not required on the target system. 13 | - On Linux, AOT binaries may depend on optional system packages. See 14 | [Install .NET on Linux](https://learn.microsoft.com/en-us/dotnet/core/install/linux) 15 | and browse to the distro specific dependencies. 16 | 17 | #### Node.js 18 | - Node.js v18 or later 19 | - Other JS runtimes may be supported in the future. 20 | 21 | ## Build requirements 22 | 23 | - .NET 8 SDK 24 | - Optional: .NET 6 SDK, if targeting .NET 6 runtime 25 | - Optional: .NET Framework 4.x developer pack, if targeting .NET Framework 26 | - Node.js v18 or later 27 | -------------------------------------------------------------------------------- /docs/scenarios/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | next: 3 | text: Dynamic .NET from JS 4 | link: ./js-dotnet-dynamic 5 | --- 6 | 7 | # JS / .NET Interop Scenarios 8 | 9 | There are four primary scenarios enabled by this project. Choose one of them for getting-started 10 | instructions: 11 | 12 | - [Dynamically invoke .NET APIs from JavaScript](./js-dotnet-dynamic)
13 | Dynamic invocation is easy to set up: all you need is the `node-api-dotnet` package and the 14 | path to a .NET assembly you want to call. It is not quite as fast as a C# addon module because 15 | marshalling code must be generated at runtime. It is best suited for simpler projects with 16 | limited interop needs. 17 | 18 | - [Develop a Node.js addon module in C#](./js-dotnet-module)
19 | A C# Node module exports specific types and methods from the module to JavaScript. It can be 20 | faster because marshalling code is generated at compile time, and the shape of the APIs 21 | exposed to JavaScript can be designed or adapted with JS interop in mind. It is best suited 22 | for more complex projects with advanced or high-performance interop requirements. 23 | 24 | - [Develop a Node.js addon module in C# with .NET Native AOT](./js-aot-module)
25 | A variation on the previous scenario, this is best suited for creation of a re-usable Node.js 26 | native addon that loads quickly and does not depend the .NET runtime. However binaries are 27 | platform-specific, so packaging and distribution is more difficult. 28 | 29 | - [Embed a JS runtime in a .NET application](./dotnet-js)
30 | Run Node.js (or another JS runtime) in a .NET application process, import `npm` packages 31 | and/or JavaScript module files and call them from .NET. 32 | 33 | All of these scenarios support 34 | [auto-generated TypeScript type definitions](../features/type-definitions), 35 | [automatic efficient marshalling](../features/js-dotnet-marshalling), 36 | and [error propagation](../reference/exceptions). 37 | -------------------------------------------------------------------------------- /docs/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | prev: false 3 | next: false 4 | --- 5 | 6 | # Support 7 | 8 | Submit bug reports and feature requests to 9 | [node-api-dotnet/issues](https://github.com/microsoft/node-api-dotnet/issues). 10 | Please search the existing issues before filing new issues to avoid duplicates. 11 | - _Exception: For security issues refer to 12 | [SECURITY.md](https://github.com/microsoft/node-api-dotnet/blob/main/SECURITY.md)._ 13 | 14 | For any other kind of questions or discussions, you may use the 15 | [GitHub Discussions](https://github.com/microsoft/node-api-dotnet/discussions) board instead. 16 | -------------------------------------------------------------------------------- /docs/tools/XmlDocMarkdown.cs: -------------------------------------------------------------------------------- 1 | using XmlDocMarkdown.Core; 2 | return XmlDocMarkdownApp.Run(args); 3 | -------------------------------------------------------------------------------- /docs/tools/XmlDocMarkdown.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /examples/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 | 10 | 11 | $(MSBuildThisFileDirectory)..\out\pkg 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | -------------------------------------------------------------------------------- /examples/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/aot-module/Example.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Examples; 5 | 6 | /// 7 | /// Example Node API module that exports a simple "hello" method. 8 | /// 9 | [JSExport] 10 | public static class Example 11 | { 12 | /// 13 | /// Gets a greeting string. 14 | /// 15 | /// Name of the greeter. 16 | /// A greeting with the name. 17 | public static string Hello(string greeter) 18 | { 19 | System.Console.WriteLine($"Hello {greeter}!"); 20 | return $"Hello {greeter}!"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/aot-module/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Minimal Example .NET AOT Node Module 3 | The `Example.cs` class defines a Node.js add-on module that is AOT-compiled, so that it does not 4 | depend on the .NET runtime. The `example.js` script loads that _native_ module as a Node.js add-on 5 | and calls a method on it. The script has access to type definitions and doc-comments for the 6 | module's APIs via the auto-generated `.d.ts` file. 7 | 8 | | Command | Explanation 9 | |----------------------------------|-------------------------------------------------- 10 | | `dotnet pack ../..` | Build Node API .NET packages. 11 | | `dotnet publish` | Install Node API .NET packages into example project; build example project and compile to native binary. 12 | | `node example.js` | Run example JS code that calls the example module. 13 | -------------------------------------------------------------------------------- /examples/aot-module/aot-module.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | true 6 | true 7 | true 8 | bin 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /examples/aot-module/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import { Example } from './bin/aot-module.js'; 5 | 6 | // Call a method exported by the .NET module. 7 | const result = Example.hello('.NET AOT'); 8 | 9 | import assert from 'assert'; 10 | assert.strictEqual(result, 'Hello .NET AOT!'); 11 | -------------------------------------------------------------------------------- /examples/aot-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-aot-module", 3 | "type": "module" 4 | } 5 | -------------------------------------------------------------------------------- /examples/aot-npm-package/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Minimal Example .NET AOT NPM Package 3 | The `lib/Example.cs` class defines a Node.js add-on module that is AOT-compiled, so that it does not 4 | depend on the .NET runtime. The AOT module is then packaged as an npm package. The `app/example.js` 5 | script loads that _native_ module via its npm package and calls a method on it. The script has 6 | access to type definitions and doc-comments for the module's APIs via the auto-generated `.d.ts` 7 | file that was included in the npm package. 8 | 9 | | Command | Explanation 10 | |-------------------------------|-------------------------------------------------- 11 | | `dotnet pack ../..` | Build Node API .NET packages. 12 | | `cd lib`
`dotnet publish` | Install Node API .NET packages into lib project; build lib project and compile to native binary; pack npm package. 13 | | `cd app`
`npm install` | Install lib project npm package into app project. 14 | | `node example.js` | Run example JS code that calls the library API. 15 | 16 | ### Building multi-platform npm packages with platform-specific AOT binaries 17 | Native AOT binaries are platform-specific. The `dotnet publish` command above creates a package 18 | only for the current OS / CPU platform (aka .NET runtime-identifier). To create a multi-platform 19 | npm package with Native AOT binaries, run `dotnet publish` separately for each runtime-identifier, 20 | and only create the package on the last one: 21 | ``` 22 | dotnet publish -r:win-x64 -p:PackNpmPackage=false 23 | dotnet publish -r:win-arm64 -p:PackNpmPackage=true 24 | ``` 25 | 26 | To create a fully cross-platform packatge, it will be necessary to compile on each targeted OS 27 | (Windows, Mac, Linux), then copy the outputs into a shared directory before creating the final 28 | npm package. 29 | -------------------------------------------------------------------------------- /examples/aot-npm-package/app/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import { Example } from 'aot-npm-package'; 5 | 6 | // Call a method exported by the .NET module. 7 | const result = Example.hello('.NET AOT'); 8 | 9 | import assert from 'node:assert'; 10 | assert.strictEqual(result, 'Hello .NET AOT!'); 11 | -------------------------------------------------------------------------------- /examples/aot-npm-package/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aot-npm-app", 3 | "private": true, 4 | "version": "0.1.0", 5 | "description": "Example Node.js app that references an npm-packaged C# Native AOT node module", 6 | "license": "MIT", 7 | "author": "Microsoft", 8 | "repository": "github:microsoft/node-api-dotnet", 9 | "main": "./example.js", 10 | "type": "module", 11 | "scripts": { 12 | }, 13 | "dependencies": { 14 | "aot-npm-package": "file:../lib" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /examples/aot-npm-package/lib/.npmignore: -------------------------------------------------------------------------------- 1 | # When packaging, ignore everything except the .node binaries, scripts, and type definitions. 2 | # (Readme and license files are always included implictly.) 3 | * 4 | !/bin/**/*.node 5 | !/bin/*.js 6 | !/bin/*.d.ts 7 | -------------------------------------------------------------------------------- /examples/aot-npm-package/lib/Example.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Examples; 5 | 6 | /// 7 | /// Example Node API module that exports a simple "hello" method. 8 | /// 9 | [JSExport] 10 | public static class Example 11 | { 12 | /// 13 | /// Gets a greeting string. 14 | /// 15 | /// Name of the greeter. 16 | /// A greeting with the name. 17 | public static string Hello(string greeter) 18 | { 19 | System.Console.WriteLine($"Hello {greeter}!"); 20 | return $"Hello {greeter}!"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/aot-npm-package/lib/aot-npm-package.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | true 8 | 9 | 10 | true 11 | true 12 | bin 13 | 14 | 17 | true 18 | 19 | 20 | 21 | true 22 | pkg 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /examples/aot-npm-package/lib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aot-npm-package", 3 | "private": true, 4 | "version": "0.2", 5 | "description": "Example npm-packaged C# Native AOT node module", 6 | "license": "MIT", 7 | "author": "Microsoft", 8 | "repository": "github:microsoft/node-api-dotnet", 9 | "type": "module", 10 | "main": "./bin/aot-npm-package.js", 11 | "scripts": { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic-classlib/ClassLib/Class1.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Examples; 5 | 6 | /// 7 | /// Example class that will be dynamically instantiated in JavaScript. 8 | /// 9 | public class Class1 10 | { 11 | /// 12 | /// Creates a new instance of the class. 13 | /// 14 | public Class1() 15 | { 16 | } 17 | 18 | /// 19 | /// Gets a greeting message. 20 | /// 21 | public string Hello(string greeter) 22 | { 23 | System.Console.WriteLine($"Hello {greeter}!"); 24 | return $"Hello {greeter}!"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic-classlib/ClassLib/ClassLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | true 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic-classlib/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Example of dynamically invoking .NET APIs from a referenced project 3 | The `example.js` script loads .NET, loads the `ClassLib` assembly, and calls `new Class1().Hello()`. 4 | 5 | | Command | Explanation 6 | |----------------------------------|-------------------------------------------------- 7 | | `dotnet pack ../..` | Build Node API .NET packages. 8 | | `dotnet build` | Build the `ClassLib` project and generate type definitions. 9 | | `npm install` | Install `node-api-dotnet` npm package into the example project. 10 | | `node example.js` | Run example JS code that dynamically invokes the class library API. 11 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic-classlib/dotnet-dynamic-classlib.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | $(MSBuildThisFileDirectory)/pkg 6 | bin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic-classlib/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const dotnet = require('node-api-dotnet'); 5 | require('./bin/ClassLib'); 6 | 7 | const Class1 = dotnet.Microsoft.JavaScript.NodeApi.Examples.Class1; 8 | const class1 = new Class1(); 9 | class1.Hello('.NET'); 10 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic-classlib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-dotnet-dynamic-classlib", 3 | "dependencies": { 4 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Minimal Example of dynamically invoking .NET APIs 3 | The `example.js` script loads .NET and calls `Console.WriteLine()`. 4 | 5 | | Command | Explanation 6 | |----------------------------------|-------------------------------------------------- 7 | | `dotnet pack ../..` | Build Node API .NET packages. 8 | | `npm install` | Install `node-api-dotnet` npm package into the example project. 9 | | `node example.js` | Run example JS code that uses that package to dynamically invoke a .NET API. 10 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const dotnet = require('node-api-dotnet'); 5 | const Console = dotnet.System.Console; 6 | Console.WriteLine('Hello from .NET!'); 7 | -------------------------------------------------------------------------------- /examples/dotnet-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-dotnet-dynamic", 3 | "dependencies": { 4 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/dotnet-module/Example.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Examples; 5 | 6 | /// 7 | /// Example Node API module that exports a simple "hello" method. 8 | /// 9 | [JSExport] 10 | public static class Example 11 | { 12 | /// 13 | /// Gets a greeting string. 14 | /// 15 | /// Name of the greeter. 16 | /// A greeting with the name. 17 | public static string Hello(string greeter) 18 | { 19 | System.Console.WriteLine($"Hello {greeter}!"); 20 | return $"Hello {greeter}!"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/dotnet-module/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Minimal Example .NET Node Module 3 | The `Example.cs` class defines a Node.js add-on module that runs on .NET. The `example.js` script 4 | loads that .NET module and calls a method on it. The script has access to type definitions and 5 | doc-comments for the module's APIs via the auto-generated `.d.ts` file. 6 | 7 | | Command | Explanation 8 | |----------------------------------|-------------------------------------------------- 9 | | `dotnet pack ../..` | Build Node API .NET packages. 10 | | `npm install` | Install Node API .NET npm package into example project. 11 | | `dotnet build` | Install Node API .NET nuget packages into example project; build example project. 12 | | `node example.js` | Run example JS code that calls the example module. 13 | 14 | ### .NET Framework 15 | To use .NET Framework, apply the follwing change to `example.js`: 16 | ```diff 17 | -const dotnet = require('node-api-dotnet'); 18 | +const dotnet = require('node-api-dotnet/net472'); 19 | ``` 20 | -------------------------------------------------------------------------------- /examples/dotnet-module/dotnet-module.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net472 5 | true 6 | bin 7 | 10 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/dotnet-module/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const Example = require('./bin/dotnet-module').Example; 5 | 6 | // Call a method exported by the .NET module. 7 | const result = Example.hello('.NET'); 8 | 9 | const assert = require('assert'); 10 | assert.strictEqual(result, 'Hello .NET!'); 11 | -------------------------------------------------------------------------------- /examples/dotnet-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-dotnet-module", 3 | "type": "commonjs", 4 | "dependencies": { 5 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/electron/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Invoking .NET APIs from an Electron app 3 | 4 | | Command | Explanation 5 | |----------------------------------|-------------------------------------------------- 6 | | `dotnet pack ../..` | Build Node API .NET packages. 7 | | `npm install` | Install `node-api-dotnet` and `electron` npm packages into the example project. 8 | | `npm run start` | Run the example Electron app. 9 | 10 | The example is from the [Electron "Quick Start" app]( 11 | https://www.electronjs.org/docs/latest/tutorial/quick-start), 12 | with some small modifications to additionally load .NET and display the .NET version obtained from 13 | `System.Environment.Version`. 14 | 15 | The `node-api-dotnet` package is loaded in the _main_ Electron process immediately after creating 16 | the window. Then the .NET version value is sent via IPC to the _renderer_ process where it is 17 | displayed on the HTML page. 18 | 19 | --- 20 | 21 | This is not intended to be an attempt to replace or compete with the great work at 22 | [Electron.NET](https://github.com/ElectronNET/Electron.NET). That project runs a full ASP.NET + 23 | Blazor stack inside an Electron app, enabling use of Blazor components to build a cross-platform 24 | client application UI. 25 | 26 | However if you're building a more traditional Electron JS app and you just need to call a few 27 | .NET APIs from JS code, then the example here offers a more lightweight approach. 28 | -------------------------------------------------------------------------------- /examples/electron/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const dotnet = require('node-api-dotnet'); 5 | const Console = dotnet.System.Console; 6 | Console.WriteLine('Hello from .NET!'); 7 | -------------------------------------------------------------------------------- /examples/electron/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello World! 6 | 7 | 8 | 9 |

Hello World!

10 |

11 | We are using Node.js , 12 | Chromium , 13 | Electron , 14 | and .NET . 15 |

16 |

17 | 18 | 19 | -------------------------------------------------------------------------------- /examples/electron/main.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow } = require('electron/main') 2 | const path = require('node:path') 3 | 4 | function createWindow () { 5 | const win = new BrowserWindow({ 6 | width: 800, 7 | height: 600, 8 | webPreferences: { 9 | preload: path.join(__dirname, 'preload.js') 10 | } 11 | }) 12 | 13 | win.loadFile('index.html') 14 | 15 | const dotnet = require('node-api-dotnet') 16 | const dotnetVersion = dotnet.System.Environment.Version.toString() 17 | win.webContents.send('dotnet-version', dotnetVersion) 18 | } 19 | 20 | app.whenReady().then(() => { 21 | createWindow() 22 | 23 | app.on('activate', () => { 24 | if (BrowserWindow.getAllWindows().length === 0) { 25 | createWindow() 26 | } 27 | }) 28 | }) 29 | 30 | app.on('window-all-closed', () => { 31 | if (process.platform !== 'darwin') { 32 | app.quit() 33 | } 34 | }) 35 | -------------------------------------------------------------------------------- /examples/electron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-electron", 3 | "dependencies": { 4 | "electron": "^30.0.1", 5 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 6 | }, 7 | "main": "main.js", 8 | "scripts": { 9 | "start": "electron ." 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /examples/electron/preload.js: -------------------------------------------------------------------------------- 1 | const { ipcRenderer } = require('electron/renderer') 2 | 3 | window.addEventListener('DOMContentLoaded', () => { 4 | const replaceText = (selector, text) => { 5 | const element = document.getElementById(selector) 6 | if (element) element.innerText = text 7 | } 8 | 9 | for (const type of ['chrome', 'node', 'electron']) { 10 | replaceText(`${type}-version`, process.versions[type]) 11 | } 12 | 13 | ipcRenderer.on('dotnet-version', (_event, value) => { 14 | const element = document.getElementById('dotnet-version') 15 | if (element) element.innerText = value 16 | }) 17 | }) 18 | -------------------------------------------------------------------------------- /examples/hermes-engine/HermesConfig.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using static Hermes.Example.HermesApi.Interop; 5 | 6 | namespace Hermes.Example; 7 | 8 | public sealed class HermesConfig : IDisposable 9 | { 10 | private hermes_config _config; 11 | private bool _isDisposed; 12 | 13 | public HermesConfig() 14 | { 15 | hermes_create_config(out _config).ThrowIfFailed(); 16 | } 17 | 18 | public void Dispose() 19 | { 20 | if (_isDisposed) return; 21 | _isDisposed = true; 22 | hermes_delete_config(_config).ThrowIfFailed(); 23 | } 24 | 25 | public static explicit operator hermes_config(HermesConfig value) => value._config; 26 | } 27 | -------------------------------------------------------------------------------- /examples/hermes-engine/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/hermes-engine/Program.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Hermes.Example; 5 | using Microsoft.JavaScript.NodeApi; 6 | 7 | JSDispatcherQueueController controller = JSDispatcherQueueController.CreateOnDedicatedThread(); 8 | 9 | HermesRuntime runtime = await HermesRuntime.Create(controller.DispatcherQueue); 10 | 11 | await runtime.RunAsync(() => 12 | { 13 | JSNativeApi.RunScript("x = 2"); 14 | Console.WriteLine($"Result: {(int)JSValue.Global["x"]}"); 15 | Console.Out.Flush(); 16 | 17 | JSNativeApi.RunScript(""" 18 | setTimeout(function() { 19 | console.log('This is printed after 1 second delay'); 20 | }, 1000); 21 | """); 22 | 23 | JSNativeApi.RunScript(""" 24 | function createPromise(delay, value) { 25 | return new Promise(function(resolve) { 26 | setTimeout(function() { 27 | resolve(value); 28 | }, delay); 29 | }); 30 | } 31 | 32 | var myPromise = createPromise(100, "myPromise"); 33 | myPromise.then(msg => { console.log(msg + " completed"); }) 34 | .catch(() => { console.log("myPromise canceled"); }); 35 | """); 36 | }); 37 | 38 | await runtime.CloseAsync(); 39 | await controller.ShutdownQueueAsync(); 40 | -------------------------------------------------------------------------------- /examples/hermes-engine/hermes-engine.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | enable 8 | Hermes.Example 9 | true 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/hermes-engine/hermes-engine.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33516.290 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "hermes-engine", "hermes-engine.csproj", "{EF350F77-7B60-4B5C-8634-8EB3153FB130}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {EF350F77-7B60-4B5C-8634-8EB3153FB130}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {EF350F77-7B60-4B5C-8634-8EB3153FB130}.Debug|Any CPU.Build.0 = Debug|Any CPU 16 | {EF350F77-7B60-4B5C-8634-8EB3153FB130}.Release|Any CPU.ActiveCfg = Release|Any CPU 17 | {EF350F77-7B60-4B5C-8634-8EB3153FB130}.Release|Any CPU.Build.0 = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {C85AD6C1-99F4-4858-BE2C-3065E5DD7CF1} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /examples/jsdom/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.IO; 4 | using Microsoft.JavaScript.NodeApi.Runtime; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.Examples; 7 | 8 | public static class Program 9 | { 10 | public static void Main() 11 | { 12 | string appDir = Path.GetDirectoryName(typeof(Program).Assembly.Location)!; 13 | string libnodePath = Path.Combine(appDir, "libnode.dll"); 14 | using NodeEmbeddingPlatform nodejsPlatform = new(libnodePath, null); 15 | using NodeEmbeddingThreadRuntime nodejs = nodejsPlatform.CreateThreadRuntime(appDir, 16 | new NodeEmbeddingRuntimeSettings 17 | { 18 | MainScript = 19 | "globalThis.require = require('module').createRequire(process.execPath);\n" 20 | }); 21 | if (Debugger.IsAttached) 22 | { 23 | int pid = Process.GetCurrentProcess().Id; 24 | Uri inspectionUri = nodejs.StartInspector(); 25 | Debug.WriteLine($"Node.js ({pid}) inspector listening at {inspectionUri.AbsoluteUri}"); 26 | } 27 | 28 | string html = "

Hello world!

"; 29 | string content = nodejs.Run(() => GetContent(nodejs, html)); 30 | Console.WriteLine(content); 31 | } 32 | 33 | private static string GetContent(NodeEmbeddingThreadRuntime nodejs, string html) 34 | { 35 | JSValue jsdomClass = nodejs.Import(module: "jsdom", property: "JSDOM"); 36 | JSValue dom = jsdomClass.CallAsConstructor(html); 37 | JSValue document = dom["window"]["document"]; 38 | string content = (string)document.CallMethod("querySelector", "p")["textContent"]; 39 | return content; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /examples/jsdom/README.md: -------------------------------------------------------------------------------- 1 | ## C# JSDom Example 2 | This project is a C# executable application that uses the JSDOM library 3 | (https://github.com/jsdom/jsdom) to parse HTML. 4 | 5 | Before building and running this project, download or build `libnode.dll` that 6 | _includes Node API embedding support_. 7 | See https://microsoft.github.io/node-api-dotnet/scenarios/dotnet-js.html 8 | 9 | | Command | Explanation 10 | |-------------------------|-------------------------------------------------- 11 | | `dotnet pack ../..` | Build Node API .NET packages. 12 | | `npm install` | Install JavaScript packages. 13 | | `dotnet build` | Install .NET nuget packages; build example project. 14 | | `dotnet run --no-build` | Run the example project. 15 | 16 | -------------------------------------------------------------------------------- /examples/jsdom/jsdom.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | Exe 6 | enable 7 | Microsoft.JavaScript.NodeApi.Examples 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/jsdom/jsdom.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33103.201 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "jsdom", "jsdom.csproj", "{76D22090-236C-4F28-8863-ACF5C66E9559}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|arm64 = Debug|arm64 11 | Debug|x64 = Debug|x64 12 | Debug|x86 = Debug|x86 13 | Release|arm64 = Release|arm64 14 | Release|x64 = Release|x64 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Debug|arm64.ActiveCfg = Debug|Any CPU 19 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Debug|arm64.Build.0 = Debug|Any CPU 20 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Debug|x64.ActiveCfg = Debug|Any CPU 21 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Debug|x64.Build.0 = Debug|Any CPU 22 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Debug|x86.ActiveCfg = Debug|Any CPU 23 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Debug|x86.Build.0 = Debug|Any CPU 24 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Release|arm64.ActiveCfg = Release|Any CPU 25 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Release|arm64.Build.0 = Release|Any CPU 26 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Release|x64.ActiveCfg = Release|Any CPU 27 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Release|x64.Build.0 = Release|Any CPU 28 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Release|x86.ActiveCfg = Release|Any CPU 29 | {76D22090-236C-4F28-8863-ACF5C66E9559}.Release|x86.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {E61C40BC-6DC2-4619-8B32-75E681FAAEA1} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /examples/jsdom/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-jsdom", 3 | "dependencies": { 4 | "jsdom": "^24.1.1", 5 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /examples/semantic-kernel/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /pkg 3 | /obj 4 | /bin 5 | 6 | *.d.ts 7 | package-lock.json 8 | -------------------------------------------------------------------------------- /examples/semantic-kernel/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Example: Using .NET Semantic Kernel to call Azure OpenAI 3 | The `example.js` script dynamically loads the `Microsoft.SemanticKernel` .NET assembly and uses it 4 | to call Azure OpenAI to summarize some text. It is a direct JavaScript translation of the C# example 5 | code in the [Semantic Kernel](https://github.com/microsoft/semantic-kernel) project readme. 6 | 7 | To run this example, first set the following environment variables referencing your 8 | [Azure OpenAI deployment](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/quickstart): 9 | - `OPENAI_ENDPOINT` 10 | - `OPENAI_DEPLOYMENT` 11 | - `OPENAI_KEY` 12 | 13 | Then run the following commands in sequence: 14 | 15 | | Command | Explanation 16 | |----------------------------------|-------------------------------------------------- 17 | | `dotnet pack ../..` | Build Node API .NET packages. 18 | | `dotnet build` | Install `SemanticKernel` nuget packages into the project and generate type definitions. 19 | | `npm install` | Install `node-api-dotnet` npm package into the project. 20 | | `node example.js` | Run example JS code that uses the above packages to call the Azure OpenAI service. 21 | -------------------------------------------------------------------------------- /examples/semantic-kernel/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import dotnet from 'node-api-dotnet'; 5 | import './bin/Microsoft.SemanticKernel.Abstractions.js'; 6 | import './bin/Microsoft.SemanticKernel.Core.js'; 7 | import './bin/Microsoft.SemanticKernel.Connectors.OpenAI.js'; 8 | 9 | const SK = dotnet.Microsoft.SemanticKernel; 10 | 11 | const kernelBuilder = SK.Kernel.CreateBuilder(); 12 | 13 | kernelBuilder.AddAzureOpenAIChatCompletion( 14 | process.env['OPENAI_DEPLOYMENT'] || '', 15 | process.env['OPENAI_ENDPOINT'] || '', 16 | process.env['OPENAI_KEY'] || '', 17 | ); 18 | 19 | const kernel = kernelBuilder.Build(); 20 | 21 | const prompt = `{{$input}} 22 | 23 | Give me the TLDR in 10 words. 24 | `; 25 | 26 | const textToSummarize = ` 27 | 1) A robot may not injure a human being or, through inaction, 28 | allow a human being to come to harm. 29 | 30 | 2) A robot must obey orders given it by human beings except where 31 | such orders would conflict with the First Law. 32 | 33 | 3) A robot must protect its own existence as long as such protection 34 | does not conflict with the First or Second Law. 35 | `; 36 | 37 | const executionSettings = new SK.Connectors.OpenAI.OpenAIPromptExecutionSettings(); 38 | executionSettings.MaxTokens = 100; 39 | 40 | const summaryFunction = kernel.CreateFunctionFromPrompt(prompt, executionSettings); 41 | 42 | const summarizeArguments = new Map([ 43 | ['input', textToSummarize], 44 | ]); 45 | 46 | const summary = await kernel.InvokeAsync( 47 | summaryFunction, new SK.KernelArguments(summarizeArguments, undefined)); 48 | 49 | console.log(); 50 | console.log(summary.toString()); 51 | -------------------------------------------------------------------------------- /examples/semantic-kernel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-semantic-kernel", 3 | "type": "module", 4 | "scripts": { 5 | "checkjs": "tsc" 6 | }, 7 | "dependencies": { 8 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 9 | }, 10 | "devDependencies": { 11 | "@types/node": "^20.8.10", 12 | "typescript": "~5.5.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/semantic-kernel/semantic-kernel.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | $(MSBuildThisFileDirectory)/pkg 6 | bin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/semantic-kernel/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | /* https://aka.ms/tsconfig */ 3 | "compilerOptions": { 4 | "target": "es2020", 5 | "module": "node16", 6 | "types": ["node"], 7 | "allowJs": true, 8 | "checkJs": true, 9 | "noEmit": true, 10 | "esModuleInterop": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "strict": true, 13 | 14 | // Diable full type-checking of type libraries, including those generated by node-api-dotnet. 15 | // Currently there are a few bugs in generated type definitions for .NET APIs, which do not 16 | // affect most JS applications as long as they don't reference the problematic APIs. 17 | "skipLibCheck": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/Square44x44Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/Square44x44Logo.scale-200.png -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/Square44x44Logo.targetsize-24_altform-unplated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/Square44x44Logo.targetsize-24_altform-unplated.png -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/StoreLogo.png -------------------------------------------------------------------------------- /examples/winui-fluid/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/node-api-dotnet/de855395dfaa9dc09e7e1dad92963af100c3dbeb/examples/winui-fluid/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /examples/winui-fluid/Fluid/IFluidContainer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.Examples.Fluid; 8 | 9 | [JSImport] 10 | public interface IFluidContainer : IDisposable 11 | { 12 | public ConnectionState ConnectionState { get; } 13 | 14 | public bool IsDirty { get; } 15 | 16 | // TODO: Marshal as "disposed" property. 17 | public bool IsDisposed { get; } 18 | 19 | public JSValue InitialObjects { get; set; } 20 | 21 | // TODO: Marshal attribute to indicate the dictionary should be marshalled as object (not Map). 22 | ////[JSMarshalAs(JSMarshal.Object)] 23 | ////public IDictionary InitialObjects { get; set; } 24 | 25 | // TODO: Automatic marshalling of stringified enums. 26 | public string AttachState { get; } 27 | 28 | public Task Attach(); 29 | 30 | public void Connect(); 31 | 32 | public void Disconnect(); 33 | 34 | ////public Task Create(); 35 | 36 | // TODO: Events 37 | /* 38 | public event EventHandler Connected; 39 | public event EventHandler Disconnected; 40 | public event EventHandler Saved; 41 | public event EventHandler Dirty; 42 | public event EventHandler Disposed; 43 | */ 44 | } 45 | 46 | public enum ConnectionState 47 | { 48 | Disconnected = 0, 49 | EstablishingConnection = 3, 50 | CatchingUp = 1, 51 | Connected = 2, 52 | } 53 | 54 | [JSImport] 55 | public struct Connection 56 | { 57 | public string Id { get; set; } 58 | 59 | public string Mode { get; set; } 60 | } 61 | -------------------------------------------------------------------------------- /examples/winui-fluid/Fluid/ISequenceDeltaEvent.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Examples.Fluid; 5 | 6 | [JSImport] 7 | public struct SequenceDeltaEvent 8 | { 9 | public bool IsLocal { get; set; } 10 | 11 | public string ClientId { get; set; } 12 | 13 | public MergeTreeDeltaOpArgs OpArgs { get; set; } 14 | } 15 | 16 | [JSImport] 17 | public struct MergeTreeDeltaOpArgs 18 | { 19 | public MergeTreeOp Op { get; set; } 20 | } 21 | 22 | [JSImport] 23 | public struct MergeTreeOp 24 | { 25 | public MergeTreeDeltaType Type { get; set; } 26 | 27 | public int? Pos1 { get; set; } 28 | 29 | public int? Pos2 { get; set; } 30 | 31 | public string? Seg { get; set; } 32 | } 33 | 34 | public enum MergeTreeDeltaType 35 | { 36 | Insert = 0, 37 | Remove = 1, 38 | Annotate = 2, 39 | Group = 3, 40 | } 41 | -------------------------------------------------------------------------------- /examples/winui-fluid/Fluid/ISharedMap.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System.Collections.Generic; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.Examples.Fluid; 7 | 8 | // This ISharedMap interface is not currently used, because the JS marshaller has 9 | // better support for IDictionary. 10 | public interface ISharedMap : IDictionary 11 | { 12 | } 13 | 14 | [JSImport] 15 | public struct SharedMapValueChangedEvent 16 | { 17 | public string Key { get; set; } 18 | 19 | public JSValue PreviousValue { get; set; } 20 | } 21 | -------------------------------------------------------------------------------- /examples/winui-fluid/Fluid/ISharedString.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Examples.Fluid; 5 | 6 | [JSImport] 7 | public interface ISharedString 8 | { 9 | public int GetLength(); 10 | 11 | public string GetText(int? start = null, int? end = null); 12 | 13 | public void InsertText(int pos, string text, JSValue props = default); 14 | 15 | public void ReplaceText(int start, int end, string text, JSValue props = default); 16 | 17 | public void RemoveText(int start, int end); 18 | 19 | // SharedString has more methods, but they aren't currently used. 20 | } 21 | -------------------------------------------------------------------------------- /examples/winui-fluid/Imports.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.UI.Xaml; 2 | -------------------------------------------------------------------------------- /examples/winui-fluid/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 8 | 9 | 13 | 14 | 15 | winui-fluid 16 | Microsoft 17 | Assets\StoreLogo.png 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /examples/winui-fluid/Properties/PublishProfiles/win10-arm64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | arm64 9 | win-arm64 10 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ 11 | true 12 | False 13 | False 14 | True 15 | 19 | 20 | -------------------------------------------------------------------------------- /examples/winui-fluid/Properties/PublishProfiles/win10-x64.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | x64 9 | win-x64 10 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ 11 | true 12 | False 13 | False 14 | True 15 | 19 | 20 | -------------------------------------------------------------------------------- /examples/winui-fluid/Properties/PublishProfiles/win10-x86.pubxml: -------------------------------------------------------------------------------- 1 |  2 | 5 | 6 | 7 | FileSystem 8 | x86 9 | win-x86 10 | bin\$(Configuration)\$(TargetFramework)\$(RuntimeIdentifier)\publish\ 11 | true 12 | False 13 | False 14 | True 15 | 19 | 20 | -------------------------------------------------------------------------------- /examples/winui-fluid/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "winui-fluid (Package)": { 4 | "commandName": "MsixPackage" 5 | }, 6 | "winui-fluid (Unpackaged)": { 7 | "commandName": "Project" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /examples/winui-fluid/README.md: -------------------------------------------------------------------------------- 1 | ## C# WinUI + JS Fluid Framework 2 | This project is a C# WinUI application that demonstrates collaborative text editing 3 | using the [Fluid Framework](https://fluidframework.com/), which has a JS-only API. 4 | 5 | Before building and running this project: 6 | - If necessary, [install tools for WinUI C# development]( 7 | https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/set-up-your-development-environment 8 | ). 9 | - Download a build of `libnode.dll` that _includes Node API embedding support_. (Soon this will be 10 | available as a nuget package, but for now you can contact us to get a copy.) Place it at 11 | `bin\win-x64\libnode.dll` relative to the repo root (not this subdirectory). 12 | 13 | | Command | Explanation 14 | |-------------------------|-------------------------------------------------- 15 | | `dotnet pack ../..` | Build Node API .NET packages. 16 | | `npm install` | Install JavaScript packages. 17 | | `dotnet build` | Install .NET nuget packages; build example project. 18 | | `npx tinylicious` | Start the local fluid development server on port 7070. 19 | | `dotnet run --no-build` | Run the example project. 20 | 21 | Launch two or more instances of the app to set up a collaborative editing session. Each instance of 22 | the application can either host or join a session. 23 | - To host a new session, click the **Start** button. Then **Copy** the session ID and send it 24 | to a guest. 25 | - To join an existing session, paste the session ID (obtained from a host) and click **Join**. 26 | 27 | All participants in the session can see each others' cursors and simultanesouly edit the document. 28 | 29 | To join remotely, forward port 7070 using `ngrok` or a similar tool. See 30 | [Testing with Tinylicious and multiple clients]( 31 | https://fluidframework.com/docs/testing/tinylicious/#testing-with-tinylicious-and-multiple-clients) 32 | -------------------------------------------------------------------------------- /examples/winui-fluid/app.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 21 | true/PM 22 | PerMonitorV2, PerMonitor 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /examples/winui-fluid/index.js: -------------------------------------------------------------------------------- 1 | const { TinyliciousClient } = require("@fluidframework/tinylicious-client"); 2 | const { ConnectionState, SharedString } = require("fluid-framework"); 3 | 4 | /** @type import('@fluidframework/common-definitions').ITelemetryBaseLogger */ 5 | const logger = { 6 | send: (event) => { 7 | console.log(`[fluid:${event.category}] ${event.eventName}`); 8 | } 9 | }; 10 | 11 | /** @returns {import('fluid-framework').SharedString} */ 12 | const getFluidData = async () => { 13 | const client = new TinyliciousClient({ logger }); 14 | 15 | /** @type import('fluid-framework').ContainerSchema */ 16 | const containerSchema = { 17 | initialObjects: { sharedString: SharedString } 18 | }; 19 | /** @type import('fluid-framework').IFluidContainer */ 20 | let container; 21 | const containerId = ''; // TODO: Get from UI? Or generate and show in UI? 22 | if (!containerId) { 23 | ({ container } = await client.createContainer(containerSchema)); 24 | const id = await container.attach(); 25 | console.log('container id: ' + id); 26 | //window.location.hash = id; 27 | } else { 28 | ({ container } = await client.getContainer(containerId, containerSchema)); 29 | if (container.connectionState !== ConnectionState.Connected) { 30 | await new Promise((resolve) => { 31 | container.once("connected", resolve); 32 | }); 33 | console.log('connected to ' + containerId); 34 | } 35 | } 36 | return container.initialObjects.sharedString; 37 | }; 38 | getFluidData(); 39 | -------------------------------------------------------------------------------- /examples/winui-fluid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-winui-fluid", 3 | "dependencies": { 4 | "@fluidframework/tinylicious-client": "^1.3.6", 5 | "fluid-framework": "^1.3.6", 6 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet", 7 | "tinylicious": "^5.0.0" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/wpf/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /pkg 3 | /obj 4 | /bin 5 | 6 | *.d.ts 7 | package-lock.json 8 | -------------------------------------------------------------------------------- /examples/wpf/README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Example: Calling WFP APIs from JS 3 | The `example.js` script loads WPF .NET assemblies and shows a WPF window with a WebView2 4 | control with a JS script that renders a mermaid diagram. 5 | 6 | _**.NET events** are not yet projected to JS 7 | ([#59](https://github.com/microsoft/node-api-dotnet/issues/59)). 8 | WPF capabilities will be limited until that issue is resolved._ 9 | 10 | | Command | Explanation 11 | |----------------------------------|-------------------------------------------------- 12 | | `dotnet pack ../..` | Build Node API .NET packages. 13 | | `dotnet build` | Generate type definitions for WPF assemblies. 14 | | `npm install` | Install `node-api-dotnet` npm package into the project. 15 | | `node example.js` | Run example JS code that calls WPF. 16 | -------------------------------------------------------------------------------- /examples/wpf/Window1.xaml: -------------------------------------------------------------------------------- 1 |  10 | 11 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/wpf/WpfExample.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0-windows 5 | $(MSBuildThisFileDirectory)/pkg 6 | bin 7 | true 8 | true 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /examples/wpf/example.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // @ts-check 5 | 6 | import * as path from 'node:path'; 7 | import { fileURLToPath } from 'node:url'; 8 | const __filename = fileURLToPath(import.meta.url); 9 | const __dirname = path.dirname(__filename); 10 | 11 | import dotnet from 'node-api-dotnet'; 12 | import './bin/PresentationFramework.js'; 13 | import './bin/WpfExample.js'; 14 | 15 | // Explicitly load some assembly dependencies that are not automatically loaded 16 | // by the NodeApi assembly resolver. (This may be improved in the future.) 17 | dotnet.load('System.Configuration.ConfigurationManager'); 18 | dotnet.load('System.Windows.Extensions'); 19 | dotnet.load(__dirname + '/pkg/microsoft.web.webview2/1.0.2088.41/lib/netcoreapp3.0/Microsoft.Web.WebView2.Wpf.dll'); 20 | dotnet.load('PresentationFramework.Aero2'); 21 | 22 | // Explicitly load some native library dependencies. 23 | dotnet.load('wpfgfx_cor3'); 24 | dotnet.load(__dirname + '/bin/runtimes/win-x64/native/WebView2Loader.dll'); 25 | 26 | // Show a simple message box. (This doesn't need most of the dependencies.) 27 | ////dotnet.System.Windows.MessageBox.Show('Hello from JS!', "Example"); 28 | 29 | // Show a WPF window with a WebView2 control that renders a mermaid diagram. 30 | const diagram = 'graph TD\n A[Hello from JS!]'; 31 | dotnet.Microsoft.JavaScript.NodeApi.Examples.Window1.CreateWebView2Window(diagram); 32 | -------------------------------------------------------------------------------- /examples/wpf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-examples-semantic-kernel", 3 | "type": "module", 4 | "dependencies": { 5 | "node-api-dotnet": "file:../../out/pkg/node-api-dotnet" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.100", 4 | "allowPrerelease": true, 5 | "rollForward": "latestFeature" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /rid.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | win-x64 5 | win-x86 6 | win-arm64 7 | 8 | 9 | osx-x64 10 | osx-arm64 11 | 12 | 13 | linux-x64 14 | linux-x86 15 | linux-arm64 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | DoNotCopy 10 | false 11 | false 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/NodeApi.DotNetHost/JSMarshallerException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Reflection; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.DotNetHost; 8 | 9 | /// 10 | /// Exception thrown by about a failure while dynamically generating 11 | /// marshaling expressions. 12 | /// 13 | public class JSMarshallerException : JSException 14 | { 15 | public JSMarshallerException(string message, Type type, Exception? innerException = null) 16 | : base(message + $" Type: {type}", innerException) 17 | { 18 | Type = type; 19 | } 20 | 21 | public JSMarshallerException(string message, MemberInfo member, Exception? innerException = null) 22 | : base(message + $" Type: {member.DeclaringType}, Member: {member}", innerException) 23 | { 24 | Type = member.DeclaringType!; 25 | Member = member; 26 | } 27 | 28 | public Type Type { get; } 29 | 30 | public MemberInfo? Member { get; } 31 | } 32 | -------------------------------------------------------------------------------- /src/NodeApi.Generator/NodeApi.Generator.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/NodeApi.Generator/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "NodeApi.Generator": { 4 | "commandName": "Project", 5 | "commandLineArgs": "--assembly System.Runtime;System.Console --typedefs System.Runtime.d.ts;System.Console.d.ts" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /src/NodeApi.Generator/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #if NETFRAMEWORK || NETSTANDARD 5 | 6 | using System; 7 | 8 | /// 9 | /// Fills in extension methods for the class that are not present 10 | /// in .NET Framework. 11 | /// 12 | internal static class StringExtensions 13 | { 14 | public static bool Contains(this string s, char c) => s.Contains(c.ToString()); 15 | 16 | public static bool StartsWith(this string s, char c) => s.StartsWith(c.ToString()); 17 | 18 | public static bool EndsWith(this string s, char c) => s.EndsWith(c.ToString()); 19 | } 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /src/NodeApi.Generator/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | #if NETFRAMEWORK || NETSTANDARD 7 | 8 | namespace Microsoft.JavaScript.NodeApi.Generator; 9 | 10 | internal static class TypeExtensions 11 | { 12 | //https://github.com/dotnet/runtime/issues/23493 13 | public static bool IsGenericTypeParameter(this Type target) 14 | { 15 | return target.IsGenericParameter && 16 | target.DeclaringType != null && 17 | target.DeclaringMethod == null; 18 | } 19 | 20 | //https://github.com/dotnet/runtime/issues/23493 21 | public static bool IsGenericMethodParameter(this Type target) 22 | { 23 | return target.IsGenericParameter && 24 | target.DeclaringMethod != null; 25 | } 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/NodeApi/Interop/JSModuleAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.Interop; 7 | 8 | /// 9 | /// Designates a non-static class or static method that initializes the JS module. 10 | /// 11 | /// 12 | /// This attribute may optionally be used once (and only once) within a .NET assembly that is 13 | /// exported to JavaScript, to allow for more control over the module lifetime or exports. 14 | /// 15 | /// If is applied to a class, the class must have a public 16 | /// constructor that takes no parameters, and may implement the 17 | /// interface. An instance of the class will be constructed when the module is loaded, and disposed 18 | /// when the module is unloaded if it implements . Public non-static 19 | /// properties and methods on the same module class are automatically exported. Those exports are 20 | /// merged with any additional items in the assembly (other classes, static properties and methods, 21 | /// etc) that are tagged with . 22 | /// 23 | /// If is applied to a public static method, then that module 24 | /// initialization method must take a single "exports" parameter and must 25 | /// return a that is the resulting value to be exported to JavaScript by the 26 | /// module. In this usage, the initializer has complete control over customizing the module exports, 27 | /// and no usage of is allowed anywhere in the assembly. The 28 | /// initializer can use to build the module object to export. 29 | /// 30 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 31 | public class JSModuleAttribute : Attribute 32 | { 33 | } 34 | -------------------------------------------------------------------------------- /src/NodeApi/Interop/JSModuleBuilderOfT.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.Interop; 8 | 9 | /// 10 | /// Builds JS module exports. 11 | /// 12 | /// Either or a custom module class that 13 | /// wraps a instance. 14 | public class JSModuleBuilder : JSPropertyDescriptorList, T> where T : class 15 | { 16 | public JSModuleBuilder() : base(Unwrap) 17 | { 18 | } 19 | 20 | private static new T? Unwrap(JSCallbackArgs _) 21 | { 22 | return (T?)JSModuleContext.Current.Module; 23 | } 24 | 25 | /// 26 | /// Exports the built properties to the module exports object. 27 | /// 28 | /// An object that represents the module instance and is 29 | /// used as the 'this' argument for any non-static methods on the module. If the object 30 | /// implements then it is also registered for disposal when 31 | /// the module is unloaded. 32 | /// Object to be returned from the module initializer. 33 | /// The module exports. 34 | public JSValue ExportModule(T module, JSObject exports) 35 | { 36 | JSModuleContext.Current.Module = module; 37 | exports.DefineProperties(Properties.ToArray()); 38 | return exports; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/NodeApi/Interop/JSModuleContext.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.Interop; 7 | 8 | /// 9 | /// Manages JavaScript interop context for the lifetime of a .NET module. 10 | /// 11 | /// 12 | /// A instance is constructed when the module is loaded and disposed 13 | /// when the module is unloaded. 14 | /// 15 | public sealed class JSModuleContext : IDisposable 16 | { 17 | /// 18 | /// Gets the current module context. 19 | /// 20 | public static JSModuleContext Current => JSValueScope.Current.ModuleContext 21 | ?? throw new InvalidCastException("No current module context."); 22 | 23 | /// 24 | /// Gets an instance of the class that represents the module, or null if there is no module 25 | /// class. 26 | /// 27 | public object? Module { get; internal set; } 28 | 29 | public bool IsDisposed { get; private set; } 30 | 31 | public void Dispose() 32 | { 33 | if (IsDisposed) return; 34 | 35 | IsDisposed = true; 36 | 37 | if (Module is IDisposable module) 38 | { 39 | module.Dispose(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/NodeApi/Interop/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Linq; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.Interop; 8 | 9 | public static class TypeExtensions 10 | { 11 | public static string FormatName(this Type type) 12 | { 13 | if (type.IsArray) 14 | { 15 | return FormatName(type.GetElementType()!) + "[]"; 16 | } 17 | 18 | static string FormatNameWithoutNamespace(Type type) 19 | { 20 | string typeName = type.Name; 21 | if (type.IsGenericType) 22 | { 23 | int nameEnd = typeName.IndexOf('`'); 24 | if (nameEnd >= 0) 25 | { 26 | typeName = typeName.Substring(0, nameEnd); 27 | } 28 | 29 | Type[] typeArgs = type.GetGenericArguments(); 30 | if (type.IsGenericTypeDefinition) 31 | { 32 | typeName += '<' + string.Join(",", typeArgs.Select((t) => t.Name)) + '>'; 33 | } 34 | else 35 | { 36 | typeName += '<' + string.Join(",", typeArgs.Select(FormatName)) + '>'; 37 | } 38 | } 39 | return typeName; 40 | } 41 | 42 | // Include the declaring type(s) of nested types. 43 | string typeName = FormatNameWithoutNamespace(type); 44 | Type? declaringType = type.DeclaringType; 45 | while (declaringType != null) 46 | { 47 | typeName = FormatNameWithoutNamespace(declaringType) + '.' + typeName; 48 | declaringType = declaringType.DeclaringType; 49 | } 50 | 51 | if (type.Namespace != null) 52 | { 53 | typeName = type.Namespace + '.' + typeName; 54 | } 55 | 56 | return typeName; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/NodeApi/JSArray.Enumerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | 8 | namespace Microsoft.JavaScript.NodeApi; 9 | 10 | public partial struct JSArray 11 | { 12 | public struct Enumerator : IEnumerator, IEnumerator 13 | { 14 | private readonly JSValue _array; 15 | private readonly int _count; 16 | private int _index; 17 | private JSValue? _current; 18 | 19 | internal Enumerator(JSValue array) 20 | { 21 | _array = array; 22 | if (array.IsArray()) 23 | { 24 | _count = array.GetArrayLength(); 25 | } 26 | else 27 | { 28 | _count = 0; 29 | } 30 | _index = 0; 31 | _current = default; 32 | } 33 | 34 | public bool MoveNext() 35 | { 36 | if (_index < _count) 37 | { 38 | _current = _array.GetElement(_index); 39 | _index++; 40 | return true; 41 | } 42 | 43 | _index = _count + 1; 44 | _current = default; 45 | return false; 46 | } 47 | 48 | public readonly JSValue Current 49 | => _current ?? throw new InvalidOperationException("Unexpected enumerator state"); 50 | 51 | readonly object? IEnumerator.Current 52 | { 53 | get 54 | { 55 | if (_index == 0 || _index == _count + 1) 56 | { 57 | throw new InvalidOperationException("Invalid enumerator state"); 58 | } 59 | return Current; 60 | } 61 | } 62 | 63 | void IEnumerator.Reset() 64 | { 65 | _index = 0; 66 | _current = default; 67 | } 68 | 69 | readonly void IDisposable.Dispose() 70 | { 71 | } 72 | } 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/NodeApi/JSAsyncIterable.Enumerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Threading.Tasks; 7 | 8 | namespace Microsoft.JavaScript.NodeApi; 9 | 10 | public partial struct JSAsyncIterable 11 | { 12 | public struct Enumerator : IAsyncEnumerator 13 | { 14 | private readonly JSValue _iterable; 15 | private readonly JSValue _iterator; 16 | private JSValue? _current; 17 | 18 | internal Enumerator(JSValue iterable) 19 | { 20 | _iterable = iterable; 21 | _iterator = _iterable.CallMethod(JSSymbol.AsyncIterator); 22 | _current = default; 23 | } 24 | 25 | public async ValueTask MoveNextAsync() 26 | { 27 | var nextPromise = (JSPromise)_iterator.CallMethod("next"); 28 | JSValue nextResult = await nextPromise.AsTask(); 29 | JSValue done = nextResult["done"]; 30 | if (done.IsBoolean() && (bool)done) 31 | { 32 | _current = default; 33 | return false; 34 | } 35 | else 36 | { 37 | _current = nextResult["value"]; 38 | return true; 39 | } 40 | } 41 | 42 | public readonly JSValue Current 43 | => _current ?? throw new InvalidOperationException("Unexpected enumerator state"); 44 | 45 | readonly ValueTask IAsyncDisposable.DisposeAsync() => default; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/NodeApi/JSCallback.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi; 5 | 6 | /// 7 | /// Represents a low-level function or method call or callback from JavaScript into .NET. 8 | /// 9 | /// Provides access to the arguments for the call, along with the `this` 10 | /// argument and an optional context object. 11 | /// The return value as a JS value. 12 | public delegate JSValue JSCallback(JSCallbackArgs args); 13 | 14 | /// 15 | /// Represents a low-level void function or method call or callback from JavaScript into .NET. 16 | /// 17 | /// Provides access to the arguments for the call, along with the `this` 18 | /// argument and an optional context object. 19 | public delegate void JSActionCallback(JSCallbackArgs args); 20 | -------------------------------------------------------------------------------- /src/NodeApi/JSImportAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi; 7 | 8 | /// 9 | /// Indicates a class or struct is imported from JavaScript. 10 | /// 11 | [AttributeUsage( 12 | AttributeTargets.Interface | 13 | AttributeTargets.Struct 14 | )] 15 | public sealed class JSImportAttribute : Attribute 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /src/NodeApi/JSIterable.Enumerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | 8 | namespace Microsoft.JavaScript.NodeApi; 9 | 10 | public partial struct JSIterable 11 | { 12 | public struct Enumerator : IEnumerator, IEnumerator 13 | { 14 | private readonly JSValue _iterable; 15 | private JSValue _iterator; 16 | private JSValue? _current; 17 | 18 | internal Enumerator(JSValue iterable) 19 | { 20 | _iterable = iterable; 21 | _iterator = _iterable.CallMethod(JSSymbol.Iterator); 22 | _current = default; 23 | } 24 | 25 | public bool MoveNext() 26 | { 27 | JSValue nextResult = _iterator.CallMethod("next"); 28 | JSValue done = nextResult["done"]; 29 | if (done.IsBoolean() && (bool)done) 30 | { 31 | _current = default; 32 | return false; 33 | } 34 | else 35 | { 36 | _current = nextResult["value"]; 37 | return true; 38 | } 39 | } 40 | 41 | public readonly JSValue Current 42 | => _current ?? throw new InvalidOperationException("Unexpected enumerator state"); 43 | 44 | readonly object? IEnumerator.Current => Current; 45 | 46 | void IEnumerator.Reset() 47 | { 48 | _iterator = _iterable.CallMethod(JSSymbol.Iterator); 49 | _current = default; 50 | } 51 | 52 | readonly void IDisposable.Dispose() 53 | { 54 | } 55 | } 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/NodeApi/JSMap.Enumerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | 7 | namespace Microsoft.JavaScript.NodeApi; 8 | 9 | public partial struct JSMap 10 | { 11 | public struct Enumerator : 12 | IEnumerator>, 13 | System.Collections.IEnumerator 14 | { 15 | private readonly JSValue _iterable; 16 | private JSValue _iterator; 17 | private KeyValuePair? _current; 18 | 19 | internal Enumerator(JSValue iterable) 20 | { 21 | _iterable = iterable; 22 | _iterator = _iterable.CallMethod(JSSymbol.Iterator); 23 | _current = default; 24 | } 25 | 26 | public bool MoveNext() 27 | { 28 | JSValue nextResult = _iterator.CallMethod("next"); 29 | JSValue done = nextResult["done"]; 30 | if (done.IsBoolean() && (bool)done) 31 | { 32 | _current = default; 33 | return false; 34 | } 35 | else 36 | { 37 | JSArray currentEntry = (JSArray)nextResult["value"]; 38 | _current = new KeyValuePair(currentEntry[0], currentEntry[1]); 39 | return true; 40 | } 41 | } 42 | 43 | public readonly KeyValuePair Current 44 | => _current ?? throw new InvalidOperationException("Unexpected enumerator state"); 45 | 46 | readonly object? System.Collections.IEnumerator.Current => Current; 47 | 48 | void System.Collections.IEnumerator.Reset() 49 | { 50 | _iterator = _iterable.CallMethod(JSSymbol.Iterator); 51 | _current = default; 52 | } 53 | 54 | readonly void IDisposable.Dispose() 55 | { 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/NodeApi/JSPropertyAttributes.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi; 7 | 8 | [Flags] 9 | public enum JSPropertyAttributes : int 10 | { 11 | Default = 0, 12 | Writable = 1 << 0, 13 | Enumerable = 1 << 1, 14 | Configurable = 1 << 2, 15 | Static = 1 << 10, 16 | DefaultMethod = Writable | Configurable, 17 | DefaultProperty = Writable | Enumerable | Configurable, 18 | } 19 | -------------------------------------------------------------------------------- /src/NodeApi/JSTypedArrayType.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi; 5 | 6 | // Matches to napi_typedarray_type 7 | public enum JSTypedArrayType : int 8 | { 9 | Int8, 10 | UInt8, 11 | UInt8Clamped, 12 | Int16, 13 | UInt16, 14 | Int32, 15 | UInt32, 16 | Float32, 17 | Float64, 18 | BigInt64, 19 | BigUInt64, 20 | } 21 | -------------------------------------------------------------------------------- /src/NodeApi/JSValueScopeClosedException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi; 7 | 8 | /// 9 | /// An exception that was caused by an attempt to access a (or a more 10 | /// specific JS value type, such as or ) 11 | /// after its was closed. 12 | /// 13 | public class JSValueScopeClosedException : ObjectDisposedException 14 | { 15 | /// 16 | /// Creates a new instance of with an optional 17 | /// object name and message. 18 | /// 19 | public JSValueScopeClosedException(JSValueScope scope, string? message = null) 20 | : base(scope.ScopeType.ToString(), message ?? GetMessage(scope)) 21 | { 22 | Scope = scope; 23 | } 24 | 25 | public JSValueScope Scope { get; } 26 | 27 | private static string GetMessage(JSValueScope scope) 28 | { 29 | return $"The JS value scope of type {scope.ScopeType} was closed.\n" + 30 | "Values created within a scope are no longer available after their scope is " + 31 | "closed. Consider using an escapable scope to promote a value to the parent scope, " + 32 | "or a reference to make a value available to a future callback scope."; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/NodeApi/JSValueType.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi; 5 | 6 | // Matches to napi_valuetype 7 | public enum JSValueType : int 8 | { 9 | Undefined, 10 | Null, 11 | Boolean, 12 | Number, 13 | String, 14 | Symbol, 15 | Object, 16 | Function, 17 | External, 18 | BigInt, 19 | } 20 | -------------------------------------------------------------------------------- /src/NodeApi/Runtime/NodeEmbeddingModuleInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Runtime; 5 | 6 | using static NodeEmbedding; 7 | 8 | public class NodeEmbeddingModuleInfo 9 | { 10 | public required string Name { get; set; } 11 | public required InitializeModuleCallback OnInitialize { get; set; } 12 | public int? NodeApiVersion { get; set; } 13 | } 14 | -------------------------------------------------------------------------------- /src/NodeApi/Runtime/NodeEmbeddingNodeApiScope.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Runtime; 5 | 6 | using System; 7 | using static JSRuntime; 8 | using static NodejsRuntime; 9 | 10 | public sealed class NodeEmbeddingNodeApiScope : IDisposable 11 | { 12 | readonly NodeEmbeddingRuntime _runtime; 13 | private node_embedding_node_api_scope _nodeApiScope; 14 | private readonly JSValueScope _valueScope; 15 | 16 | public NodeEmbeddingNodeApiScope(NodeEmbeddingRuntime runtime) 17 | { 18 | _runtime = runtime; 19 | NodeEmbedding.JSRuntime.EmbeddingRuntimeOpenNodeApiScope( 20 | runtime.Handle, out _nodeApiScope, out napi_env env) 21 | .ThrowIfFailed(); 22 | _valueScope = new JSValueScope( 23 | JSValueScopeType.Root, env, NodeEmbedding.JSRuntime); 24 | } 25 | 26 | /// 27 | /// Gets a value indicating whether the Node.js embedding Node-API scope is disposed. 28 | /// 29 | public bool IsDisposed { get; private set; } 30 | 31 | /// 32 | /// Disposes the Node.js embedding Node-API scope. 33 | /// 34 | public void Dispose() 35 | { 36 | if (IsDisposed) return; 37 | IsDisposed = true; 38 | 39 | _valueScope.Dispose(); 40 | NodeEmbedding.JSRuntime.EmbeddingRuntimeCloseNodeApiScope( 41 | _runtime.Handle, _nodeApiScope) 42 | .ThrowIfFailed(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/NodeApi/Runtime/NodeEmbeddingPlatformSettings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.Runtime; 5 | 6 | using static NodeEmbedding; 7 | using static NodejsRuntime; 8 | 9 | public class NodeEmbeddingPlatformSettings 10 | { 11 | public string? LibNodePath { get; set; } 12 | public NodeEmbeddingPlatformFlags? PlatformFlags { get; set; } 13 | public string[]? Args { get; set; } 14 | public ConfigurePlatformCallback? ConfigurePlatform { get; set; } 15 | 16 | public unsafe ConfigurePlatformCallback CreateConfigurePlatformCallback() 17 | => new((config) => 18 | { 19 | if (PlatformFlags != null) 20 | { 21 | NodeEmbedding.JSRuntime.EmbeddingPlatformConfigSetFlags(config, PlatformFlags.Value) 22 | .ThrowIfFailed(); 23 | } 24 | ConfigurePlatform?.Invoke(config); 25 | }); 26 | } 27 | -------------------------------------------------------------------------------- /src/NodeApi/import.cjs: -------------------------------------------------------------------------------- 1 | // This module wraps the ES import keyword in a CommonJS function, 2 | // to enable directly importing ES modules into .NET. 3 | module.exports = function importModule(modulePath) { return import(modulePath); }; 4 | -------------------------------------------------------------------------------- /src/node-api-dotnet/generator/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Copyright (c) Microsoft Corporation. 4 | // Licensed under the MIT License. 5 | 6 | const path = require('path'); 7 | const assemblyDir = path.join(__dirname, 'net8.0'); 8 | 9 | const dotnet = require('node-api-dotnet'); 10 | 11 | // The generator depends on these assemblies; for now they have to be loaded explicitly. 12 | dotnet.load(path.join(assemblyDir, 'System.Reflection.MetadataLoadContext.dll')); 13 | dotnet.load(path.join(assemblyDir, 'Microsoft.CodeAnalysis.dll')); 14 | dotnet.load(path.join(assemblyDir, 'Microsoft.JavaScript.NodeApi.Generator.dll')); 15 | const Generator = dotnet.Microsoft.JavaScript.NodeApi.Generator; 16 | 17 | const args = process.argv.slice(2); 18 | Generator.Program.Main(args); 19 | -------------------------------------------------------------------------------- /src/node-api-dotnet/generator/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-generator", 3 | "version": "0.1.0", 4 | "description": "Node-API for .Net code generator", 5 | "main": "index.js", 6 | "bin": "index.js", 7 | "license": "MIT", 8 | "author": "Microsoft", 9 | "dependencies": { 10 | "node-api-dotnet": "0.1.0" 11 | }, 12 | "keywords": [ 13 | "Node-API", 14 | "NAPI", 15 | "generator", 16 | ".Net", 17 | "dotnet" 18 | ], 19 | "repository": "github:microsoft/node-api-dotnet", 20 | "homepage": "https://github.com/microsoft/node-api-dotnet#readme", 21 | "bugs": { 22 | "url": "https://github.com/microsoft/node-api-dotnet/issues" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/node-api-dotnet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet", 3 | "version": "0.1.0", 4 | "description": "Node-API bindings for .Net", 5 | "license": "MIT", 6 | "author": "Microsoft", 7 | "scripts": { 8 | }, 9 | "type": "commonjs", 10 | "exports": { 11 | ".": "./index.js" 12 | }, 13 | "types": "./index.d.ts", 14 | "keywords": [ 15 | "Node-API", 16 | "NAPI", 17 | ".Net", 18 | "dotnet" 19 | ], 20 | "repository": "github:microsoft/node-api-dotnet", 21 | "homepage": "https://github.com/microsoft/node-api-dotnet#readme", 22 | "bugs": { 23 | "url": "https://github.com/microsoft/node-api-dotnet/issues" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/node-api-dotnet/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": ["es2018"], 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/TestCases/.gitignore: -------------------------------------------------------------------------------- 1 | # Test case project files are auto-generated. 2 | *.csproj 3 | 4 | # TS type definitions files are auto-generated. 5 | *.d.ts 6 | -------------------------------------------------------------------------------- /test/TestCases/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 13 | 14 | 15 | 16 | 19 | 20 | 21 | 22 | 25 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /test/TestCases/NuGet.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet-init/ModuleInitializer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Microsoft.JavaScript.NodeApi.Interop; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.TestCases; 8 | 9 | public class ModuleInitializer 10 | { 11 | [JSModule] 12 | public static JSValue Initialize(JSRuntimeContext context, JSObject exports) 13 | { 14 | Console.WriteLine("Module.Initialize()"); 15 | 16 | string? exportValue = Environment.GetEnvironmentVariable("TEST_DOTNET_MODULE_INIT_EXPORT"); 17 | if (!string.IsNullOrEmpty(exportValue)) 18 | { 19 | // Export a single string value instead of the `exports` object. 20 | return exportValue; 21 | } 22 | 23 | // Export a module with a JS property that doesn't map to any C# property. 24 | JSModuleBuilder moduleBuilder = new(); 25 | moduleBuilder.AddProperty("test", JSValue.GetBoolean(true)); 26 | return moduleBuilder.ExportModule(context, exports); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet-init/custom_export.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | process.env['TEST_DOTNET_MODULE_INIT_EXPORT'] = 'test'; 7 | 8 | const binding = require('../common').binding; 9 | 10 | assert.strictEqual(typeof binding, 'string'); 11 | assert.strictEqual(binding, 'test'); 12 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet-init/custom_init.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | const binding = require('../common').binding; 7 | 8 | assert.strictEqual(typeof binding, 'object'); 9 | assert.strictEqual(binding.test, true); 10 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/Another.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.TestCases; 7 | 8 | #pragma warning disable CA1822 // Mark members as static 9 | 10 | [JSExport] 11 | public class Another 12 | { 13 | public Another() 14 | { 15 | Console.WriteLine("Another({init})"); 16 | } 17 | 18 | public static string StaticValue 19 | { 20 | get 21 | { 22 | Console.WriteLine("Another.StaticValue.get()"); 23 | return "static"; 24 | } 25 | } 26 | 27 | public string InstanceValue 28 | { 29 | get 30 | { 31 | Console.WriteLine("Another.InstanceValue.get()"); 32 | return "instance"; 33 | } 34 | } 35 | 36 | public static bool StaticMethod(bool arg1, int arg2) 37 | { 38 | Console.WriteLine($"Another.StaticMethod({arg1}, {arg2})"); 39 | return true; 40 | } 41 | 42 | public bool InstanceMethod(string arg) 43 | { 44 | Console.WriteLine($"Another.InstanceMethod({arg})"); 45 | return false; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/Counter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.TestCases; 8 | 9 | /// 10 | /// Enables testing static state. 11 | /// 12 | [JSExport] 13 | public static class Counter 14 | { 15 | private static int s_count; 16 | 17 | public static int Count() 18 | { 19 | int result = Interlocked.Increment(ref s_count); 20 | 21 | Console.WriteLine($"Counter.Count() => {result}"); 22 | 23 | return result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/Delegates.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | using Microsoft.JavaScript.NodeApi.Interop; 8 | 9 | namespace Microsoft.JavaScript.NodeApi.TestCases; 10 | 11 | [JSExport] 12 | public delegate string TestDelegate(string value); 13 | 14 | 15 | [JSExport] 16 | public static class Delegates 17 | { 18 | public delegate string NestedDelegate(string value); 19 | 20 | public static void CallAction(Action actionDelegate, int value) => actionDelegate(value); 21 | 22 | public static int CallFunc(Func funcDelegate, int value) => funcDelegate(value); 23 | 24 | public static string CallDelegate(TestDelegate testDelegate, string value) => testDelegate(value); 25 | 26 | public static string CallDotnetDelegate(Func callDelegate) 27 | => callDelegate((string value) => "#" + value); 28 | 29 | public static async Task WaitUntilCancelled(CancellationToken cancellation) 30 | { 31 | JSSynchronizationContext syncContext = JSSynchronizationContext.Current!; 32 | TaskCompletionSource completion = new(); 33 | cancellation.Register(() => syncContext.Post(() => completion.SetResult(true))); 34 | await completion.Task; 35 | } 36 | 37 | public static async Task CallDelegateAndCancel( 38 | Func cancellableDelegate) 39 | { 40 | CancellationTokenSource cancellationSource = new(); 41 | Task delegateTask = cancellableDelegate(cancellationSource.Token); 42 | await Task.Delay(100); 43 | cancellationSource.Cancel(); 44 | await delegateTask; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/Errors.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using System.Threading.Tasks; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.TestCases; 8 | 9 | [JSExport] 10 | public static class Errors 11 | { 12 | public static void ThrowDotnetError(string message) 13 | { 14 | throw new Exception(message); 15 | } 16 | 17 | public static void ThrowJSError(string message, IJSErrors jsErrors) 18 | { 19 | jsErrors.ThrowJSError(message); 20 | } 21 | 22 | public static async Task ThrowAsyncDotnetError(string message) 23 | { 24 | await Task.Yield(); 25 | throw new Exception(message); 26 | } 27 | } 28 | 29 | [JSExport] 30 | public interface IJSErrors 31 | { 32 | void ThrowJSError(string message); 33 | } 34 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/ExtensionMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.TestCases; 7 | 8 | public class SubclassOfGenericClass : GenericClass 9 | { 10 | public SubclassOfGenericClass(string value) : base(value) { } 11 | 12 | public static IGenericInterface Create(string value) 13 | => new SubclassOfGenericClass(value); 14 | } 15 | 16 | public static class TestClassExtensions 17 | { 18 | public static string GetValueOrDefault(this ClassObject obj, string defaultValue) 19 | => obj.Value ?? defaultValue; 20 | 21 | public static T GetGenericValueOrDefault(this GenericClass obj, T defaultValue) 22 | => obj.Value ?? defaultValue; 23 | 24 | public static string GetGenericStringValueOrDefault(this GenericClass obj, string defaultValue) 25 | => obj.Value ?? defaultValue; 26 | } 27 | 28 | public static class TestInterfaceExtensions 29 | { 30 | public static int? ToInteger(this ITestInterface obj) 31 | => int.TryParse(obj.Value, out int value) ? (int?)value : null; 32 | 33 | public static int? GenericToInteger(this IGenericInterface obj) 34 | => int.TryParse(obj.Value?.ToString(), out int value) ? (int?)value : null; 35 | 36 | public static int? GenericStringToInteger(this IGenericInterface obj) 37 | => int.TryParse(obj.Value, out int value) ? (int?)value : null; 38 | } 39 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/Generics.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.TestCases; 5 | 6 | #pragma warning disable CA1822 // Mark members as static 7 | 8 | // Note these types do not have [JSExport] attributes: static binding does not support generics. 9 | 10 | public interface IGenericInterface 11 | { 12 | T Value { get; set; } 13 | } 14 | 15 | public class GenericClass : IGenericInterface 16 | { 17 | public GenericClass(T value) { Value = value; } 18 | public T Value { get; set; } 19 | public T GetValue(T value) => value; 20 | } 21 | 22 | public class GenericClassWithConstraint where T : struct 23 | { 24 | public GenericClassWithConstraint(T value) { Value = value; } 25 | public T Value { get; set; } 26 | public T GetValue(T value) => value; 27 | } 28 | 29 | public struct GenericStruct 30 | { 31 | public GenericStruct(T value) { Value = value; } 32 | public T Value { get; set; } 33 | public readonly T GetValue(T value) => value; 34 | } 35 | 36 | public static class StaticClassWithGenericMethods 37 | { 38 | public static T GetValue(T value) => value; 39 | } 40 | 41 | public class NonstaticClassWithGenericMethods 42 | { 43 | public T GetValue(T value) => value; 44 | } 45 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/Hello.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | 6 | namespace Microsoft.JavaScript.NodeApi.TestCases; 7 | 8 | public static class Hello 9 | { 10 | /// 11 | /// Gets a greeting string for testing. 12 | /// 13 | /// Name of the greeter. 14 | /// A greeting with the name. 15 | [JSExport("hello")] 16 | public static string Test(string greeter) 17 | { 18 | Console.WriteLine($"Hello(\"{greeter}\")"); 19 | return $"Hello {greeter}!"; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/ModuleClass.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using System; 5 | using Microsoft.JavaScript.NodeApi.Interop; 6 | 7 | namespace Microsoft.JavaScript.NodeApi.TestCases; 8 | 9 | #pragma warning disable CA1822 // Mark members as static 10 | 11 | /// 12 | /// An instance of this class is constructed when the module is loaded and disposed when the 13 | /// module is unloaded. Public instance properties and methods on the module class are 14 | /// automatically exported. 15 | /// 16 | [JSModule] 17 | public sealed class ModuleClass : IDisposable 18 | { 19 | /// 20 | /// The module class must have a public constructor that takes either no parameters 21 | /// or a single JSRuntimeContext parameter. 22 | /// 23 | public ModuleClass() 24 | { 25 | } 26 | 27 | public void Dispose() 28 | { 29 | } 30 | 31 | public string ModuleProperty { get; set; } = "test"; 32 | 33 | public string ModuleMethod(string greeter) 34 | { 35 | string stringValue = greeter; 36 | return $"Hello {stringValue}!"; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/ModuleExports.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.TestCases; 5 | 6 | public static class ModuleExports 7 | { 8 | private static string s_value = "test"; 9 | 10 | [JSExport] 11 | public static JSValue MergedProperty 12 | { 13 | get => s_value; 14 | set => s_value = (string)value; 15 | } 16 | 17 | [JSExport] 18 | public static JSValue MergedMethod(JSCallbackArgs args) 19 | { 20 | string stringValue = (string)args[0]; 21 | return $"Hello {stringValue}!"; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/OptionalParameters.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | namespace Microsoft.JavaScript.NodeApi.TestCases; 5 | 6 | [JSExport] 7 | public static class OptionalParameters 8 | { 9 | public static string DefaultNull(string a, string? b = null) 10 | { 11 | b ??= "(null)"; 12 | return $"{a},{b}"; 13 | } 14 | 15 | public static string DefaultFalse(bool a, bool b = false) 16 | { 17 | return $"{a},{b}"; 18 | } 19 | 20 | public static string DefaultZero(int a, int b = 0) 21 | { 22 | return $"{a},{b}"; 23 | } 24 | 25 | public static string DefaultEmptyString(string a, string b = "") 26 | { 27 | return $"{a},{b}"; 28 | } 29 | 30 | public static string Multiple(string a, string? b = null, int c = 0) 31 | { 32 | return $"{a},{b},{c}"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/async_methods.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | const common = require('../common'); 6 | 7 | /** @type {import('./napi-dotnet')} */ 8 | const binding = common.binding; 9 | 10 | common.runTest(async () => { 11 | const result = await binding.async_method('buddy'); 12 | assert.strictEqual(result, 'Hey buddy!'); 13 | 14 | const result2 = await binding.async_method_cs('buddy'); 15 | assert.strictEqual(result2, 'Hey buddy!'); 16 | 17 | const result3 = await binding.async_interface.testAsync('buddy'); 18 | assert.strictEqual(result3, 'Hey buddy!'); 19 | 20 | // Invoke a C# method that calls back to a JS object that implements an interface. 21 | const asyncInterfaceImpl = { 22 | async testAsync(greeting) { return `Hello, ${greeting}!`; } 23 | }; 24 | const result4 = await binding.async_interface_reverse(asyncInterfaceImpl, 'buddy'); 25 | assert.strictEqual(result4, 'Hello, buddy!'); 26 | 27 | // A JS object that implements an interface can be returned from C#. 28 | binding.async_interface = asyncInterfaceImpl; 29 | assert.strictEqual(binding.async_interface, asyncInterfaceImpl); 30 | 31 | // Invoke C# methods that return ValueTask. 32 | await binding.async_method_valuetask(); 33 | const result5 = await binding.async_method_valuetask_of_string('buddy'); 34 | assert.strictEqual(result5, 'Hey buddy!'); 35 | }); 36 | 37 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/dynamic_no_namespace_type.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | const dotnet = require('../common').dotnet; 7 | 8 | // Load the test module using dynamic binding `load()` instead of static binding `require()`. 9 | const assemblyPath = process.env.NODE_API_TEST_MODULE_PATH; 10 | dotnet.load(assemblyPath); 11 | 12 | // The unnamespaced type should be skipped. 13 | assert.strictEqual(dotnet.NoNamespaceType, undefined); 14 | 15 | assert.notStrictEqual(dotnet.Microsoft.JavaScript.NodeApi.TestCases.NoNamespaceInterfaceImpl, undefined) 16 | 17 | assert.notStrictEqual(dotnet.Microsoft.JavaScript.NodeApi.TestCases.NoNamespaceTypeImpl, undefined) 18 | 19 | assert.notStrictEqual(dotnet.Microsoft.JavaScript.NodeApi.TestCases.NoNamespaceContainer, undefined) 20 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/dynamic_optional_params.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | // This only tests dynamic invocation because optional parameters 7 | // are not yet implemented for static binding. 8 | 9 | const dotnet = require('../common').dotnet; 10 | 11 | const assemblyPath = process.env.NODE_API_TEST_MODULE_PATH; 12 | const assembly = dotnet.load(assemblyPath); 13 | const OptionalParameters = dotnet.Microsoft.JavaScript.NodeApi.TestCases.OptionalParameters; 14 | 15 | assert.strictEqual('a,(null)', OptionalParameters.DefaultNull('a')); 16 | assert.strictEqual('True,False', OptionalParameters.DefaultFalse(true)); 17 | assert.strictEqual('1,0', OptionalParameters.DefaultZero(1)); 18 | assert.strictEqual('a,', OptionalParameters.DefaultEmptyString('a')); 19 | assert.strictEqual('a,b,0', OptionalParameters.Multiple('a', 'b')); 20 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/hello.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | /** @type {import('./napi-dotnet')} */ 7 | const binding = require('../common').binding; 8 | 9 | // Call a method exported by the addon module. 10 | const result = binding.hello('world'); 11 | 12 | assert.strictEqual(result, 'Hello world!'); 13 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/module_class.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | /** @type {import('./napi-dotnet')} */ 7 | const binding = require('../common').binding; 8 | 9 | assert.strictEqual(typeof binding, 'object'); 10 | 11 | assert.strictEqual(binding.moduleProperty, 'test'); 12 | assert.strictEqual(binding.moduleMethod('test'), 'Hello test!'); 13 | assert.strictEqual(binding.mergedProperty, 'test'); 14 | assert.strictEqual(binding.mergedMethod('test'), 'Hello test!'); 15 | 16 | /* 17 | // Delete the cached binding. This should invoke the module Dispose() method. 18 | // TODO: With CLR hosting, there should be a way to delete one .NET module. 19 | delete require.cache[dotnetHost]; 20 | delete require.cache[dotnetModule]; 21 | */ 22 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/multi_instance.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | const { Worker, isMainThread, parentPort } = require('worker_threads'); 6 | 7 | /** @typedef {import('./napi-dotnet')} Binding */ 8 | /** @type Binding */ 9 | const binding = require('../common').binding; 10 | 11 | const testModulePath = require('../common').testModulePath; 12 | const isAot = /\.node$/.test(testModulePath); 13 | 14 | if (isMainThread) { 15 | // Increment the static counter to 2. 16 | const count1 = binding.Counter.count(); 17 | assert.strictEqual(count1, 1); 18 | assert.strictEqual(binding.Counter.count(), 2); 19 | 20 | // AOT modules do not get reloaded when the node module is rebound, so their static data is 21 | // not isolated across threads. But .NET hosted modules do get reloaded with isolated static data, 22 | // so in that case the worker-thread counter should be independent. 23 | const expectedCount = isAot ? 3 : 1; 24 | const worker = new Worker(__filename); 25 | worker.on('message', (count3) => assert.strictEqual(count3, expectedCount)); 26 | } else { 27 | const count3 = binding.Counter.count(); 28 | parentPort.postMessage(count3) 29 | } 30 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/object_map.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // Test the JSRuntimeContext "object map" which keeps track of JS wrapper objects 5 | // for corresponding .NET objects. 6 | 7 | const assert = require('assert'); 8 | 9 | /** @type {import('./napi-dotnet')} */ 10 | const binding = require('../common').binding; 11 | 12 | const ComplexTypes = binding.ComplexTypes; 13 | assert.strictEqual(typeof ComplexTypes, 'object'); 14 | 15 | let obj1 = ComplexTypes.classObject; 16 | assert(obj1); 17 | 18 | // The same JS wrapper instance should be returned every time. 19 | let obj2 = ComplexTypes.classObject; 20 | assert.strictEqual(obj1, obj2); 21 | 22 | // Force the JS wrapper object to be collected. 23 | obj1 = obj2 = undefined; 24 | global.gc(); 25 | 26 | // A new JS wrapper object should be created. 27 | let obj3 = ComplexTypes.classObject; 28 | assert(obj3); 29 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/subclass.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // When exporting base classes and subclasses to JavaScript, the base members should be available 5 | // on the subclass instances, and the JS prototype chain should be set up correctly. 6 | 7 | const assert = require('assert'); 8 | 9 | /** @type {import('./napi-dotnet')} */ 10 | const binding = require('../common').binding; 11 | 12 | const BaseClass = binding.BaseClass; 13 | assert.strictEqual(typeof BaseClass, 'function'); 14 | 15 | const SubClass = binding.SubClass; 16 | assert.strictEqual(typeof SubClass, 'function'); 17 | 18 | const baseInstance = new BaseClass(1); 19 | assert.strictEqual(baseInstance.value1, 1); 20 | assert.strictEqual(baseInstance.constructor, BaseClass); 21 | assert(baseInstance instanceof BaseClass); 22 | assert.strictEqual(Object.getPrototypeOf(baseInstance), BaseClass.prototype); 23 | 24 | const subInstance = new SubClass(2, 3); 25 | assert.strictEqual(subInstance.value1, 2); 26 | assert.strictEqual(subInstance.value2, 3); 27 | assert.strictEqual(subInstance.constructor, SubClass); 28 | assert(subInstance instanceof SubClass); 29 | assert(subInstance instanceof BaseClass); 30 | assert.strictEqual(Object.getPrototypeOf(subInstance), SubClass.prototype); 31 | assert.strictEqual(Object.getPrototypeOf(SubClass.prototype), BaseClass.prototype); 32 | 33 | const IBaseInterface = binding.IBaseInterface; 34 | assert.strictEqual(typeof IBaseInterface, 'function'); 35 | 36 | const ISubInterface = binding.ISubInterface; 37 | assert.strictEqual(typeof ISubInterface, 'function'); 38 | 39 | // Note there is no JS prototype chain for interfaces, because .NET interfaces can have 40 | // multiple bases, which cannot be represented as JS prototypes. 41 | 42 | const baseInstance2 = new BaseClass({ value1: 11 }); 43 | assert.strictEqual(baseInstance2.value1, 11); 44 | const subInstance2 = new SubClass({ value1: 12, value2: 13 }); 45 | assert.strictEqual(subInstance2.value1, 12); 46 | assert.strictEqual(subInstance2.value2, 13); 47 | -------------------------------------------------------------------------------- /test/TestCases/napi-dotnet/thread_safety.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | 6 | /** @type {import('./napi-dotnet')} */ 7 | const binding = require('../common').binding; 8 | 9 | const ThreadSafety = binding.ThreadSafety; 10 | 11 | async function test() { 12 | let delegateCalled = false; 13 | await ThreadSafety.callDelegateFromOtherThread(() => delegateCalled = true); 14 | assert(delegateCalled); 15 | 16 | let interfaceMethodArgument = false; 17 | await ThreadSafety.callInterfaceMethodFromOtherThread( 18 | { 19 | echo: (value) => { 20 | interfaceMethodArgument = value; 21 | return value; 22 | } 23 | }, 24 | 'test'); 25 | assert.strictEqual(interfaceMethodArgument, 'test'); 26 | 27 | const count = await ThreadSafety.enumerateCollectionFromOtherThread([1, 2, 3]); 28 | assert.strictEqual(count, 3); 29 | 30 | const map = new Map(); 31 | map.set('a', '1'); 32 | map.set('b', '2'); 33 | map.set('c', '3'); 34 | const mapSize = await ThreadSafety.enumerateDictionaryFromOtherThread(map); 35 | assert.strictEqual(mapSize, 3); 36 | 37 | const modifyResult = await ThreadSafety.modifyDictionaryFromOtherThread(map, 'a'); 38 | assert(modifyResult); 39 | assert(!map.has('a')); 40 | assert.strictEqual(map.size, 2); 41 | } 42 | test().catch((err) => { 43 | console.error(err); 44 | process.exit(1); 45 | }); 46 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/basic_types/array.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | 6 | namespace Microsoft.JavaScript.NodeApiTest; 7 | 8 | public class TestBasicTypesArray : TestHelper, ITestObject 9 | { 10 | private static JSValue CreateArray(JSCallbackArgs args) 11 | => (args.Length > 0) ? new JSArray((int)args[0]) : new JSArray(); 12 | 13 | private static JSValue GetLength(JSCallbackArgs args) 14 | => ((JSArray)args[0]).Length; 15 | 16 | private static JSValue Get(JSCallbackArgs args) 17 | => ((JSArray)args[0])[(int)args[1]]; 18 | 19 | private static JSValue Set(JSCallbackArgs args) 20 | { 21 | var array = (JSArray)args[0]; 22 | array[(int)args[1]] = args[2]; 23 | return JSValue.Undefined; 24 | } 25 | 26 | public JSObject Init() => new() 27 | { 28 | Method(CreateArray), 29 | Method(GetLength), 30 | Method(Get), 31 | Method(Set), 32 | }; 33 | } 34 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/basic_types/array.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | const assert = require('assert'); 6 | 7 | module.exports = require('../../common').runTest(test); 8 | 9 | function test(binding) { 10 | // create empty array 11 | const array = binding.basicTypesArray.createArray(); 12 | assert.strictEqual(binding.basicTypesArray.getLength(array), 0); 13 | 14 | // create array with length 15 | const arrayWithLength = binding.basicTypesArray.createArray(10); 16 | assert.strictEqual(binding.basicTypesArray.getLength(arrayWithLength), 10); 17 | 18 | // set function test 19 | binding.basicTypesArray.set(array, 0, 10); 20 | binding.basicTypesArray.set(array, 1, 'test'); 21 | binding.basicTypesArray.set(array, 2, 3.0); 22 | 23 | // check length after set data 24 | assert.strictEqual(binding.basicTypesArray.getLength(array), 3); 25 | 26 | // get function test 27 | assert.strictEqual(binding.basicTypesArray.get(array, 0), 10); 28 | assert.strictEqual(binding.basicTypesArray.get(array, 1), 'test'); 29 | assert.strictEqual(binding.basicTypesArray.get(array, 2), 3.0); 30 | 31 | // overwrite test 32 | binding.basicTypesArray.set(array, 0, 5); 33 | assert.strictEqual(binding.basicTypesArray.get(array, 0), 5); 34 | 35 | // out of index test 36 | assert.strictEqual(binding.basicTypesArray.get(array, 5), undefined); 37 | } 38 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/basic_types/boolean.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | 6 | namespace Microsoft.JavaScript.NodeApiTest; 7 | 8 | public class TestBasicTypesBoolean : TestHelper, ITestObject 9 | { 10 | private static JSValue CreateBoolean(JSCallbackArgs args) 11 | => JSValue.GetBoolean((bool)args[0]); 12 | 13 | private static JSValue CreateBooleanFromPrimitive(JSCallbackArgs args) 14 | => (bool)args[0]; 15 | 16 | public JSObject Init() => new() 17 | { 18 | Method(CreateBoolean), 19 | Method(CreateBooleanFromPrimitive), 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/basic_types/boolean.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test(binding) { 11 | const bool1 = binding.basicTypesBoolean.createBoolean(true); 12 | assert.strictEqual(bool1, true); 13 | 14 | const bool2 = binding.basicTypesBoolean.createBoolean(false); 15 | assert.strictEqual(bool2, false); 16 | 17 | const bool3 = binding.basicTypesBoolean.createBooleanFromPrimitive(true); 18 | assert.strictEqual(bool3, true); 19 | 20 | const bool4 = binding.basicTypesBoolean.createBooleanFromPrimitive(false); 21 | assert.strictEqual(bool4, false); 22 | } 23 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/bigint.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | const assert = require('assert'); 6 | 7 | module.exports = require('../common').runTest(test); 8 | 9 | function test (binding) { 10 | const { 11 | isLossless, 12 | isBigInt, 13 | testInt64, 14 | testUInt64, 15 | testWords, 16 | testWordSpan, 17 | testBigInteger 18 | } = binding.bigInt; 19 | 20 | [ 21 | 0n, 22 | -0n, 23 | 1n, 24 | -1n, 25 | 100n, 26 | 2121n, 27 | -1233n, 28 | 986583n, 29 | -976675n, 30 | 98765432213456789876546896323445679887645323232436587988766545658n, 31 | -4350987086545760976737453646576078997096876957864353245245769809n 32 | ].forEach((num) => { 33 | if (num > -(2n ** 63n) && num < 2n ** 63n) { 34 | assert.strictEqual(testInt64(num), num); 35 | assert.strictEqual(isLossless(num, true), true); 36 | } else { 37 | assert.strictEqual(isLossless(num, true), false); 38 | } 39 | 40 | if (num >= 0 && num < 2n ** 64n) { 41 | assert.strictEqual(testUInt64(num), num); 42 | assert.strictEqual(isLossless(num, false), true); 43 | } else { 44 | assert.strictEqual(isLossless(num, false), false); 45 | } 46 | 47 | assert.strictEqual(isBigInt(num), true); 48 | 49 | assert.strictEqual(num, testWords(num)); 50 | assert.strictEqual(num, testWordSpan(num)); 51 | assert.strictEqual(num, testBigInteger(num, num.toString())); 52 | }); 53 | } 54 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/delete_property.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | using Microsoft.JavaScript.NodeApi.Runtime; 6 | 7 | namespace Microsoft.JavaScript.NodeApiTest; 8 | 9 | public partial class TestObject 10 | { 11 | private static JSValue DeletePropertyWithNapiValue(JSCallbackArgs args) 12 | { 13 | JSValue obj = args[0]; 14 | JSValue key = args[1]; 15 | return obj.DeleteProperty((JSRuntime.napi_value)key); 16 | } 17 | 18 | private static JSValue DeletePropertyWithNapiWrapperValue(JSCallbackArgs args) 19 | { 20 | JSValue obj = args[0]; 21 | JSValue key = args[1]; 22 | return obj.DeleteProperty(key); 23 | } 24 | 25 | private static JSValue DeletePropertyWithUtf8StyleString(JSCallbackArgs args) 26 | { 27 | JSValue obj = args[0]; 28 | JSValue key = args[1]; 29 | return obj.DeleteProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8())); 30 | } 31 | 32 | private static JSValue DeletePropertyWithCSharpStyleString(JSCallbackArgs args) 33 | { 34 | JSValue obj = args[0]; 35 | JSValue key = args[1]; 36 | return obj.DeleteProperty((string)key); 37 | } 38 | 39 | private static JSValue DeletePropertyWithUInt32(JSCallbackArgs args) 40 | { 41 | JSValue obj = args[0]; 42 | JSValue key = args[1]; 43 | return obj.DeleteProperty((uint)key); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/delete_property.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test (binding) { 11 | function testDeleteProperty (nativeDeleteProperty) { 12 | const obj = { one: 1, two: 2 }; 13 | Object.defineProperty(obj, 'three', { configurable: false, value: 3 }); 14 | assert.strictEqual(nativeDeleteProperty(obj, 'one'), true); 15 | assert.strictEqual(nativeDeleteProperty(obj, 'missing'), true); 16 | 17 | /* Returns true for all cases except when the property is an own non- 18 | configurable property, in which case, false is returned in non-strict mode. */ 19 | assert.strictEqual(nativeDeleteProperty(obj, 'three'), false); 20 | assert.deepStrictEqual(obj, { two: 2 }); 21 | } 22 | 23 | function testShouldThrowErrorIfKeyIsInvalid (nativeDeleteProperty) { 24 | assert.throws(() => { 25 | nativeDeleteProperty(undefined, 'test'); 26 | }, /Cannot convert undefined or null to object/); 27 | } 28 | 29 | const testObj = { 15: 42, three: 3 }; 30 | binding.object.deletePropertyWithUInt32(testObj, 15); 31 | assert.strictEqual(Object.prototype.hasOwnProperty.call(testObj, 15), false); 32 | 33 | testDeleteProperty(binding.object.deletePropertyWithNapiValue); 34 | testDeleteProperty(binding.object.deletePropertyWithNapiWrapperValue); 35 | testDeleteProperty(binding.object.deletePropertyWithUtf8StyleString); 36 | testDeleteProperty(binding.object.deletePropertyWithCSharpStyleString); 37 | 38 | testShouldThrowErrorIfKeyIsInvalid(binding.object.deletePropertyWithNapiValue); 39 | testShouldThrowErrorIfKeyIsInvalid(binding.object.deletePropertyWithNapiWrapperValue); 40 | testShouldThrowErrorIfKeyIsInvalid(binding.object.deletePropertyWithUtf8StyleString); 41 | testShouldThrowErrorIfKeyIsInvalid(binding.object.deletePropertyWithCSharpStyleString); 42 | } 43 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/finalizer.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | 6 | namespace Microsoft.JavaScript.NodeApiTest; 7 | 8 | public partial class TestObject 9 | { 10 | private static JSValue AddFinalizer(JSCallbackArgs args) 11 | { 12 | JSValue result = JSValue.CreateObject(); 13 | JSReference objRef = new(result); 14 | args[0].AddFinalizer(() => 15 | { 16 | if (objRef.GetValue() is JSValue value) 17 | { 18 | value.SetProperty("finalizerCalled", true); 19 | } 20 | objRef.Dispose(); 21 | }); 22 | return result; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/finalizer.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | const testUtil = require('../testUtil'); 8 | 9 | module.exports = require('../../common').runTest(test); 10 | 11 | function createWeakRef (binding, bindingToTest) { 12 | return binding.object[bindingToTest]({}); 13 | } 14 | 15 | function test (binding) { 16 | let obj1; 17 | return testUtil.runGCTests([ 18 | 'addFinalizer', 19 | () => { 20 | obj1 = createWeakRef(binding, 'addFinalizer'); 21 | }, 22 | () => assert.deepStrictEqual(obj1, { finalizerCalled: true }) 23 | ]); 24 | } 25 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/get_property.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | using Microsoft.JavaScript.NodeApi.Runtime; 6 | 7 | namespace Microsoft.JavaScript.NodeApiTest; 8 | 9 | public partial class TestObject 10 | { 11 | private static JSValue GetPropertyWithNapiValue(JSCallbackArgs args) 12 | { 13 | JSValue obj = args[0]; 14 | JSValue key = args[1]; 15 | return obj.GetProperty((JSRuntime.napi_value)key); 16 | } 17 | 18 | private static JSValue GetPropertyWithNapiWrapperValue(JSCallbackArgs args) 19 | { 20 | JSValue obj = args[0]; 21 | JSValue key = args[1]; 22 | return obj.GetProperty(key); 23 | } 24 | 25 | private static JSValue GetPropertyWithUtf8StyleString(JSCallbackArgs args) 26 | { 27 | JSValue obj = args[0]; 28 | JSValue key = args[1]; 29 | return obj.GetProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8())); 30 | } 31 | 32 | private static JSValue GetPropertyWithCSharpStyleString(JSCallbackArgs args) 33 | { 34 | JSValue obj = args[0]; 35 | JSValue key = args[1]; 36 | return obj.GetProperty((string)key); 37 | } 38 | 39 | private static JSValue GetPropertyWithUInt32(JSCallbackArgs args) 40 | { 41 | JSValue obj = args[0]; 42 | JSValue key = args[1]; 43 | return obj.GetProperty((uint)key); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/get_property.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test(binding) { 11 | function testGetProperty(nativeGetProperty) { 12 | const obj = { test: 1 }; 13 | assert.strictEqual(nativeGetProperty(obj, 'test'), 1); 14 | } 15 | 16 | function testShouldReturnUndefinedIfKeyIsNotPresent(nativeGetProperty) { 17 | const obj = {}; 18 | assert.strictEqual(nativeGetProperty(obj, 'test'), undefined); 19 | } 20 | 21 | function testShouldThrowErrorIfKeyIsInvalid(nativeGetProperty) { 22 | assert.throws(() => { 23 | nativeGetProperty(undefined, 'test'); 24 | }, /Cannot convert undefined or null to object/); 25 | } 26 | 27 | const testObject = { 42: 100 }; 28 | const property = binding.object.getPropertyWithUInt32(testObject, 42); 29 | assert.strictEqual(property, 100); 30 | 31 | const nativeFunctions = [ 32 | binding.object.getPropertyWithNapiValue, 33 | binding.object.getPropertyWithNapiWrapperValue, 34 | binding.object.getPropertyWithUtf8StyleString, 35 | binding.object.getPropertyWithCSharpStyleString 36 | ]; 37 | 38 | nativeFunctions.forEach((nativeFunction) => { 39 | testGetProperty(nativeFunction); 40 | testShouldReturnUndefinedIfKeyIsNotPresent(nativeFunction); 41 | testShouldThrowErrorIfKeyIsInvalid(nativeFunction); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/has_own_property.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | using Microsoft.JavaScript.NodeApi.Runtime; 6 | 7 | namespace Microsoft.JavaScript.NodeApiTest; 8 | 9 | public partial class TestObject 10 | { 11 | private static JSValue HasOwnPropertyWithNapiValue(JSCallbackArgs args) 12 | { 13 | JSValue obj = args[0]; 14 | JSValue key = args[1]; 15 | return obj.HasOwnProperty((JSRuntime.napi_value)key); 16 | } 17 | 18 | private static JSValue HasOwnPropertyWithNapiWrapperValue(JSCallbackArgs args) 19 | { 20 | JSValue obj = args[0]; 21 | JSValue key = args[1]; 22 | return obj.HasOwnProperty(key); 23 | } 24 | 25 | private static JSValue HasOwnPropertyWithUtf8StyleString(JSCallbackArgs args) 26 | { 27 | JSValue obj = args[0]; 28 | JSValue key = args[1]; 29 | return obj.HasOwnProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8())); 30 | } 31 | 32 | private static JSValue HasOwnPropertyWithCSharpStyleString(JSCallbackArgs args) 33 | { 34 | JSValue obj = args[0]; 35 | JSValue key = args[1]; 36 | return obj.HasOwnProperty((string)key); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/has_own_property.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test (binding) { 11 | function testHasOwnProperty (nativeHasOwnProperty) { 12 | const obj = { one: 1 }; 13 | 14 | Object.defineProperty(obj, 'two', { value: 2 }); 15 | 16 | assert.strictEqual(nativeHasOwnProperty(obj, 'one'), true); 17 | assert.strictEqual(nativeHasOwnProperty(obj, 'two'), true); 18 | assert.strictEqual('toString' in obj, true); 19 | assert.strictEqual(nativeHasOwnProperty(obj, 'toString'), false); 20 | } 21 | 22 | function testShouldThrowErrorIfKeyIsInvalid (nativeHasOwnProperty) { 23 | assert.throws(() => { 24 | nativeHasOwnProperty(undefined, 'test'); 25 | }, /Cannot convert undefined or null to object/); 26 | } 27 | 28 | testHasOwnProperty(binding.object.hasOwnPropertyWithNapiValue); 29 | testHasOwnProperty(binding.object.hasOwnPropertyWithNapiWrapperValue); 30 | testHasOwnProperty(binding.object.hasOwnPropertyWithUtf8StyleString); 31 | testHasOwnProperty(binding.object.hasOwnPropertyWithCSharpStyleString); 32 | 33 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasOwnPropertyWithNapiValue); 34 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasOwnPropertyWithNapiWrapperValue); 35 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasOwnPropertyWithUtf8StyleString); 36 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasOwnPropertyWithCSharpStyleString); 37 | } 38 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/has_property.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | using Microsoft.JavaScript.NodeApi.Runtime; 6 | 7 | namespace Microsoft.JavaScript.NodeApiTest; 8 | 9 | public partial class TestObject 10 | { 11 | private static JSValue HasPropertyWithNapiValue(JSCallbackArgs args) 12 | { 13 | JSValue obj = args[0]; 14 | JSValue key = args[1]; 15 | return obj.HasProperty((JSRuntime.napi_value)key); 16 | } 17 | 18 | private static JSValue HasPropertyWithNapiWrapperValue(JSCallbackArgs args) 19 | { 20 | JSValue obj = args[0]; 21 | JSValue key = args[1]; 22 | return obj.HasProperty(key); 23 | } 24 | 25 | private static JSValue HasPropertyWithUtf8StyleString(JSCallbackArgs args) 26 | { 27 | JSValue obj = args[0]; 28 | JSValue key = args[1]; 29 | return obj.HasProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8())); 30 | } 31 | 32 | private static JSValue HasPropertyWithCSharpStyleString(JSCallbackArgs args) 33 | { 34 | JSValue obj = args[0]; 35 | JSValue key = args[1]; 36 | return obj.HasProperty((string)key); 37 | } 38 | 39 | private static JSValue HasPropertyWithUInt32(JSCallbackArgs args) 40 | { 41 | JSValue obj = args[0]; 42 | JSValue key = args[1]; 43 | return obj.HasProperty((uint)key); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/has_property.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test (binding) { 11 | function testHasProperty (nativeHasProperty) { 12 | const obj = { one: 1 }; 13 | 14 | Object.defineProperty(obj, 'two', { value: 2 }); 15 | 16 | assert.strictEqual(nativeHasProperty(obj, 'one'), true); 17 | assert.strictEqual(nativeHasProperty(obj, 'two'), true); 18 | assert.strictEqual('toString' in obj, true); 19 | assert.strictEqual(nativeHasProperty(obj, 'toString'), true); 20 | } 21 | 22 | function testShouldThrowErrorIfKeyIsInvalid (nativeHasProperty) { 23 | assert.throws(() => { 24 | nativeHasProperty(undefined, 'test'); 25 | }, /Cannot convert undefined or null to object/); 26 | } 27 | 28 | const objectWithInt32Key = { 12: 101 }; 29 | assert.strictEqual(binding.object.hasPropertyWithUInt32(objectWithInt32Key, 12), true); 30 | 31 | testHasProperty(binding.object.hasPropertyWithNapiValue); 32 | testHasProperty(binding.object.hasPropertyWithNapiWrapperValue); 33 | testHasProperty(binding.object.hasPropertyWithUtf8StyleString); 34 | testHasProperty(binding.object.hasPropertyWithCSharpStyleString); 35 | 36 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasPropertyWithNapiValue); 37 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasPropertyWithNapiWrapperValue); 38 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasPropertyWithUtf8StyleString); 39 | testShouldThrowErrorIfKeyIsInvalid(binding.object.hasPropertyWithCSharpStyleString); 40 | } 41 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/object_freeze_seal.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | 6 | namespace Microsoft.JavaScript.NodeApiTest; 7 | 8 | public partial class TestObjectFreezeSeal : TestHelper, ITestObject 9 | { 10 | private static JSValue Freeze(JSCallbackArgs args) 11 | { 12 | JSValue obj = args[0]; 13 | obj.Freeze(); 14 | return true; 15 | } 16 | 17 | private static JSValue Seal(JSCallbackArgs args) 18 | { 19 | JSValue obj = args[0]; 20 | obj.Seal(); 21 | return true; 22 | } 23 | 24 | public JSObject Init() => new() 25 | { 26 | Method(Freeze), 27 | Method(Seal), 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/object_freeze_seal.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test(binding) { 11 | { 12 | const obj = { x: 'a', y: 'b', z: 'c' }; 13 | assert.strictEqual(binding.objectFreezeSeal.freeze(obj), true); 14 | assert.strictEqual(Object.isFrozen(obj), true); 15 | assert.throws(() => { 16 | obj.x = 10; 17 | }, /Cannot assign to read only property 'x' of object '#/); 18 | assert.throws(() => { 19 | obj.w = 15; 20 | }, /Cannot add property w, object is not extensible/); 21 | assert.throws(() => { 22 | delete obj.x; 23 | }, /Cannot delete property 'x' of #/); 24 | } 25 | 26 | { 27 | const obj = new Proxy({ x: 'a', y: 'b', z: 'c' }, { 28 | preventExtensions() { 29 | throw new Error('foo'); 30 | } 31 | }); 32 | 33 | assert.throws(() => { 34 | binding.objectFreezeSeal.freeze(obj); 35 | }, /foo/); 36 | } 37 | 38 | { 39 | const obj = { x: 'a', y: 'b', z: 'c' }; 40 | assert.strictEqual(binding.objectFreezeSeal.seal(obj), true); 41 | assert.strictEqual(Object.isSealed(obj), true); 42 | assert.throws(() => { 43 | obj.w = 'd'; 44 | }, /Cannot add property w, object is not extensible/); 45 | assert.throws(() => { 46 | delete obj.x; 47 | }, /Cannot delete property 'x' of #/); 48 | // Sealed objects allow updating existing properties, 49 | // so this should not throw. 50 | obj.x = 'd'; 51 | } 52 | 53 | { 54 | const obj = new Proxy({ x: 'a', y: 'b', z: 'c' }, { 55 | preventExtensions() { 56 | throw new Error('foo'); 57 | } 58 | }); 59 | 60 | assert.throws(() => { 61 | binding.objectFreezeSeal.seal(obj); 62 | }, /foo/); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/set_property.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | using Microsoft.JavaScript.NodeApi.Runtime; 6 | 7 | namespace Microsoft.JavaScript.NodeApiTest; 8 | 9 | public partial class TestObject 10 | { 11 | private static JSValue SetPropertyWithNapiValue(JSCallbackArgs args) 12 | { 13 | JSValue obj = args[0]; 14 | JSValue key = args[1]; 15 | JSValue value = args[2]; 16 | obj.SetProperty((JSRuntime.napi_value)key, value); 17 | return JSValue.Undefined; 18 | } 19 | 20 | private static JSValue SetPropertyWithNapiWrapperValue(JSCallbackArgs args) 21 | { 22 | JSValue obj = args[0]; 23 | JSValue key = args[1]; 24 | JSValue value = args[2]; 25 | obj.SetProperty(key, value); 26 | return JSValue.Undefined; 27 | } 28 | 29 | private static JSValue SetPropertyWithUtf8StyleString(JSCallbackArgs args) 30 | { 31 | JSValue obj = args[0]; 32 | JSValue key = args[1]; 33 | JSValue value = args[2]; 34 | obj.SetProperty(JSValue.CreateStringUtf8(key.GetValueStringUtf8()), value); 35 | return JSValue.Undefined; 36 | } 37 | 38 | private static JSValue SetPropertyWithCSharpStyleString(JSCallbackArgs args) 39 | { 40 | JSValue obj = args[0]; 41 | JSValue key = args[1]; 42 | JSValue value = args[2]; 43 | obj.SetProperty((string)key, value); 44 | return JSValue.Undefined; 45 | } 46 | 47 | private static JSValue SetPropertyWithUInt32(JSCallbackArgs args) 48 | { 49 | JSValue obj = args[0]; 50 | JSValue key = args[1]; 51 | JSValue value = args[2]; 52 | obj.SetProperty((uint)key, value); 53 | return JSValue.Undefined; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/set_property.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test(binding) { 11 | function testSetProperty(nativeSetProperty, key = 'test') { 12 | const obj = {}; 13 | nativeSetProperty(obj, key, 1); 14 | assert.strictEqual(obj[key], 1); 15 | } 16 | 17 | function testShouldThrowErrorIfKeyIsInvalid(nativeSetProperty) { 18 | assert.throws(() => { 19 | nativeSetProperty(undefined, 'test', 1); 20 | }, /Cannot convert undefined or null to object/); 21 | } 22 | 23 | testSetProperty(binding.object.setPropertyWithNapiValue); 24 | testSetProperty(binding.object.setPropertyWithNapiWrapperValue); 25 | testSetProperty(binding.object.setPropertyWithUtf8StyleString); 26 | testSetProperty(binding.object.setPropertyWithCSharpStyleString); 27 | testSetProperty(binding.object.setPropertyWithUInt32, 12); 28 | 29 | testShouldThrowErrorIfKeyIsInvalid(binding.object.setPropertyWithNapiValue); 30 | testShouldThrowErrorIfKeyIsInvalid(binding.object.setPropertyWithNapiWrapperValue); 31 | testShouldThrowErrorIfKeyIsInvalid(binding.object.setPropertyWithUtf8StyleString); 32 | testShouldThrowErrorIfKeyIsInvalid(binding.object.setPropertyWithCSharpStyleString); 33 | } 34 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/subscript_operator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | using Microsoft.JavaScript.NodeApi; 5 | 6 | namespace Microsoft.JavaScript.NodeApiTest; 7 | 8 | public partial class TestObject 9 | { 10 | private static JSValue SubscriptGetWithUtf8StyleString(JSCallbackArgs args) 11 | { 12 | JSValue obj = args[0]; 13 | byte[] key = args[1].GetValueStringUtf8(); 14 | return obj[JSValue.CreateStringUtf8(key)]; 15 | } 16 | 17 | private static JSValue SubscriptGetWithCSharpStyleString(JSCallbackArgs args) 18 | { 19 | JSValue obj = args[0]; 20 | string key = (string)args[1]; 21 | return obj[key]; 22 | } 23 | 24 | private static JSValue SubscriptGetAtIndex(JSCallbackArgs args) 25 | { 26 | JSValue obj = args[0]; 27 | uint index = (uint)args[1]; 28 | return obj[index]; 29 | } 30 | 31 | private static JSValue SubscriptSetWithUtf8StyleString(JSCallbackArgs args) 32 | { 33 | JSValue obj = args[0]; 34 | byte[] key = args[1].GetValueStringUtf8(); 35 | JSValue value = args[2]; 36 | obj[JSValue.CreateStringUtf8(key)] = value; 37 | return JSValue.Undefined; 38 | } 39 | 40 | private static JSValue SubscriptSetWithCSharpStyleString(JSCallbackArgs args) 41 | { 42 | JSValue obj = args[0]; 43 | string key = (string)args[1]; 44 | JSValue value = args[2]; 45 | obj[key] = value; 46 | return JSValue.Undefined; 47 | } 48 | 49 | private static JSValue SubscriptSetAtIndex(JSCallbackArgs args) 50 | { 51 | JSValue obj = args[0]; 52 | uint index = (uint)args[1]; 53 | JSValue value = args[2]; 54 | obj[index] = value; 55 | return JSValue.Undefined; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/object/subscript_operator.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | 'use strict'; 5 | 6 | const assert = require('assert'); 7 | 8 | module.exports = require('../../common').runTest(test); 9 | 10 | function test(binding) { 11 | function testProperty(obj, key, value, nativeGetProperty, nativeSetProperty) { 12 | nativeSetProperty(obj, key, value); 13 | assert.strictEqual(nativeGetProperty(obj, key), value); 14 | } 15 | 16 | testProperty({}, 'key', 'value', binding.object.subscriptGetWithUtf8StyleString, binding.object.subscriptSetWithUtf8StyleString); 17 | testProperty({ key: 'override me' }, 'key', 'value', binding.object.subscriptGetWithCSharpStyleString, binding.object.subscriptSetWithCSharpStyleString); 18 | testProperty({}, 0, 'value', binding.object.subscriptGetAtIndex, binding.object.subscriptSetAtIndex); 19 | testProperty({ key: 'override me' }, 0, 'value', binding.object.subscriptGetAtIndex, binding.object.subscriptSetAtIndex); 20 | } 21 | -------------------------------------------------------------------------------- /test/TestCases/node-addon-api/testUtil.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | // Run each test function in sequence, 5 | // with an async delay and GC call between each. 6 | 7 | function tick(x) { 8 | return new Promise((resolve) => { 9 | setImmediate(function ontick() { 10 | if (--x === 0) { 11 | resolve(); 12 | } else { 13 | setImmediate(ontick); 14 | } 15 | }); 16 | }); 17 | } 18 | 19 | async function runGCTests(tests) { 20 | // Break up test list into a list of lists of the form 21 | // [ [ 'test name', function() {}, ... ], ..., ]. 22 | const testList = []; 23 | let currentTest; 24 | for (const item of tests) { 25 | if (typeof item === 'string') { 26 | currentTest = []; 27 | testList.push(currentTest); 28 | } 29 | currentTest.push(item); 30 | } 31 | 32 | for (const test of testList) { 33 | await (async function (test) { 34 | let title; 35 | for (let i = 0; i < test.length; i++) { 36 | if (i === 0) { 37 | title = test[i]; 38 | } else { 39 | try { 40 | test[i](); 41 | } catch (e) { 42 | console.error('Test failed: ' + title); 43 | throw e; 44 | } 45 | if (i < tests.length - 1) { 46 | global.gc(); 47 | await tick(10); 48 | } 49 | } 50 | } 51 | })(test); 52 | } 53 | } 54 | 55 | module.exports = { 56 | runGCTests 57 | }; 58 | -------------------------------------------------------------------------------- /test/TestCases/projects/.gitignore: -------------------------------------------------------------------------------- 1 | !*.csproj 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /test/TestCases/projects/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bin 6 | false 7 | false 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/TestCases/projects/Module.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | #pragma warning disable CA1050 // Declare types in namespaces 5 | #pragma warning disable CA1822 // Mark members as static 6 | 7 | using Microsoft.JavaScript.NodeApi; 8 | 9 | [assembly: JSExport] 10 | 11 | // Tests exporting top-level properties on the JS module. 12 | [JSExport(false)] 13 | public static class ModuleProperties 14 | { 15 | [JSExport] 16 | public static string ReadOnlyProperty { get; } = "ROProperty"; 17 | 18 | [JSExport] 19 | public static string ReadWriteProperty { get; set; } = "RWProperty"; 20 | 21 | [JSExport] 22 | public static string Method(string arg) => arg; 23 | } 24 | 25 | public class ModuleClass 26 | { 27 | public ModuleClass(string value) 28 | { 29 | Property = value; 30 | } 31 | 32 | public string Property { get; } 33 | 34 | public string Method(string arg) => arg; 35 | } 36 | 37 | namespace TestNamespace 38 | { 39 | [JSExport("default")] 40 | public static class DefaultClass 41 | { 42 | public static string Method(string arg) => arg; 43 | 44 | public static TestEnum EnumProperty { get; set; } 45 | } 46 | 47 | [JSExport("ModuleEnum")] 48 | public enum TestEnum 49 | { 50 | None = 0, 51 | One = 1, 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/js-cjs-dynamic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/net472.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | const dotnet = require('node-api-dotnet/net472'); 6 | 7 | require('./bin/mscorlib'); 8 | 9 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 10 | assert.strictEqual(dotnet.frameworkMoniker, 'net472'); 11 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/net8.0.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | const dotnet = require('node-api-dotnet/net8.0'); 6 | 7 | require('./bin/System.Runtime'); 8 | require('./bin/System.Console'); 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net8.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/net9.0.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | const dotnet = require('node-api-dotnet/net9.0'); 6 | 7 | require('./bin/System.Runtime'); 8 | require('./bin/System.Console'); 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net9.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-js-cjs-dynamic", 3 | "scripts": { 4 | "compile": "tsc" 5 | }, 6 | "dependencies": { 7 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 8 | }, 9 | "devDependencies": { 10 | "@types/node": "^18.16.14", 11 | "typescript": "~5.5.4" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true 8 | }, 9 | "include": ["*.js", "bin/*.js"], 10 | "exclude": ["net472.js", "node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-dynamic/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true 8 | }, 9 | "include": ["net472.js", "bin/*.js"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-module/js-cjs-module.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-js-cjs-module", 3 | "scripts": { 4 | "compile": "tsc" 5 | }, 6 | "dependencies": { 7 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 8 | }, 9 | "devDependencies": { 10 | "@types/node": "^18.16.14", 11 | "typescript": "~5.5.4" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-module/test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | const assert = require('assert'); 5 | const testModule = require('./bin/js-cjs-module'); 6 | 7 | assert.strictEqual(testModule.readOnlyProperty, 'ROProperty'); 8 | assert.strictEqual(testModule.readWriteProperty, 'RWProperty'); 9 | testModule.readWriteProperty = 'test'; 10 | assert.strictEqual(testModule.readWriteProperty, 'test'); 11 | assert.strictEqual(typeof testModule.method, 'function'); 12 | assert.strictEqual(testModule.method('test'), 'test'); 13 | 14 | const { ModuleClass } = testModule; 15 | assert.strictEqual(typeof new ModuleClass('test'), 'object'); 16 | assert.strictEqual(new ModuleClass('test').property, 'test'); 17 | assert.strictEqual(new ModuleClass('test').method('test2'), 'test2'); 18 | 19 | const { ModuleEnum } = testModule; 20 | assert.strictEqual(typeof ModuleEnum, 'object'); 21 | assert.strictEqual(ModuleEnum.None, 0); 22 | assert.strictEqual(ModuleEnum.One, 1); 23 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true 8 | }, 9 | "include": ["*.js", "bin/*.js"], 10 | "exclude": ["net472.js", "node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-cjs-module/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true 8 | }, 9 | "include": ["net472.js", "bin/*.js"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/js-esm-dynamic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/net472.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import assert from 'assert'; 5 | import dotnet from 'node-api-dotnet/net472'; 6 | 7 | import './bin/mscorlib.js'; 8 | 9 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 10 | assert.strictEqual(dotnet.frameworkMoniker, 'net472'); 11 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/net8.0.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import assert from 'assert'; 5 | import dotnet from 'node-api-dotnet/net8.0'; 6 | 7 | import './bin/System.Runtime.js'; 8 | import './bin/System.Console.js'; 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net8.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/net9.0.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import assert from 'assert'; 5 | import dotnet from 'node-api-dotnet/net9.0'; 6 | 7 | import './bin/System.Runtime.js'; 8 | import './bin/System.Console.js'; 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net9.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-js-esm-dynamic", 3 | "type": "module", 4 | "scripts": { 5 | "compile": "tsc" 6 | }, 7 | "dependencies": { 8 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 9 | }, 10 | "devDependencies": { 11 | "@types/node": "^18.16.14", 12 | "typescript": "~5.5.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true 8 | }, 9 | "include": ["*.js", "bin/*.js"], 10 | "exclude": ["net472.js", "node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-dynamic/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true 8 | }, 9 | "include": ["net472.js", "bin/*.js"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-module/js-esm-module.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-js-esm-module", 3 | "type": "module", 4 | "scripts": { 5 | "compile": "tsc" 6 | }, 7 | "dependencies": { 8 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 9 | }, 10 | "devDependencies": { 11 | "@types/node": "^18.16.14", 12 | "typescript": "~5.5.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-module/test.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import assert from 'assert'; 5 | import DefaultClass, { 6 | method, 7 | readOnlyProperty, 8 | ModuleClass, 9 | ModuleEnum, 10 | } from './bin/js-esm-module.js'; 11 | 12 | assert.strictEqual(typeof DefaultClass, 'object'); 13 | assert.strictEqual(DefaultClass.method('test'), 'test'); 14 | 15 | assert.strictEqual(readOnlyProperty, 'ROProperty'); 16 | assert.strictEqual(typeof method, 'function'); 17 | assert.strictEqual(method('test'), 'test'); 18 | 19 | assert.strictEqual(typeof new ModuleClass('test'), 'object'); 20 | assert.strictEqual(new ModuleClass('test').property, 'test'); 21 | assert.strictEqual(new ModuleClass('test').method('test2'), 'test2'); 22 | 23 | assert.strictEqual(typeof ModuleEnum, 'object'); 24 | assert.strictEqual(ModuleEnum.None, 0); 25 | assert.strictEqual(ModuleEnum.One, 1); 26 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true, 8 | "esModuleInterop": true 9 | }, 10 | "include": ["*.js", "bin/*.js"], 11 | "exclude": ["net472.js", "node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /test/TestCases/projects/js-esm-module/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "noEmit": true, 8 | "esModuleInterop": true 9 | }, 10 | "include": ["net472.js", "bin/*.js"], 11 | "exclude": ["node_modules"] 12 | } 13 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/net472.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import * as dotnet from 'node-api-dotnet/net472'; 6 | 7 | import './bin/mscorlib'; 8 | 9 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 10 | assert.strictEqual(dotnet.frameworkMoniker, 'net472'); 11 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/net8.0.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import * as dotnet from 'node-api-dotnet/net8.0'; 6 | 7 | import './bin/System.Runtime'; 8 | import './bin/System.Console'; 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net8.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/net9.0.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import * as dotnet from 'node-api-dotnet/net9.0'; 6 | 7 | import './bin/System.Runtime'; 8 | import './bin/System.Console'; 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net9.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-ts-cjs-dynamic", 3 | "scripts": { 4 | "compile": "tsc" 5 | }, 6 | "dependencies": { 7 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 8 | }, 9 | "devDependencies": { 10 | "@types/node": "^18.16.14", 11 | "typescript": "~5.5.4" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/ts-cjs-dynamic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "outDir": "." 6 | }, 7 | "include": ["*.ts"], 8 | "exclude": ["net472.ts", "node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-dynamic/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "allowJs": true, 6 | "checkJs": true, 7 | "outDir": "out" 8 | }, 9 | "include": ["net472.ts", "bin/*.js"], 10 | "exclude": ["node_modules"] 11 | } 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-module/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-js-cjs-module", 3 | "scripts": { 4 | "compile": "tsc" 5 | }, 6 | "dependencies": { 7 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 8 | }, 9 | "devDependencies": { 10 | "@types/node": "^18.16.14", 11 | "typescript": "~5.5.4" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-module/test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import * as testModule from './bin/ts-cjs-module'; 6 | 7 | assert.strictEqual(testModule.readOnlyProperty, 'ROProperty'); 8 | assert.strictEqual(typeof testModule.method, 'function'); 9 | assert.strictEqual(testModule.method('test'), 'test'); 10 | 11 | const { ModuleClass } = testModule; 12 | assert.strictEqual(typeof new ModuleClass('test'), 'object'); 13 | assert.strictEqual(new ModuleClass('test').property, 'test'); 14 | assert.strictEqual(new ModuleClass('test').method('test2'), 'test2'); 15 | 16 | const { ModuleEnum } = testModule; 17 | assert.strictEqual(typeof ModuleEnum, 'object'); 18 | assert.strictEqual(ModuleEnum.None, 0); 19 | assert.strictEqual(ModuleEnum.One, 1); 20 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-module/ts-cjs-module.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "outDir": "." 6 | }, 7 | "include": ["*.ts"], 8 | "exclude": ["net472.ts", "node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-cjs-module/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "target": "ES2022", 5 | "outDir": "." 6 | }, 7 | "include": ["net472.ts"], 8 | "exclude": ["node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/net472.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import dotnet from 'node-api-dotnet/net472'; 6 | 7 | import './bin/mscorlib.js'; 8 | 9 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 10 | assert.strictEqual(dotnet.frameworkMoniker, 'net472'); 11 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/net8.0.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import dotnet from 'node-api-dotnet/net8.0'; 6 | 7 | import './bin/System.Runtime.js'; 8 | import './bin/System.Console.js'; 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net8.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/net9.0.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import * as assert from 'assert'; 5 | import dotnet from 'node-api-dotnet/net9.0'; 6 | 7 | import './bin/System.Runtime.js'; 8 | import './bin/System.Console.js'; 9 | 10 | dotnet.System.Console.WriteLine(`Hello from .NET ${dotnet.runtimeVersion}!`); 11 | assert.strictEqual(dotnet.frameworkMoniker, 'net9.0'); 12 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-ts-esm-dynamic", 3 | "type": "module", 4 | "scripts": { 5 | "compile": "tsc" 6 | }, 7 | "dependencies": { 8 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 9 | }, 10 | "devDependencies": { 11 | "@types/node": "^18.16.14", 12 | "typescript": "~5.5.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/ts-esm-dynamic.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "outDir": "." 6 | }, 7 | "include": ["*.ts"], 8 | "exclude": ["net472.ts", "node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-dynamic/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "outDir": "." 6 | }, 7 | "include": ["net472.ts"], 8 | "exclude": ["node_modules"] 9 | } 10 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-module/.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-module/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-tests-js-esm-module", 3 | "type": "module", 4 | "scripts": { 5 | "compile": "tsc" 6 | }, 7 | "dependencies": { 8 | "node-api-dotnet": "file:../../../../out/pkg/node-api-dotnet" 9 | }, 10 | "devDependencies": { 11 | "@types/node": "^18.16.14", 12 | "typescript": "~5.5.4" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-module/test.ts: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. 2 | // Licensed under the MIT License. 3 | 4 | import assert from 'assert'; 5 | import DefaultClass, { 6 | method, 7 | readOnlyProperty, 8 | ModuleClass, 9 | ModuleEnum, 10 | } from './bin/ts-esm-module.js'; 11 | 12 | assert.strictEqual(typeof DefaultClass, 'object'); 13 | assert.strictEqual(DefaultClass.method('test'), 'test'); 14 | 15 | assert.strictEqual(readOnlyProperty, 'ROProperty'); 16 | assert.strictEqual(typeof method, 'function'); 17 | assert.strictEqual(method('test'), 'test'); 18 | 19 | assert.strictEqual(typeof new ModuleClass('test'), 'object'); 20 | assert.strictEqual(new ModuleClass('test').property, 'test'); 21 | assert.strictEqual(new ModuleClass('test').method('test2'), 'test2'); 22 | 23 | assert.strictEqual(typeof ModuleEnum, 'object'); 24 | assert.strictEqual(ModuleEnum.None, 0); 25 | assert.strictEqual(ModuleEnum.One, 1); 26 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-module/ts-esm-module.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-module/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "outDir": ".", 6 | "esModuleInterop": true 7 | }, 8 | "include": ["*.ts"], 9 | "exclude": ["net472.ts", "node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /test/TestCases/projects/ts-esm-module/tsconfig.net472.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "Node16", 4 | "target": "ES2022", 5 | "outDir": ".", 6 | "esModuleInterop": true 7 | }, 8 | "include": ["net472.ts"], 9 | "exclude": ["node_modules"] 10 | } 11 | -------------------------------------------------------------------------------- /test/test-cjs-package/index.js: -------------------------------------------------------------------------------- 1 | exports.test = function test() { return 'test'; } 2 | -------------------------------------------------------------------------------- /test/test-cjs-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-test-cjs-package", 3 | "type": "commonjs", 4 | "main": "index.js" 5 | } 6 | -------------------------------------------------------------------------------- /test/test-esm-package/feature.js: -------------------------------------------------------------------------------- 1 | export function test2() { return 'test2'; } 2 | -------------------------------------------------------------------------------- /test/test-esm-package/index.js: -------------------------------------------------------------------------------- 1 | export function test() { return 'test'; } 2 | -------------------------------------------------------------------------------- /test/test-esm-package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-api-dotnet-test-cjs-package", 3 | "type": "module", 4 | "exports": { 5 | ".": "./index.js", 6 | "./feature": "./feature.js" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/test-module.cjs: -------------------------------------------------------------------------------- 1 | exports.test = function test() { return 'test'; } 2 | -------------------------------------------------------------------------------- /test/test-module.mjs: -------------------------------------------------------------------------------- 1 | export function test() { return 'test'; } 2 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | 4 | "version": "0.9", 5 | 6 | "publicReleaseRefSpec": [ 7 | "^refs/heads/main$", 8 | "^refs/heads/v\\d+(?:.\\d+)?$", 9 | "^refs/heads/releases/.+$" 10 | ], 11 | "cloudBuild": { 12 | "setVersionVariables": true, 13 | "buildNumber": { 14 | "enabled": true, 15 | "includeCommitId": { 16 | "when": "nonPublicReleaseOnly", 17 | "where": "fourthVersionComponent" 18 | } 19 | } 20 | } 21 | } 22 | --------------------------------------------------------------------------------