diff --git a/docs/contribute/plugin/_category_.json b/docs/contribute/plugin/_category_.json index fcdcda0b..d5890d31 100644 --- a/docs/contribute/plugin/_category_.json +++ b/docs/contribute/plugin/_category_.json @@ -3,6 +3,6 @@ "position": 3, "link": { "type": "generated-index", - "description": "we will learn how to the WasmEdge Plugin System." + "description": "We will learn how to develop the plug-ins for WasmEdge." } } diff --git a/docs/contribute/plugin/develop_plugin_c.md b/docs/contribute/plugin/develop_plugin_c.md index 446686fc..1784380b 100644 --- a/docs/contribute/plugin/develop_plugin_c.md +++ b/docs/contribute/plugin/develop_plugin_c.md @@ -4,27 +4,62 @@ sidebar_position: 2 # Develop WasmEdge Plug-in in C API -WasmEdge provides a C++ based API for registering extension modules and host functions. While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, the plugin API allows such extensions to be incorporated into WasmEdge's own building and releasing process. +By developing a plug-in, one can extend the functionality of WasmEdge and customize it to suit specific needs. WasmEdge provides a C based API for registering extension modules and host functions. While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, the plug-in API allows such extensions to be incorporated into WasmEdge's building and releasing process. Here is a flowchart showing all the steps needed for developing WasmEdge Plug-in - + +```mermaid +graph LR; +A[Developing WasmEdge Plug-in in C] +A --> B(Set up the development environment) +A --> C(Create a WasmEdge plug-in project) +A --> D(Write the plug-in code) +A --> E(Build the plug-in) +A --> F(Test and debug the plug-in) +B --> E +C --> D +D --> E +``` + +This flowchart illustrates developing a WasmEdge plug-in, showcasing the steps from choosing a programming language to finalizing and releasing the plug-in. + +## Set up the development environment + +To start developing WasmEdge plug-ins, it is essential to correctly set up the development environment. This section provides step-by-step instructions for WasmEdge plug-in development - + +**Install a WasmEdge runtime**: You can download the latest version of WasmEdge from [GitHub repository](https://github.com/wasmEdge/wasmEdge). Follow the instructions in the [installation guide](../../start/install.md) for your specific operating system. -## Prerequisites +After installing WasmEdge, you need to set up the build environment. If you're using Linux or other platforms, you can follow the instructions in the [build environment setup guide](../source/os/linux.md). -For developing the WasmEdge plug-in in C API, please [install WasmEdge](../../start/install.md#install) first. +## Create a WasmEdge plug-in project -## Example +To create a WasmEdge plug-in project, follow these steps: -Assume that the plug-in example is in the file `testplugin.c`. +- **Set up the project directory**: Create a directory structure for your plug-in project. You can use a standard structure for the chosen language or create your structure. To create a project directory structure, use the following commands: -### Host Functions + ```bash + mkdir testplugin + cd testplugin + mkdir src include build + ``` -The goal of the plug-in is to provide the host functions which can be imported when instantiating WASM. +- **Add configuration files**: Add configuration files specifying the plug-in name, version, and dependencies. The specific files and content depend on the chosen programming language and build system. -Therefore, developers can implement their plug-in host functions first, as the same as the [host functions in WasmEdge C API](../../embed/c/reference/latest.md#host-functions). +- **Add any necessary libraries or dependencies**: Include any required libraries or dependencies for your plug-in. Modify the configuration files created in the previous step to include the required dependencies. + +## Write the plug-in code + +To create a plug-in with host functions and modules, follow these steps: + +- **Implement host function definitions**: In this step, you must define the host functions that will be imported when instantiating the WASM module. These functions will perform specific operations and return results. + + Therefore, developers can first implement their plug-in host functions, like the [host functions in WasmEdge C API](/embed/c/reference/latest.md#host-functions). :::note -For the more details about the [external data](../../embed/c/host_function.md#host-data) and [calling frame context](../../embed/c/host_function.md#calling-frame-context), please refer to the host function guide. +For more details about the [external data](/embed/c/host_function.md#host-data) and [calling frame context](/embed/c/host_function.md#calling-frame-context), please refer to the host function guide. ::: +Here's an example of two host functions, `HostFuncAdd` and `HostFuncSub`, that add and subtract two `int32_t` numbers, respectively: + ```c #include @@ -51,152 +86,147 @@ WasmEdge_Result HostFuncSub(void *Data, } ``` -### Host Modules +- **Implement the module creation functions**: In this step, you need to implement the module creation function that creates an instance of the module. This function will be called when the plug-in is loaded. -Then developers should implement the module creation functions. + Here's an example of a module creation function named `CreateTestModule`: -Noticed that there can be several module instances in a plug-in shared library. Here take a module named as `wasmedge_plugintest_c_module` for the example. - -```c -/* The creation function of creating the module instance. */ -WasmEdge_ModuleInstanceContext * -CreateTestModule(const struct WasmEdge_ModuleDescriptor *Desc) { - /* - * The `Desc` is the const pointer to the module descriptor struct: - * - * typedef struct WasmEdge_ModuleDescriptor { - * const char *Name; - * const char *Description; - * WasmEdge_ModuleInstanceContext *(*Create)( - * const struct WasmEdge_ModuleDescriptor *); - * } WasmEdge_ModuleDescriptor; - * - * Developers can get the name and the description from this descriptor. - */ - - /* Exported module name of this module instance. */ - WasmEdge_String ModuleName = - WasmEdge_StringCreateByCString("wasmedge_plugintest_c_module"); - WasmEdge_ModuleInstanceContext *Mod = - WasmEdge_ModuleInstanceCreate(ModuleName); - WasmEdge_StringDelete(ModuleName); - - WasmEdge_String FuncName; - WasmEdge_FunctionTypeContext *FType; - WasmEdge_FunctionInstanceContext *FuncCxt; - enum WasmEdge_ValType ParamTypes[2], ReturnTypes[1]; - ParamTypes[0] = WasmEdge_ValType_I32; - ParamTypes[1] = WasmEdge_ValType_I32; - ReturnTypes[0] = WasmEdge_ValType_I32; - - /* Create and add the host function instances into the module instance. */ - FType = WasmEdge_FunctionTypeCreate(ParamTypes, 2, ReturnTypes, 1); - FuncName = WasmEdge_StringCreateByCString("add"); - FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncAdd, NULL, 0); - WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); - WasmEdge_StringDelete(FuncName); - FuncName = WasmEdge_StringCreateByCString("sub"); - FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncSub, NULL, 0); - WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); - WasmEdge_StringDelete(FuncName); - WasmEdge_FunctionTypeDelete(FType); - - return Mod; -} -``` - -### Plug-in Descriptions - -For constructing the plug-in, developers should supply the descriptions of this plug-in and the modules. - -```c -/* The module descriptor array. There can be multiple modules in a plug-in. */ -static WasmEdge_ModuleDescriptor ModuleDesc[] = {{ + ```c + /* The creation function of creating the module instance. */ + WasmEdge_ModuleInstanceContext * + CreateTestModule(const struct WasmEdge_ModuleDescriptor *Desc) { /* - * Module name. This is the name for searching and creating the module - * instance context by the `WasmEdge_PluginCreateModule()` API. - */ - .Name = "wasmedge_plugintest_c_module", - /* Module description. */ - .Description = "This is for the plugin tests in WasmEdge C API.", - /* Creation function pointer. */ - .Create = CreateTestModule, -}}; - -/* The plug-in descriptor */ -static WasmEdge_PluginDescriptor Desc[] = {{ - /* - * Plug-in name. This is the name for searching the plug-in context by the - * `WasmEdge_PluginFind()` API. - */ - .Name = "wasmedge_plugintest_c", - /* Plug-in description. */ - .Description = "", - /* Plug-in API version. */ - .APIVersion = WasmEdge_Plugin_CurrentAPIVersion, - /* Plug-in version. Developers can define the version of this plug-in. */ - .Version = - { - .Major = 0, - .Minor = 1, - .Patch = 0, - .Build = 0, - }, - /* Module count in this plug-in. */ - .ModuleCount = 1, - /* Plug-in option description count in this plug-in (Work in progress). */ - .ProgramOptionCount = 0, - /* Pointer to the module description array. */ - .ModuleDescriptions = ModuleDesc, - /* Pointer to the plug-in option description array (Work in progress). */ - .ProgramOptions = NULL, -}}; -``` - -### Plug-in Options - -WORK IN PROGRESS. This section is reserved for the feature in the future. - -### Implement the Get Descriptor API - -The final step is to implement the `WasmEdge_Plugin_GetDescriptor()` API to return the plug-in descriptor. - -```c -WASMEDGE_CAPI_PLUGIN_EXPORT const WasmEdge_PluginDescriptor * -WasmEdge_Plugin_GetDescriptor(void) { - return &Desc; -} -``` - -## Build - -To build the plug-in shared library, developers can choose to build stand-alone by the compiler or use cmake. - -### Build with Command - -```bash -clang -shared -std=c11 -DWASMEDGE_PLUGIN testplugin.c -lwasmedge -o libwasmedgePluginTest.so -``` - -### Build in CMake - -```cmake -add_library(wasmedgePluginTest - SHARED - testplugin.c -) - -set_target_properties(wasmedgePluginTest PROPERTIES - C_STANDARD 11 -) - -target_compile_options(wasmedgePluginTest - PUBLIC - -DWASMEDGE_PLUGIN -) - -target_link_libraries(wasmedgePluginTest - PRIVATE - wasmedge -) -``` + * The `Desc` is the const pointer to the module descriptor struct: + * + * typedef struct WasmEdge_ModuleDescriptor { + * const char *Name; + * const char *Description; + * WasmEdge_ModuleInstanceContext *(*Create)( + * const struct WasmEdge_ModuleDescriptor *); + * } WasmEdge_ModuleDescriptor; + * + * Developers can get the name and description from this descriptor. + */ + + /* Exported module name of this module instance. */ + WasmEdge_String ModuleName = + WasmEdge_StringCreateByCString("wasmedge_plugintest_c_module"); + WasmEdge_ModuleInstanceContext *Mod = + WasmEdge_ModuleInstanceCreate(ModuleName); + WasmEdge_StringDelete(ModuleName); + + WasmEdge_String FuncName; + WasmEdge_FunctionTypeContext *FType; + WasmEdge_FunctionInstanceContext *FuncCxt; + enum WasmEdge_ValType ParamTypes[2], ReturnTypes[1]; + ParamTypes[0] = WasmEdge_ValType_I32; + ParamTypes[1] = WasmEdge_ValType_I32; + ReturnTypes[0] = WasmEdge_ValType_I32; + + /* Create and add the host function instances into the module instance. */ + FType = WasmEdge_FunctionTypeCreate(ParamTypes, 2, ReturnTypes, 1); + FuncName = WasmEdge_StringCreateByCString("add"); + FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncAdd, NULL, 0); + WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); + WasmEdge_StringDelete(FuncName); + FuncName = WasmEdge_StringCreateByCString("sub"); + FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncSub, NULL, 0); + WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_FunctionTypeDelete(FType); + + return Mod; + } + ``` + + There can be several module instances in a plug-in shared library. Here in the above code snippet, take a module named `wasmedge_plugintest_c_module` for the example. + +- **Supply the plug-in descriptions**- In this step, you need to provide the descriptions of the plug-in and the modules it contains. These descriptions will be used for searching and creating the plug-in and module instances. + + Here's an example of the plug-in and module descriptors: + + ```c + /* The module descriptor array. There can be multiple modules in a plug-in. */ + static WasmEdge_ModuleDescriptor ModuleDesc[] = {{ + /* + * Module name. This is the name for searching and creating the module + * instance context by the `WasmEdge_PluginCreateModule()` API. + */ + .Name = "wasmedge_plugintest_c_module", + /* Module description. */ + .Description = "This is for the plugin tests in WasmEdge C API.", + /* Creation function pointer. */ + .Create = CreateTestModule, + }}; + + /* The plug-in descriptor */ + static WasmEdge_PluginDescriptor Desc[] = {{ + /* + * Plug-in name. This is the name for searching the plug-in context by the + * `WasmEdge_PluginFind()` API. + */ + .Name = "wasmedge_plugintest_c", + /* Plug-in description. */ + .Description = "", + /* Plug-in API version. */ + .APIVersion = WasmEdge_Plugin_CurrentAPIVersion, + /* Plug-in version. Developers can define the version of this plug-in. */ + .Version = + { + .Major = 0, + .Minor = 1, + .Patch = 0, + .Build = 0, + }, + /* Module count in this plug-in. */ + .ModuleCount = 1, + /* Plug-in option description count in this plug-in (Work in progress). */ + .ProgramOptionCount = 0, + /* Pointer to the module description array. */ + .ModuleDescriptions = ModuleDesc, + /* Pointer to the plug-in option description array (Work in progress). */ + .ProgramOptions = NULL, + }}; + ``` + + These descriptions define the name, description, version, and creation function of the plug-in and the name and description of the module it contains. + +Remember to implement any additional functions or structures your plug-in requires to fulfill its functionality. + +Following these steps and implementing the necessary functions and descriptors, you can create a plug-in with host functions and modules in WasmEdge C API. You can continue developing your plug-in by adding functionality and implementing the desired behavior. + +- **Plug-in option** - _WORK IN PROGRESS. This section is reserved for the feature in the future._ + +## Build your plug-in + +To build the WasmEdge plug-in shared library, you have two options: build it directly using the compiler or CMake. Here are the instructions for both methods: + +- **Build with Command**: if you choose to build the plug-in using the command line, run the following command in the terminal: + + This command compiles the `testplugin.c` file into a shared library named `libwasmedgePluginTest.so`. The `-std=c11` flag sets the C language standard to C11, and the `-DWASMEDGE_PLUGIN` flag defines the WASMEDGE_PLUGIN macro, which can be used in your code. + +- **Build with CMake**: If you prefer to use CMake to build the plug-in, create a `CMakeLists.txt` file in the root directory of your project and add the following content to the CMakeLists.txt file: + + ```cmake + add_library(wasmedgePluginTest + SHARED + testplugin.c + ) + + set_target_properties(wasmedgePluginTest PROPERTIES + C_STANDARD 11 + ) + + target_compile_options(wasmedgePluginTest + PUBLIC + -DWASMEDGE_PLUGIN + ) + + target_link_libraries(wasmedgePluginTest + PRIVATE + wasmedge + ) + ``` + + This CMake configuration sets up a build target called `wasmedgePluginTest`. It compiles the `testplugin.c` file into a shared library. The `C_STANDARD 11` property sets the C language standard to C11. The `target_compile_options` command defines the `WASMEDGE_PLUGIN` macro using the `-DWASMEDGE_PLUGIN` flag. Finally, the `target_link_libraries` command links the wasmedge library to the plug-in. + +Once you have set up either the command-line build or the CMake build, you can execute the corresponding build command or generate build files using CMake, which will compile your plug-in source code and produce the shared library file `(libwasmedgePluginTest.so)`. diff --git a/docs/contribute/plugin/develop_plugin_cpp.md b/docs/contribute/plugin/develop_plugin_cpp.md index a4a63919..7a5e6a07 100644 --- a/docs/contribute/plugin/develop_plugin_cpp.md +++ b/docs/contribute/plugin/develop_plugin_cpp.md @@ -4,170 +4,200 @@ sidebar_position: 3 # Develop WasmEdge Plug-in in C++ API +By developing a plug-in, one can extend the functionality of WasmEdge and customize it to suit specific needs. WasmEdge provides a C based API for registering extension modules and host functions. While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, the plug-in API allows such extensions to be incorporated into WasmEdge's building and releasing process. + :::note -We recommend developers to [develop plug-ins in WasmEdge C API](develop_plugin_c.md). +It is recommended that developers choose the WasmEdge [C API](develop_plugin_c.md) for plug-in development because of the support, compatibility, and flexibility the WasmEdge runtime provides. ::: -## Prerequisites +Here is a flowchart showing all the steps needed for developing WasmEdge Plug-in - + +```mermaid +graph TD; +A[Develop WasmEdge Plug-in in C++ API] +A --> B(Set up development environment) +B --> C(Create project directory) +C --> D(Add configuration files) +D --> E(Install necessary tools and dependencies) +E --> F(Enable specific backends or components) +F --> G(Write plug-in code) +G --> H(Build plug-in) +C --> I(Define plug-in API) +H --> I +I --> J(Compile WasmEdge plug-in) +J --> K(Test and debug plug-in) +``` -For developing the WasmEdge plug-in in internal C++, developers should [build WasmEdge from source](../source/build_from_src.md). +This flowchart illustrates developing a WasmEdge plug-in, showcasing the steps from choosing a programming language to finalizing and releasing the plug-in. -## Example +## Set up a development environment -Assume that the plug-in example is in the file `testplugin.h` and `testplugin.cpp`. +To start developing WasmEdge plug-ins, it is essential to correctly set up the development environment. This section provides step-by-step instructions for WasmEdge plug-in development - -### Host Functions and Modules +**Build WasmEdge from source**: For developing the WasmEdge plug-in in C++, you must build WasmEdge from source. Follow the[build WasmEdge from source](../source/build_from_src.md) for instructions. -The goal of the plug-in is to provide the host functions which can be imported when instantiating WASM. Therefore, developers should implement their plug-in host functions in WasmEdge internal C++ first. Assume that the host function implementations are in the `testplugin.h`. +After installing WasmEdge, you need to set up the build environment. If you're using Linux or other platforms, you can follow the instructions in the [build environment setup guide](../source/os/linux.md). -```cpp -#pragma once +## Create a WasmEdge plug-in project -#include "plugin/plugin.h" +To create a WasmEdge plug-in project, follow these steps: -#include -#include +- **Set up the project directory**: Create a directory structure for your plug-in project. You can use a standard structure for the chosen language or create your structure. To create a project directory structure, use the following commands: -namespace WasmEdge { -namespace Host { + ```bash + mkdir testplugin + cd testplugin + mkdir src include build + ``` -// The environment class. For the register object. -class WasmEdgePluginTestEnv { -public: - WasmEdgePluginTestEnv() noexcept = default; - - static Plugin::PluginRegister Register; -}; - -// The host function base template class. For inheriting the environment class -// reference. -template -class WasmEdgePluginTestFunc : public Runtime::HostFunction { -public: - WasmEdgePluginTestFunc(WasmEdgePluginTestEnv &HostEnv) - : Runtime::HostFunction(0), Env(HostEnv) {} - -protected: - WasmEdgePluginTestEnv &Env; -}; - -// The host function to add 2 int32_t numbers. -class WasmEdgePluginTestFuncAdd - : public WasmEdgePluginTestFunc { -public: - WasmEdgePluginTestFuncAdd(WasmEdgePluginTestEnv &HostEnv) - : WasmEdgePluginTestFunc(HostEnv) {} - Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { - return A + B; - } -}; - -// The host function to sub 2 int32_t numbers. -class WasmEdgePluginTestFuncSub - : public WasmEdgePluginTestFunc { -public: - WasmEdgePluginTestFuncSub(WasmEdgePluginTestEnv &HostEnv) - : WasmEdgePluginTestFunc(HostEnv) {} - Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { - return A - B; - } -}; - -// The host module class. There can be several modules in a plug-in. -class WasmEdgePluginTestModule : public Runtime::Instance::ModuleInstance { -public: - WasmEdgePluginTestModule() - : Runtime::Instance::ModuleInstance("wasmedge_plugintest_cpp_module") { - addHostFunc("add", std::make_unique(Env)); - addHostFunc("sub", std::make_unique(Env)); - } +- **Add necessary libraries or dependencies**: Include any required libraries or dependencies for your plug-in. Modify the configuration files created in the previous step to include the required dependencies. - WasmEdgePluginTestEnv &getEnv() { return Env; } +## Write plug-in code -private: - WasmEdgePluginTestEnv Env; -}; +To create a plug-in with host functions and modules, follow these steps: -} // namespace Host -} // namespace WasmEdge -``` +- **Host Functions and Modules**: The plug-in aims to provide the host functions that can be imported when instantiating WASM. Therefore, developers should first implement their plug-in host functions in WasmEdge internal C++. Assume that the host function implementations are in the `testplugin.h`. -### Creation Functions for Modules + ```cpp + #pragma once -Then developers should implement the module creation functions. Assume that the following implementations are all in the `testplugin.cpp`. + #include "plug-in/plug-in.h" -```cpp -#include "testplugin.h" + #include + #include -namespace WasmEdge { -namespace Host { -namespace { + namespace WasmEdge { + namespace Host { -Runtime::Instance::ModuleInstance * -create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { - // There can be several modules in a plug-in. For that, developers should - // implement several `create` functions for each module. - return new WasmEdgePluginTestModule; -} + // The environment class. For the register object. + class WasmEdgePluginTestEnv { + public: + WasmEdgePluginTestEnv() noexcept = default; -} // namespace -} // namespace Host -} // namespace WasmEdge -``` + static Plugin::PluginRegister Register; + }; -### Plug-in Descriptions + // The host function base template class. For inheriting the environment class + // reference. + template + class WasmEdgePluginTestFunc : public Runtime::HostFunction { + public: + WasmEdgePluginTestFunc(WasmEdgePluginTestEnv &HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} -For constructing the plug-in, developers should supply the descriptions of this plug-in and the modules. + protected: + WasmEdgePluginTestEnv &Env; + }; -```cpp -namespace WasmEdge { -namespace Host { -namespace { - -Plugin::Plugin::PluginDescriptor Descriptor{ - // Plug-in name. This is the name for searching the plug-in context by the - // `WasmEdge_PluginFind()` C API. - .Name = "wasmedge_plugintest_cpp", - // Plug-in description. - .Description = "", - // Plug-in API version. - .APIVersion = Plugin::Plugin::CurrentAPIVersion, - // Plug-in version. - .Version = {0, 10, 0, 0}, - // Module count in this plug-in. - .ModuleCount = 1, - // Pointer to module description array. - .ModuleDescriptions = - // The module descriptor array. - (Plugin::PluginModule::ModuleDescriptor[]){ - { - // Module name. This is the name for searching and creating the - // module instance context by the - // `WasmEdge_PluginCreateModule()` C API. - .Name = "wasmedge_plugintest_cpp_module", - // Module description. - .Description = "This is for the plugin tests in WasmEdge.", - // Creation function pointer. - .Create = create, - }, - }, - // Plug-in options (Work in progress). - .AddOptions = nullptr, -}; - -} // namespace -} // namespace Host -} // namespace WasmEdge -``` + // The host function to add 2 int32_t numbers. + class WasmEdgePluginTestFuncAdd + : public WasmEdgePluginTestFunc { + public: + WasmEdgePluginTestFuncAdd(WasmEdgePluginTestEnv &HostEnv) + : WasmEdgePluginTestFunc(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { + return A + B; + } + }; + + // The host function to sub 2 int32_t numbers. + class WasmEdgePluginTestFuncSub + : public WasmEdgePluginTestFunc { + public: + WasmEdgePluginTestFuncSub(WasmEdgePluginTestEnv &HostEnv) + : WasmEdgePluginTestFunc(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { + return A - B; + } + }; + + // The host module class. There can be several modules in a plug-in. + class WasmEdgePluginTestModule : public Runtime::Instance::ModuleInstance { + public: + WasmEdgePluginTestModule() + : Runtime::Instance::ModuleInstance("wasmedge_plugintest_cpp_module") { + addHostFunc("add", std::make_unique(Env)); + addHostFunc("sub", std::make_unique(Env)); + } + + WasmEdgePluginTestEnv &getEnv() { return Env; } + + private: + WasmEdgePluginTestEnv Env; + }; -### Plug-in Options + } // namespace Host + } // namespace WasmEdge + ``` -WORK IN PROGRESS. This section is reserved for the feature in the future. +- **Creation Functions for Modules**: Then developers should implement the module creation functions. Assume the following implementations are all in the `testplugin.cpp`. -### Implement the Plug-in Descriptor Registration + ```cpp + #include "testplugin.h" -The final step is to implement the `Plugin::PluginRegister` initialization with the plug-in descriptor. + namespace WasmEdge { + namespace Host { + namespace { + + Runtime::Instance::ModuleInstance * + create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + // There can be several modules in a plug-in. For that, developers should + // implement several `create` functions for each module. + return new WasmEdgePluginTestModule; + } + + } // namespace + } // namespace Host + } // namespace WasmEdge + ``` + +- **Plug-in Descriptions**: For constructing the plug-in, developers should supply the descriptions of this plug-in and the modules. + + ```cpp + namespace WasmEdge { + namespace Host { + namespace { + + Plugin::Plugin::PluginDescriptor Descriptor{ + //Plug-in name - for searching the plug-in context by the + // `WasmEdge_PluginFind()` C API. + .Name = "wasmedge_plugintest_cpp", + //Plug-in description. + .Description = "", + //Plug-in API version. + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + //Plug-in version. + .Version = {0, 10, 0, 0}, + // Module count in this plug-in. + .ModuleCount = 1, + // Pointer to module description array. + .ModuleDescriptions = + // The module descriptor array. + (Plugin::PluginModule::ModuleDescriptor[]){ + { + // Module name. This is the name for searching and creating the + // module instance context by the + // `WasmEdge_PluginCreateModule()` C API. + .Name = "wasmedge_plugintest_cpp_module", + // Module description. + .Description = "This is for the plugin tests in WasmEdge.", + // Creation function pointer. + .Create = create, + }, + }, + //Plug-in options (Work in progress). + .AddOptions = nullptr, + }; + + } // namespace + } // namespace Host + } // namespace WasmEdge + ``` + +- **Plug-in Options**: WORK IN PROGRESS. This section is reserved for the feature in the future. + +- **Implement Plug-in Descriptor Registration**: The final step is to implement the `Plugin::PluginRegister` initialization with the plug-in descriptor. ```cpp namespace WasmEdge { @@ -179,58 +209,55 @@ Plugin::PluginRegister WasmEdgePluginTestEnv::Register(&Descriptor); } // namespace WasmEdge ``` -## Build +Remember to implement any additional functions or structures your plug-in requires to fulfill its functionality. -To build the plug-in shared library, developers should build in cmake with the WasmEdge source. +Following these steps and implementing the necessary functions and descriptors, you can create a plug-in with host functions and modules in WasmEdge C++ API. You can continue developing your plug-in by adding functionality and implementing the desired behavior. -Assume that the folder `test` is created under the `/plugins`. +## Build plug-in -Add this line in the `/plugins/CMakeLists.txt`: +To build the plug-in shared library, developers should build in CMake with the WasmEdge source. -```cmake -add_subdirectory(test) -``` +- Assume that the' test' folder is created under the `/plug-ins`. Add this line in the `/plugins/CMakeLists.txt`: -Copy the `testplugin.h` and `testplugin.cpp` into the `/plugins/test` directory. + ```cmake + add_subdirectory(test) + ``` -And then edit the file `/plugins/test/CMakeLists.txt`: +- Copy the `testplugin.h` and `testplugin.cpp` into the `/plugins/test` directory. And then edit the file `/plugins/test/CMakeLists.txt`: -```cmake -wasmedge_add_library(wasmedgePluginTest - SHARED - testplugin.cpp -) - -target_compile_options(wasmedgePluginTest - PUBLIC - -DWASMEDGE_PLUGIN -) + ```cmake + wasmedge_add_library(wasmedgePluginTest + SHARED + env.cpp + func.cpp + module.cpp + testplugin.cpp + ) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin") - target_link_options(wasmedgePluginTest + target_compile_options(wasmedgePluginTest PUBLIC - -Wl,-U,__ZN8WasmEdge6Plugin14PluginRegisterC1EPKNS0_6Plugin16PluginDescriptorE - -Wl,-U,__ZN8WasmEdge6Plugin14PluginRegisterD1Ev + -DWASMEDGE_PLUGIN ) -endif() - -target_include_directories(wasmedgePluginTest - PUBLIC - $ - ${CMAKE_CURRENT_SOURCE_DIR} -) - -if(WASMEDGE_LINK_PLUGINS_STATIC) - target_link_libraries(wasmedgePluginTest - PRIVATE - wasmedgeCAPI - ) -else() - target_link_libraries(wasmedgePluginTest - PRIVATE - wasmedge_shared + + target_include_directories(wasmedgePluginTest + PUBLIC + $ + ${CMAKE_CURRENT_SOURCE_DIR} ) -endif() -``` -Then you can [follow the guide to build from source](../source/os/linux.md). + if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginTest + PRIVATE + wasmedgeCAPI + ) + else() + target_link_libraries(wasmedgePluginTest + PRIVATE + wasmedge_shared + ) + endif() + + install(TARGETS wasmedgePluginTest DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) + ``` + +Follow the guide to [build WasmEdge from source](../source/os/linux.md), according to your specific operating system (e.g., Linux), which will include building the plug-in shared library along with WasmEdge. diff --git a/docs/contribute/plugin/develop_plugin_rustsdk.md b/docs/contribute/plugin/develop_plugin_rustsdk.md index 35f27d07..8176ff89 100644 --- a/docs/contribute/plugin/develop_plugin_rustsdk.md +++ b/docs/contribute/plugin/develop_plugin_rustsdk.md @@ -1,49 +1,78 @@ +--- +sidebar_position: 4 +--- + # Develop WasmEdge Plug-in in Rust SDK with witc -Once you complete C++ plugin code, you can use witc[^1] to generate Rust Plugin SDK +By developing a plug-in, one can extend the functionality of WasmEdge and customize it to suit specific needs. WasmEdge provides a Rust-based API for registering extension modules and host functions. -## Example wasmedge_opencvmini +```mermaid +graph TD +A[Build WasmEdge from source] -- witc --> B[Generate Rust Plug-in Code] +B -- SDK Crate --> C[Create SDK Crate] +C -- Module File --> D[Create Module File] +D -- Wrapper Functions --> E[Write Wrapper Functions in src/lib.rs] +``` -Consider you get a file `wasmedge_opencvmini.wit` with below content + +:::note +It is recommended that developers choose the WasmEdge [C API](develop_plugin_c.md) for plug-in development because of the support, compatibility, and flexibility the WasmEdge runtime provides. +::: -```wit -imdecode: func(buf: list) -> u32 -imshow: func(window-name: string, mat-key: u32) -> unit -waitkey: func(delay: u32) -> unit -``` +## Set up the development environment -Using witc can generate Rust plugin code for it +To start developing WasmEdge plug-ins, it is essential to properly set up the development environment. This section provides step-by-step instructions for WasmEdge plug-in development - -```shell -witc plugin wasmedge_opencvmini.wit -``` +- **Build WasmEdge from source**: For developing the WasmEdge plug-in in C++, you must build WasmEdge from source. Follow the[build WasmEdge from source](../source/build_from_src.md) for instructions. Once you complete the C++ plug-in code, you can use witc[^1] to generate Rust Plug-in SDK. -Now, you will create a SDK crate by +After installing WasmEdge, you need to set up the build environment. If you're using Linux or other platforms, you can follow the instructions in the [build environment setup guide](../source/os/linux.md). -```shell -cargo new --lib opencvmini-sdk && cd opencvmini-sdk -``` +## Write the plug-in code -witc put rust code to stdout, therefore, you might like to create a new module file for generated code +To develop a WasmEdge Plug-in in Rust using the witc tool, you can follow these steps: -```shell -witc plugin wasmedge_opencvmini.wit > src/generated.rs -``` +- **Generate Rust Plug-in Code**: Consider you have a file named `wasmedge_opencvmini.wit` with the following content: -Finally, you write down `mod generated` in `src/lib.rs` to access the code, and write some wrappers + ```wit + imdecode: func(buf: list) -> u32 + imshow: func(window-name: string, mat-key: u32) -> unit + waitkey: func(delay: u32) -> unit + ``` -```rust -mod generated; + You can use the witc tool to generate Rust plug-in code for it by running the following command: -pub fn imdecode(buf: &[u8]) -> u32 { - unsafe { generated::imdecode(buf.as_ptr(), buf.len()) } -} -pub fn imshow(window_name: &str, mat_key: u32) -> () { - unsafe { generated::imshow(window_name.as_ptr(), window_name.len(), mat_key) } -} -pub fn waitkey(delay: u32) -> () { - unsafe { generated::waitkey(delay) } -} -``` + ```shell + witc plugin wasmedge_opencvmini.wit + ``` + +- **Create SDK Crate**: You need to create an SDK crate for your plug-in. Run the following command to create a new crate named `opencvmini-sdk`: + + ```shell + cargo new --lib opencvmini-sdk && cd opencvmini-sdk + ``` + +- **Create Module File**: The witc tool puts the Rust code to stdout. To capture the generated code, create a new module file named `src/generated.rs` and run the following command: + + ```shell + witc plugin wasmedge_opencvmini.wit > src/generated.rs + ``` + +- **Write Wrapper Functions**: In the `src/lib.rs` file of your crate, write the following code of `mod generated` to access the generated code and create wrapper functions: + + ```rust + mod generated; + + pub fn imdecode(buf: &[u8]) -> u32 { + unsafe { generated::imdecode(buf.as_ptr(), buf.len()) } + } + pub fn imshow(window_name: &str, mat_key: u32) -> () { + unsafe { generated::imshow(window_name.as_ptr(), window_name.len(), mat_key) } + } + pub fn waitkey(delay: u32) -> () { + unsafe { generated::waitkey(delay) } + } + ``` + + This code imports the generated module and provides safe wrapper functions for each generated function. [^1]: diff --git a/docs/contribute/plugin/intro.md b/docs/contribute/plugin/intro.md index b735b6d2..67267473 100644 --- a/docs/contribute/plugin/intro.md +++ b/docs/contribute/plugin/intro.md @@ -4,23 +4,76 @@ sidebar_position: 1 # WasmEdge Plug-in System Introduction -While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, developers should implement the host functions before compilation. +While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, developers should implement the host functions before compilation. However, for a more flexible and dynamic extension of the host functions, WasmEdge provides a plug-in architecture to load the plug-in shared library. -For the other solutions, WasmEdge provides the plug-in architecture to load the plug-in shared library for easier extending of the host functions. +A WasmEdge plug-in is a software component that extends the functionality of the WasmEdge runtime. Currently, developers can follow the guides to implement the plug-ins in [C API](develop_plugin_c.md) (recommended), [C++](develop_plugin_cpp.md) and [Rust](develop_plugin_rustsdk.md). With the help of the WasmEdge SDKs in the supported languages, developers can load and register the host functions from the plug-in shared libraries, allowing them to seamlessly integrate the plug-ins into the WasmEdge runtime as if they were part of the core runtime. -With developing the plug-ins, WasmEdge SDKs in the supported languages can load and register the host functions from the plug-in shared libraries. +```mermaid +graph LR + A((Host Application)) -- Loads --> B((Plug-in Shared Library)) + B -- Registers --> C((Wasmedge Runtime)) +``` -In current, developers can follow the guides to implement the plug-ins in [C API (recommended)](develop_plugin_c.md) or [C++](develop_plugin_cpp.md). +## Benefits of Using WasmEdge Plug-in + +WasmEdge plug-ins are designed to extend the functionality of the WasmEdge runtime and can be helpful for developers and end-users in several ways: + +- **Customization:** WasmEdge plug-ins can be customized to suit the specific needs of a project. Developers can create plug-ins that integrate with other systems or tools or provide unique functionality unavailable in the core WasmEdge runtime. + +- **Performance:** WasmEdge plug-ins are designed to work seamlessly with the core runtime, minimizing overhead and maximizing performance, which means they can provide additional functionality without sacrificing performance. + +- **Ease of use:** WasmEdge plug-ins are easy to use and integrate with the WasmEdge runtime. Developers can load the plug-in into the runtime and use its functions as part of the core runtime. + +- **Scalability:** Developers can compile their compute-intensive functions into host functions and package them into a plug-in to provide the better performance as running in native code. + +WasmEdge plug-ins can provide developers and users with a versatile, customizable, high-performance, and secure way to extend the functionality of the WasmEdge runtime. WasmEdge plug-ins can also improve scalability and ease of use, making it easier to build and deploy complex applications on edge devices. ## Loadable Plug-in -Loadable plugin is a standalone `.so`/`.dylib`/`.dll` file that WasmEdge can load during runtime environment, and provide modules to be imported. +Loadable plug-ins are standalone shared libraries (`.so`/`.dylib`/`.dll` files) that the WasmEdge runtime environment can load at runtime. These plug-ins can provide additional functionality to the WasmEdge runtime environment, such as new modules that can be imported by WebAssembly modules. + +### Creating Loadable Plug-in + +To create a loadable plug-in for WasmEdge, developers can use the WasmEdge Plug-in SDK, which provides a set of Rust, C, and C++ APIs for creating and registering plug-ins. The SDK also includes [example code](https://github.com/WasmEdge/WasmEdge/tree/master/examples/plugin/get-string) that demonstrates creating a simple plug-in that returns a string. By following the provided examples and leveraging the SDK's APIs, developers can quickly build custom plug-ins tailored to their specific needs. + +### Loading plug-in from paths + +To use the loadable plug-ins, developers need to load them from specific paths into the WasmEdge runtime environment. The loading process involves the following steps: + +- Loadable plug-ins can be loaded from default paths by calling the `WasmEdge_PluginLoadWithDefaultPaths()` API. The default paths include: + + - The path specified in the environment variable `WASMEDGE_PLUGIN_PATH`. + - The `./plugin/` directory relative to the WasmEdge installation path. + - The `./wasmedge/` directory is located under the library path if WasmEdge is installed in a system directory such as `/usr` and `/usr/local`. + +- If the plug-ins are located in a specific path or directory, developers can use the `WasmEdge_PluginLoadFromPath("PATH_TO_PLUGIN/plug-in.so")` API to load the plug-ins from that particular location. + +The WasmEdge runtime environment will search for the loadable plug-ins in the specified paths and load them if found. + +The following flowchart shows the process of loading loadable plug-ins into the WasmEdge runtime environment from specific paths: + +```mermaid +graph LR + A((Start)) --> B(Loadable Plug-ins) + B --> C{Load Plug-ins} + C --> D[Load from Default Paths] + C --> E[Load from Specific Path] + C --> F[Load from Specific Directory] + D --> G{Is Plug-in Found?} + E --> G + F --> G + G -- Yes --> H(Load Plug-in) + H --> I(End) + G -- No --> I +``` + +The flowchart shows loading loadable plug-ins into the WasmEdge runtime environment. The process involves searching for plug-ins in default paths, a specific path, or a specific directory. If a plug-in is found in any of these locations, it is loaded into the runtime environment. The flowchart enables developers to quickly load plug-ins and extend the capabilities of the WasmEdge runtime. -Please [refer to the plugin example code](https://github.com/WasmEdge/WasmEdge/tree/master/examples/plugin/get-string). +By following this flowchart, developers can effectively load loadable plug-ins into the WasmEdge runtime environment from specific paths, expanding the runtime's functionality according to their requirements. ## WasmEdge Currently Released Plug-ins -There are several plug-in releases with the WasmEdge official releases. Please check the following table to check the release status and how to build from source with the plug-ins. +There are several plug-in releases with the WasmEdge official releases. Please check the following table to check the release status and how to build from the source with the plug-ins. | Plug-in | Rust Crate | Released Platforms | Build Steps | | --- | --- | --- | --- | diff --git a/docusaurus.config.js b/docusaurus.config.js index 9f4a9a4c..b68fc2b4 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -58,30 +58,32 @@ const config = { }), ], ], - - themes : [ + + themes: [ [ "@easyops-cn/docusaurus-search-local", /** @type {import("@easyops-cn/docusaurus-search-local").PluginOptions} */ // @ts-ignore { - docsRouteBasePath: '/', - hashed: true, - indexBlog: false, - indexPages: true, - language: ["en", "zh"], - highlightSearchTermsOnTargetPage: true, - explicitSearchResultPath: true, - searchBarShortcut: true, - searchBarShortcutHint: true, - searchBarPosition: "right", + docsRouteBasePath: '/', + hashed: true, + indexBlog: false, + indexPages: true, + language: ["en", "zh"], + highlightSearchTermsOnTargetPage: true, + explicitSearchResultPath: true, + searchBarShortcut: true, + searchBarShortcutHint: true, + searchBarPosition: "right", }, - ], ], + ], + themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ ({ + metadata: [{ name: 'keywords', content: 'wasmedge, wasm, web assembly, rust, cncf, edge devices, cloud, serverless' }, { name: 'twitter:card', content: 'summary' }], image: "./static/img/wasm_logo.png", announcementBar: { id: "start", @@ -130,15 +132,15 @@ const config = { }, docs: { sidebar: { - hideable: true, + hideable: true, }, - }, + }, footer: { logo: { alt: 'WasmEdge logo', src: '/img/wasmedge_logo.svg', href: 'https://wasmedge.org/', - }, + }, style: 'dark', links: [ { @@ -211,4 +213,13 @@ const config = { }), }; -module.exports = config; +// Extending config to inlcude mermaid also +const extendedConfig = { + ...config, + markdown: { + mermaid: true, + }, + themes: ['@docusaurus/theme-mermaid'], +}; + +module.exports = extendedConfig; diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/_category_.json b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/_category_.json index fcdcda0b..d5890d31 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/_category_.json +++ b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/_category_.json @@ -3,6 +3,6 @@ "position": 3, "link": { "type": "generated-index", - "description": "we will learn how to the WasmEdge Plugin System." + "description": "We will learn how to develop the plug-ins for WasmEdge." } } diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_c.md b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_c.md index 446686fc..1784380b 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_c.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_c.md @@ -4,27 +4,62 @@ sidebar_position: 2 # Develop WasmEdge Plug-in in C API -WasmEdge provides a C++ based API for registering extension modules and host functions. While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, the plugin API allows such extensions to be incorporated into WasmEdge's own building and releasing process. +By developing a plug-in, one can extend the functionality of WasmEdge and customize it to suit specific needs. WasmEdge provides a C based API for registering extension modules and host functions. While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, the plug-in API allows such extensions to be incorporated into WasmEdge's building and releasing process. Here is a flowchart showing all the steps needed for developing WasmEdge Plug-in - + +```mermaid +graph LR; +A[Developing WasmEdge Plug-in in C] +A --> B(Set up the development environment) +A --> C(Create a WasmEdge plug-in project) +A --> D(Write the plug-in code) +A --> E(Build the plug-in) +A --> F(Test and debug the plug-in) +B --> E +C --> D +D --> E +``` + +This flowchart illustrates developing a WasmEdge plug-in, showcasing the steps from choosing a programming language to finalizing and releasing the plug-in. + +## Set up the development environment + +To start developing WasmEdge plug-ins, it is essential to correctly set up the development environment. This section provides step-by-step instructions for WasmEdge plug-in development - + +**Install a WasmEdge runtime**: You can download the latest version of WasmEdge from [GitHub repository](https://github.com/wasmEdge/wasmEdge). Follow the instructions in the [installation guide](../../start/install.md) for your specific operating system. -## Prerequisites +After installing WasmEdge, you need to set up the build environment. If you're using Linux or other platforms, you can follow the instructions in the [build environment setup guide](../source/os/linux.md). -For developing the WasmEdge plug-in in C API, please [install WasmEdge](../../start/install.md#install) first. +## Create a WasmEdge plug-in project -## Example +To create a WasmEdge plug-in project, follow these steps: -Assume that the plug-in example is in the file `testplugin.c`. +- **Set up the project directory**: Create a directory structure for your plug-in project. You can use a standard structure for the chosen language or create your structure. To create a project directory structure, use the following commands: -### Host Functions + ```bash + mkdir testplugin + cd testplugin + mkdir src include build + ``` -The goal of the plug-in is to provide the host functions which can be imported when instantiating WASM. +- **Add configuration files**: Add configuration files specifying the plug-in name, version, and dependencies. The specific files and content depend on the chosen programming language and build system. -Therefore, developers can implement their plug-in host functions first, as the same as the [host functions in WasmEdge C API](../../embed/c/reference/latest.md#host-functions). +- **Add any necessary libraries or dependencies**: Include any required libraries or dependencies for your plug-in. Modify the configuration files created in the previous step to include the required dependencies. + +## Write the plug-in code + +To create a plug-in with host functions and modules, follow these steps: + +- **Implement host function definitions**: In this step, you must define the host functions that will be imported when instantiating the WASM module. These functions will perform specific operations and return results. + + Therefore, developers can first implement their plug-in host functions, like the [host functions in WasmEdge C API](/embed/c/reference/latest.md#host-functions). :::note -For the more details about the [external data](../../embed/c/host_function.md#host-data) and [calling frame context](../../embed/c/host_function.md#calling-frame-context), please refer to the host function guide. +For more details about the [external data](/embed/c/host_function.md#host-data) and [calling frame context](/embed/c/host_function.md#calling-frame-context), please refer to the host function guide. ::: +Here's an example of two host functions, `HostFuncAdd` and `HostFuncSub`, that add and subtract two `int32_t` numbers, respectively: + ```c #include @@ -51,152 +86,147 @@ WasmEdge_Result HostFuncSub(void *Data, } ``` -### Host Modules +- **Implement the module creation functions**: In this step, you need to implement the module creation function that creates an instance of the module. This function will be called when the plug-in is loaded. -Then developers should implement the module creation functions. + Here's an example of a module creation function named `CreateTestModule`: -Noticed that there can be several module instances in a plug-in shared library. Here take a module named as `wasmedge_plugintest_c_module` for the example. - -```c -/* The creation function of creating the module instance. */ -WasmEdge_ModuleInstanceContext * -CreateTestModule(const struct WasmEdge_ModuleDescriptor *Desc) { - /* - * The `Desc` is the const pointer to the module descriptor struct: - * - * typedef struct WasmEdge_ModuleDescriptor { - * const char *Name; - * const char *Description; - * WasmEdge_ModuleInstanceContext *(*Create)( - * const struct WasmEdge_ModuleDescriptor *); - * } WasmEdge_ModuleDescriptor; - * - * Developers can get the name and the description from this descriptor. - */ - - /* Exported module name of this module instance. */ - WasmEdge_String ModuleName = - WasmEdge_StringCreateByCString("wasmedge_plugintest_c_module"); - WasmEdge_ModuleInstanceContext *Mod = - WasmEdge_ModuleInstanceCreate(ModuleName); - WasmEdge_StringDelete(ModuleName); - - WasmEdge_String FuncName; - WasmEdge_FunctionTypeContext *FType; - WasmEdge_FunctionInstanceContext *FuncCxt; - enum WasmEdge_ValType ParamTypes[2], ReturnTypes[1]; - ParamTypes[0] = WasmEdge_ValType_I32; - ParamTypes[1] = WasmEdge_ValType_I32; - ReturnTypes[0] = WasmEdge_ValType_I32; - - /* Create and add the host function instances into the module instance. */ - FType = WasmEdge_FunctionTypeCreate(ParamTypes, 2, ReturnTypes, 1); - FuncName = WasmEdge_StringCreateByCString("add"); - FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncAdd, NULL, 0); - WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); - WasmEdge_StringDelete(FuncName); - FuncName = WasmEdge_StringCreateByCString("sub"); - FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncSub, NULL, 0); - WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); - WasmEdge_StringDelete(FuncName); - WasmEdge_FunctionTypeDelete(FType); - - return Mod; -} -``` - -### Plug-in Descriptions - -For constructing the plug-in, developers should supply the descriptions of this plug-in and the modules. - -```c -/* The module descriptor array. There can be multiple modules in a plug-in. */ -static WasmEdge_ModuleDescriptor ModuleDesc[] = {{ + ```c + /* The creation function of creating the module instance. */ + WasmEdge_ModuleInstanceContext * + CreateTestModule(const struct WasmEdge_ModuleDescriptor *Desc) { /* - * Module name. This is the name for searching and creating the module - * instance context by the `WasmEdge_PluginCreateModule()` API. - */ - .Name = "wasmedge_plugintest_c_module", - /* Module description. */ - .Description = "This is for the plugin tests in WasmEdge C API.", - /* Creation function pointer. */ - .Create = CreateTestModule, -}}; - -/* The plug-in descriptor */ -static WasmEdge_PluginDescriptor Desc[] = {{ - /* - * Plug-in name. This is the name for searching the plug-in context by the - * `WasmEdge_PluginFind()` API. - */ - .Name = "wasmedge_plugintest_c", - /* Plug-in description. */ - .Description = "", - /* Plug-in API version. */ - .APIVersion = WasmEdge_Plugin_CurrentAPIVersion, - /* Plug-in version. Developers can define the version of this plug-in. */ - .Version = - { - .Major = 0, - .Minor = 1, - .Patch = 0, - .Build = 0, - }, - /* Module count in this plug-in. */ - .ModuleCount = 1, - /* Plug-in option description count in this plug-in (Work in progress). */ - .ProgramOptionCount = 0, - /* Pointer to the module description array. */ - .ModuleDescriptions = ModuleDesc, - /* Pointer to the plug-in option description array (Work in progress). */ - .ProgramOptions = NULL, -}}; -``` - -### Plug-in Options - -WORK IN PROGRESS. This section is reserved for the feature in the future. - -### Implement the Get Descriptor API - -The final step is to implement the `WasmEdge_Plugin_GetDescriptor()` API to return the plug-in descriptor. - -```c -WASMEDGE_CAPI_PLUGIN_EXPORT const WasmEdge_PluginDescriptor * -WasmEdge_Plugin_GetDescriptor(void) { - return &Desc; -} -``` - -## Build - -To build the plug-in shared library, developers can choose to build stand-alone by the compiler or use cmake. - -### Build with Command - -```bash -clang -shared -std=c11 -DWASMEDGE_PLUGIN testplugin.c -lwasmedge -o libwasmedgePluginTest.so -``` - -### Build in CMake - -```cmake -add_library(wasmedgePluginTest - SHARED - testplugin.c -) - -set_target_properties(wasmedgePluginTest PROPERTIES - C_STANDARD 11 -) - -target_compile_options(wasmedgePluginTest - PUBLIC - -DWASMEDGE_PLUGIN -) - -target_link_libraries(wasmedgePluginTest - PRIVATE - wasmedge -) -``` + * The `Desc` is the const pointer to the module descriptor struct: + * + * typedef struct WasmEdge_ModuleDescriptor { + * const char *Name; + * const char *Description; + * WasmEdge_ModuleInstanceContext *(*Create)( + * const struct WasmEdge_ModuleDescriptor *); + * } WasmEdge_ModuleDescriptor; + * + * Developers can get the name and description from this descriptor. + */ + + /* Exported module name of this module instance. */ + WasmEdge_String ModuleName = + WasmEdge_StringCreateByCString("wasmedge_plugintest_c_module"); + WasmEdge_ModuleInstanceContext *Mod = + WasmEdge_ModuleInstanceCreate(ModuleName); + WasmEdge_StringDelete(ModuleName); + + WasmEdge_String FuncName; + WasmEdge_FunctionTypeContext *FType; + WasmEdge_FunctionInstanceContext *FuncCxt; + enum WasmEdge_ValType ParamTypes[2], ReturnTypes[1]; + ParamTypes[0] = WasmEdge_ValType_I32; + ParamTypes[1] = WasmEdge_ValType_I32; + ReturnTypes[0] = WasmEdge_ValType_I32; + + /* Create and add the host function instances into the module instance. */ + FType = WasmEdge_FunctionTypeCreate(ParamTypes, 2, ReturnTypes, 1); + FuncName = WasmEdge_StringCreateByCString("add"); + FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncAdd, NULL, 0); + WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); + WasmEdge_StringDelete(FuncName); + FuncName = WasmEdge_StringCreateByCString("sub"); + FuncCxt = WasmEdge_FunctionInstanceCreate(FType, HostFuncSub, NULL, 0); + WasmEdge_ModuleInstanceAddFunction(Mod, FuncName, FuncCxt); + WasmEdge_StringDelete(FuncName); + WasmEdge_FunctionTypeDelete(FType); + + return Mod; + } + ``` + + There can be several module instances in a plug-in shared library. Here in the above code snippet, take a module named `wasmedge_plugintest_c_module` for the example. + +- **Supply the plug-in descriptions**- In this step, you need to provide the descriptions of the plug-in and the modules it contains. These descriptions will be used for searching and creating the plug-in and module instances. + + Here's an example of the plug-in and module descriptors: + + ```c + /* The module descriptor array. There can be multiple modules in a plug-in. */ + static WasmEdge_ModuleDescriptor ModuleDesc[] = {{ + /* + * Module name. This is the name for searching and creating the module + * instance context by the `WasmEdge_PluginCreateModule()` API. + */ + .Name = "wasmedge_plugintest_c_module", + /* Module description. */ + .Description = "This is for the plugin tests in WasmEdge C API.", + /* Creation function pointer. */ + .Create = CreateTestModule, + }}; + + /* The plug-in descriptor */ + static WasmEdge_PluginDescriptor Desc[] = {{ + /* + * Plug-in name. This is the name for searching the plug-in context by the + * `WasmEdge_PluginFind()` API. + */ + .Name = "wasmedge_plugintest_c", + /* Plug-in description. */ + .Description = "", + /* Plug-in API version. */ + .APIVersion = WasmEdge_Plugin_CurrentAPIVersion, + /* Plug-in version. Developers can define the version of this plug-in. */ + .Version = + { + .Major = 0, + .Minor = 1, + .Patch = 0, + .Build = 0, + }, + /* Module count in this plug-in. */ + .ModuleCount = 1, + /* Plug-in option description count in this plug-in (Work in progress). */ + .ProgramOptionCount = 0, + /* Pointer to the module description array. */ + .ModuleDescriptions = ModuleDesc, + /* Pointer to the plug-in option description array (Work in progress). */ + .ProgramOptions = NULL, + }}; + ``` + + These descriptions define the name, description, version, and creation function of the plug-in and the name and description of the module it contains. + +Remember to implement any additional functions or structures your plug-in requires to fulfill its functionality. + +Following these steps and implementing the necessary functions and descriptors, you can create a plug-in with host functions and modules in WasmEdge C API. You can continue developing your plug-in by adding functionality and implementing the desired behavior. + +- **Plug-in option** - _WORK IN PROGRESS. This section is reserved for the feature in the future._ + +## Build your plug-in + +To build the WasmEdge plug-in shared library, you have two options: build it directly using the compiler or CMake. Here are the instructions for both methods: + +- **Build with Command**: if you choose to build the plug-in using the command line, run the following command in the terminal: + + This command compiles the `testplugin.c` file into a shared library named `libwasmedgePluginTest.so`. The `-std=c11` flag sets the C language standard to C11, and the `-DWASMEDGE_PLUGIN` flag defines the WASMEDGE_PLUGIN macro, which can be used in your code. + +- **Build with CMake**: If you prefer to use CMake to build the plug-in, create a `CMakeLists.txt` file in the root directory of your project and add the following content to the CMakeLists.txt file: + + ```cmake + add_library(wasmedgePluginTest + SHARED + testplugin.c + ) + + set_target_properties(wasmedgePluginTest PROPERTIES + C_STANDARD 11 + ) + + target_compile_options(wasmedgePluginTest + PUBLIC + -DWASMEDGE_PLUGIN + ) + + target_link_libraries(wasmedgePluginTest + PRIVATE + wasmedge + ) + ``` + + This CMake configuration sets up a build target called `wasmedgePluginTest`. It compiles the `testplugin.c` file into a shared library. The `C_STANDARD 11` property sets the C language standard to C11. The `target_compile_options` command defines the `WASMEDGE_PLUGIN` macro using the `-DWASMEDGE_PLUGIN` flag. Finally, the `target_link_libraries` command links the wasmedge library to the plug-in. + +Once you have set up either the command-line build or the CMake build, you can execute the corresponding build command or generate build files using CMake, which will compile your plug-in source code and produce the shared library file `(libwasmedgePluginTest.so)`. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_cpp.md b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_cpp.md index a4a63919..7a5e6a07 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_cpp.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_cpp.md @@ -4,170 +4,200 @@ sidebar_position: 3 # Develop WasmEdge Plug-in in C++ API +By developing a plug-in, one can extend the functionality of WasmEdge and customize it to suit specific needs. WasmEdge provides a C based API for registering extension modules and host functions. While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, the plug-in API allows such extensions to be incorporated into WasmEdge's building and releasing process. + :::note -We recommend developers to [develop plug-ins in WasmEdge C API](develop_plugin_c.md). +It is recommended that developers choose the WasmEdge [C API](develop_plugin_c.md) for plug-in development because of the support, compatibility, and flexibility the WasmEdge runtime provides. ::: -## Prerequisites +Here is a flowchart showing all the steps needed for developing WasmEdge Plug-in - + +```mermaid +graph TD; +A[Develop WasmEdge Plug-in in C++ API] +A --> B(Set up development environment) +B --> C(Create project directory) +C --> D(Add configuration files) +D --> E(Install necessary tools and dependencies) +E --> F(Enable specific backends or components) +F --> G(Write plug-in code) +G --> H(Build plug-in) +C --> I(Define plug-in API) +H --> I +I --> J(Compile WasmEdge plug-in) +J --> K(Test and debug plug-in) +``` -For developing the WasmEdge plug-in in internal C++, developers should [build WasmEdge from source](../source/build_from_src.md). +This flowchart illustrates developing a WasmEdge plug-in, showcasing the steps from choosing a programming language to finalizing and releasing the plug-in. -## Example +## Set up a development environment -Assume that the plug-in example is in the file `testplugin.h` and `testplugin.cpp`. +To start developing WasmEdge plug-ins, it is essential to correctly set up the development environment. This section provides step-by-step instructions for WasmEdge plug-in development - -### Host Functions and Modules +**Build WasmEdge from source**: For developing the WasmEdge plug-in in C++, you must build WasmEdge from source. Follow the[build WasmEdge from source](../source/build_from_src.md) for instructions. -The goal of the plug-in is to provide the host functions which can be imported when instantiating WASM. Therefore, developers should implement their plug-in host functions in WasmEdge internal C++ first. Assume that the host function implementations are in the `testplugin.h`. +After installing WasmEdge, you need to set up the build environment. If you're using Linux or other platforms, you can follow the instructions in the [build environment setup guide](../source/os/linux.md). -```cpp -#pragma once +## Create a WasmEdge plug-in project -#include "plugin/plugin.h" +To create a WasmEdge plug-in project, follow these steps: -#include -#include +- **Set up the project directory**: Create a directory structure for your plug-in project. You can use a standard structure for the chosen language or create your structure. To create a project directory structure, use the following commands: -namespace WasmEdge { -namespace Host { + ```bash + mkdir testplugin + cd testplugin + mkdir src include build + ``` -// The environment class. For the register object. -class WasmEdgePluginTestEnv { -public: - WasmEdgePluginTestEnv() noexcept = default; - - static Plugin::PluginRegister Register; -}; - -// The host function base template class. For inheriting the environment class -// reference. -template -class WasmEdgePluginTestFunc : public Runtime::HostFunction { -public: - WasmEdgePluginTestFunc(WasmEdgePluginTestEnv &HostEnv) - : Runtime::HostFunction(0), Env(HostEnv) {} - -protected: - WasmEdgePluginTestEnv &Env; -}; - -// The host function to add 2 int32_t numbers. -class WasmEdgePluginTestFuncAdd - : public WasmEdgePluginTestFunc { -public: - WasmEdgePluginTestFuncAdd(WasmEdgePluginTestEnv &HostEnv) - : WasmEdgePluginTestFunc(HostEnv) {} - Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { - return A + B; - } -}; - -// The host function to sub 2 int32_t numbers. -class WasmEdgePluginTestFuncSub - : public WasmEdgePluginTestFunc { -public: - WasmEdgePluginTestFuncSub(WasmEdgePluginTestEnv &HostEnv) - : WasmEdgePluginTestFunc(HostEnv) {} - Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { - return A - B; - } -}; - -// The host module class. There can be several modules in a plug-in. -class WasmEdgePluginTestModule : public Runtime::Instance::ModuleInstance { -public: - WasmEdgePluginTestModule() - : Runtime::Instance::ModuleInstance("wasmedge_plugintest_cpp_module") { - addHostFunc("add", std::make_unique(Env)); - addHostFunc("sub", std::make_unique(Env)); - } +- **Add necessary libraries or dependencies**: Include any required libraries or dependencies for your plug-in. Modify the configuration files created in the previous step to include the required dependencies. - WasmEdgePluginTestEnv &getEnv() { return Env; } +## Write plug-in code -private: - WasmEdgePluginTestEnv Env; -}; +To create a plug-in with host functions and modules, follow these steps: -} // namespace Host -} // namespace WasmEdge -``` +- **Host Functions and Modules**: The plug-in aims to provide the host functions that can be imported when instantiating WASM. Therefore, developers should first implement their plug-in host functions in WasmEdge internal C++. Assume that the host function implementations are in the `testplugin.h`. -### Creation Functions for Modules + ```cpp + #pragma once -Then developers should implement the module creation functions. Assume that the following implementations are all in the `testplugin.cpp`. + #include "plug-in/plug-in.h" -```cpp -#include "testplugin.h" + #include + #include -namespace WasmEdge { -namespace Host { -namespace { + namespace WasmEdge { + namespace Host { -Runtime::Instance::ModuleInstance * -create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { - // There can be several modules in a plug-in. For that, developers should - // implement several `create` functions for each module. - return new WasmEdgePluginTestModule; -} + // The environment class. For the register object. + class WasmEdgePluginTestEnv { + public: + WasmEdgePluginTestEnv() noexcept = default; -} // namespace -} // namespace Host -} // namespace WasmEdge -``` + static Plugin::PluginRegister Register; + }; -### Plug-in Descriptions + // The host function base template class. For inheriting the environment class + // reference. + template + class WasmEdgePluginTestFunc : public Runtime::HostFunction { + public: + WasmEdgePluginTestFunc(WasmEdgePluginTestEnv &HostEnv) + : Runtime::HostFunction(0), Env(HostEnv) {} -For constructing the plug-in, developers should supply the descriptions of this plug-in and the modules. + protected: + WasmEdgePluginTestEnv &Env; + }; -```cpp -namespace WasmEdge { -namespace Host { -namespace { - -Plugin::Plugin::PluginDescriptor Descriptor{ - // Plug-in name. This is the name for searching the plug-in context by the - // `WasmEdge_PluginFind()` C API. - .Name = "wasmedge_plugintest_cpp", - // Plug-in description. - .Description = "", - // Plug-in API version. - .APIVersion = Plugin::Plugin::CurrentAPIVersion, - // Plug-in version. - .Version = {0, 10, 0, 0}, - // Module count in this plug-in. - .ModuleCount = 1, - // Pointer to module description array. - .ModuleDescriptions = - // The module descriptor array. - (Plugin::PluginModule::ModuleDescriptor[]){ - { - // Module name. This is the name for searching and creating the - // module instance context by the - // `WasmEdge_PluginCreateModule()` C API. - .Name = "wasmedge_plugintest_cpp_module", - // Module description. - .Description = "This is for the plugin tests in WasmEdge.", - // Creation function pointer. - .Create = create, - }, - }, - // Plug-in options (Work in progress). - .AddOptions = nullptr, -}; - -} // namespace -} // namespace Host -} // namespace WasmEdge -``` + // The host function to add 2 int32_t numbers. + class WasmEdgePluginTestFuncAdd + : public WasmEdgePluginTestFunc { + public: + WasmEdgePluginTestFuncAdd(WasmEdgePluginTestEnv &HostEnv) + : WasmEdgePluginTestFunc(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { + return A + B; + } + }; + + // The host function to sub 2 int32_t numbers. + class WasmEdgePluginTestFuncSub + : public WasmEdgePluginTestFunc { + public: + WasmEdgePluginTestFuncSub(WasmEdgePluginTestEnv &HostEnv) + : WasmEdgePluginTestFunc(HostEnv) {} + Expect body(const Runtime::CallingFrame &, uint32_t A, uint32_t B) { + return A - B; + } + }; + + // The host module class. There can be several modules in a plug-in. + class WasmEdgePluginTestModule : public Runtime::Instance::ModuleInstance { + public: + WasmEdgePluginTestModule() + : Runtime::Instance::ModuleInstance("wasmedge_plugintest_cpp_module") { + addHostFunc("add", std::make_unique(Env)); + addHostFunc("sub", std::make_unique(Env)); + } + + WasmEdgePluginTestEnv &getEnv() { return Env; } + + private: + WasmEdgePluginTestEnv Env; + }; -### Plug-in Options + } // namespace Host + } // namespace WasmEdge + ``` -WORK IN PROGRESS. This section is reserved for the feature in the future. +- **Creation Functions for Modules**: Then developers should implement the module creation functions. Assume the following implementations are all in the `testplugin.cpp`. -### Implement the Plug-in Descriptor Registration + ```cpp + #include "testplugin.h" -The final step is to implement the `Plugin::PluginRegister` initialization with the plug-in descriptor. + namespace WasmEdge { + namespace Host { + namespace { + + Runtime::Instance::ModuleInstance * + create(const Plugin::PluginModule::ModuleDescriptor *) noexcept { + // There can be several modules in a plug-in. For that, developers should + // implement several `create` functions for each module. + return new WasmEdgePluginTestModule; + } + + } // namespace + } // namespace Host + } // namespace WasmEdge + ``` + +- **Plug-in Descriptions**: For constructing the plug-in, developers should supply the descriptions of this plug-in and the modules. + + ```cpp + namespace WasmEdge { + namespace Host { + namespace { + + Plugin::Plugin::PluginDescriptor Descriptor{ + //Plug-in name - for searching the plug-in context by the + // `WasmEdge_PluginFind()` C API. + .Name = "wasmedge_plugintest_cpp", + //Plug-in description. + .Description = "", + //Plug-in API version. + .APIVersion = Plugin::Plugin::CurrentAPIVersion, + //Plug-in version. + .Version = {0, 10, 0, 0}, + // Module count in this plug-in. + .ModuleCount = 1, + // Pointer to module description array. + .ModuleDescriptions = + // The module descriptor array. + (Plugin::PluginModule::ModuleDescriptor[]){ + { + // Module name. This is the name for searching and creating the + // module instance context by the + // `WasmEdge_PluginCreateModule()` C API. + .Name = "wasmedge_plugintest_cpp_module", + // Module description. + .Description = "This is for the plugin tests in WasmEdge.", + // Creation function pointer. + .Create = create, + }, + }, + //Plug-in options (Work in progress). + .AddOptions = nullptr, + }; + + } // namespace + } // namespace Host + } // namespace WasmEdge + ``` + +- **Plug-in Options**: WORK IN PROGRESS. This section is reserved for the feature in the future. + +- **Implement Plug-in Descriptor Registration**: The final step is to implement the `Plugin::PluginRegister` initialization with the plug-in descriptor. ```cpp namespace WasmEdge { @@ -179,58 +209,55 @@ Plugin::PluginRegister WasmEdgePluginTestEnv::Register(&Descriptor); } // namespace WasmEdge ``` -## Build +Remember to implement any additional functions or structures your plug-in requires to fulfill its functionality. -To build the plug-in shared library, developers should build in cmake with the WasmEdge source. +Following these steps and implementing the necessary functions and descriptors, you can create a plug-in with host functions and modules in WasmEdge C++ API. You can continue developing your plug-in by adding functionality and implementing the desired behavior. -Assume that the folder `test` is created under the `/plugins`. +## Build plug-in -Add this line in the `/plugins/CMakeLists.txt`: +To build the plug-in shared library, developers should build in CMake with the WasmEdge source. -```cmake -add_subdirectory(test) -``` +- Assume that the' test' folder is created under the `/plug-ins`. Add this line in the `/plugins/CMakeLists.txt`: -Copy the `testplugin.h` and `testplugin.cpp` into the `/plugins/test` directory. + ```cmake + add_subdirectory(test) + ``` -And then edit the file `/plugins/test/CMakeLists.txt`: +- Copy the `testplugin.h` and `testplugin.cpp` into the `/plugins/test` directory. And then edit the file `/plugins/test/CMakeLists.txt`: -```cmake -wasmedge_add_library(wasmedgePluginTest - SHARED - testplugin.cpp -) - -target_compile_options(wasmedgePluginTest - PUBLIC - -DWASMEDGE_PLUGIN -) + ```cmake + wasmedge_add_library(wasmedgePluginTest + SHARED + env.cpp + func.cpp + module.cpp + testplugin.cpp + ) -if(CMAKE_SYSTEM_NAME MATCHES "Darwin") - target_link_options(wasmedgePluginTest + target_compile_options(wasmedgePluginTest PUBLIC - -Wl,-U,__ZN8WasmEdge6Plugin14PluginRegisterC1EPKNS0_6Plugin16PluginDescriptorE - -Wl,-U,__ZN8WasmEdge6Plugin14PluginRegisterD1Ev + -DWASMEDGE_PLUGIN ) -endif() - -target_include_directories(wasmedgePluginTest - PUBLIC - $ - ${CMAKE_CURRENT_SOURCE_DIR} -) - -if(WASMEDGE_LINK_PLUGINS_STATIC) - target_link_libraries(wasmedgePluginTest - PRIVATE - wasmedgeCAPI - ) -else() - target_link_libraries(wasmedgePluginTest - PRIVATE - wasmedge_shared + + target_include_directories(wasmedgePluginTest + PUBLIC + $ + ${CMAKE_CURRENT_SOURCE_DIR} ) -endif() -``` -Then you can [follow the guide to build from source](../source/os/linux.md). + if(WASMEDGE_LINK_PLUGINS_STATIC) + target_link_libraries(wasmedgePluginTest + PRIVATE + wasmedgeCAPI + ) + else() + target_link_libraries(wasmedgePluginTest + PRIVATE + wasmedge_shared + ) + endif() + + install(TARGETS wasmedgePluginTest DESTINATION ${CMAKE_INSTALL_LIBDIR}/wasmedge) + ``` + +Follow the guide to [build WasmEdge from source](../source/os/linux.md), according to your specific operating system (e.g., Linux), which will include building the plug-in shared library along with WasmEdge. diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_rustsdk.md b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_rustsdk.md index 35f27d07..8176ff89 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_rustsdk.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/develop_plugin_rustsdk.md @@ -1,49 +1,78 @@ +--- +sidebar_position: 4 +--- + # Develop WasmEdge Plug-in in Rust SDK with witc -Once you complete C++ plugin code, you can use witc[^1] to generate Rust Plugin SDK +By developing a plug-in, one can extend the functionality of WasmEdge and customize it to suit specific needs. WasmEdge provides a Rust-based API for registering extension modules and host functions. -## Example wasmedge_opencvmini +```mermaid +graph TD +A[Build WasmEdge from source] -- witc --> B[Generate Rust Plug-in Code] +B -- SDK Crate --> C[Create SDK Crate] +C -- Module File --> D[Create Module File] +D -- Wrapper Functions --> E[Write Wrapper Functions in src/lib.rs] +``` -Consider you get a file `wasmedge_opencvmini.wit` with below content + +:::note +It is recommended that developers choose the WasmEdge [C API](develop_plugin_c.md) for plug-in development because of the support, compatibility, and flexibility the WasmEdge runtime provides. +::: -```wit -imdecode: func(buf: list) -> u32 -imshow: func(window-name: string, mat-key: u32) -> unit -waitkey: func(delay: u32) -> unit -``` +## Set up the development environment -Using witc can generate Rust plugin code for it +To start developing WasmEdge plug-ins, it is essential to properly set up the development environment. This section provides step-by-step instructions for WasmEdge plug-in development - -```shell -witc plugin wasmedge_opencvmini.wit -``` +- **Build WasmEdge from source**: For developing the WasmEdge plug-in in C++, you must build WasmEdge from source. Follow the[build WasmEdge from source](../source/build_from_src.md) for instructions. Once you complete the C++ plug-in code, you can use witc[^1] to generate Rust Plug-in SDK. -Now, you will create a SDK crate by +After installing WasmEdge, you need to set up the build environment. If you're using Linux or other platforms, you can follow the instructions in the [build environment setup guide](../source/os/linux.md). -```shell -cargo new --lib opencvmini-sdk && cd opencvmini-sdk -``` +## Write the plug-in code -witc put rust code to stdout, therefore, you might like to create a new module file for generated code +To develop a WasmEdge Plug-in in Rust using the witc tool, you can follow these steps: -```shell -witc plugin wasmedge_opencvmini.wit > src/generated.rs -``` +- **Generate Rust Plug-in Code**: Consider you have a file named `wasmedge_opencvmini.wit` with the following content: -Finally, you write down `mod generated` in `src/lib.rs` to access the code, and write some wrappers + ```wit + imdecode: func(buf: list) -> u32 + imshow: func(window-name: string, mat-key: u32) -> unit + waitkey: func(delay: u32) -> unit + ``` -```rust -mod generated; + You can use the witc tool to generate Rust plug-in code for it by running the following command: -pub fn imdecode(buf: &[u8]) -> u32 { - unsafe { generated::imdecode(buf.as_ptr(), buf.len()) } -} -pub fn imshow(window_name: &str, mat_key: u32) -> () { - unsafe { generated::imshow(window_name.as_ptr(), window_name.len(), mat_key) } -} -pub fn waitkey(delay: u32) -> () { - unsafe { generated::waitkey(delay) } -} -``` + ```shell + witc plugin wasmedge_opencvmini.wit + ``` + +- **Create SDK Crate**: You need to create an SDK crate for your plug-in. Run the following command to create a new crate named `opencvmini-sdk`: + + ```shell + cargo new --lib opencvmini-sdk && cd opencvmini-sdk + ``` + +- **Create Module File**: The witc tool puts the Rust code to stdout. To capture the generated code, create a new module file named `src/generated.rs` and run the following command: + + ```shell + witc plugin wasmedge_opencvmini.wit > src/generated.rs + ``` + +- **Write Wrapper Functions**: In the `src/lib.rs` file of your crate, write the following code of `mod generated` to access the generated code and create wrapper functions: + + ```rust + mod generated; + + pub fn imdecode(buf: &[u8]) -> u32 { + unsafe { generated::imdecode(buf.as_ptr(), buf.len()) } + } + pub fn imshow(window_name: &str, mat_key: u32) -> () { + unsafe { generated::imshow(window_name.as_ptr(), window_name.len(), mat_key) } + } + pub fn waitkey(delay: u32) -> () { + unsafe { generated::waitkey(delay) } + } + ``` + + This code imports the generated module and provides safe wrapper functions for each generated function. [^1]: diff --git a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/intro.md b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/intro.md index b735b6d2..67267473 100644 --- a/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/intro.md +++ b/i18n/zh/docusaurus-plugin-content-docs/current/contribute/plugin/intro.md @@ -4,23 +4,76 @@ sidebar_position: 1 # WasmEdge Plug-in System Introduction -While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, developers should implement the host functions before compilation. +While the WasmEdge language SDKs allow registering host functions from a host (wrapping) application, developers should implement the host functions before compilation. However, for a more flexible and dynamic extension of the host functions, WasmEdge provides a plug-in architecture to load the plug-in shared library. -For the other solutions, WasmEdge provides the plug-in architecture to load the plug-in shared library for easier extending of the host functions. +A WasmEdge plug-in is a software component that extends the functionality of the WasmEdge runtime. Currently, developers can follow the guides to implement the plug-ins in [C API](develop_plugin_c.md) (recommended), [C++](develop_plugin_cpp.md) and [Rust](develop_plugin_rustsdk.md). With the help of the WasmEdge SDKs in the supported languages, developers can load and register the host functions from the plug-in shared libraries, allowing them to seamlessly integrate the plug-ins into the WasmEdge runtime as if they were part of the core runtime. -With developing the plug-ins, WasmEdge SDKs in the supported languages can load and register the host functions from the plug-in shared libraries. +```mermaid +graph LR + A((Host Application)) -- Loads --> B((Plug-in Shared Library)) + B -- Registers --> C((Wasmedge Runtime)) +``` -In current, developers can follow the guides to implement the plug-ins in [C API (recommended)](develop_plugin_c.md) or [C++](develop_plugin_cpp.md). +## Benefits of Using WasmEdge Plug-in + +WasmEdge plug-ins are designed to extend the functionality of the WasmEdge runtime and can be helpful for developers and end-users in several ways: + +- **Customization:** WasmEdge plug-ins can be customized to suit the specific needs of a project. Developers can create plug-ins that integrate with other systems or tools or provide unique functionality unavailable in the core WasmEdge runtime. + +- **Performance:** WasmEdge plug-ins are designed to work seamlessly with the core runtime, minimizing overhead and maximizing performance, which means they can provide additional functionality without sacrificing performance. + +- **Ease of use:** WasmEdge plug-ins are easy to use and integrate with the WasmEdge runtime. Developers can load the plug-in into the runtime and use its functions as part of the core runtime. + +- **Scalability:** Developers can compile their compute-intensive functions into host functions and package them into a plug-in to provide the better performance as running in native code. + +WasmEdge plug-ins can provide developers and users with a versatile, customizable, high-performance, and secure way to extend the functionality of the WasmEdge runtime. WasmEdge plug-ins can also improve scalability and ease of use, making it easier to build and deploy complex applications on edge devices. ## Loadable Plug-in -Loadable plugin is a standalone `.so`/`.dylib`/`.dll` file that WasmEdge can load during runtime environment, and provide modules to be imported. +Loadable plug-ins are standalone shared libraries (`.so`/`.dylib`/`.dll` files) that the WasmEdge runtime environment can load at runtime. These plug-ins can provide additional functionality to the WasmEdge runtime environment, such as new modules that can be imported by WebAssembly modules. + +### Creating Loadable Plug-in + +To create a loadable plug-in for WasmEdge, developers can use the WasmEdge Plug-in SDK, which provides a set of Rust, C, and C++ APIs for creating and registering plug-ins. The SDK also includes [example code](https://github.com/WasmEdge/WasmEdge/tree/master/examples/plugin/get-string) that demonstrates creating a simple plug-in that returns a string. By following the provided examples and leveraging the SDK's APIs, developers can quickly build custom plug-ins tailored to their specific needs. + +### Loading plug-in from paths + +To use the loadable plug-ins, developers need to load them from specific paths into the WasmEdge runtime environment. The loading process involves the following steps: + +- Loadable plug-ins can be loaded from default paths by calling the `WasmEdge_PluginLoadWithDefaultPaths()` API. The default paths include: + + - The path specified in the environment variable `WASMEDGE_PLUGIN_PATH`. + - The `./plugin/` directory relative to the WasmEdge installation path. + - The `./wasmedge/` directory is located under the library path if WasmEdge is installed in a system directory such as `/usr` and `/usr/local`. + +- If the plug-ins are located in a specific path or directory, developers can use the `WasmEdge_PluginLoadFromPath("PATH_TO_PLUGIN/plug-in.so")` API to load the plug-ins from that particular location. + +The WasmEdge runtime environment will search for the loadable plug-ins in the specified paths and load them if found. + +The following flowchart shows the process of loading loadable plug-ins into the WasmEdge runtime environment from specific paths: + +```mermaid +graph LR + A((Start)) --> B(Loadable Plug-ins) + B --> C{Load Plug-ins} + C --> D[Load from Default Paths] + C --> E[Load from Specific Path] + C --> F[Load from Specific Directory] + D --> G{Is Plug-in Found?} + E --> G + F --> G + G -- Yes --> H(Load Plug-in) + H --> I(End) + G -- No --> I +``` + +The flowchart shows loading loadable plug-ins into the WasmEdge runtime environment. The process involves searching for plug-ins in default paths, a specific path, or a specific directory. If a plug-in is found in any of these locations, it is loaded into the runtime environment. The flowchart enables developers to quickly load plug-ins and extend the capabilities of the WasmEdge runtime. -Please [refer to the plugin example code](https://github.com/WasmEdge/WasmEdge/tree/master/examples/plugin/get-string). +By following this flowchart, developers can effectively load loadable plug-ins into the WasmEdge runtime environment from specific paths, expanding the runtime's functionality according to their requirements. ## WasmEdge Currently Released Plug-ins -There are several plug-in releases with the WasmEdge official releases. Please check the following table to check the release status and how to build from source with the plug-ins. +There are several plug-in releases with the WasmEdge official releases. Please check the following table to check the release status and how to build from the source with the plug-ins. | Plug-in | Rust Crate | Released Platforms | Build Steps | | --- | --- | --- | --- | diff --git a/package-lock.json b/package-lock.json index 1de47f15..b6f7eda1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@docusaurus/core": "^2.4.0", "@docusaurus/preset-classic": "^2.4.0", + "@docusaurus/theme-mermaid": "^2.4.1", "@easyops-cn/docusaurus-search-local": "^0.35.0", "@mdx-js/react": "^1.6.22", "@node-rs/jieba": "^1.7.0", @@ -1999,6 +2000,11 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz", + "integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==" + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -2709,6 +2715,28 @@ "react-dom": "^16.8.4 || ^17.0.0" } }, + "node_modules/@docusaurus/theme-mermaid": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-2.4.1.tgz", + "integrity": "sha512-cM0ImKIqZfjmlaC+uAjep39kNBvb1bjz429QBHGs32maob4+UnRzVPPpCUCltyPVb4xjG5h1Tyq4pHzhtIikqA==", + "dependencies": { + "@docusaurus/core": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", + "@mdx-js/react": "^1.6.22", + "mermaid": "^9.2.2", + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.14" + }, + "peerDependencies": { + "react": "^16.8.4 || ^17.0.0", + "react-dom": "^16.8.4 || ^17.0.0" + } + }, "node_modules/@docusaurus/theme-search-algolia": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz", @@ -6342,6 +6370,14 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -6710,12 +6746,462 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "node_modules/cytoscape": { + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.25.0.tgz", + "integrity": "sha512-7MW3Iz57mCUo6JQCho6CmPBCbTlJr7LzyEtIkutG255HLVd4XuBg2I9BkTZLI/e4HoaOB/BiAzXuQybQ95+r9Q==", + "dependencies": { + "heap": "^0.2.6", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==" + }, + "node_modules/d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/d3-dsv/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.9.tgz", + "integrity": "sha512-rYR4QfVmy+sR44IBDvVtcAmOReGBvRCWDpO2QjYwqgh9yijw6eSHBqaPG/LIOEy7aBsniLvtMW6pg19qJhq60w==", + "dependencies": { + "d3": "^7.8.2", + "lodash-es": "^4.17.21" + } + }, "node_modules/damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "node_modules/dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -6982,6 +7468,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "dependencies": { + "robust-predicates": "^3.0.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -7159,6 +7653,11 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz", + "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==" + }, "node_modules/domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -7236,6 +7735,11 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, + "node_modules/elkjs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", + "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -9424,6 +9928,11 @@ "he": "bin/he" } }, + "node_modules/heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==" + }, "node_modules/history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -9997,6 +10506,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", @@ -10839,6 +11356,11 @@ "json-buffer": "3.0.0" } }, + "node_modules/khroma": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", + "integrity": "sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -10912,6 +11434,11 @@ "shell-quote": "^1.7.3" } }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + }, "node_modules/leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -11187,6 +11714,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "node_modules/lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", @@ -12189,6 +12721,37 @@ "node": ">= 8" } }, + "node_modules/mermaid": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.4.3.tgz", + "integrity": "sha512-TLkQEtqhRSuEHSE34lh5bCa94KATCyluAXmFnNI2PRZwOpXFeqiJWwZl+d2CcemE1RS6QbbueSSq9QIg8Uxcyw==", + "dependencies": { + "@braintree/sanitize-url": "^6.0.0", + "cytoscape": "^3.23.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.1.0", + "d3": "^7.4.0", + "dagre-d3-es": "7.0.9", + "dayjs": "^1.11.7", + "dompurify": "2.4.3", + "elkjs": "^0.8.2", + "khroma": "^2.0.0", + "lodash-es": "^4.17.21", + "non-layered-tidy-tree-layout": "^2.0.2", + "stylis": "^4.1.2", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.0", + "web-worker": "^1.2.0" + } + }, + "node_modules/mermaid/node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -12942,6 +13505,11 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" + }, "node_modules/normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -14827,6 +15395,18 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "node_modules/react-loadable": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-loadable/-/react-loadable-5.5.0.tgz", + "integrity": "sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg==", + "peer": true, + "dependencies": { + "prop-types": "^15.5.0" + }, + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-loadable-ssr-addon-v5-slorber": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", @@ -18123,6 +18703,11 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "node_modules/rtl-detect": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", @@ -18173,6 +18758,11 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "node_modules/rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -19184,6 +19774,11 @@ "node": ">=8" } }, + "node_modules/stylis": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz", + "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -19702,6 +20297,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tsconfig-paths": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", @@ -20715,6 +21318,11 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-worker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", + "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -22871,6 +23479,11 @@ "to-fast-properties": "^2.0.0" } }, + "@braintree/sanitize-url": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.2.tgz", + "integrity": "sha512-Tbsj02wXCbqGmzdnXNk0SOF19ChhRU70BsroIi4Pm6Ehp56in6vch94mfbdQ17DozxkL3BAVjbZ4Qc1a0HFRAg==" + }, "@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -23390,6 +24003,21 @@ "utility-types": "^3.10.0" } }, + "@docusaurus/theme-mermaid": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@docusaurus/theme-mermaid/-/theme-mermaid-2.4.1.tgz", + "integrity": "sha512-cM0ImKIqZfjmlaC+uAjep39kNBvb1bjz429QBHGs32maob4+UnRzVPPpCUCltyPVb4xjG5h1Tyq4pHzhtIikqA==", + "requires": { + "@docusaurus/core": "2.4.1", + "@docusaurus/module-type-aliases": "2.4.1", + "@docusaurus/theme-common": "2.4.1", + "@docusaurus/types": "2.4.1", + "@docusaurus/utils-validation": "2.4.1", + "@mdx-js/react": "^1.6.22", + "mermaid": "^9.2.2", + "tslib": "^2.4.0" + } + }, "@docusaurus/theme-search-algolia": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/@docusaurus/theme-search-algolia/-/theme-search-algolia-2.4.1.tgz", @@ -26021,6 +26649,14 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "requires": { + "layout-base": "^1.0.0" + } + }, "cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -26265,12 +26901,344 @@ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" }, + "cytoscape": { + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.25.0.tgz", + "integrity": "sha512-7MW3Iz57mCUo6JQCho6CmPBCbTlJr7LzyEtIkutG255HLVd4XuBg2I9BkTZLI/e4HoaOB/BiAzXuQybQ95+r9Q==", + "requires": { + "heap": "^0.2.6", + "lodash": "^4.17.21" + } + }, + "cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "requires": { + "cose-base": "^1.0.0" + } + }, + "cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "requires": { + "cose-base": "^2.2.0" + }, + "dependencies": { + "cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "requires": { + "layout-base": "^2.0.0" + } + }, + "layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==" + } + } + }, + "d3": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.8.5.tgz", + "integrity": "sha512-JgoahDG51ncUfJu6wX/1vWQEqOflgXyl4MaHqlcSruTez7yhaRKR9i8VjjcQGeS2en/jnFivXuaIMnseMMt0XA==", + "requires": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + } + }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==" + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + } + }, + "d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "requires": { + "d3-path": "1 - 3" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "requires": { + "d3-array": "^3.2.0" + } + }, + "d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "requires": { + "delaunator": "5" + } + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "requires": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "requires": { + "d3-dsv": "1 - 3" + } + }, + "d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "requires": { + "d3-array": "2.5.0 - 3" + } + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" + }, + "d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==" + }, + "d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==" + }, + "d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==" + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-scale-chromatic": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz", + "integrity": "sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==", + "requires": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "requires": { + "d3-path": "^3.1.0" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "requires": { + "d3-time": "1 - 3" + } + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, + "d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + } + }, + "dagre-d3-es": { + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.9.tgz", + "integrity": "sha512-rYR4QfVmy+sR44IBDvVtcAmOReGBvRCWDpO2QjYwqgh9yijw6eSHBqaPG/LIOEy7aBsniLvtMW6pg19qJhq60w==", + "requires": { + "d3": "^7.8.2", + "lodash-es": "^4.17.21" + } + }, "damerau-levenshtein": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", "dev": true }, + "dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -26457,6 +27425,14 @@ "slash": "^3.0.0" } }, + "delaunator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.0.0.tgz", + "integrity": "sha512-AyLvtyJdbv/U1GkiS6gUUzclRoAY4Gs75qkMygJJhU75LW4DNuSF2RMzpxs9jw9Oz1BobHjTdkG3zdP55VxAqw==", + "requires": { + "robust-predicates": "^3.0.0" + } + }, "depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -26584,6 +27560,11 @@ "domelementtype": "^2.3.0" } }, + "dompurify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz", + "integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==" + }, "domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -26648,6 +27629,11 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, + "elkjs": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.8.2.tgz", + "integrity": "sha512-L6uRgvZTH+4OF5NE/MBbzQx/WYpru1xCBE9respNj6qznEewGUIfhzmm7horWWxbNO2M0WckQypGctR8lH79xQ==" + }, "emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -28265,6 +29251,11 @@ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==" }, + "heap": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/heap/-/heap-0.2.7.tgz", + "integrity": "sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==" + }, "history": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz", @@ -28696,6 +29687,11 @@ "side-channel": "^1.0.4" } }, + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, "interpret": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", @@ -29261,6 +30257,11 @@ "json-buffer": "3.0.0" } }, + "khroma": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", + "integrity": "sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==" + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -29322,6 +30323,11 @@ "shell-quote": "^1.7.3" } }, + "layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==" + }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", @@ -29518,6 +30524,11 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, "lodash.curry": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz", @@ -30288,6 +31299,36 @@ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, + "mermaid": { + "version": "9.4.3", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.4.3.tgz", + "integrity": "sha512-TLkQEtqhRSuEHSE34lh5bCa94KATCyluAXmFnNI2PRZwOpXFeqiJWwZl+d2CcemE1RS6QbbueSSq9QIg8Uxcyw==", + "requires": { + "@braintree/sanitize-url": "^6.0.0", + "cytoscape": "^3.23.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.1.0", + "d3": "^7.4.0", + "dagre-d3-es": "7.0.9", + "dayjs": "^1.11.7", + "dompurify": "2.4.3", + "elkjs": "^0.8.2", + "khroma": "^2.0.0", + "lodash-es": "^4.17.21", + "non-layered-tidy-tree-layout": "^2.0.2", + "stylis": "^4.1.2", + "ts-dedent": "^2.2.0", + "uuid": "^9.0.0", + "web-worker": "^1.2.0" + }, + "dependencies": { + "uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" + } + } + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -30729,6 +31770,11 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, + "non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==" + }, "normalize-package-data": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", @@ -32021,6 +33067,15 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-loadable": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/react-loadable/-/react-loadable-5.5.0.tgz", + "integrity": "sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg==", + "peer": true, + "requires": { + "prop-types": "^15.5.0" + } + }, "react-loadable-ssr-addon-v5-slorber": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/react-loadable-ssr-addon-v5-slorber/-/react-loadable-ssr-addon-v5-slorber-1.0.1.tgz", @@ -34788,6 +35843,11 @@ "glob": "^7.1.3" } }, + "robust-predicates": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz", + "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" + }, "rtl-detect": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/rtl-detect/-/rtl-detect-1.0.4.tgz", @@ -34818,6 +35878,11 @@ "queue-microtask": "^1.2.2" } }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, "rxjs": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", @@ -35610,6 +36675,11 @@ "stylelint-config-recommended": "^9.0.0" } }, + "stylis": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz", + "integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ==" + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -35982,6 +37052,11 @@ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz", "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==" }, + "ts-dedent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.2.0.tgz", + "integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==" + }, "tsconfig-paths": { "version": "3.14.2", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", @@ -36688,6 +37763,11 @@ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" }, + "web-worker": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.2.0.tgz", + "integrity": "sha512-PgF341avzqyx60neE9DD+XS26MMNMoUQRz9NOZwW32nPQrF6p77f1htcnjBSEV8BGMKZ16choqUG4hyI0Hx7mA==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index e425f273..f0255faf 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "dependencies": { "@docusaurus/core": "^2.4.0", "@docusaurus/preset-classic": "^2.4.0", + "@docusaurus/theme-mermaid": "^2.4.1", "@easyops-cn/docusaurus-search-local": "^0.35.0", "@mdx-js/react": "^1.6.22", "@node-rs/jieba": "^1.7.0",