();
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 |
--------------------------------------------------------------------------------