From 398c415e683904f5db610e1bade451e3b49c1b92 Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Wed, 1 Apr 2026 16:19:57 -0500 Subject: [PATCH 1/2] Add VitePress documentation site with compilable code samples - VitePress site in docs/ with orange JasperFx-branded theme - 21 documentation pages across 5 sections: Getting Started, Code Generation, Command Line, Configuration, Extension Methods - Code Generation section with Mermaid architecture diagram, detailed Frame/Variable/MethodCall/GeneratedType reference pages - Command Line section covering setup, writing commands, arguments/flags, environment checks, and describe command - CritterStackDefaults and JasperFxOptions configuration docs - Extension method reference for String, Enumerable, and Reflection helpers - All code samples in compilable DocSamples project using mdsnippets - Netlify deployment config targeting docs.jasperfx.net - Root package.json with mdsnippets + concurrently for docs workflow Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 4 + docs/.gitignore | 3 + docs/.vitepress/config.ts | 108 + docs/.vitepress/theme/custom.css | 30 + docs/.vitepress/theme/index.ts | 4 + docs/cli/arguments-flags.md | 100 + docs/cli/describe.md | 91 + docs/cli/environment-checks.md | 180 + docs/cli/index.md | 82 + docs/cli/writing-commands.md | 128 + docs/codegen/built-in-frames.md | 242 ++ docs/codegen/cli.md | 141 + docs/codegen/frames.md | 159 + docs/codegen/generated-types.md | 205 + docs/codegen/index.md | 99 + docs/codegen/method-call.md | 161 + docs/codegen/variables.md | 100 + docs/configuration/critter-stack-defaults.md | 76 + docs/configuration/jasperfx-options.md | 70 + docs/extensions/enumerable-extensions.md | 68 + docs/extensions/index.md | 46 + docs/extensions/reflection-extensions.md | 68 + docs/extensions/string-extensions.md | 60 + docs/guide/index.md | 31 + docs/guide/installation.md | 47 + docs/guide/quickstart.md | 84 + docs/index.md | 29 + docs/package.json | 15 + docs/public/jasperfx-logo.png | Bin 0 -> 114672 bytes mdsnippets.json | 8 + netlify.toml | 7 + package-lock.json | 3936 ++++++++++++++++++ package.json | 14 + src/DocSamples/ArgumentFlagSamples.cs | 25 + src/DocSamples/BuiltInFramesSamples.cs | 142 + src/DocSamples/CliSetupSamples.cs | 37 + src/DocSamples/CodegenCliSamples.cs | 64 + src/DocSamples/CodegenOverviewSamples.cs | 37 + src/DocSamples/ConfigurationSamples.cs | 43 + src/DocSamples/DescribeSamples.cs | 22 + src/DocSamples/DocSamples.csproj | 23 + src/DocSamples/EnvironmentCheckSamples.cs | 53 + src/DocSamples/ExtensionSamples.cs | 53 + src/DocSamples/FramesSamples.cs | 81 + src/DocSamples/GeneratedTypesSamples.cs | 123 + src/DocSamples/MethodCallSamples.cs | 116 + src/DocSamples/QuickStartSamples.cs | 19 + src/DocSamples/VariablesSamples.cs | 61 + src/DocSamples/WritingCommandSamples.cs | 36 + 49 files changed, 7331 insertions(+) create mode 100644 docs/.gitignore create mode 100644 docs/.vitepress/config.ts create mode 100644 docs/.vitepress/theme/custom.css create mode 100644 docs/.vitepress/theme/index.ts create mode 100644 docs/cli/arguments-flags.md create mode 100644 docs/cli/describe.md create mode 100644 docs/cli/environment-checks.md create mode 100644 docs/cli/index.md create mode 100644 docs/cli/writing-commands.md create mode 100644 docs/codegen/built-in-frames.md create mode 100644 docs/codegen/cli.md create mode 100644 docs/codegen/frames.md create mode 100644 docs/codegen/generated-types.md create mode 100644 docs/codegen/index.md create mode 100644 docs/codegen/method-call.md create mode 100644 docs/codegen/variables.md create mode 100644 docs/configuration/critter-stack-defaults.md create mode 100644 docs/configuration/jasperfx-options.md create mode 100644 docs/extensions/enumerable-extensions.md create mode 100644 docs/extensions/index.md create mode 100644 docs/extensions/reflection-extensions.md create mode 100644 docs/extensions/string-extensions.md create mode 100644 docs/guide/index.md create mode 100644 docs/guide/installation.md create mode 100644 docs/guide/quickstart.md create mode 100644 docs/index.md create mode 100644 docs/package.json create mode 100644 docs/public/jasperfx-logo.png create mode 100644 mdsnippets.json create mode 100644 netlify.toml create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/DocSamples/ArgumentFlagSamples.cs create mode 100644 src/DocSamples/BuiltInFramesSamples.cs create mode 100644 src/DocSamples/CliSetupSamples.cs create mode 100644 src/DocSamples/CodegenCliSamples.cs create mode 100644 src/DocSamples/CodegenOverviewSamples.cs create mode 100644 src/DocSamples/ConfigurationSamples.cs create mode 100644 src/DocSamples/DescribeSamples.cs create mode 100644 src/DocSamples/DocSamples.csproj create mode 100644 src/DocSamples/EnvironmentCheckSamples.cs create mode 100644 src/DocSamples/ExtensionSamples.cs create mode 100644 src/DocSamples/FramesSamples.cs create mode 100644 src/DocSamples/GeneratedTypesSamples.cs create mode 100644 src/DocSamples/MethodCallSamples.cs create mode 100644 src/DocSamples/QuickStartSamples.cs create mode 100644 src/DocSamples/VariablesSamples.cs create mode 100644 src/DocSamples/WritingCommandSamples.cs diff --git a/.gitignore b/.gitignore index e7c4576..8565fee 100644 --- a/.gitignore +++ b/.gitignore @@ -399,3 +399,7 @@ FodyWeavers.xsd .idea/ .DS_Store src/CommandLineRunner/description.txt + +# VitePress documentation +docs/.vitepress/cache +docs/.vitepress/dist diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..94aa6e0 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,3 @@ +.vitepress/cache +.vitepress/dist +node_modules diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts new file mode 100644 index 0000000..79dd736 --- /dev/null +++ b/docs/.vitepress/config.ts @@ -0,0 +1,108 @@ +import { defineConfig } from 'vitepress' +import { withMermaid } from 'vitepress-plugin-mermaid' + +export default withMermaid( + defineConfig({ + title: 'JasperFx', + description: 'The foundational .NET library behind the Critter Stack', + head: [ + ['link', { rel: 'icon', href: '/jasperfx-logo.png' }] + ], + + themeConfig: { + logo: '/jasperfx-logo.png', + + nav: [ + { text: 'Guide', link: '/guide/' }, + { text: 'Code Generation', link: '/codegen/' }, + { text: 'Command Line', link: '/cli/' }, + { text: 'Configuration', link: '/configuration/critter-stack-defaults' }, + { + text: 'Ecosystem', + items: [ + { text: 'Marten', link: 'https://martendb.io' }, + { text: 'Wolverine', link: 'https://wolverinefx.io' }, + { text: 'Weasel', link: 'https://weasel.jasperfx.net' }, + { text: 'GitHub', link: 'https://github.com/JasperFx/jasperfx' } + ] + } + ], + + sidebar: [ + { + text: 'Getting Started', + collapsed: false, + items: [ + { text: 'Introduction', link: '/guide/' }, + { text: 'Installation', link: '/guide/installation' }, + { text: 'Quick Start', link: '/guide/quickstart' } + ] + }, + { + text: 'Code Generation', + collapsed: false, + items: [ + { text: 'Overview & Architecture', link: '/codegen/' }, + { text: 'Frames', link: '/codegen/frames' }, + { text: 'Variables', link: '/codegen/variables' }, + { text: 'MethodCall', link: '/codegen/method-call' }, + { text: 'Generated Types & Methods', link: '/codegen/generated-types' }, + { text: 'Built-in Frames', link: '/codegen/built-in-frames' }, + { text: 'CLI: codegen Command', link: '/codegen/cli' } + ] + }, + { + text: 'Command Line', + collapsed: false, + items: [ + { text: 'Setup & Integration', link: '/cli/' }, + { text: 'Writing Commands', link: '/cli/writing-commands' }, + { text: 'Arguments & Flags', link: '/cli/arguments-flags' }, + { text: 'Environment Checks', link: '/cli/environment-checks' }, + { text: 'Describe Command', link: '/cli/describe' } + ] + }, + { + text: 'Configuration', + collapsed: true, + items: [ + { text: 'CritterStackDefaults', link: '/configuration/critter-stack-defaults' }, + { text: 'JasperFxOptions', link: '/configuration/jasperfx-options' } + ] + }, + { + text: 'Extension Methods', + collapsed: true, + items: [ + { text: 'Overview', link: '/extensions/' }, + { text: 'String Extensions', link: '/extensions/string-extensions' }, + { text: 'Enumerable Extensions', link: '/extensions/enumerable-extensions' }, + { text: 'Reflection Extensions', link: '/extensions/reflection-extensions' } + ] + } + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/JasperFx/jasperfx' } + ], + + editLink: { + pattern: 'https://github.com/JasperFx/jasperfx/edit/main/docs/:path' + }, + + footer: { + message: 'Released under the MIT License.', + copyright: 'Copyright JasperFx Software' + }, + + search: { + provider: 'local' + } + }, + + mermaid: {}, + mermaidPlugin: { + class: 'mermaid' + } + }) +) diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css new file mode 100644 index 0000000..91ee6e0 --- /dev/null +++ b/docs/.vitepress/theme/custom.css @@ -0,0 +1,30 @@ +:root { + --vp-c-brand-1: #C26A1A; + --vp-c-brand-2: #D4782B; + --vp-c-brand-3: #E08A3D; + --vp-c-brand-soft: rgba(194, 106, 26, 0.14); + + --vp-home-hero-name-color: transparent; + --vp-home-hero-name-background: linear-gradient(135deg, #C26A1A 0%, #E08A3D 100%); + --vp-home-hero-image-background-image: linear-gradient(135deg, rgba(194, 106, 26, 0.3) 0%, rgba(224, 138, 61, 0.2) 100%); + --vp-home-hero-image-filter: blur(44px); + + --vp-button-brand-border: transparent; + --vp-button-brand-text: #fff; + --vp-button-brand-bg: #C26A1A; + --vp-button-brand-hover-border: transparent; + --vp-button-brand-hover-text: #fff; + --vp-button-brand-hover-bg: #D4782B; + --vp-button-brand-active-border: transparent; + --vp-button-brand-active-text: #fff; + --vp-button-brand-active-bg: #A85A16; +} + +.dark { + --vp-c-brand-1: #D4782B; + --vp-c-brand-2: #E08A3D; + --vp-c-brand-3: #ECA050; + --vp-c-brand-soft: rgba(212, 120, 43, 0.16); + + --vp-home-hero-image-background-image: linear-gradient(135deg, rgba(194, 106, 26, 0.2) 0%, rgba(224, 138, 61, 0.15) 100%); +} diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000..42fe9a9 --- /dev/null +++ b/docs/.vitepress/theme/index.ts @@ -0,0 +1,4 @@ +import DefaultTheme from 'vitepress/theme' +import './custom.css' + +export default DefaultTheme diff --git a/docs/cli/arguments-flags.md b/docs/cli/arguments-flags.md new file mode 100644 index 0000000..1e09a06 --- /dev/null +++ b/docs/cli/arguments-flags.md @@ -0,0 +1,100 @@ +# Arguments and Flags + +Command inputs are plain C# classes whose properties are mapped to arguments and flags. + +## Defining an Input Class + + + +```cs +public class BuildInput +{ + [Description("The target configuration")] + public string Configuration { get; set; } = "Debug"; + + [Description("The output directory")] + public string OutputPath { get; set; } = "./bin"; + + [FlagAlias("verbose", 'v')] + [Description("Enable verbose output")] + public bool VerboseFlag { get; set; } + + [FlagAlias("force", 'f')] + [Description("Force a clean rebuild")] + public bool ForceFlag { get; set; } + + [Description("Maximum degree of parallelism")] + public int ParallelCount { get; set; } = 4; +} +``` +snippet source | anchor + + +```cs +public class BuildInput +{ + [Description("The target configuration")] + public string Configuration { get; set; } = "Debug"; + + [Description("The output directory")] + public string OutputPath { get; set; } = "./bin"; + + [FlagAlias("verbose", 'v')] + [Description("Enable verbose output")] + public bool VerboseFlag { get; set; } + + [FlagAlias("force", 'f')] + [Description("Force a clean rebuild")] + public bool ForceFlag { get; set; } + + [Description("Maximum degree of parallelism")] + public int ParallelCount { get; set; } = 4; +} +``` +snippet source | anchor + + +## Arguments + +Public properties that are not suffixed with `Flag` are treated as positional arguments. They are matched in the order they appear on the class. + +- **Required arguments** -- Non-nullable properties without a default value +- **Optional arguments** -- Properties with a default value + +## Flags + +Properties whose names end with `Flag` are treated as command line flags (options). + +### Flag Aliases + +Use `[FlagAlias]` to define short and long flag names: + +```csharp +[FlagAlias("verbose", 'v')] +public bool VerboseFlag { get; set; } +``` + +This allows both `--verbose` and `-v` on the command line. + +### Flag Types + +| .NET Type | CLI Syntax | Example | +|-----------|-----------|---------| +| `bool` | `--flag` | `--verbose` | +| `string` | `--flag value` | `--output ./bin` | +| `int` | `--flag value` | `--parallel 8` | +| `Enum` | `--flag value` | `--level Debug` | + +## Description Attribute + +Use `[Description]` on properties to provide help text displayed in the CLI: + +```csharp +[Description("The target configuration")] +public string Configuration { get; set; } = "Debug"; +``` + +## Next Steps + +- [Writing Commands](/cli/writing-commands) -- Build commands using input classes +- [Environment Checks](/cli/environment-checks) -- Startup validation diff --git a/docs/cli/describe.md b/docs/cli/describe.md new file mode 100644 index 0000000..9231aca --- /dev/null +++ b/docs/cli/describe.md @@ -0,0 +1,91 @@ +# Describe Command + +The `describe` command outputs a summary of your application's configuration and registered components. It is built in and available automatically. + +## Running Describe + +```bash +dotnet run -- describe +``` + +This prints information about all registered `ISystemPart` instances, including those added by Critter Stack libraries like Marten and Wolverine. + +## Custom System Parts + +Implement `ISystemPart` to add your own sections to the describe output: + + + +```cs +public class MessagingSystemPart : SystemPartBase +{ + public MessagingSystemPart() + : base("Messaging Subsystem", new Uri("system://messaging")) + { + } + + public override Task WriteToConsole() + { + AnsiConsole.MarkupLine("[bold]Transport:[/] RabbitMQ"); + AnsiConsole.MarkupLine("[bold]Queues:[/] 12 active"); + AnsiConsole.MarkupLine("[bold]Consumers:[/] 8 running"); + return Task.CompletedTask; + } +} +``` +snippet source | anchor + + +```cs +public class MessagingSystemPart : SystemPartBase +{ + public MessagingSystemPart() + : base("Messaging Subsystem", new Uri("system://messaging")) + { + } + + public override Task WriteToConsole() + { + AnsiConsole.MarkupLine("[bold]Transport:[/] RabbitMQ"); + AnsiConsole.MarkupLine("[bold]Queues:[/] 12 active"); + AnsiConsole.MarkupLine("[bold]Consumers:[/] 8 running"); + return Task.CompletedTask; + } +} +``` +snippet source | anchor + + +Register your system part through `JasperFxOptions`: + +```csharp +services.AddJasperFx(opts => +{ + opts.Services.AddSingleton(); +}); +``` + +## IDescriptionWriter + +The `IDescriptionWriter` interface provides methods for structured output: + +| Method | Purpose | +|--------|---------| +| `BulletItem(string)` | Write a bullet point | +| `Header(string)` | Write a section header | +| `Write(string)` | Write plain text | + +## Built-in System Parts + +JasperFx itself registers a system part for `JasperFxOptions` that reports: + +- Active profile (Development, Staging, Production) +- Required files +- Registered environment checks + +Other Critter Stack libraries add their own parts automatically when referenced. + +## Next Steps + +- [Environment Checks](/cli/environment-checks) -- Validate dependencies at startup +- [JasperFx Options](/configuration/jasperfx-options) -- Full options reference diff --git a/docs/cli/environment-checks.md b/docs/cli/environment-checks.md new file mode 100644 index 0000000..3f159a3 --- /dev/null +++ b/docs/cli/environment-checks.md @@ -0,0 +1,180 @@ +# Environment Checks + +Environment checks let you verify that external dependencies are available when your application starts. + +## Registering Checks + +Use the `CheckEnvironment` extension methods on `IServiceCollection`: + + + +```cs +public static void RegisterChecks(IServiceCollection services) +{ + // Async check with IServiceProvider access + services.CheckEnvironment( + "Database is reachable", + async (IServiceProvider sp, CancellationToken ct) => + { + // Throw an exception to indicate failure + await Task.CompletedTask; + }); + + // Synchronous check + services.CheckEnvironment( + "Configuration file exists", + (IServiceProvider sp) => + { + if (!File.Exists("appsettings.json")) + { + throw new FileNotFoundException("Missing configuration file"); + } + }); +} +``` +snippet source | anchor + + +```cs +public static void RegisterChecks(IServiceCollection services) +{ + // Async check with IServiceProvider access + services.CheckEnvironment( + "Database is reachable", + async (IServiceProvider sp, CancellationToken ct) => + { + // Throw an exception to indicate failure + await Task.CompletedTask; + }); + + // Synchronous check + services.CheckEnvironment( + "Configuration file exists", + (IServiceProvider sp) => + { + if (!File.Exists("appsettings.json")) + { + throw new FileNotFoundException("Missing configuration file"); + } + }); +} +``` +snippet source | anchor + + +## Typed Service Checks + +You can resolve a registered service and check it directly: + + + +```cs +public static void RegisterTypedCheck(IServiceCollection services) +{ + services.CheckEnvironment( + "Required config keys present", + config => + { + if (config?.GetValue("ConnectionString") is null) + { + throw new Exception("ConnectionString is required"); + } + }); +} +``` +snippet source | anchor + + +```cs +public static void RegisterTypedCheck(IServiceCollection services) +{ + services.CheckEnvironment( + "Required config keys present", + config => + { + if (config?.GetValue("ConnectionString") is null) + { + throw new Exception("ConnectionString is required"); + } + }); +} +``` +snippet source | anchor + + +## Running Checks + +Run all registered checks from the command line: + +```bash +dotnet run -- check-env +``` + +Each check runs and reports success or failure. The command exits with a non-zero code if any check fails. + +## Inline Registration via JasperFxOptions + +You can also register checks directly through `JasperFxOptions`: + + + +```cs +public static void ConfigureOptions(IServiceCollection services) +{ + services.AddJasperFx(opts => + { + // Register an environment check inline + opts.RegisterEnvironmentCheck( + "Database connectivity", + async (sp, ct) => + { + // Verify your database is accessible + await Task.CompletedTask; + }); + }); +} +``` +snippet source | anchor + + +```cs +public static void ConfigureOptions(IServiceCollection services) +{ + services.AddJasperFx(opts => + { + // Register an environment check inline + opts.RegisterEnvironmentCheck( + "Database connectivity", + async (sp, ct) => + { + // Verify your database is accessible + await Task.CompletedTask; + }); + }); +} +``` +snippet source | anchor + + +## Required Files + +A common check is verifying that a configuration file exists. JasperFx provides a shorthand: + +```csharp +services.AddJasperFx(opts => +{ + opts.RequireFile("appsettings.json"); + opts.RequireFile("certs/server.pfx"); +}); +``` + +## Best Practices + +- Keep checks fast. They run at startup and slow checks delay your application. +- Throw descriptive exceptions so failures are easy to diagnose. +- Use environment checks for external dependencies (databases, files, services) rather than internal validation. + +## Next Steps + +- [Describe](/cli/describe) -- Customize application description output +- [Configuration](/configuration/jasperfx-options) -- Full options reference diff --git a/docs/cli/index.md b/docs/cli/index.md new file mode 100644 index 0000000..23249b8 --- /dev/null +++ b/docs/cli/index.md @@ -0,0 +1,82 @@ +# Command Line Tooling + +JasperFx includes a lightweight CLI framework for building commands that integrate with `Microsoft.Extensions.Hosting`. + +## Enabling the CLI + +Wire up the JasperFx command line by calling `ApplyJasperFxExtensions` on your host builder: + + + +```cs +await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); +``` +snippet source | anchor + + +```cs +await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); +``` +snippet source | anchor + + +Alternatively, use `RunJasperFxCommands` for more control over host configuration: + + + +```cs +var builder = Host.CreateDefaultBuilder(); + +builder.ConfigureServices(services => +{ + // Register your services here +}); + +await builder + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); +``` +snippet source | anchor + + +```cs +var builder = Host.CreateDefaultBuilder(); + +builder.ConfigureServices(services => +{ + // Register your services here +}); + +await builder + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); +``` +snippet source | anchor + + +## Built-in Commands + +JasperFx ships with several commands out of the box: + +| Command | Description | +|---------|-------------| +| `help` | List all available commands | +| `describe` | Describe the application configuration | +| `check-env` | Run all registered environment checks | + +## Command Discovery + +Commands are discovered automatically from referenced assemblies that carry the `[JasperFxTool]` attribute. Your own commands are found through assembly scanning. + +## Topics + +- [Writing Commands](/cli/writing-commands) -- Create synchronous and async commands +- [Arguments and Flags](/cli/arguments-flags) -- Define inputs with attributes +- [Environment Checks](/cli/environment-checks) -- Validate runtime dependencies +- [Describe](/cli/describe) -- Customize the describe output diff --git a/docs/cli/writing-commands.md b/docs/cli/writing-commands.md new file mode 100644 index 0000000..7fcb6ac --- /dev/null +++ b/docs/cli/writing-commands.md @@ -0,0 +1,128 @@ +# Writing Commands + +JasperFx provides two base classes for building CLI commands. + +## Synchronous Commands + +Extend `JasperFxCommand` for commands that do not need async operations: + + + +```cs +[Description("Say hello to someone")] +public class GreetingCommand : JasperFxCommand +{ + public override bool Execute(GreetingInput input) + { + Console.WriteLine($"Hello, {input.Name}!"); + return true; + } +} +``` +snippet source | anchor + + +```cs +[Description("Say hello to someone")] +public class GreetingCommand : JasperFxCommand +{ + public override bool Execute(GreetingInput input) + { + Console.WriteLine($"Hello, {input.Name}!"); + return true; + } +} +``` +snippet source | anchor + + +The `Execute` method returns `true` for success or `false` for failure. The exit code is set accordingly. + +## Async Commands + +Extend `JasperFxAsyncCommand` when you need to perform async work: + + + +```cs +[Description("Say hello to someone asynchronously")] +public class AsyncGreetingCommand : JasperFxAsyncCommand +{ + public override async Task Execute(GreetingInput input) + { + await Task.Delay(100); + Console.WriteLine($"Hello, {input.Name}!"); + return true; + } +} +``` +snippet source | anchor + + +```cs +[Description("Say hello to someone asynchronously")] +public class AsyncGreetingCommand : JasperFxAsyncCommand +{ + public override async Task Execute(GreetingInput input) + { + await Task.Delay(100); + Console.WriteLine($"Hello, {input.Name}!"); + return true; + } +} +``` +snippet source | anchor + + +## Input Classes + +Every command takes an input class that defines its arguments and flags: + + + +```cs +public class GreetingInput +{ + [Description("The name to greet")] + public string Name { get; set; } = "World"; +} +``` +snippet source | anchor + + +```cs +public class GreetingInput +{ + [Description("The name to greet")] + public string Name { get; set; } = "World"; +} +``` +snippet source | anchor + + +Properties on the input class are automatically mapped to command line arguments. See [Arguments and Flags](/cli/arguments-flags) for the full attribute reference. + +## Command Naming + +By default, the command name is derived from the class name by removing the `Command` suffix and converting to kebab-case. For example, `GreetingCommand` becomes `greeting`. + +## Usage Patterns + +Commands can define multiple usage patterns similar to Git: + +```csharp +public class MyCommand : JasperFxCommand +{ + public MyCommand() + { + Usage("Default usage").Arguments(x => x.Name); + } + + public override bool Execute(MyInput input) => true; +} +``` + +## Next Steps + +- [Arguments and Flags](/cli/arguments-flags) -- Detailed attribute reference +- [Environment Checks](/cli/environment-checks) -- Register startup validations diff --git a/docs/codegen/built-in-frames.md b/docs/codegen/built-in-frames.md new file mode 100644 index 0000000..07584f9 --- /dev/null +++ b/docs/codegen/built-in-frames.md @@ -0,0 +1,242 @@ +# Built-in Frames + +JasperFx ships with several ready-to-use `Frame` implementations. These cover the most common code generation patterns so you rarely need to write custom frames for straightforward scenarios. + +## CommentFrame + +Writes a single-line C# comment into the generated code. Useful for making generated source more readable. + + + +```cs +public static void UsingCommentFrame() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Worker", typeof(IWorker)); + var method = type.MethodFor(nameof(IWorker.Execute)); + + // CommentFrame writes a C# comment line + method.Frames.Add(new CommentFrame("Begin processing")); + method.Frames.Code("Console.WriteLine(\"Working...\");"); +} + +public interface IWorker +{ + void Execute(); +} +``` +snippet source | anchor + + +Generated output: + +``` +// Begin processing +``` + +## CodeFrame + +A general-purpose frame that writes a single statement from a format string. Variable placeholders are resolved automatically. + + + +```cs +public static void UsingCodeFrame() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Processor", typeof(IProcessor)); + var method = type.MethodFor(nameof(IProcessor.Process)); + + // CodeFrame uses a format string with variable placeholders + method.Frames.Code("Console.WriteLine({0});", Use.Type()); +} + +public interface IProcessor +{ + void Process(string input); +} +``` +snippet source | anchor + + +The `{0}` placeholder is replaced by the resolved variable's `Usage` name. You can reference multiple variables with `{1}`, `{2}`, etc. + +## ReturnFrame + +Generates a `return` statement, optionally returning a resolved variable. + + + +```cs +public static void UsingReturnFrame() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Checker", typeof(IChecker)); + var method = type.MethodFor(nameof(IChecker.IsValid)); + + method.Frames.Code("var result = {0} != null;", Use.Type()); + + // ReturnFrame generates "return ;" + method.Frames.Add(new ReturnFrame(typeof(bool))); +} + +public interface IChecker +{ + bool IsValid(object input); +} +``` +snippet source | anchor + + +- `new ReturnFrame()` -- generates `return;` for void methods. +- `new ReturnFrame(typeof(bool))` -- resolves a `bool` variable and generates `return ;`. +- `new ReturnFrame(variable)` -- generates `return ;` for a specific variable. + +## MethodCall + +Generates a call to an existing method with full argument and return value resolution. This is the most commonly used frame and has its own dedicated page. + + + +```cs +public static void UsingMethodCallFrame() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Invoker", typeof(IInvoker)); + var method = type.MethodFor(nameof(IInvoker.Invoke)); + + // MethodCall generates a call to a static or instance method + var call = new MethodCall(typeof(Console), nameof(Console.WriteLine)); + method.Frames.Add(call); +} + +public interface IInvoker +{ + void Invoke(string message); +} +``` +snippet source | anchor + + +See [MethodCall](./method-call) for the full reference. + +## ConstructorFrame + +Generates a `new` expression for a given type, resolving constructor arguments through the variable system. + + + +```cs +public static void UsingConstructorFrame() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("ServiceBuilder", typeof(IServiceBuilder)); + var method = type.MethodFor(nameof(IServiceBuilder.Build)); + + // ConstructorFrame generates "var widget = new Widget();" + var ctor = new ConstructorFrame(() => new Widget()); + method.Frames.Add(ctor); +} + +public interface IServiceBuilder +{ + Widget Build(); +} + +public class Widget; +``` +snippet source | anchor + + +The generic `ConstructorFrame` variant accepts a lambda expression to identify the constructor. The generated code will be something like: + +``` +var widget = new Widget(); +``` + +### ConstructorCallMode + +| Mode | Generated Code | +|------|---------------| +| `Variable` | `var x = new T(...);` (default) | +| `ReturnValue` | `return new T(...);` | +| `UsingNestedVariable` | `using var x = new T(...);` | + +## IfBlock + +Wraps inner frames in a conditional `if` block. + + + +```cs +public static void UsingIfBlock() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Guard", typeof(IGuard)); + var method = type.MethodFor(nameof(IGuard.Check)); + + // IfBlock wraps inner frames in an if statement + var inner = new CodeFrame(false, "Console.WriteLine(\"Input is not null\");"); + method.Frames.Add(new IfBlock("input != null", inner)); +} + +public interface IGuard +{ + void Check(object input); +} +``` +snippet source | anchor + + +You can pass a string condition or a `Variable` (uses the variable's `Usage` property as the condition). + +## ThrowExceptionFrame + +Generates a `throw new ExceptionType(...)` statement. + +```csharp +var frame = new ThrowExceptionFrame(someVariable); +// Generates: throw new System.InvalidOperationException(someVariable); +``` + +## TemplateFrame + +An abstract base for frames that use a template string with typed variable placeholders. Subclass it and override `Template()`: + +```csharp +public class MyFrame : TemplateFrame +{ + protected override string Template() + { + var input = Arg(); + return $"Console.WriteLine({input});"; + } +} +``` + +The `Arg()` method creates a placeholder that the engine resolves to a real variable during code arrangement. + +## Summary + +| Frame | Purpose | +|-------|---------| +| `CommentFrame` | Writes a `// comment` line | +| `CodeFrame` | Writes a single statement from a format string | +| `ReturnFrame` | Writes `return;` or `return variable;` | +| `MethodCall` | Calls an existing method | +| `ConstructorFrame` | Calls `new T(...)` | +| `IfBlock` | Wraps frames in `if (condition) { }` | +| `ThrowExceptionFrame` | Throws an exception | +| `TemplateFrame` | Template-based code with typed placeholders | diff --git a/docs/codegen/cli.md b/docs/codegen/cli.md new file mode 100644 index 0000000..5410fe1 --- /dev/null +++ b/docs/codegen/cli.md @@ -0,0 +1,141 @@ +# CLI: codegen Command + +JasperFx provides a `codegen` command through its CLI tooling that lets you manage generated code ahead of time. This is essential for production deployments where you want the fastest possible startup by avoiding runtime compilation. + +## Setup + +To use the `codegen` command, your application must integrate the JasperFx command line extensions: + + + +```cs +public static async Task SetupWithCodegenCommand(string[] args) +{ + return await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); + + // Run with: dotnet run -- codegen preview + // Run with: dotnet run -- codegen write + // Run with: dotnet run -- codegen delete +} +``` +snippet source | anchor + + +## TypeLoadMode + +The `TypeLoadMode` enum on `GenerationRules` controls how generated types are loaded at runtime: + +### Dynamic + + + +```cs +public static void ConfigureDynamicMode() +{ + // Always generate types at runtime. Best for development. + var rules = new GenerationRules("MyApp.Generated") + { + TypeLoadMode = TypeLoadMode.Dynamic + }; +} +``` +snippet source | anchor + + +Always generates and compiles types at runtime. This is the default and is the best choice during development because changes to configuration are immediately reflected without a separate build step. + +### Auto + + + +```cs +public static void ConfigureAutoMode() +{ + // Try to load pre-built types first, fall back to runtime generation + var rules = new GenerationRules("MyApp.Generated") + { + TypeLoadMode = TypeLoadMode.Auto + }; +} +``` +snippet source | anchor + + +Tries to load pre-built types from the application assembly first. If the types are not found, falls back to runtime generation and exports the new source code. This is a good middle ground for staging environments. + +### Static + + + +```cs +public static void ConfigureStaticMode() +{ + // Types must be pre-built in the application assembly. + // Throws if generated types are missing. + var rules = new GenerationRules("MyApp.Generated") + { + TypeLoadMode = TypeLoadMode.Static + }; +} +``` +snippet source | anchor + + +Types must already exist in the pre-built application assembly. If any generated type is missing, the application throws an exception at startup. This provides the fastest startup time and is recommended for production. + +## Commands + +### codegen preview + +```bash +dotnet run -- codegen preview +``` + +Generates all source code and writes it to the console without modifying any files. Use this to inspect the generated code before committing it. + +### codegen write + +```bash +dotnet run -- codegen write +``` + +Generates all source code and writes the files into the project directory. The generated files are then compiled into the assembly on the next `dotnet build`. After writing, you can switch to `TypeLoadMode.Static` or `TypeLoadMode.Auto` to load the pre-built types. + +### codegen delete + +```bash +dotnet run -- codegen delete +``` + +Removes all previously generated source files from the project directory. Use this to clean up before regenerating or when switching back to `TypeLoadMode.Dynamic`. + +## Recommended Workflow + +1. **During development**, use `TypeLoadMode.Dynamic` so types are always regenerated as you change configuration. +2. **Before deploying**, run `dotnet run -- codegen write` to persist the generated source files. +3. **In production**, switch to `TypeLoadMode.Static` for the fastest startup. The pre-built types load directly from the compiled assembly with no Roslyn overhead. + +```mermaid +graph LR + Dev["Development
Dynamic"] -->|codegen write| Build["CI Build
Auto"] + Build -->|deploy| Prod["Production
Static"] + Prod -->|codegen delete| Dev +``` + +## Environment-Based Configuration + +A common pattern is to select the `TypeLoadMode` based on the hosting environment: + +```csharp +var rules = new GenerationRules("MyApp.Generated") +{ + TypeLoadMode = builder.Environment.IsDevelopment() + ? TypeLoadMode.Dynamic + : TypeLoadMode.Static +}; +``` + +This gives you runtime generation during development and pre-built types in production without any manual switching. diff --git a/docs/codegen/frames.md b/docs/codegen/frames.md new file mode 100644 index 0000000..552bec3 --- /dev/null +++ b/docs/codegen/frames.md @@ -0,0 +1,159 @@ +# Frames + +Frames are the fundamental building blocks of the JasperFx code generation model. Each `Frame` is responsible for writing one or more lines of C# source code into a generated method body. + +## The Frame Base Class + +All frames derive from the abstract `Frame` class in `JasperFx.CodeGeneration.Frames`. A frame declares: + +- Whether it is **async** (its constructor receives a `bool isAsync` flag). +- Which **Variables** it creates (the `creates` list). +- Which **Variables** it uses/depends on (the `uses` list). +- An optional **Next** frame in the chain. + +The single abstract method every frame must implement: + +``` +void GenerateCode(GeneratedMethod method, ISourceWriter writer) +``` + +Inside `GenerateCode`, the frame writes C# text through the `ISourceWriter` and then typically calls `Next?.GenerateCode(method, writer)` to continue the chain. + +## SyncFrame and AsyncFrame + +JasperFx provides two convenience base classes so you do not have to pass the `isAsync` flag manually: + +- **`SyncFrame`** -- sets `isAsync` to `false`. Use for frames that produce synchronous code. +- **`AsyncFrame`** -- sets `isAsync` to `true`. Use when the generated code must `await` something. + +## Writing a Custom Sync Frame + + + +```cs +public class LogMessageFrame : SyncFrame +{ + private readonly string _message; + private Variable? _logger; + + public LogMessageFrame(string message) + { + _message = message; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write($"Console.WriteLine(\"{_message}\");"); + + // Always call through to the next frame in the chain + Next?.GenerateCode(method, writer); + } +} +``` +snippet source | anchor + + +Key points: + +1. Inherit from `SyncFrame` (or `AsyncFrame` for async code). +2. Override `GenerateCode` to write your C# lines through the `ISourceWriter`. +3. Always call `Next?.GenerateCode(method, writer)` at the end so the next frame in the chain can emit its code. + +## Writing a Custom Async Frame + + + +```cs +public class LoadEntityFrame : AsyncFrame +{ + private readonly Type _entityType; + private Variable? _id; + + public LoadEntityFrame(Type entityType) + { + _entityType = entityType; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + var entityVariable = Create(_entityType); + + writer.Write( + $"var {entityVariable.Usage} = await repository.LoadAsync<{_entityType.Name}>({_id?.Usage ?? "id"});"); + + Next?.GenerateCode(method, writer); + } +} +``` +snippet source | anchor + + +Async frames work identically except they extend `AsyncFrame` and typically emit `await` expressions. + +## Wrapping Frames + +A frame can wrap subsequent frames by setting `Wraps = true`. This is useful for try/catch blocks, using blocks, timing wrappers, and similar patterns. + + + +```cs +public class StopwatchFrame : SyncFrame +{ + public StopwatchFrame() + { + // Mark this frame as wrapping inner frames + Wraps = true; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write("var stopwatch = System.Diagnostics.Stopwatch.StartNew();"); + writer.Write("BLOCK:try"); + + // Let the inner frames generate their code + Next?.GenerateCode(method, writer); + + writer.FinishBlock(); // end try + writer.Write("BLOCK:finally"); + writer.Write("stopwatch.Stop();"); + writer.Write("Console.WriteLine($\"Elapsed: {stopwatch.ElapsedMilliseconds}ms\");"); + writer.FinishBlock(); // end finally + } +} +``` +snippet source | anchor + + +When `Wraps` is `true`, the code generation engine knows that this frame opens a scope that encloses the next frame(s). + +## Creating Variables from a Frame + +Frames can declare that they "create" a variable. This is how the variable resolution system knows which frame must run before another: + +```csharp +// Inside a Frame subclass +var result = Create(); // registers the variable in this.creates +``` + +Any downstream frame that needs a `MyService` variable will automatically depend on this frame. + +## Variable Dependencies + +Frames can also declare variables they "use": + +```csharp +uses.Add(someVariable); +``` + +The code generation engine uses these `creates` and `uses` declarations to determine the correct ordering of frames and to resolve variables across the method. + +## Frame Ordering + +When you add frames to a `GeneratedMethod`, the engine: + +1. Collects all frames and their variable dependencies. +2. Topologically sorts frames so that a frame producing a variable always appears before frames consuming it. +3. Chains frames together via their `Next` property. +4. Calls `GenerateCode` on the first frame, which cascades through the chain. + +You do not need to worry about insertion order for most cases -- the dependency graph handles it. However, if two frames have no dependency relationship, they will appear in the order you added them. diff --git a/docs/codegen/generated-types.md b/docs/codegen/generated-types.md new file mode 100644 index 0000000..09e918d --- /dev/null +++ b/docs/codegen/generated-types.md @@ -0,0 +1,205 @@ +# Generated Types & Methods + +The `GeneratedAssembly`, `GeneratedType`, and `GeneratedMethod` classes form the structural backbone of the JasperFx code generation system. Together they define what classes and methods will be generated, compiled, and optionally persisted. + +## GeneratedAssembly + +`GeneratedAssembly` is the top-level container. It holds a collection of `GeneratedType` instances and produces a single C# source file when `GenerateCode()` is called. + +```csharp +var rules = new GenerationRules("MyApp.Generated"); +var assembly = new GeneratedAssembly(rules); +``` + +Key members: + +| Member | Description | +|--------|-------------| +| `Rules` | The `GenerationRules` governing namespace, type load mode, and variable sources. | +| `Namespace` | The C# namespace for all generated types. | +| `GeneratedTypes` | Read-only list of types added to this assembly. | +| `AddType(name, baseType)` | Creates a new `GeneratedType` that inherits from or implements the given type. | +| `GenerateCode()` | Arranges all frames and returns the complete C# source code. | + +## GeneratedType + +A `GeneratedType` represents a single class to be generated. It can inherit from a base class, implement interfaces, and hold injected fields. + +### Inheriting from a Base Class + + + +```cs +public static string BuildGeneratedType() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + // Create a type that inherits from a base class + var type = assembly.AddType("MyMessageHandler", typeof(MessageHandlerBase)); + + // The method defined on the base class is discovered automatically. + // Retrieve it by name. + var handleMethod = type.MethodFor("Handle"); + + // Add frames to define the method body + handleMethod.Frames.Code("Console.WriteLine(\"Handling message...\");"); + handleMethod.Frames.Code("return Task.CompletedTask;"); + + // Generate all source code for the assembly + var code = assembly.GenerateCode(); + + return code; +} + +public abstract class MessageHandlerBase +{ + public abstract Task Handle(Message message); +} + +public class Message; +``` +snippet source | anchor + + +When a type inherits from a base class, the engine: + +1. Discovers all overridable methods on the base and adds them as `GeneratedMethod` entries. +2. Reads the base class constructor parameters and registers them as `InjectedField` entries on the generated type. + +### Implementing an Interface + + + +```cs +public static string ImplementInterface() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + // Create a type that implements an interface + var type = assembly.AddType("WidgetValidator", typeof(IValidator)); + + var method = type.MethodFor(nameof(IValidator.Validate)); + method.Frames.Code("return {0} != null;", Use.Type()); + + return assembly.GenerateCode(); +} + +public interface IValidator +{ + bool Validate(object input); +} +``` +snippet source | anchor + + +All methods declared on the interface are added as `GeneratedMethod` instances that you populate with frames. + +### Injected Fields + + + +```cs +public static string TypeWithInjectedFields() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("NotificationSender", typeof(NotificationSenderBase)); + + // The InjectedField appears as a constructor argument and private field + var loggerField = new InjectedField(typeof(ILogger)); + type.AllInjectedFields.Add(loggerField); + + var method = type.MethodFor("Send"); + method.Frames.Code("Console.WriteLine(\"Sending notification\");"); + + return assembly.GenerateCode(); +} + +public abstract class NotificationSenderBase +{ + public abstract void Send(string recipient, string body); +} + +public interface ILogger +{ + void Log(string message); +} +``` +snippet source | anchor + + +An `InjectedField` generates: +- A constructor parameter. +- A `private readonly` field. +- An assignment in the constructor body. + +Any frame that needs the field's type will resolve to the injected field automatically. + +## GeneratedMethod + +A `GeneratedMethod` holds the `Frames` collection that defines the method body. Methods are either discovered from a base class / interface or added manually. + +### Discovered Methods + +When you call `assembly.AddType("Name", typeof(SomeBase))`, all overridable methods on `SomeBase` become `GeneratedMethod` entries. Retrieve them with: + +```csharp +var method = type.MethodFor("Handle"); +``` + +### Custom Methods + + + +```cs +public static string AddCustomMethod() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Calculator", typeof(object)); + + // Add a custom void method + var method = type.AddVoidMethod("PrintSum", + new Argument(typeof(int), "a"), + new Argument(typeof(int), "b")); + + method.Frames.Code("Console.WriteLine(a + b);"); + + // Add a method that returns a value + var multiply = type.AddMethodThatReturns("Multiply", + new Argument(typeof(int), "x"), + new Argument(typeof(int), "y")); + + multiply.Frames.Code("return x * y;"); + + return assembly.GenerateCode(); +} +``` +snippet source | anchor + + +`AddVoidMethod` and `AddMethodThatReturns` let you define methods that do not come from a base class or interface. + +## Frames Collection + +The `Frames` property on `GeneratedMethod` is a `FramesCollection`. You interact with it primarily through: + +- `Frames.Add(frame)` -- add any `Frame` instance. +- `Frames.Code(format, args)` -- shorthand to add a `CodeFrame` with a format string. + +During `GenerateCode()`, the engine arranges frames by resolving variable dependencies, chains them together, and invokes `GenerateCode` on each frame in order. + +## GenerationRules + +`GenerationRules` controls assembly-wide settings: + +| Property | Description | +|----------|-------------| +| `GeneratedNamespace` | Default namespace for generated types. | +| `TypeLoadMode` | `Dynamic`, `Auto`, or `Static`. See [CLI: codegen Command](./cli). | +| `Sources` | Collection of `IVariableSource` implementations for custom variable resolution. | +| `Assemblies` | Referenced assemblies available during compilation. | diff --git a/docs/codegen/index.md b/docs/codegen/index.md new file mode 100644 index 0000000..61b1ce4 --- /dev/null +++ b/docs/codegen/index.md @@ -0,0 +1,99 @@ +# Code Generation Overview + +JasperFx includes a runtime code generation framework that builds and compiles C# classes on the fly. This is the same engine that powers the middleware pipelines in [Wolverine](https://wolverinefx.io) and the document session internals in [Marten](https://martendb.io). + +## Why Runtime Code Generation? + +Many frameworks rely on reflection or expression trees to wire up handlers, middleware, and data access at runtime. JasperFx takes a different approach: it generates actual C# source code, then compiles it using Roslyn. The result is code that runs at the same speed as hand-written C# with full debuggability -- you can inspect the generated source and set breakpoints in it. + +Key benefits: + +- **Performance** -- generated code compiles to native IL with no reflection overhead at invocation time. +- **Transparency** -- you can preview the exact C# that will be generated before it runs. +- **Extensibility** -- the frame model lets library authors compose code from reusable building blocks. + +## Architecture + +The code generation system is organized around a small set of core concepts: + +```mermaid +graph TD + GA[GeneratedAssembly] -->|contains| GT[GeneratedType] + GT -->|contains| GM[GeneratedMethod] + GM -->|contains| F[Frames] + F -->|produces/consumes| V[Variables] + F -->|specialized| MC[MethodCall] + F -->|specialized| CF[ConstructorFrame] + F -->|specialized| CdF[CodeFrame] +``` + +| Concept | Purpose | +|---------|---------| +| **GeneratedAssembly** | Top-level container. Holds one or more types and produces the final C# source file. | +| **GeneratedType** | A single class to be generated. Can inherit from a base class or implement interfaces. | +| **GeneratedMethod** | A method within a generated type. Holds the ordered collection of Frames. | +| **Frame** | A unit of code generation. Each frame writes one or more lines of C# into the method body. | +| **Variable** | Represents a C# variable flowing through frames. Tracks type, name, and which frame creates it. | + +## Quick Example + + + +```cs +public static string GenerateGreeterCode() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + // Add a new type that implements IGreeter + var type = assembly.AddType("HelloGreeter", typeof(IGreeter)); + + // Get the method defined by the interface + var method = type.MethodFor("Greet"); + + // Add a frame that writes a line of code + method.Frames.Code("return \"Hello, \" + {0};", Use.Type()); + + // Generate the C# source code + var code = assembly.GenerateCode(); + + return code; +} + +public interface IGreeter +{ + string Greet(string name); +} +``` +snippet source | anchor + + +## How It Works + +1. Create a `GeneratedAssembly` with a set of `GenerationRules`. +2. Add one or more `GeneratedType` entries, specifying base classes or interfaces. +3. Retrieve `GeneratedMethod` instances (discovered from the base type or added manually). +4. Populate each method with `Frame` objects that describe the code to generate. +5. Call `GenerateCode()` to produce the C# source text. +6. Optionally compile the assembly at runtime to get live `Type` instances. + +## TypeLoadMode + +JasperFx supports three strategies for loading generated types, controlled by the `TypeLoadMode` enum on `GenerationRules`: + +| Mode | Behavior | +|------|----------| +| `Dynamic` | Always generate and compile at runtime. Best for development. | +| `Auto` | Try to load pre-built types from the application assembly; fall back to runtime generation. | +| `Static` | Types must exist in the pre-built assembly. Throws if missing. Fastest startup. | + +See [CLI: codegen Command](./cli) for tooling that writes generated code ahead of time. + +## Next Steps + +- [Frames](./frames) -- learn how the Frame model works and how to write custom frames. +- [Variables](./variables) -- understand how variables flow between frames. +- [MethodCall](./method-call) -- the most commonly used frame for calling existing methods. +- [Generated Types & Methods](./generated-types) -- assembling complete types. +- [Built-in Frames](./built-in-frames) -- catalog of frames shipped with JasperFx. +- [CLI: codegen Command](./cli) -- ahead-of-time code generation tooling. diff --git a/docs/codegen/method-call.md b/docs/codegen/method-call.md new file mode 100644 index 0000000..70804a8 --- /dev/null +++ b/docs/codegen/method-call.md @@ -0,0 +1,161 @@ +# MethodCall + +`MethodCall` is the most commonly used `Frame` in the JasperFx code generation system. It generates a call to an existing .NET method -- either static or instance -- and automatically wires up arguments and return values through the variable resolution system. + +## Basic Usage + + + +```cs +public static void BasicMethodCall() +{ + // Create a MethodCall by type and method name + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrder)); + + // The ReturnVariable is automatically created from the method's return type + Console.WriteLine(call.ReturnVariable!.VariableType); // typeof(OrderResult) + + // Arguments array matches the method's parameters + Console.WriteLine(call.Arguments.Length); // matches parameter count +} +``` +snippet source | anchor + + +When you create a `MethodCall`, the frame inspects the target method via reflection and: + +1. Sets `IsAsync` based on whether the method returns `Task` or `ValueTask`. +2. Creates a `ReturnVariable` if the method has a non-void return type (unwrapping `Task` to `T`). +3. Allocates an `Arguments` array matching the method's parameters. + +## Async Methods + + + +```cs +public static void AsyncMethodCall() +{ + // Async methods are automatically detected + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrderAsync)); + + // The frame knows it is async + Console.WriteLine(call.IsAsync); // true + + // ReturnType unwraps Task to T + Console.WriteLine(call.ReturnVariable!.VariableType); // typeof(OrderResult) +} +``` +snippet source | anchor + + +Async methods are detected automatically. The generated code will emit `await` before the method call, and the enclosing generated method will be marked as `async`. + +## ReturnAction + +The `ReturnAction` property controls how the method call's return value is rendered in the generated code: + + + +```cs +public static void ReturnActions() +{ + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrder)); + + // Initialize: generates "var orderResult = ProcessOrder(...);" + call.ReturnAction = ReturnAction.Initialize; + + // Assign: generates "orderResult = ProcessOrder(...);" + call.ReturnAction = ReturnAction.Assign; + + // Return: generates "return ProcessOrder(...);" + call.ReturnAction = ReturnAction.Return; +} +``` +snippet source | anchor + + +| Value | Generated Code | +|-------|---------------| +| `Initialize` | `var result = Method(...);` | +| `Assign` | `result = Method(...);` | +| `Return` | `return Method(...);` | + +The default is `Initialize`. + +## DisposalMode + +When a method returns an `IDisposable` or `IAsyncDisposable`, you can wrap it in a using block: + + + +```cs +public static void disposal_mode_example() +{ + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.CreateConnection)); + + // Wrap the return value in a using block + call.DisposalMode = DisposalMode.UsingBlock; +} +``` +snippet source | anchor + + +| Value | Behavior | +|-------|----------| +| `None` | No disposal handling (default). | +| `UsingBlock` | Wraps the call in a `using` statement so the return value is disposed at the end of scope. | + +## Arguments + +The `Arguments` array on a `MethodCall` holds one `Variable` per method parameter. By default, arguments are left `null` and resolved automatically by the variable system during code arrangement. You can also pin a specific variable to an argument slot: + +```csharp +var call = new MethodCall(typeof(Service), nameof(Service.DoWork)); +call.Arguments[0] = someSpecificVariable; +``` + +This is useful when you need to override the default resolution for a particular parameter. + +## Using MethodCall in a Generated Type + + + +```cs +public static string UseMethodCallInGeneratedType() +{ + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("OrderHandler", typeof(IOrderHandler)); + var method = type.MethodFor(nameof(IOrderHandler.Handle)); + + // Add a MethodCall frame + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrder)); + method.Frames.Add(call); + + return assembly.GenerateCode(); +} +``` +snippet source | anchor + + +## Instance vs. Static Methods + +- **Static methods** -- the generated code calls the method directly on the type (e.g., `OrderProcessor.ProcessOrder(...)`). +- **Instance methods** -- the code generation engine resolves a variable of the handler type and calls the method on that instance (e.g., `orderProcessor.ProcessOrder(...)`). The instance variable is resolved through the same mechanism as any other variable (injected field, method argument, or variable source). + +## HandlerType + +The `HandlerType` property identifies the type that owns the method. For instance methods, a variable of this type will be resolved or created so the call can be made. + +## Tuple Return Values + +If the target method returns a `ValueTuple`, `MethodCall` automatically deconstructs the tuple into individual variables: + +```csharp +// If the method returns (string Name, int Age) +// the generated code will be: +// var (name, age) = Method(...); +``` + +Each element becomes a separate `Variable` that downstream frames can reference. diff --git a/docs/codegen/variables.md b/docs/codegen/variables.md new file mode 100644 index 0000000..cb5b5dd --- /dev/null +++ b/docs/codegen/variables.md @@ -0,0 +1,100 @@ +# Variables + +The `Variable` class in `JasperFx.CodeGeneration.Model` represents a named, typed value flowing through generated code. Variables are the primary mechanism frames use to declare their inputs and outputs, enabling the code generation engine to resolve dependencies and order frames automatically. + +## Creating Variables + + + +```cs +public static void CreateVariables() +{ + // Create a variable with an auto-generated name based on the type + var widget = new Variable(typeof(Widget), "widget"); + + // The Usage property is the C# identifier used in generated code + Console.WriteLine(widget.Usage); // "widget" + + // DefaultArgName generates a camelCase name from the type + var defaultName = Variable.DefaultArgName(typeof(Widget)); + Console.WriteLine(defaultName); // "widget" + + // Variable tied to a creating Frame + var frame = new MethodCall(typeof(WidgetFactory), nameof(WidgetFactory.Build)); + var returnVar = frame.ReturnVariable; + Console.WriteLine(returnVar!.Creator == frame); // true +} +``` +snippet source | anchor + + +## Key Properties + +| Property | Type | Description | +|----------|------|-------------| +| `VariableType` | `Type` | The .NET type of the variable. | +| `Usage` | `string` | The C# identifier used in generated source code. | +| `Creator` | `Frame?` | The frame that creates this variable, if any. | + +## Default Naming + +`Variable.DefaultArgName(Type)` produces a conventional camelCase name from a type: + + + +```cs +public static void DefaultArgNameExamples() +{ + // Simple types use lowercase type name + Console.WriteLine(Variable.DefaultArgName(typeof(Widget))); // "widget" + + // Arrays get "Array" suffix + Console.WriteLine(Variable.DefaultArgName(typeof(int[]))); // "intArray" + + // Generic types include inner type + Console.WriteLine(Variable.DefaultArgName(typeof(List))); // "listOfString" + + // Reserved C# keywords get an @ prefix + Console.WriteLine(Variable.DefaultArgName(typeof(Event))); // "@event" +} +``` +snippet source | anchor + + +The naming rules are: + +- Simple types use the lowercase type name (e.g., `Widget` becomes `widget`). +- Array types append `Array` (e.g., `int[]` becomes `intArray`). +- Generic types include the inner type (e.g., `List` becomes `listOfString`). +- If the resulting name is a C# reserved keyword, it is prefixed with `@` (e.g., `Event` becomes `@event`). + +## Variables and Frames + +Every `Frame` maintains two lists: + +- **`creates`** -- variables this frame produces. Downstream frames that need this type will depend on this frame. +- **`uses`** -- variables this frame consumes. The engine will find or create the producing frame automatically. + +When a frame calls `Create()` or `Create(Type)`, the returned `Variable` has its `Creator` set to that frame and is added to the frame's `creates` list. + +## Variable Resolution + +During code arrangement, the engine resolves variables in this order: + +1. **Locally created variables** -- a variable created by a frame earlier in the chain. +2. **Method arguments** -- parameters declared on the `GeneratedMethod`. +3. **Injected fields** -- fields declared on the `GeneratedType` (constructor-injected dependencies). +4. **Variable sources** -- custom `IVariableSource` implementations registered on the `GenerationRules`. + +If a variable cannot be resolved through any of these sources, the code generation will throw an exception describing the missing dependency. + +## InjectedField + +`InjectedField` is a specialized `Variable` that represents a constructor parameter and corresponding private field on the generated type: + +```csharp +var field = new InjectedField(typeof(ILogger)); +type.AllInjectedFields.Add(field); +``` + +This produces a constructor parameter and a `private readonly` field assignment in the generated class. Any frame that needs an `ILogger` variable will automatically resolve to this injected field. diff --git a/docs/configuration/critter-stack-defaults.md b/docs/configuration/critter-stack-defaults.md new file mode 100644 index 0000000..732990e --- /dev/null +++ b/docs/configuration/critter-stack-defaults.md @@ -0,0 +1,76 @@ +# Critter Stack Defaults + +JasperFx provides a set of opinionated defaults for applications built on the Critter Stack (Marten, Wolverine, and related libraries). + +## Applying Defaults + +Use `AddJasperFx` on `IServiceCollection` to register JasperFx services with configuration: + + + +```cs +public static IHostBuilder ConfigureWithDefaults() +{ + return Host.CreateDefaultBuilder() + .ConfigureServices(services => + { + services.AddJasperFx(opts => + { + // Require a file to exist at application startup + opts.RequireFile("appsettings.json"); + + // Set the development environment name if non-standard + opts.DevelopmentEnvironmentName = "Local"; + }); + }); +} +``` +snippet source | anchor + + +## What Gets Registered + +Calling `AddJasperFx` registers: + +- `JasperFxOptions` as a singleton +- Environment check infrastructure +- System part discovery for the `describe` command +- Assembly scanning for command discovery + +## Profiles + +JasperFx supports named profiles to vary behavior by environment: + +| Profile | Typical Use | +|---------|-------------| +| `Development` | Local development with verbose logging | +| `Staging` | Pre-production validation | +| `Production` | Optimized for reliability | + +Set the active profile in configuration: + +```csharp +services.AddJasperFx(opts => +{ + opts.ActiveProfile = "Production"; +}); +``` + +## Required Files + +Register files that must exist for the application to start: + +```csharp +services.AddJasperFx(opts => +{ + opts.RequireFile("appsettings.json"); + opts.RequireFile("keys/signing.key"); +}); +``` + +These are automatically verified by the `check-env` command. + +## Next Steps + +- [JasperFx Options](/configuration/jasperfx-options) -- Detailed options reference +- [Environment Checks](/cli/environment-checks) -- Runtime dependency validation diff --git a/docs/configuration/jasperfx-options.md b/docs/configuration/jasperfx-options.md new file mode 100644 index 0000000..717d291 --- /dev/null +++ b/docs/configuration/jasperfx-options.md @@ -0,0 +1,70 @@ +# JasperFx Options + +`JasperFxOptions` is the central configuration class for JasperFx. It extends `SystemPartBase` and participates in the describe command output. + +## Registering Options + + + +```cs +public static void ConfigureOptions(IServiceCollection services) +{ + services.AddJasperFx(opts => + { + // Register an environment check inline + opts.RegisterEnvironmentCheck( + "Database connectivity", + async (sp, ct) => + { + // Verify your database is accessible + await Task.CompletedTask; + }); + }); +} +``` +snippet source | anchor + + +## Key Properties + +| Property | Type | Default | Description | +|----------|------|---------|-------------| +| `ActiveProfile` | `string` | `"Development"` | The current application profile | +| `RequiredFiles` | `string[]` | `[]` | Files that must exist at startup | +| `RememberedApplicationAssembly` | `Assembly?` | `null` | Override the detected application assembly | + +## RequireFile + +Tell JasperFx that a file path is required. This adds a file-exists check to environment tests: + +```csharp +opts.RequireFile("appsettings.json"); +``` + +## RegisterEnvironmentCheck + +Register an inline environment check: + +```csharp +opts.RegisterEnvironmentCheck( + "Redis is reachable", + async (sp, ct) => + { + // throw on failure + }); +``` + +## Application Assembly Detection + +JasperFx automatically detects the main application assembly for scanning. In test scenarios, you can override this: + +```csharp +JasperFxOptions.RememberedApplicationAssembly = typeof(MyApp).Assembly; +``` + +This is useful when test runners or IDEs change the entry assembly. + +## Next Steps + +- [Critter Stack Defaults](/configuration/critter-stack-defaults) -- Opinionated setup +- [Environment Checks](/cli/environment-checks) -- Startup validation diff --git a/docs/extensions/enumerable-extensions.md b/docs/extensions/enumerable-extensions.md new file mode 100644 index 0000000..3eff127 --- /dev/null +++ b/docs/extensions/enumerable-extensions.md @@ -0,0 +1,68 @@ +# Enumerable Extensions + +JasperFx.Core provides extension methods for working with collections and enumerables. + +## Usage + +```csharp +using JasperFx.Core; +``` + +## Examples + + + +```cs +public void EnumerableHelpers() +{ + var items = new List { "a", "b", "c", "a" }; + + // AddRange that works on IList + items.Fill("d"); + + // Add only if not already present + items.Fill("a"); // no-op if already present + + // Each / EachAsync for side effects + items.Each(item => Console.WriteLine(item)); +} +``` +snippet source | anchor + + +## Available Methods + +| Method | Description | +|--------|-------------| +| `Fill(item)` | Adds an item to a list (alias for `Add`) | +| `FillWithUnique(item)` | Adds only if the item is not already in the list | +| `Each(action)` | Executes an action for each item | +| `EachAsync(func)` | Executes an async function for each item sequentially | +| `AddRange(items)` | Adds multiple items to an `IList` | +| `IsEmpty()` | Returns true if the enumerable has no elements | +| `Top(n)` | Returns the first N items | +| `As()` | Casts each element to type T | + +## Fill vs Add + +`Fill` is semantically equivalent to `Add` but reads better in fluent chains. `FillWithUnique` is useful for building distinct collections without using `HashSet`: + +```csharp +var tags = new List(); +tags.FillWithUnique("dotnet"); +tags.FillWithUnique("dotnet"); // no duplicate added +``` + +## Each vs ForEach + +`Each` works on any `IEnumerable`, not just `List`: + +```csharp +IEnumerable items = GetItems(); +items.Each(item => Process(item)); +``` + +## Next Steps + +- [String Extensions](/extensions/string-extensions) +- [Reflection Extensions](/extensions/reflection-extensions) diff --git a/docs/extensions/index.md b/docs/extensions/index.md new file mode 100644 index 0000000..7e10514 --- /dev/null +++ b/docs/extensions/index.md @@ -0,0 +1,46 @@ +# Utility Extensions + +JasperFx.Core provides a collection of extension methods used throughout the Critter Stack. These are general-purpose helpers available in any .NET project. + +## Installation + +If you only need the extensions without the full JasperFx framework: + +```bash +dotnet add package JasperFx.Core +``` + +## Categories + +### String Extensions + +Helpers for case conversion, empty checks, joining, and common string operations. + +[Read more](/extensions/string-extensions) + +### Enumerable Extensions + +Methods for working with collections including `Fill`, `Each`, and `AddRange` variants. + +[Read more](/extensions/enumerable-extensions) + +### Reflection Extensions + +Type inspection helpers for checking interface implementation, generating readable type names, and working with generics. + +[Read more](/extensions/reflection-extensions) + +## Namespace + +All extension methods live in the `JasperFx.Core` or `JasperFx.Core.Reflection` namespaces: + +```csharp +using JasperFx.Core; +using JasperFx.Core.Reflection; +``` + +## Next Steps + +- [String Extensions](/extensions/string-extensions) +- [Enumerable Extensions](/extensions/enumerable-extensions) +- [Reflection Extensions](/extensions/reflection-extensions) diff --git a/docs/extensions/reflection-extensions.md b/docs/extensions/reflection-extensions.md new file mode 100644 index 0000000..4c70b3c --- /dev/null +++ b/docs/extensions/reflection-extensions.md @@ -0,0 +1,68 @@ +# Reflection Extensions + +JasperFx.Core.Reflection provides helpers for type inspection, generic type manipulation, and readable type name generation. + +## Usage + +```csharp +using JasperFx.Core.Reflection; +``` + +## Examples + + + +```cs +public void ReflectionHelpers() +{ + // Check if a type implements an interface + var implements = typeof(List).CanBeCastTo>(); + + // Get a human-readable type name + var name = typeof(Dictionary).FullNameInCode(); + + // Close an open generic type + var closed = typeof(List<>).CloseAndBuildAs(typeof(string)); +} +``` +snippet source | anchor + + +## Available Methods + +| Method | Description | +|--------|-------------| +| `Implements()` | Checks if a type implements an interface or base class | +| `Implements(type)` | Non-generic overload of the above | +| `FullNameInCode()` | Returns a C#-readable full type name with generics | +| `NameInCode()` | Returns a short C#-readable type name | +| `CloseAndBuildAs(params)` | Closes an open generic and creates an instance | +| `HasAttribute()` | Checks if a member has a specific attribute | +| `GetAttribute()` | Gets a specific attribute from a member | +| `IsConcreteTypeOf()` | Checks if a type is a non-abstract implementation | + +## Readable Type Names + +`FullNameInCode()` produces names that look like actual C# code: + +```csharp +typeof(int).FullNameInCode(); // "int" +typeof(string[]).FullNameInCode(); // "string[]" +typeof(Dictionary).FullNameInCode(); // "System.Collections.Generic.Dictionary" +typeof(int?).FullNameInCode(); // "int?" +``` + +## Closing Open Generics + +`CloseAndBuildAs` is useful for plugin architectures: + +```csharp +// Given: public class Repository : IRepository { } +var repo = typeof(Repository<>) + .CloseAndBuildAs>(typeof(Order)); +``` + +## Next Steps + +- [String Extensions](/extensions/string-extensions) +- [Enumerable Extensions](/extensions/enumerable-extensions) diff --git a/docs/extensions/string-extensions.md b/docs/extensions/string-extensions.md new file mode 100644 index 0000000..7fa0896 --- /dev/null +++ b/docs/extensions/string-extensions.md @@ -0,0 +1,60 @@ +# String Extensions + +JasperFx.Core provides several extension methods for common string operations. + +## Usage + +```csharp +using JasperFx.Core; +``` + +## Examples + + + +```cs +public void StringHelpers() +{ + // Convert to camel case + var camel = "SomePropertyName".ToCamelCase(); + // => "somePropertyName" + + // Check if a string is empty or whitespace + var isEmpty = "".IsEmpty(); + var isNotEmpty = "hello".IsNotEmpty(); + + // Joining strings + var joined = new[] { "one", "two", "three" }.Join(", "); +} +``` +snippet source | anchor + + +## Available Methods + +| Method | Description | +|--------|-------------| +| `ToCamelCase()` | Converts PascalCase to camelCase | +| `IsEmpty()` | Returns true if the string is null, empty, or whitespace | +| `IsNotEmpty()` | Inverse of `IsEmpty()` | +| `Join(separator)` | Joins an enumerable of strings with a separator | +| `ToDelimitedString(delimiter)` | Converts a collection to a delimited string | +| `EqualsIgnoreCase(other)` | Case-insensitive string comparison | +| `Matches(pattern)` | Regex match helper | +| `SplitOnNewLine()` | Splits on `\n` and `\r\n` | +| `ToFullPath()` | Resolves a relative path to a full filesystem path | + +## Null Safety + +Most string extensions handle null input gracefully: + +```csharp +string? value = null; +value.IsEmpty(); // true +value.IsNotEmpty(); // false +``` + +## Next Steps + +- [Enumerable Extensions](/extensions/enumerable-extensions) +- [Reflection Extensions](/extensions/reflection-extensions) diff --git a/docs/guide/index.md b/docs/guide/index.md new file mode 100644 index 0000000..e1d80fd --- /dev/null +++ b/docs/guide/index.md @@ -0,0 +1,31 @@ +# Introduction + +JasperFx is the shared infrastructure library that underpins the Critter Stack family of .NET libraries, including [Marten](https://martendb.io) and [Wolverine](https://wolverine.netlify.app). + +## What Does JasperFx Provide? + +JasperFx gives you: + +- **Command line tooling** -- A lightweight framework for building CLI commands with argument parsing, flag support, and automatic help generation. +- **Environment checks** -- Register checks that run at application startup to verify external dependencies are available. +- **Describe command** -- A built-in command that outputs a summary of your application's configuration and registered components. +- **Configuration** -- `JasperFxOptions` and Critter Stack defaults for consistent application setup. +- **Utility extensions** -- String, enumerable, and reflection helpers used throughout the Critter Stack. + +## Target Frameworks + +JasperFx targets .NET 8.0, 9.0, and 10.0. + +## Source Code + +The source code is available on [GitHub](https://github.com/JasperFx/jasperfx). + +## Getting Help + +File issues on the [GitHub issue tracker](https://github.com/JasperFx/jasperfx/issues) or join the [Critter Stack Discord](https://discord.gg/WMxrvegf8H). + +## Next Steps + +- [Installation](/guide/installation) -- Add JasperFx to your project +- [Quick Start](/guide/quickstart) -- Get running in minutes +- [CLI Commands](/cli/) -- Build custom commands diff --git a/docs/guide/installation.md b/docs/guide/installation.md new file mode 100644 index 0000000..4965f02 --- /dev/null +++ b/docs/guide/installation.md @@ -0,0 +1,47 @@ +# Installation + +## NuGet Package + +Install the main JasperFx package from NuGet: + +```bash +dotnet add package JasperFx +``` + +This brings in the core library including command line tooling, environment checks, and configuration support. + +## Core Extensions Only + +If you only need the utility extension methods (string, enumerable, reflection), you can install the lighter-weight core package: + +```bash +dotnet add package JasperFx.Core +``` + +## Prerequisites + +- .NET 8.0 SDK or later +- A `Microsoft.Extensions.Hosting` compatible application (for CLI and environment check features) + +## Verifying Installation + +After installing, verify the package is available by adding JasperFx to your host builder: + +```csharp +using Microsoft.Extensions.Hosting; + +await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions(args); +``` + +Run your application with the `help` command to see available commands: + +```bash +dotnet run -- help +``` + +## Next Steps + +- [Quick Start](/guide/quickstart) -- Wire up JasperFx in a minimal application +- [CLI Commands](/cli/) -- Learn about the command line framework diff --git a/docs/guide/quickstart.md b/docs/guide/quickstart.md new file mode 100644 index 0000000..6280ae9 --- /dev/null +++ b/docs/guide/quickstart.md @@ -0,0 +1,84 @@ +# Quick Start + +Get a JasperFx-enabled application running in under a minute. + +## Minimal Setup + +Create a new console application and install JasperFx: + +```bash +dotnet new console -n MyApp +cd MyApp +dotnet add package JasperFx +``` + +Replace the contents of `Program.cs`: + + + +```cs +await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); +``` +snippet source | anchor + + +## Running Commands + +With this setup you immediately get access to built-in commands: + +```bash +# Show all available commands +dotnet run -- help + +# Describe the application configuration +dotnet run -- describe + +# Run environment checks +dotnet run -- check-env +``` + +## Adding Custom Commands + +You can register your own commands by creating classes that extend `JasperFxCommand` or `JasperFxAsyncCommand`. See [Writing Commands](/cli/writing-commands) for details. + +## Adding Environment Checks + +Register checks to verify your application's external dependencies at startup: + + + +```cs +public static void RegisterChecks(IServiceCollection services) +{ + // Async check with IServiceProvider access + services.CheckEnvironment( + "Database is reachable", + async (IServiceProvider sp, CancellationToken ct) => + { + // Throw an exception to indicate failure + await Task.CompletedTask; + }); + + // Synchronous check + services.CheckEnvironment( + "Configuration file exists", + (IServiceProvider sp) => + { + if (!File.Exists("appsettings.json")) + { + throw new FileNotFoundException("Missing configuration file"); + } + }); +} +``` +snippet source | anchor + + +## What Next? + +- [Writing Commands](/cli/writing-commands) -- Create custom CLI commands +- [Environment Checks](/cli/environment-checks) -- Validate your runtime environment +- [Configuration](/configuration/critter-stack-defaults) -- Configure JasperFx options diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..c94cb03 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,29 @@ +--- +layout: home + +hero: + name: JasperFx + text: Shared Infrastructure for the Critter Stack + tagline: Command line tooling, configuration, environment checks, and utility extensions for .NET applications + actions: + - theme: brand + text: Get Started + link: /guide/quickstart + - theme: alt + text: View on GitHub + link: https://github.com/JasperFx/jasperfx + +features: + - title: Command Line Tooling + details: Build robust CLI commands with argument parsing, flags, and built-in help generation. + link: /cli/ + - title: Environment Checks + details: Register startup checks to verify database connectivity, required files, and service availability. + link: /cli/environment-checks + - title: Configuration + details: Opinionated defaults and options for the Critter Stack ecosystem including Wolverine and Marten. + link: /configuration/critter-stack-defaults + - title: Utility Extensions + details: Helpful extension methods for strings, enumerables, and reflection used across the Critter Stack. + link: /extensions/ +--- diff --git a/docs/package.json b/docs/package.json new file mode 100644 index 0000000..c6e84bc --- /dev/null +++ b/docs/package.json @@ -0,0 +1,15 @@ +{ + "name": "jasperfx-docs", + "private": true, + "type": "module", + "scripts": { + "dev": "vitepress dev", + "build": "vitepress build", + "preview": "vitepress preview" + }, + "devDependencies": { + "vitepress": "^1.6.3", + "vitepress-plugin-mermaid": "^2.0.17", + "mermaid": "^11.4.1" + } +} diff --git a/docs/public/jasperfx-logo.png b/docs/public/jasperfx-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..3c25f0a0856558b99e2240852321de6ba1389904 GIT binary patch literal 114672 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%0D^k_+DtEd5;Rvh?N>GB+X3Y)y{~cVk?x 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

-! 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
  • _Gy&4BmLG4;kaYdmJTc8g&=?1=bVk!RisfH#$K2ppZi z)PA^ZC`d8BT6>fsU>D3Z_S5(q)97U*8>h45>u?EWoG(X8BfnmNN?iXTaX~o{@S^$I zqJ^CHb05Sbd?bT4FI}KK6*zu+kfZKTyrBBlI!xu(FS6~6RjF$?8Uj6Q_3VqnV3n3- zEc)NNI!w-Huy2H;c0EWk`YIZy)5p9{fjjTT&~h2be~=#}Zq=$ISSrcUwEXYS2tkdZ zS1;VF$Ww_!Nj%4!WhoC`x@(>ZSVWBS#W75-TNb)(iQ7Gu`b$xk0H@&bKsH#nz{_8qPZyFI?Fh?zJA%^XZEU$MSh0y`uY{C!t9W~ z&9{f)7*e0u=eP%kDq#H9x7c-EFrFXiBkXhz-Nq{*0TuMCeuU&|-|8Fi^1H<~J>hd0 zmz`jNM)vm`JIdZ997dcXwQF7|DIE@Gzy`;mtiTK^)EU^o36j|{pW}l` zzgI+M?GCiB4JH{=NXkbuNv{){$Hvm5`KQnS-A865|DpYN^U-ohhle%lGeQ1LCf!Er zHm_|o;J8A{FO5!W^+ziOAhV_75xsiQPpBBvwXJ2E7~AJadhHPq*VIsp+269kg>&&6 zXHM4fD7Ua8Plyj0g}}OMM1cggEcXZS0nar<1uX&~cjGzU|6pKT3ZDJKx!DG7T1O!x z0}hE!^`oZg&hOWKftPqO$I^O4EDN8b%;ln8_P$An@TmEay_?5E@LfQRoPa_TQ~}q8 zfMvMPG&r@Y@8A?_TQRIatkPSpPA=PO*+Y8t{0tv-fsXD%sGY;us&$)|J+x0Dw@RgO zFQqZnGQD13Y_Ru)8?=E0*y;mpL$0VZq)k8Dor>|U>cy9_eLTwSlmI?w{GFfHT$95O z(3gSr@Mx=Kp2Co=^7wEM7eI0FiB5tMs!OC(p4qIrWURVyIazs?BafxM0dpo$=S<

    &3V;O0zL!rT0^r~zr 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 A?*IS* literal 0 HcmV?d00001 diff --git a/mdsnippets.json b/mdsnippets.json new file mode 100644 index 0000000..0940249 --- /dev/null +++ b/mdsnippets.json @@ -0,0 +1,8 @@ +{ + "Convention": "InPlaceOverwrite", + "LinkFormat": "GitHub", + "UrlPrefix": "https://github.com/JasperFx/jasperfx/blob/master", + "ExcludeMarkdownDirectories": [], + "ExcludeSnippetDirectories": [], + "TreatMissingAsWarning": false +} diff --git a/netlify.toml b/netlify.toml new file mode 100644 index 0000000..1d962cd --- /dev/null +++ b/netlify.toml @@ -0,0 +1,7 @@ +[build] + base = "docs" + publish = ".vitepress/dist" + command = "npm install && npm run build" + +[build.environment] + NODE_VERSION = "20" diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..001117f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3936 @@ +{ + "name": "jasperfx", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "concurrently": "^9.1.2", + "mermaid": "^11.4.1", + "vitepress": "^1.6.3", + "vitepress-plugin-mermaid": "^2.0.17" + } + }, + "node_modules/@algolia/abtesting": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.16.1.tgz", + "integrity": "sha512-Xxk4l00pYI+jE0PNw8y0MvsQWh5278WRtZQav8/BMMi3HKi2xmeuqe11WJ3y8/6nuBHdv39w76OpJb09TMfAVQ==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/autocomplete-core": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-core/-/autocomplete-core-1.17.7.tgz", + "integrity": "sha512-BjiPOW6ks90UKl7TwMv7oNQMnzU+t/wk9mgIDi6b1tXpUek7MW0lbNOUHpvam9pe3lVCf4xPFT+lK7s+e+fs7Q==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-plugin-algolia-insights": "1.17.7", + "@algolia/autocomplete-shared": "1.17.7" + } + }, + "node_modules/@algolia/autocomplete-plugin-algolia-insights": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-plugin-algolia-insights/-/autocomplete-plugin-algolia-insights-1.17.7.tgz", + "integrity": "sha512-Jca5Ude6yUOuyzjnz57og7Et3aXjbwCSDf/8onLHSQgw1qW3ALl9mrMWaXb5FmPVkV3EtkD2F/+NkT6VHyPu9A==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "search-insights": ">= 1 < 3" + } + }, + "node_modules/@algolia/autocomplete-preset-algolia": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-preset-algolia/-/autocomplete-preset-algolia-1.17.7.tgz", + "integrity": "sha512-ggOQ950+nwbWROq2MOCIL71RE0DdQZsceqrg32UqnhDz8FlO9rL8ONHNsI2R1MH0tkgVIDKI/D0sMiUchsFdWA==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-shared": "1.17.7" + }, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/autocomplete-shared": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/@algolia/autocomplete-shared/-/autocomplete-shared-1.17.7.tgz", + "integrity": "sha512-o/1Vurr42U/qskRSuhBH+VKxMvkkUVTLU6WZQr+L5lGZZLYWyhdzWjW0iGXY7EkwRTjBqvN2EsR81yCTGV/kmg==", + "dev": true, + "peerDependencies": { + "@algolia/client-search": ">= 4.9.1 < 6", + "algoliasearch": ">= 4.9.1 < 6" + } + }, + "node_modules/@algolia/client-abtesting": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.50.1.tgz", + "integrity": "sha512-4peZlPXMwTOey9q1rQKMdCnwZb/E95/1e+7KujXpLLSh0FawJzg//U2NM+r4AiJy4+naT2MTBhj0K30yshnVTA==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-analytics": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.50.1.tgz", + "integrity": "sha512-i+aWHHG8NZvGFHtPeMZkxL2Loc6Fm7iaRo15lYSMx8gFL+at9vgdWxhka7mD1fqxkrxXsQstUBCIsSY8FvkEOw==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-common": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.50.1.tgz", + "integrity": "sha512-Hw52Fwapyk/7hMSV/fI4+s3H9MGZEUcRh4VphyXLAk2oLYdndVUkc6KBi0zwHSzwPAr+ZBwFPe2x6naUt9mZGw==", + "dev": true, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-insights": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.50.1.tgz", + "integrity": "sha512-Bn/wtwhJ7p1OD/6pY+Zzn+zlu2N/SJnH46md/PAbvqIzmjVuwjNwD4y0vV5Ov8naeukXdd7UU9v550+v8+mtlg==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-personalization": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.50.1.tgz", + "integrity": "sha512-0V4Tu0RWR8YxkgI9EPVOZHGE4K5pEIhkLNN0CTkP/rnPsqaaSQpNMYW3/mGWdiKOWbX0iVmwLB9QESk3H0jS5g==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-query-suggestions": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.50.1.tgz", + "integrity": "sha512-jofcWNYMXJDDr87Z2eivlWY6o71Zn7F7aOvQCXSDAo9QTlyf7BhXEsZymLUvF0O1yU9Q9wvrjAWn8uVHYnAvgw==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/client-search": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.50.1.tgz", + "integrity": "sha512-OteRb8WubcmEvU0YlMJwCXs3Q6xrdkb0v50/qZBJP1TF0CvujFZQM++9BjEkTER/Jr9wbPHvjSFKnbMta0b4dQ==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/ingestion": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.50.1.tgz", + "integrity": "sha512-0GmfSgDQK6oiIVXnJvGxtNFOfosBspRTR7csCOYCTL1P8QtxX2vDCIKwTM7xdSAEbJaZ43QlWg25q0Qdsndz8Q==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/monitoring": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.50.1.tgz", + "integrity": "sha512-ySuigKEe4YjYV3si8NVk9BHQpFj/1B+ON7DhhvTvbrZJseHQQloxzq0yHwKmznSdlO6C956fx4pcfOKkZClsyg==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/recommend": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.50.1.tgz", + "integrity": "sha512-Cp8T/B0gVmjFlzzp6eP47hwKh5FGyeqQp1N48/ANDdvdiQkPqLyFHQVDwLBH0LddfIPQE+yqmZIgmKc82haF4A==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-browser-xhr": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.50.1.tgz", + "integrity": "sha512-XKdGGLikfrlK66ZSXh/vWcXZZ8Vg3byDFbJD8pwEvN1FoBRGxhxya476IY2ohoTymLa4qB5LBRlIa+2TLHx3Uw==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-fetch": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.50.1.tgz", + "integrity": "sha512-mBAU6WyVsDwhHyGM+nodt1/oebHxgvuLlOAoMGbj/1i6LygDHZWDgL1t5JEs37x9Aywv7ZGhqbM1GsfZ54sU6g==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@algolia/requester-node-http": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.50.1.tgz", + "integrity": "sha512-qmo1LXrNKLHvJE6mdQbLnsZAoZvj7VyF2ft4xmbSGWI2WWm87fx/CjUX4kEExt4y0a6T6nEts6ofpUfH5TEE1A==", + "dev": true, + "dependencies": { + "@algolia/client-common": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "dev": true, + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "dev": true + }, + "node_modules/@chevrotain/cst-dts-gen": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/cst-dts-gen/-/cst-dts-gen-11.1.2.tgz", + "integrity": "sha512-XTsjvDVB5nDZBQB8o0o/0ozNelQtn2KrUVteIHSlPd2VAV2utEb6JzyCJaJ8tGxACR4RiBNWy5uYUHX2eji88Q==", + "dev": true, + "dependencies": { + "@chevrotain/gast": "11.1.2", + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/cst-dts-gen/node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "dev": true + }, + "node_modules/@chevrotain/gast": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/gast/-/gast-11.1.2.tgz", + "integrity": "sha512-Z9zfXR5jNZb1Hlsd/p+4XWeUFugrHirq36bKzPWDSIacV+GPSVXdk+ahVWZTwjhNwofAWg/sZg58fyucKSQx5g==", + "dev": true, + "dependencies": { + "@chevrotain/types": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/@chevrotain/gast/node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "dev": true + }, + "node_modules/@chevrotain/regexp-to-ast": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/regexp-to-ast/-/regexp-to-ast-11.1.2.tgz", + "integrity": "sha512-nMU3Uj8naWer7xpZTYJdxbAs6RIv/dxYzkYU8GSwgUtcAAlzjcPfX1w+RKRcYG8POlzMeayOQ/znfwxEGo5ulw==", + "dev": true + }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "dev": true + }, + "node_modules/@chevrotain/utils": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-11.1.2.tgz", + "integrity": "sha512-4mudFAQ6H+MqBTfqLmU7G1ZwRzCLfJEooL/fsF6rCX5eePMbGhoy5n4g+G4vlh2muDcsCTJtL+uKbOzWxs5LHA==", + "dev": true + }, + "node_modules/@docsearch/css": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/css/-/css-3.8.2.tgz", + "integrity": "sha512-y05ayQFyUmCXze79+56v/4HpycYF3uFqB78pLPrSV5ZKAlDuIAAJNhaRi8tTdRNXh05yxX/TyNnzD6LwSM89vQ==", + "dev": true + }, + "node_modules/@docsearch/js": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/js/-/js-3.8.2.tgz", + "integrity": "sha512-Q5wY66qHn0SwA7Taa0aDbHiJvaFJLOJyHmooQ7y8hlwwQLQ/5WwCcoX0g7ii04Qi2DJlHsd0XXzJ8Ypw9+9YmQ==", + "dev": true, + "dependencies": { + "@docsearch/react": "3.8.2", + "preact": "^10.0.0" + } + }, + "node_modules/@docsearch/react": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/@docsearch/react/-/react-3.8.2.tgz", + "integrity": "sha512-xCRrJQlTt8N9GU0DG4ptwHRkfnSnD/YpdeaXe02iKfqs97TkZJv60yE+1eq/tjPcVnTW8dP5qLP7itifFVV5eg==", + "dev": true, + "dependencies": { + "@algolia/autocomplete-core": "1.17.7", + "@algolia/autocomplete-preset-algolia": "1.17.7", + "@docsearch/css": "3.8.2", + "algoliasearch": "^5.14.2" + }, + "peerDependencies": { + "@types/react": ">= 16.8.0 < 19.0.0", + "react": ">= 16.8.0 < 19.0.0", + "react-dom": ">= 16.8.0 < 19.0.0", + "search-insights": ">= 1 < 3" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "search-insights": { + "optional": true + } + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@iconify-json/simple-icons": { + "version": "1.2.76", + "resolved": "https://registry.npmjs.org/@iconify-json/simple-icons/-/simple-icons-1.2.76.tgz", + "integrity": "sha512-lLRlA8yaf+1L5VCPRvR9lynoSklsddKHEylchmZJKdj/q2xVQ1ZAEJ8SCQlv9cbgtMefnlyM98U+8Si2aoFZPA==", + "dev": true, + "dependencies": { + "@iconify/types": "*" + } + }, + "node_modules/@iconify/types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@iconify/types/-/types-2.0.0.tgz", + "integrity": "sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==", + "dev": true + }, + "node_modules/@iconify/utils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.0.tgz", + "integrity": "sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==", + "dev": true, + "dependencies": { + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "mlly": "^1.8.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@mermaid-js/mermaid-mindmap": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-mindmap/-/mermaid-mindmap-9.3.0.tgz", + "integrity": "sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==", + "dev": true, + "optional": true, + "dependencies": { + "@braintree/sanitize-url": "^6.0.0", + "cytoscape": "^3.23.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.1.0", + "d3": "^7.0.0", + "khroma": "^2.0.0", + "non-layered-tidy-tree-layout": "^2.0.2" + } + }, + "node_modules/@mermaid-js/mermaid-mindmap/node_modules/@braintree/sanitize-url": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", + "dev": true, + "optional": true + }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.0.tgz", + "integrity": "sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==", + "dev": true, + "dependencies": { + "langium": "^4.0.0" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz", + "integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz", + "integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz", + "integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz", + "integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz", + "integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz", + "integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz", + "integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz", + "integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz", + "integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz", + "integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz", + "integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz", + "integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz", + "integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz", + "integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz", + "integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz", + "integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz", + "integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz", + "integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz", + "integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz", + "integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz", + "integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz", + "integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz", + "integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz", + "integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz", + "integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@shikijs/core": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", + "integrity": "sha512-uu/8RExTKtavlpH7XqnVYBrfBkUc20ngXiX9NSrBhOVZYv/7XQRKUyhtkeflY5QsxC0GbJThCerruZfsUaSldg==", + "dev": true, + "dependencies": { + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.4" + } + }, + "node_modules/@shikijs/engine-javascript": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-2.5.0.tgz", + "integrity": "sha512-VjnOpnQf8WuCEZtNUdjjwGUbtAVKuZkVQ/5cHy/tojVVRIRtlWMYVjyWhxOmIq05AlSOv72z7hRNRGVBgQOl0w==", + "dev": true, + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^3.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-2.5.0.tgz", + "integrity": "sha512-pGd1wRATzbo/uatrCIILlAdFVKdxImWJGQ5rFiB5VZi2ve5xj3Ax9jny8QvkaV93btQEwR/rSz5ERFpC5mKNIw==", + "dev": true, + "dependencies": { + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-2.5.0.tgz", + "integrity": "sha512-Qfrrt5OsNH5R+5tJ/3uYBBZv3SuGmnRPejV9IlIbFH3HTGLDlkqgHymAlzklVmKBjAaVmkPkyikAV/sQ1wSL+w==", + "dev": true, + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/themes": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-2.5.0.tgz", + "integrity": "sha512-wGrk+R8tJnO0VMzmUExHR+QdSaPUl/NKs+a4cQQRWyoc3YFbUzuLEi/KWK1hj+8BfHRKm2jNhhJck1dfstJpiw==", + "dev": true, + "dependencies": { + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/transformers": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/transformers/-/transformers-2.5.0.tgz", + "integrity": "sha512-SI494W5X60CaUwgi8u4q4m4s3YAFSxln3tzNjOSYqq54wlVgz0/NbbXEb3mdLbqMBztcmS7bVTaEd2w0qMmfeg==", + "dev": true, + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/types": "2.5.0" + } + }, + "node_modules/@shikijs/types": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-2.5.0.tgz", + "integrity": "sha512-ygl5yhxki9ZLNuNpPitBWvcy9fsSKKaRuO4BAlMyagszQidxcpLAr0qiW/q43DtSIDxO6hEbtYLiFZNXO/hdGw==", + "dev": true, + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true + }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "dev": true + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "dev": true + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "dev": true + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "dev": true + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dev": true, + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "dev": true + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "dev": true + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "dev": true, + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "dev": true + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "dev": true, + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", + "dev": true + }, + "node_modules/@types/markdown-it": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.2.tgz", + "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", + "dev": true, + "dependencies": { + "@types/linkify-it": "^5", + "@types/mdurl": "^2" + } + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", + "dev": true + }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "optional": true + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.21", + "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz", + "integrity": "sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==", + "dev": true + }, + "node_modules/@ungap/structured-clone": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", + "dev": true + }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, + "node_modules/@vitejs/plugin-vue": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", + "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==", + "dev": true, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.31.tgz", + "integrity": "sha512-k/ueL14aNIEy5Onf0OVzR8kiqF/WThgLdFhxwa4e/KF/0qe38IwIdofoSWBTvvxQOesaz6riAFAUaYjoF9fLLQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.2", + "@vue/shared": "3.5.31", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.31.tgz", + "integrity": "sha512-BMY/ozS/xxjYqRFL+tKdRpATJYDTTgWSo0+AJvJNg4ig+Hgb0dOsHPXvloHQ5hmlivUqw1Yt2pPIqp4e0v1GUw==", + "dev": true, + "dependencies": { + "@vue/compiler-core": "3.5.31", + "@vue/shared": "3.5.31" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.31.tgz", + "integrity": "sha512-M8wpPgR9UJ8MiRGjppvx9uWJfLV7A/T+/rL8s/y3QG3u0c2/YZgff3d6SuimKRIhcYnWg5fTfDMlz2E6seUW8Q==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.2", + "@vue/compiler-core": "3.5.31", + "@vue/compiler-dom": "3.5.31", + "@vue/compiler-ssr": "3.5.31", + "@vue/shared": "3.5.31", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.31.tgz", + "integrity": "sha512-h0xIMxrt/LHOvJKMri+vdYT92BrK3HFLtDqq9Pr/lVVfE4IyKZKvWf0vJFW10Yr6nX02OR4MkJwI0c1HDa1hog==", + "dev": true, + "dependencies": { + "@vue/compiler-dom": "3.5.31", + "@vue/shared": "3.5.31" + } + }, + "node_modules/@vue/devtools-api": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-7.7.9.tgz", + "integrity": "sha512-kIE8wvwlcZ6TJTbNeU2HQNtaxLx3a84aotTITUuL/4bzfPxzajGBOoqjMhwZJ8L9qFYDU/lAYMEEm11dnZOD6g==", + "dev": true, + "dependencies": { + "@vue/devtools-kit": "^7.7.9" + } + }, + "node_modules/@vue/devtools-kit": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.9.tgz", + "integrity": "sha512-PyQ6odHSgiDVd4hnTP+aDk2X4gl2HmLDfiyEnn3/oV+ckFDuswRs4IbBT7vacMuGdwY/XemxBoh302ctbsptuA==", + "dev": true, + "dependencies": { + "@vue/devtools-shared": "^7.7.9", + "birpc": "^2.3.0", + "hookable": "^5.5.3", + "mitt": "^3.0.1", + "perfect-debounce": "^1.0.0", + "speakingurl": "^14.0.1", + "superjson": "^2.2.2" + } + }, + "node_modules/@vue/devtools-shared": { + "version": "7.7.9", + "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.9.tgz", + "integrity": "sha512-iWAb0v2WYf0QWmxCGy0seZNDPdO3Sp5+u78ORnyeonS6MT4PC7VPrryX2BpMJrwlDeaZ6BD4vP4XKjK0SZqaeA==", + "dev": true, + "dependencies": { + "rfdc": "^1.4.1" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.31.tgz", + "integrity": "sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==", + "dev": true, + "dependencies": { + "@vue/shared": "3.5.31" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.31.tgz", + "integrity": "sha512-AZPmIHXEAyhpkmN7aWlqjSfYynmkWlluDNPHMCZKFHH+lLtxP/30UJmoVhXmbDoP1Ng0jG0fyY2zCj1PnSSA6Q==", + "dev": true, + "dependencies": { + "@vue/reactivity": "3.5.31", + "@vue/shared": "3.5.31" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.31.tgz", + "integrity": "sha512-xQJsNRmGPeDCJq/u813tyonNgWBFjzfVkBwDREdEWndBnGdHLHgkwNBQxLtg4zDrzKTEcnikUy1UUNecb3lJ6g==", + "dev": true, + "dependencies": { + "@vue/reactivity": "3.5.31", + "@vue/runtime-core": "3.5.31", + "@vue/shared": "3.5.31", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.31.tgz", + "integrity": "sha512-GJuwRvMcdZX/CriUnyIIOGkx3rMV3H6sOu0JhdKbduaeCji6zb60iOGMY7tFoN24NfsUYoFBhshZtGxGpxO4iA==", + "dev": true, + "dependencies": { + "@vue/compiler-ssr": "3.5.31", + "@vue/shared": "3.5.31" + }, + "peerDependencies": { + "vue": "3.5.31" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.31.tgz", + "integrity": "sha512-nBxuiuS9Lj5bPkPbWogPUnjxxWpkRniX7e5UBQDWl6Fsf4roq9wwV+cR7ezQ4zXswNvPIlsdj1slcLB7XCsRAw==", + "dev": true + }, + "node_modules/@vueuse/core": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz", + "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==", + "dev": true, + "dependencies": { + "@types/web-bluetooth": "^0.0.21", + "@vueuse/metadata": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/integrations": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-12.8.2.tgz", + "integrity": "sha512-fbGYivgK5uBTRt7p5F3zy6VrETlV9RtZjBqd1/HxGdjdckBgBM4ugP8LHpjolqTj14TXTxSK1ZfgPbHYyGuH7g==", + "dev": true, + "dependencies": { + "@vueuse/core": "12.8.2", + "@vueuse/shared": "12.8.2", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "async-validator": "^4", + "axios": "^1", + "change-case": "^5", + "drauu": "^0.4", + "focus-trap": "^7", + "fuse.js": "^7", + "idb-keyval": "^6", + "jwt-decode": "^4", + "nprogress": "^0.2", + "qrcode": "^1.5", + "sortablejs": "^1", + "universal-cookie": "^7" + }, + "peerDependenciesMeta": { + "async-validator": { + "optional": true + }, + "axios": { + "optional": true + }, + "change-case": { + "optional": true + }, + "drauu": { + "optional": true + }, + "focus-trap": { + "optional": true + }, + "fuse.js": { + "optional": true + }, + "idb-keyval": { + "optional": true + }, + "jwt-decode": { + "optional": true + }, + "nprogress": { + "optional": true + }, + "qrcode": { + "optional": true + }, + "sortablejs": { + "optional": true + }, + "universal-cookie": { + "optional": true + } + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz", + "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.8.2", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz", + "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==", + "dev": true, + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/algoliasearch": { + "version": "5.50.1", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.50.1.tgz", + "integrity": "sha512-/bwdue1/8LWELn/DBalGRfuLsXBLXULJo/yOeavJtDu8rBwxIzC6/Rz9Jg19S21VkJvRuZO1k8CZXBMS73mYbA==", + "dev": true, + "dependencies": { + "@algolia/abtesting": "1.16.1", + "@algolia/client-abtesting": "5.50.1", + "@algolia/client-analytics": "5.50.1", + "@algolia/client-common": "5.50.1", + "@algolia/client-insights": "5.50.1", + "@algolia/client-personalization": "5.50.1", + "@algolia/client-query-suggestions": "5.50.1", + "@algolia/client-search": "5.50.1", + "@algolia/ingestion": "1.50.1", + "@algolia/monitoring": "1.50.1", + "@algolia/recommend": "5.50.1", + "@algolia/requester-browser-xhr": "5.50.1", + "@algolia/requester-fetch": "5.50.1", + "@algolia/requester-node-http": "5.50.1" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/birpc": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.9.0.tgz", + "integrity": "sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/character-entities-html4": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/character-entities-legacy": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chevrotain": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-11.1.2.tgz", + "integrity": "sha512-opLQzEVriiH1uUQ4Kctsd49bRoFDXGGSC4GUqj7pGyxM3RehRhvTlZJc1FL/Flew2p5uwxa1tUDWKzI4wNM8pg==", + "dev": true, + "dependencies": { + "@chevrotain/cst-dts-gen": "11.1.2", + "@chevrotain/gast": "11.1.2", + "@chevrotain/regexp-to-ast": "11.1.2", + "@chevrotain/types": "11.1.2", + "@chevrotain/utils": "11.1.2", + "lodash-es": "4.17.23" + } + }, + "node_modules/chevrotain-allstar": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/chevrotain-allstar/-/chevrotain-allstar-0.3.1.tgz", + "integrity": "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==", + "dev": true, + "dependencies": { + "lodash-es": "^4.17.21" + }, + "peerDependencies": { + "chevrotain": "^11.0.0" + } + }, + "node_modules/chevrotain/node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/comma-separated-tokens": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/concurrently": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz", + "integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==", + "dev": true, + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.8.3", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-4.0.5.tgz", + "integrity": "sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==", + "dev": true, + "dependencies": { + "is-what": "^5.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "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==", + "dev": true, + "dependencies": { + "layout-base": "^1.0.0" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true + }, + "node_modules/cytoscape": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.33.1.tgz", + "integrity": "sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dev": true, + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dev": true, + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "dev": true + }, + "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==", + "dev": true, + "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.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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==", + "dev": true, + "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.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "dev": true, + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "dev": true + }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "dev": true, + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/dompurify": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", + "dev": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emoji-regex-xs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-1.0.0.tgz", + "integrity": "sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==", + "dev": true + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/focus-trap": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.8.0.tgz", + "integrity": "sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==", + "dev": true, + "dependencies": { + "tabbable": "^6.4.0" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hast-util-to-html": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/unist": "^3.0.0", + "ccount": "^2.0.0", + "comma-separated-tokens": "^2.0.0", + "hast-util-whitespace": "^3.0.0", + "html-void-elements": "^3.0.0", + "mdast-util-to-hast": "^13.0.0", + "property-information": "^7.0.0", + "space-separated-tokens": "^2.0.0", + "stringify-entities": "^4.0.0", + "zwitch": "^2.0.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-whitespace": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hookable": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz", + "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", + "dev": true + }, + "node_modules/html-void-elements": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "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==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-what": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-5.5.0.tgz", + "integrity": "sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/katex": { + "version": "0.16.44", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.44.tgz", + "integrity": "sha512-EkxoDTk8ufHqHlf9QxGwcxeLkWRR3iOuYfRpfORgYfqc8s13bgb+YtRY59NK5ZpRaCwq1kqA6a5lpX8C/eLphQ==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/langium": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/langium/-/langium-4.2.1.tgz", + "integrity": "sha512-zu9QWmjpzJcomzdJQAHgDVhLGq5bLosVak1KVa40NzQHXfqr4eAHupvnPOVXEoLkg6Ocefvf/93d//SB7du4YQ==", + "dev": true, + "dependencies": { + "chevrotain": "~11.1.1", + "chevrotain-allstar": "~0.3.1", + "vscode-languageserver": "~9.0.1", + "vscode-languageserver-textdocument": "~1.0.11", + "vscode-uri": "~3.1.0" + }, + "engines": { + "node": ">=20.10.0", + "npm": ">=10.2.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==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", + "integrity": "sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==", + "dev": true + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mark.js": { + "version": "8.11.1", + "resolved": "https://registry.npmjs.org/mark.js/-/mark.js-8.11.1.tgz", + "integrity": "sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==", + "dev": true + }, + "node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/mdast-util-to-hast": { + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", + "dev": true, + "dependencies": { + "@types/hast": "^3.0.0", + "@types/mdast": "^4.0.0", + "@ungap/structured-clone": "^1.0.0", + "devlop": "^1.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "trim-lines": "^3.0.0", + "unist-util-position": "^5.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mermaid": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.14.0.tgz", + "integrity": "sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==", + "dev": true, + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.0", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "katex": "^0.16.25", + "khroma": "^2.1.0", + "lodash-es": "^4.17.23", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/minisearch": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/minisearch/-/minisearch-7.2.0.tgz", + "integrity": "sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg==", + "dev": true + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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==", + "dev": true, + "optional": true + }, + "node_modules/oniguruma-to-es": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-3.1.1.tgz", + "integrity": "sha512-bUH8SDvPkH3ho3dvwJwfonjlQ4R80vjyvrU8YpxuROddv55vAEJrTuCuCVUhhsHbtlD9tGGbaNApGQckXhS8iQ==", + "dev": true, + "dependencies": { + "emoji-regex-xs": "^1.0.0", + "regex": "^6.0.1", + "regex-recursion": "^6.0.2" + } + }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true + }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "dev": true + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true + }, + "node_modules/perfect-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz", + "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "dev": true + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "dev": true, + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/preact": { + "version": "10.29.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz", + "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/property-information": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/regex/-/regex-6.1.0.tgz", + "integrity": "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==", + "dev": true, + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-recursion": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", + "dev": true, + "dependencies": { + "regex-utilities": "^2.3.0" + } + }, + "node_modules/regex-utilities": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "dev": true + }, + "node_modules/rollup": { + "version": "4.60.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.1.tgz", + "integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.1", + "@rollup/rollup-android-arm64": "4.60.1", + "@rollup/rollup-darwin-arm64": "4.60.1", + "@rollup/rollup-darwin-x64": "4.60.1", + "@rollup/rollup-freebsd-arm64": "4.60.1", + "@rollup/rollup-freebsd-x64": "4.60.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.1", + "@rollup/rollup-linux-arm-musleabihf": "4.60.1", + "@rollup/rollup-linux-arm64-gnu": "4.60.1", + "@rollup/rollup-linux-arm64-musl": "4.60.1", + "@rollup/rollup-linux-loong64-gnu": "4.60.1", + "@rollup/rollup-linux-loong64-musl": "4.60.1", + "@rollup/rollup-linux-ppc64-gnu": "4.60.1", + "@rollup/rollup-linux-ppc64-musl": "4.60.1", + "@rollup/rollup-linux-riscv64-gnu": "4.60.1", + "@rollup/rollup-linux-riscv64-musl": "4.60.1", + "@rollup/rollup-linux-s390x-gnu": "4.60.1", + "@rollup/rollup-linux-x64-gnu": "4.60.1", + "@rollup/rollup-linux-x64-musl": "4.60.1", + "@rollup/rollup-openbsd-x64": "4.60.1", + "@rollup/rollup-openharmony-arm64": "4.60.1", + "@rollup/rollup-win32-arm64-msvc": "4.60.1", + "@rollup/rollup-win32-ia32-msvc": "4.60.1", + "@rollup/rollup-win32-x64-gnu": "4.60.1", + "@rollup/rollup-win32-x64-msvc": "4.60.1", + "fsevents": "~2.3.2" + } + }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "dev": true, + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/search-insights": { + "version": "2.17.3", + "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", + "integrity": "sha512-RQPdCYTa8A68uM2jwxoY842xDhvx3E5LFL1LxvxCNMev4o5mLuokczhzjAgGwUZBAmOKZknArSxLKmXtIi2AxQ==", + "dev": true, + "peer": true + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shiki": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-2.5.0.tgz", + "integrity": "sha512-mI//trrsaiCIPsja5CNfsyNOqgAZUb6VpJA+340toL42UpzQlXpwRV9nch69X6gaUxrr9kaOOa6e3y3uAkGFxQ==", + "dev": true, + "dependencies": { + "@shikijs/core": "2.5.0", + "@shikijs/engine-javascript": "2.5.0", + "@shikijs/engine-oniguruma": "2.5.0", + "@shikijs/langs": "2.5.0", + "@shikijs/themes": "2.5.0", + "@shikijs/types": "2.5.0", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/speakingurl": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz", + "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stringify-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", + "dev": true, + "dependencies": { + "character-entities-html4": "^2.0.0", + "character-entities-legacy": "^3.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/stylis": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.6.tgz", + "integrity": "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==", + "dev": true + }, + "node_modules/superjson": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.6.tgz", + "integrity": "sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA==", + "dev": true, + "dependencies": { + "copy-anything": "^4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "dev": true + }, + "node_modules/tinyexec": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz", + "integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-lines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", + "dev": true, + "funding": { + "type": "github", + "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==", + "dev": true, + "engines": { + "node": ">=6.10" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true + }, + "node_modules/unist-util-is": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.1.tgz", + "integrity": "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-position": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.1.0.tgz", + "integrity": "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.2.tgz", + "integrity": "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/uuid": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", + "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/vfile": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.3.tgz", + "integrity": "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==", + "dev": true, + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.4.21", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", + "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", + "dev": true, + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vitepress": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/vitepress/-/vitepress-1.6.4.tgz", + "integrity": "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg==", + "dev": true, + "dependencies": { + "@docsearch/css": "3.8.2", + "@docsearch/js": "3.8.2", + "@iconify-json/simple-icons": "^1.2.21", + "@shikijs/core": "^2.1.0", + "@shikijs/transformers": "^2.1.0", + "@shikijs/types": "^2.1.0", + "@types/markdown-it": "^14.1.2", + "@vitejs/plugin-vue": "^5.2.1", + "@vue/devtools-api": "^7.7.0", + "@vue/shared": "^3.5.13", + "@vueuse/core": "^12.4.0", + "@vueuse/integrations": "^12.4.0", + "focus-trap": "^7.6.4", + "mark.js": "8.11.1", + "minisearch": "^7.1.1", + "shiki": "^2.1.0", + "vite": "^5.4.14", + "vue": "^3.5.13" + }, + "bin": { + "vitepress": "bin/vitepress.js" + }, + "peerDependencies": { + "markdown-it-mathjax3": "^4", + "postcss": "^8" + }, + "peerDependenciesMeta": { + "markdown-it-mathjax3": { + "optional": true + }, + "postcss": { + "optional": true + } + } + }, + "node_modules/vitepress-plugin-mermaid": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/vitepress-plugin-mermaid/-/vitepress-plugin-mermaid-2.0.17.tgz", + "integrity": "sha512-IUzYpwf61GC6k0XzfmAmNrLvMi9TRrVRMsUyCA8KNXhg/mQ1VqWnO0/tBVPiX5UoKF1mDUwqn5QV4qAJl6JnUg==", + "dev": true, + "optionalDependencies": { + "@mermaid-js/mermaid-mindmap": "^9.3.0" + }, + "peerDependencies": { + "mermaid": "10 || 11", + "vitepress": "^1.0.0 || ^1.0.0-alpha" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dev": true, + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dev": true, + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", + "dev": true + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true + }, + "node_modules/vue": { + "version": "3.5.31", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.31.tgz", + "integrity": "sha512-iV/sU9SzOlmA/0tygSmjkEN6Jbs3nPoIPFhCMLD2STrjgOU8DX7ZtzMhg4ahVwf5Rp9KoFzcXeB1ZrVbLBp5/Q==", + "dev": true, + "dependencies": { + "@vue/compiler-dom": "3.5.31", + "@vue/compiler-sfc": "3.5.31", + "@vue/runtime-dom": "3.5.31", + "@vue/server-renderer": "3.5.31", + "@vue/shared": "3.5.31" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..5a5ef15 --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "scripts": { + "mdsnippets": "mdsnippets", + "docs": "concurrently --group mdsnippets \"vitepress dev docs --port 5050 --open\"", + "docs-build": "concurrently --group mdsnippets \"vitepress build docs\"" + }, + "devDependencies": { + "concurrently": "^9.1.2", + "vitepress": "^1.6.3", + "vitepress-plugin-mermaid": "^2.0.17", + "mermaid": "^11.4.1" + } +} diff --git a/src/DocSamples/ArgumentFlagSamples.cs b/src/DocSamples/ArgumentFlagSamples.cs new file mode 100644 index 0000000..4095687 --- /dev/null +++ b/src/DocSamples/ArgumentFlagSamples.cs @@ -0,0 +1,25 @@ +using JasperFx.CommandLine; + +namespace DocSamples; + +#region sample_build_input +public class BuildInput +{ + [Description("The target configuration")] + public string Configuration { get; set; } = "Debug"; + + [Description("The output directory")] + public string OutputPath { get; set; } = "./bin"; + + [FlagAlias("verbose", 'v')] + [Description("Enable verbose output")] + public bool VerboseFlag { get; set; } + + [FlagAlias("force", 'f')] + [Description("Force a clean rebuild")] + public bool ForceFlag { get; set; } + + [Description("Maximum degree of parallelism")] + public int ParallelCount { get; set; } = 4; +} +#endregion diff --git a/src/DocSamples/BuiltInFramesSamples.cs b/src/DocSamples/BuiltInFramesSamples.cs new file mode 100644 index 0000000..aee6927 --- /dev/null +++ b/src/DocSamples/BuiltInFramesSamples.cs @@ -0,0 +1,142 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace DocSamples; + +public class BuiltInFramesSamples +{ + #region sample_comment_frame_usage + + public static void UsingCommentFrame() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Worker", typeof(IWorker)); + var method = type.MethodFor(nameof(IWorker.Execute)); + + // CommentFrame writes a C# comment line + method.Frames.Add(new CommentFrame("Begin processing")); + method.Frames.Code("Console.WriteLine(\"Working...\");"); + } + + public interface IWorker + { + void Execute(); + } + + #endregion + + #region sample_code_frame_usage + + public static void UsingCodeFrame() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Processor", typeof(IProcessor)); + var method = type.MethodFor(nameof(IProcessor.Process)); + + // CodeFrame uses a format string with variable placeholders + method.Frames.Code("Console.WriteLine({0});", Use.Type()); + } + + public interface IProcessor + { + void Process(string input); + } + + #endregion + + #region sample_return_frame_usage + + public static void UsingReturnFrame() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Checker", typeof(IChecker)); + var method = type.MethodFor(nameof(IChecker.IsValid)); + + method.Frames.Code("var result = {0} != null;", Use.Type()); + + // ReturnFrame generates "return ;" + method.Frames.Add(new ReturnFrame(typeof(bool))); + } + + public interface IChecker + { + bool IsValid(object input); + } + + #endregion + + #region sample_if_block_usage + + public static void UsingIfBlock() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Guard", typeof(IGuard)); + var method = type.MethodFor(nameof(IGuard.Check)); + + // IfBlock wraps inner frames in an if statement + var inner = new CodeFrame(false, "Console.WriteLine(\"Input is not null\");"); + method.Frames.Add(new IfBlock("input != null", inner)); + } + + public interface IGuard + { + void Check(object input); + } + + #endregion + + #region sample_constructor_frame_usage + + public static void UsingConstructorFrame() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("ServiceBuilder", typeof(IServiceBuilder)); + var method = type.MethodFor(nameof(IServiceBuilder.Build)); + + // ConstructorFrame generates "var widget = new Widget();" + var ctor = new ConstructorFrame(() => new Widget()); + method.Frames.Add(ctor); + } + + public interface IServiceBuilder + { + Widget Build(); + } + + public class Widget; + + #endregion + + #region sample_method_call_frame_usage + + public static void UsingMethodCallFrame() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Invoker", typeof(IInvoker)); + var method = type.MethodFor(nameof(IInvoker.Invoke)); + + // MethodCall generates a call to a static or instance method + var call = new MethodCall(typeof(Console), nameof(Console.WriteLine)); + method.Frames.Add(call); + } + + public interface IInvoker + { + void Invoke(string message); + } + + #endregion +} diff --git a/src/DocSamples/CliSetupSamples.cs b/src/DocSamples/CliSetupSamples.cs new file mode 100644 index 0000000..37494b7 --- /dev/null +++ b/src/DocSamples/CliSetupSamples.cs @@ -0,0 +1,37 @@ +using JasperFx; +using Microsoft.Extensions.Hosting; + +namespace DocSamples; + +public class CliSetupSamples +{ + public async Task setup_jasperfx_cli() + { + var args = Array.Empty(); + + #region sample_apply_jasperfx_extensions + await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); + #endregion + } + + public async Task run_jasperfx_commands() + { + var args = Array.Empty(); + + #region sample_run_jasperfx_commands + var builder = Host.CreateDefaultBuilder(); + + builder.ConfigureServices(services => + { + // Register your services here + }); + + await builder + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); + #endregion + } +} diff --git a/src/DocSamples/CodegenCliSamples.cs b/src/DocSamples/CodegenCliSamples.cs new file mode 100644 index 0000000..ecdb187 --- /dev/null +++ b/src/DocSamples/CodegenCliSamples.cs @@ -0,0 +1,64 @@ +using JasperFx; +using JasperFx.CodeGeneration; +using Microsoft.Extensions.Hosting; + +namespace DocSamples; + +public class CodegenCliSamples +{ + #region sample_type_load_mode_dynamic + + public static void ConfigureDynamicMode() + { + // Always generate types at runtime. Best for development. + var rules = new GenerationRules("MyApp.Generated") + { + TypeLoadMode = TypeLoadMode.Dynamic + }; + } + + #endregion + + #region sample_type_load_mode_static + + public static void ConfigureStaticMode() + { + // Types must be pre-built in the application assembly. + // Throws if generated types are missing. + var rules = new GenerationRules("MyApp.Generated") + { + TypeLoadMode = TypeLoadMode.Static + }; + } + + #endregion + + #region sample_type_load_mode_auto + + public static void ConfigureAutoMode() + { + // Try to load pre-built types first, fall back to runtime generation + var rules = new GenerationRules("MyApp.Generated") + { + TypeLoadMode = TypeLoadMode.Auto + }; + } + + #endregion + + #region sample_codegen_cli_setup + + public static async Task SetupWithCodegenCommand(string[] args) + { + return await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); + + // Run with: dotnet run -- codegen preview + // Run with: dotnet run -- codegen write + // Run with: dotnet run -- codegen delete + } + + #endregion +} diff --git a/src/DocSamples/CodegenOverviewSamples.cs b/src/DocSamples/CodegenOverviewSamples.cs new file mode 100644 index 0000000..1702173 --- /dev/null +++ b/src/DocSamples/CodegenOverviewSamples.cs @@ -0,0 +1,37 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace DocSamples; + +public class CodegenOverviewSamples +{ + #region sample_codegen_overview + + public static string GenerateGreeterCode() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + // Add a new type that implements IGreeter + var type = assembly.AddType("HelloGreeter", typeof(IGreeter)); + + // Get the method defined by the interface + var method = type.MethodFor("Greet"); + + // Add a frame that writes a line of code + method.Frames.Code("return \"Hello, \" + {0};", Use.Type()); + + // Generate the C# source code + var code = assembly.GenerateCode(); + + return code; + } + + public interface IGreeter + { + string Greet(string name); + } + + #endregion +} diff --git a/src/DocSamples/ConfigurationSamples.cs b/src/DocSamples/ConfigurationSamples.cs new file mode 100644 index 0000000..205b89d --- /dev/null +++ b/src/DocSamples/ConfigurationSamples.cs @@ -0,0 +1,43 @@ +using JasperFx; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; + +namespace DocSamples; + +public class ConfigurationSamples +{ + #region sample_critter_stack_defaults + public static IHostBuilder ConfigureWithDefaults() + { + return Host.CreateDefaultBuilder() + .ConfigureServices(services => + { + services.AddJasperFx(opts => + { + // Require a file to exist at application startup + opts.RequireFile("appsettings.json"); + + // Set the development environment name if non-standard + opts.DevelopmentEnvironmentName = "Local"; + }); + }); + } + #endregion + + #region sample_add_jasperfx_options + public static void ConfigureOptions(IServiceCollection services) + { + services.AddJasperFx(opts => + { + // Register an environment check inline + opts.RegisterEnvironmentCheck( + "Database connectivity", + async (sp, ct) => + { + // Verify your database is accessible + await Task.CompletedTask; + }); + }); + } + #endregion +} diff --git a/src/DocSamples/DescribeSamples.cs b/src/DocSamples/DescribeSamples.cs new file mode 100644 index 0000000..e73c414 --- /dev/null +++ b/src/DocSamples/DescribeSamples.cs @@ -0,0 +1,22 @@ +using JasperFx.CommandLine.Descriptions; +using Spectre.Console; + +namespace DocSamples; + +#region sample_custom_system_part +public class MessagingSystemPart : SystemPartBase +{ + public MessagingSystemPart() + : base("Messaging Subsystem", new Uri("system://messaging")) + { + } + + public override Task WriteToConsole() + { + AnsiConsole.MarkupLine("[bold]Transport:[/] RabbitMQ"); + AnsiConsole.MarkupLine("[bold]Queues:[/] 12 active"); + AnsiConsole.MarkupLine("[bold]Consumers:[/] 8 running"); + return Task.CompletedTask; + } +} +#endregion diff --git a/src/DocSamples/DocSamples.csproj b/src/DocSamples/DocSamples.csproj new file mode 100644 index 0000000..18ac9c4 --- /dev/null +++ b/src/DocSamples/DocSamples.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + false + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + diff --git a/src/DocSamples/EnvironmentCheckSamples.cs b/src/DocSamples/EnvironmentCheckSamples.cs new file mode 100644 index 0000000..2cf7103 --- /dev/null +++ b/src/DocSamples/EnvironmentCheckSamples.cs @@ -0,0 +1,53 @@ +using JasperFx.Environment; +using Microsoft.Extensions.DependencyInjection; + +namespace DocSamples; + +public class EnvironmentCheckSamples +{ + #region sample_register_environment_check + public static void RegisterChecks(IServiceCollection services) + { + // Async check with IServiceProvider access + services.CheckEnvironment( + "Database is reachable", + async (IServiceProvider sp, CancellationToken ct) => + { + // Throw an exception to indicate failure + await Task.CompletedTask; + }); + + // Synchronous check + services.CheckEnvironment( + "Configuration file exists", + (IServiceProvider sp) => + { + if (!File.Exists("appsettings.json")) + { + throw new FileNotFoundException("Missing configuration file"); + } + }); + } + #endregion + + #region sample_environment_check_with_service + public static void RegisterTypedCheck(IServiceCollection services) + { + services.CheckEnvironment( + "Required config keys present", + config => + { + if (config?.GetValue("ConnectionString") is null) + { + throw new Exception("ConnectionString is required"); + } + }); + } + #endregion +} + +// Placeholder for sample compilation +public interface IConfiguration +{ + T? GetValue(string key); +} diff --git a/src/DocSamples/ExtensionSamples.cs b/src/DocSamples/ExtensionSamples.cs new file mode 100644 index 0000000..9276c7f --- /dev/null +++ b/src/DocSamples/ExtensionSamples.cs @@ -0,0 +1,53 @@ +using JasperFx.Core; +using JasperFx.Core.Reflection; + +namespace DocSamples; + +public class ExtensionSamples +{ + #region sample_string_extensions + public void StringHelpers() + { + // Convert to camel case + var camel = "SomePropertyName".ToCamelCase(); + // => "somePropertyName" + + // Check if a string is empty or whitespace + var isEmpty = "".IsEmpty(); + var isNotEmpty = "hello".IsNotEmpty(); + + // Joining strings + var joined = new[] { "one", "two", "three" }.Join(", "); + } + #endregion + + #region sample_enumerable_extensions + public void EnumerableHelpers() + { + var items = new List { "a", "b", "c", "a" }; + + // AddRange that works on IList + items.Fill("d"); + + // Add only if not already present + items.Fill("a"); // no-op if already present + + // Each / EachAsync for side effects + items.Each(item => Console.WriteLine(item)); + } + #endregion + + #region sample_reflection_extensions + public void ReflectionHelpers() + { + // Check if a type implements an interface + var implements = typeof(List).CanBeCastTo>(); + + // Get a human-readable type name + var name = typeof(Dictionary).FullNameInCode(); + + // Close an open generic type + var closed = typeof(List<>).CloseAndBuildAs(typeof(string)); + } + #endregion +} diff --git a/src/DocSamples/FramesSamples.cs b/src/DocSamples/FramesSamples.cs new file mode 100644 index 0000000..ab399fa --- /dev/null +++ b/src/DocSamples/FramesSamples.cs @@ -0,0 +1,81 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace DocSamples; + +#region sample_custom_sync_frame + +public class LogMessageFrame : SyncFrame +{ + private readonly string _message; + private Variable? _logger; + + public LogMessageFrame(string message) + { + _message = message; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write($"Console.WriteLine(\"{_message}\");"); + + // Always call through to the next frame in the chain + Next?.GenerateCode(method, writer); + } +} + +#endregion + +#region sample_custom_async_frame + +public class LoadEntityFrame : AsyncFrame +{ + private readonly Type _entityType; + private Variable? _id; + + public LoadEntityFrame(Type entityType) + { + _entityType = entityType; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + var entityVariable = Create(_entityType); + + writer.Write( + $"var {entityVariable.Usage} = await repository.LoadAsync<{_entityType.Name}>({_id?.Usage ?? "id"});"); + + Next?.GenerateCode(method, writer); + } +} + +#endregion + +#region sample_wrapping_frame + +public class StopwatchFrame : SyncFrame +{ + public StopwatchFrame() + { + // Mark this frame as wrapping inner frames + Wraps = true; + } + + public override void GenerateCode(GeneratedMethod method, ISourceWriter writer) + { + writer.Write("var stopwatch = System.Diagnostics.Stopwatch.StartNew();"); + writer.Write("BLOCK:try"); + + // Let the inner frames generate their code + Next?.GenerateCode(method, writer); + + writer.FinishBlock(); // end try + writer.Write("BLOCK:finally"); + writer.Write("stopwatch.Stop();"); + writer.Write("Console.WriteLine($\"Elapsed: {stopwatch.ElapsedMilliseconds}ms\");"); + writer.FinishBlock(); // end finally + } +} + +#endregion diff --git a/src/DocSamples/GeneratedTypesSamples.cs b/src/DocSamples/GeneratedTypesSamples.cs new file mode 100644 index 0000000..5f40119 --- /dev/null +++ b/src/DocSamples/GeneratedTypesSamples.cs @@ -0,0 +1,123 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace DocSamples; + +public class GeneratedTypesSamples +{ + #region sample_building_generated_type + + public static string BuildGeneratedType() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + // Create a type that inherits from a base class + var type = assembly.AddType("MyMessageHandler", typeof(MessageHandlerBase)); + + // The method defined on the base class is discovered automatically. + // Retrieve it by name. + var handleMethod = type.MethodFor("Handle"); + + // Add frames to define the method body + handleMethod.Frames.Code("Console.WriteLine(\"Handling message...\");"); + handleMethod.Frames.Code("return Task.CompletedTask;"); + + // Generate all source code for the assembly + var code = assembly.GenerateCode(); + + return code; + } + + public abstract class MessageHandlerBase + { + public abstract Task Handle(Message message); + } + + public class Message; + + #endregion + + #region sample_generated_type_with_interface + + public static string ImplementInterface() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + // Create a type that implements an interface + var type = assembly.AddType("WidgetValidator", typeof(IValidator)); + + var method = type.MethodFor(nameof(IValidator.Validate)); + method.Frames.Code("return {0} != null;", Use.Type()); + + return assembly.GenerateCode(); + } + + public interface IValidator + { + bool Validate(object input); + } + + #endregion + + #region sample_generated_type_injected_fields + + public static string TypeWithInjectedFields() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("NotificationSender", typeof(NotificationSenderBase)); + + // The InjectedField appears as a constructor argument and private field + var loggerField = new InjectedField(typeof(ILogger)); + type.AllInjectedFields.Add(loggerField); + + var method = type.MethodFor("Send"); + method.Frames.Code("Console.WriteLine(\"Sending notification\");"); + + return assembly.GenerateCode(); + } + + public abstract class NotificationSenderBase + { + public abstract void Send(string recipient, string body); + } + + public interface ILogger + { + void Log(string message); + } + + #endregion + + #region sample_generated_method_custom + + public static string AddCustomMethod() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("Calculator", typeof(object)); + + // Add a custom void method + var method = type.AddVoidMethod("PrintSum", + new Argument(typeof(int), "a"), + new Argument(typeof(int), "b")); + + method.Frames.Code("Console.WriteLine(a + b);"); + + // Add a method that returns a value + var multiply = type.AddMethodThatReturns("Multiply", + new Argument(typeof(int), "x"), + new Argument(typeof(int), "y")); + + multiply.Frames.Code("return x * y;"); + + return assembly.GenerateCode(); + } + + #endregion +} diff --git a/src/DocSamples/MethodCallSamples.cs b/src/DocSamples/MethodCallSamples.cs new file mode 100644 index 0000000..b00bf16 --- /dev/null +++ b/src/DocSamples/MethodCallSamples.cs @@ -0,0 +1,116 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace DocSamples; + +public class MethodCallSamples +{ + #region sample_method_call_basic + + public static void BasicMethodCall() + { + // Create a MethodCall by type and method name + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrder)); + + // The ReturnVariable is automatically created from the method's return type + Console.WriteLine(call.ReturnVariable!.VariableType); // typeof(OrderResult) + + // Arguments array matches the method's parameters + Console.WriteLine(call.Arguments.Length); // matches parameter count + } + + #endregion + + #region sample_method_call_async + + public static void AsyncMethodCall() + { + // Async methods are automatically detected + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrderAsync)); + + // The frame knows it is async + Console.WriteLine(call.IsAsync); // true + + // ReturnType unwraps Task to T + Console.WriteLine(call.ReturnVariable!.VariableType); // typeof(OrderResult) + } + + #endregion + + #region sample_method_call_return_action + + public static void ReturnActions() + { + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrder)); + + // Initialize: generates "var orderResult = ProcessOrder(...);" + call.ReturnAction = ReturnAction.Initialize; + + // Assign: generates "orderResult = ProcessOrder(...);" + call.ReturnAction = ReturnAction.Assign; + + // Return: generates "return ProcessOrder(...);" + call.ReturnAction = ReturnAction.Return; + } + + #endregion + + #region sample_method_call_disposal + + public static void disposal_mode_example() + { + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.CreateConnection)); + + // Wrap the return value in a using block + call.DisposalMode = DisposalMode.UsingBlock; + } + + #endregion + + #region sample_method_call_in_generated_type + + public static string UseMethodCallInGeneratedType() + { + var rules = new GenerationRules("MyApp.Generated"); + var assembly = new GeneratedAssembly(rules); + + var type = assembly.AddType("OrderHandler", typeof(IOrderHandler)); + var method = type.MethodFor(nameof(IOrderHandler.Handle)); + + // Add a MethodCall frame + var call = new MethodCall(typeof(OrderProcessor), nameof(OrderProcessor.ProcessOrder)); + method.Frames.Add(call); + + return assembly.GenerateCode(); + } + + #endregion + + public interface IOrderHandler + { + OrderResult Handle(Order order); + } + + public class Order; + + public class OrderResult; + + public class OrderProcessor + { + public static OrderResult ProcessOrder(Order order) + { + return new OrderResult(); + } + + public static Task ProcessOrderAsync(Order order) + { + return Task.FromResult(new OrderResult()); + } + + public static IDisposable CreateConnection() + { + throw new NotImplementedException(); + } + } +} diff --git a/src/DocSamples/QuickStartSamples.cs b/src/DocSamples/QuickStartSamples.cs new file mode 100644 index 0000000..45664a9 --- /dev/null +++ b/src/DocSamples/QuickStartSamples.cs @@ -0,0 +1,19 @@ +using JasperFx; +using Microsoft.Extensions.Hosting; + +namespace DocSamples; + +public class QuickStartSamples +{ + public async Task quickstart_minimal() + { + var args = Array.Empty(); + + #region sample_quickstart_minimal + await Host + .CreateDefaultBuilder() + .ApplyJasperFxExtensions() + .RunJasperFxCommands(args); + #endregion + } +} diff --git a/src/DocSamples/VariablesSamples.cs b/src/DocSamples/VariablesSamples.cs new file mode 100644 index 0000000..e45bbb9 --- /dev/null +++ b/src/DocSamples/VariablesSamples.cs @@ -0,0 +1,61 @@ +using JasperFx.CodeGeneration; +using JasperFx.CodeGeneration.Frames; +using JasperFx.CodeGeneration.Model; + +namespace DocSamples; + +public class VariablesSamples +{ + #region sample_variable_creation + + public static void CreateVariables() + { + // Create a variable with an auto-generated name based on the type + var widget = new Variable(typeof(Widget), "widget"); + + // The Usage property is the C# identifier used in generated code + Console.WriteLine(widget.Usage); // "widget" + + // DefaultArgName generates a camelCase name from the type + var defaultName = Variable.DefaultArgName(typeof(Widget)); + Console.WriteLine(defaultName); // "widget" + + // Variable tied to a creating Frame + var frame = new MethodCall(typeof(WidgetFactory), nameof(WidgetFactory.Build)); + var returnVar = frame.ReturnVariable; + Console.WriteLine(returnVar!.Creator == frame); // true + } + + #endregion + + #region sample_variable_default_arg_names + + public static void DefaultArgNameExamples() + { + // Simple types use lowercase type name + Console.WriteLine(Variable.DefaultArgName(typeof(Widget))); // "widget" + + // Arrays get "Array" suffix + Console.WriteLine(Variable.DefaultArgName(typeof(int[]))); // "intArray" + + // Generic types include inner type + Console.WriteLine(Variable.DefaultArgName(typeof(List))); // "listOfString" + + // Reserved C# keywords get an @ prefix + Console.WriteLine(Variable.DefaultArgName(typeof(Event))); // "@event" + } + + #endregion + + public class Widget; + + public class Event; + + public class WidgetFactory + { + public static Widget Build() + { + return new Widget(); + } + } +} diff --git a/src/DocSamples/WritingCommandSamples.cs b/src/DocSamples/WritingCommandSamples.cs new file mode 100644 index 0000000..a3d5c61 --- /dev/null +++ b/src/DocSamples/WritingCommandSamples.cs @@ -0,0 +1,36 @@ +using JasperFx.CommandLine; + +namespace DocSamples; + +#region sample_greeting_input +public class GreetingInput +{ + [Description("The name to greet")] + public string Name { get; set; } = "World"; +} +#endregion + +#region sample_greeting_command +[Description("Say hello to someone")] +public class GreetingCommand : JasperFxCommand +{ + public override bool Execute(GreetingInput input) + { + Console.WriteLine($"Hello, {input.Name}!"); + return true; + } +} +#endregion + +#region sample_async_greeting_command +[Description("Say hello to someone asynchronously")] +public class AsyncGreetingCommand : JasperFxAsyncCommand +{ + public override async Task Execute(GreetingInput input) + { + await Task.Delay(100); + Console.WriteLine($"Hello, {input.Name}!"); + return true; + } +} +#endregion From 27efacad8bebf0fb0c43cd64fa49c17b1b92d01f Mon Sep 17 00:00:00 2001 From: "Jeremy D. Miller" Date: Thu, 2 Apr 2026 09:22:53 -0500 Subject: [PATCH 2/2] Add Publish Docs GitHub Action for Netlify deployment Builds DocSamples, runs mdsnippets, builds VitePress, and deploys to Netlify. Triggers on pushes to main that touch docs/, src/DocSamples/, or mdsnippets.json. Also supports manual workflow_dispatch. Requires NETLIFY_AUTH_TOKEN and NETLIFY_SITE_ID secrets. Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/publish-docs.yml | 57 ++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/publish-docs.yml diff --git a/.github/workflows/publish-docs.yml b/.github/workflows/publish-docs.yml new file mode 100644 index 0000000..45658f9 --- /dev/null +++ b/.github/workflows/publish-docs.yml @@ -0,0 +1,57 @@ +name: Publish Docs + +on: + push: + branches: [main] + paths: + - 'docs/**' + - 'src/DocSamples/**' + - 'mdsnippets.json' + - 'package.json' + workflow_dispatch: + +env: + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1 + +jobs: + publish: + name: Build and deploy docs to Netlify + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + + - name: Install .NET 10.0.x + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 10.0.x + + - name: Build DocSamples + run: dotnet build src/DocSamples/DocSamples.csproj -c Release + + - name: Install mdsnippets + run: dotnet tool install -g markdownSnippets.tool + + - name: Run mdsnippets + run: mdsnippets + + - name: Install npm dependencies + run: npm ci + + - name: Build VitePress site + run: npx vitepress build docs + + - name: Deploy to Netlify + uses: nwtgck/actions-netlify@v3 + with: + publish-dir: docs/.vitepress/dist + production-deploy: true + env: + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}