From c8308cab90b64273f1627b7420edaa87c5aed48b Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sat, 25 Apr 2026 04:00:47 +0100 Subject: [PATCH 1/8] Experiments in custom API documentation generation --- QPlayer.sln | 24 +- StarlightDocNet/MDStringBuilder.cs | 239 ++ StarlightDocNet/Program.cs | 357 ++ .../Properties/launchSettings.json | 8 + StarlightDocNet/README.md | 10 + StarlightDocNet/StarlightDocNet.csproj | 10 + docs/api_docs.xml | 3184 +++++++++++++++++ 7 files changed, 3831 insertions(+), 1 deletion(-) create mode 100644 StarlightDocNet/MDStringBuilder.cs create mode 100644 StarlightDocNet/Program.cs create mode 100644 StarlightDocNet/Properties/launchSettings.json create mode 100644 StarlightDocNet/README.md create mode 100644 StarlightDocNet/StarlightDocNet.csproj create mode 100644 docs/api_docs.xml diff --git a/QPlayer.sln b/QPlayer.sln index d50cb3d..5463275 100644 --- a/QPlayer.sln +++ b/QPlayer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 18 -VisualStudioVersion = 18.3.11512.155 d18.3 +VisualStudioVersion = 18.3.11512.155 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QPlayer", "QPlayer\QPlayer.csproj", "{AC3A2BB3-F46C-45D0-986F-D28AC74A8649}" EndProject @@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QPlayer.SourceGenerator", " EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QPlayer.MagicQCTRLPlugin", "QPlayer.MagicQCTRLPlugin\QPlayer.MagicQCTRLPlugin.csproj", "{A42C1C9E-A605-4629-9831-EB94EE360584}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StarlightDocNet", "StarlightDocNet\StarlightDocNet.csproj", "{C3B27B5B-C834-4271-A8D2-9C31BEA020E7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -145,6 +147,26 @@ Global {A42C1C9E-A605-4629-9831-EB94EE360584}.Release|x64.Build.0 = Release|Any CPU {A42C1C9E-A605-4629-9831-EB94EE360584}.Release|x86.ActiveCfg = Release|Any CPU {A42C1C9E-A605-4629-9831-EB94EE360584}.Release|x86.Build.0 = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|ARM.ActiveCfg = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|ARM.Build.0 = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|ARM64.Build.0 = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|x64.ActiveCfg = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|x64.Build.0 = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|x86.ActiveCfg = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Debug|x86.Build.0 = Debug|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|Any CPU.Build.0 = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|ARM.ActiveCfg = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|ARM.Build.0 = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|ARM64.ActiveCfg = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|ARM64.Build.0 = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|x64.ActiveCfg = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|x64.Build.0 = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|x86.ActiveCfg = Release|Any CPU + {C3B27B5B-C834-4271-A8D2-9C31BEA020E7}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/StarlightDocNet/MDStringBuilder.cs b/StarlightDocNet/MDStringBuilder.cs new file mode 100644 index 0000000..5f1e534 --- /dev/null +++ b/StarlightDocNet/MDStringBuilder.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace StarlightDocNet; + +public class MDStringBuilder +{ + protected readonly StringBuilder sb = new(); + + public readonly static MDStringBuilder Shared = new(); + + public MDStringBuilder Clear() + { + sb.Clear(); + return this; + } + + public override string ToString() + { + return sb.ToString(); + } + + public static implicit operator string(MDStringBuilder md) => md.ToString(); + + public MDStringBuilder Add(char c) + { + sb.Append(c); + return this; + } + + public MDStringBuilder Add(string s) + { + sb.Append(s); + return this; + } + + public MDStringBuilder Add(ref StringBuilder.AppendInterpolatedStringHandler s) + { + sb.Append(ref s); + return this; + } + + public MDStringBuilder Add(int x) + { + sb.Append(x); + return this; + } + + public MDStringBuilder Add(float x) + { + sb.Append(x); + return this; + } + + public MDStringBuilder Line(string s) + { + sb.AppendLine(s); + return this; + } + + public MDStringBuilder Line(char c) + { + sb.Append(c).AppendLine(); + return this; + } + + public MDStringBuilder Line(int x) + { + sb.Append(x).AppendLine(); + return this; + } + + public MDStringBuilder Line(float x) + { + sb.Append(x).AppendLine(); + return this; + } + + public MDStringBuilder Line(ref StringBuilder.AppendInterpolatedStringHandler s) + { + sb.AppendLine(ref s); + return this; + } + + public MDStringBuilder H1(string s) + { + sb.Append("# ").AppendLine(s); + return this; + } + + public MDStringBuilder H2(string s) + { + sb.Append("## ").AppendLine(s); + return this; + } + + public MDStringBuilder H3(string s) + { + sb.Append("### ").AppendLine(s); + return this; + } + + public MDStringBuilder H4(string s) + { + sb.Append("### ").AppendLine(s); + return this; + } + + public MDStringBuilder Code(string s) + { + sb.Append('`').Append(s).Append('`'); + return this; + } + + public MDStringBuilder Italic(string s) + { + sb.Append('*').Append(s).Append('*'); + return this; + } + + public MDStringBuilder Bold(string s) + { + sb.Append("**").Append(s).Append("**"); + return this; + } + + public MDStringBuilder Link(string s) + { + sb.Append(s); + return this; + } + + public MDStringBuilder Link(string url, string text) + { + sb.Append('[').Append(text).Append("](").Append(url).Append(')'); + return this; + } + + public MDStringBuilder Image(string img, string alt) + { + sb.Append("![").Append(alt).Append("](").Append(img).Append(')'); + return this; + } + + public MDStringBuilder Image(string img, string alt, string url) + { + sb.Append("[![").Append(alt).Append("](").Append(img).Append(")](").Append(url).Append(')'); + return this; + } + + public MDStringBuilder MetaHeader(string title, string? description = null, int? order = null) + { + sb.AppendLine("---"); + sb.Append("title: ").AppendLine(title); + if (description != null) + sb.Append("description: ").AppendLine(description); + if (order != null) + sb.Append("order: ").AppendLine(order.Value.ToString()); + sb.AppendLine("---").AppendLine(); + return this; + } + + public CodeBlockBuilder CodeBlock(string? language = null) => new(sb, language); + + public TableBuilder Table() => new(this); + + public readonly struct CodeBlockBuilder : IDisposable + { + private readonly StringBuilder sb; + + public CodeBlockBuilder(StringBuilder sb, string? language) + { + this.sb = sb; + if (language == null) + sb.AppendLine("```"); + else + sb.Append("```").Append(language).AppendLine(); + } + + public readonly void Dispose() + { + sb.AppendLine("```"); + } + } + + public struct TableBuilder : IDisposable + { + private readonly MDStringBuilder md; + private readonly StringBuilder sb; + private bool firstRow = false; + private int nCols = 0; + private int col = 0; + + public TableBuilder(MDStringBuilder md) + { + this.md = md; + this.sb = md.sb; + firstRow = true; + } + + public MDStringBuilder HeaderCell(string s) + { + Program.Assert(firstRow); + sb.Append(" | ").Append(s); + nCols++; + return md; + } + + public MDStringBuilder Cell(string s) + { + if (firstRow) + { + firstRow = false; + sb.AppendLine(" | "); + sb.Append(" |"); + for (int i = 0; i < nCols; i++) + sb.Append("---|"); + sb.AppendLine(); + } + sb.Append(" | ").Append(s); + col++; + if (col == nCols) + { + col = 0; + sb.AppendLine(" | "); + } + + return md; + } + + public void Dispose() + { + for (; col < nCols;) + Cell(" "); + sb.AppendLine(); + } + } +} diff --git a/StarlightDocNet/Program.cs b/StarlightDocNet/Program.cs new file mode 100644 index 0000000..0c721cb --- /dev/null +++ b/StarlightDocNet/Program.cs @@ -0,0 +1,357 @@ +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Xml; + +namespace StarlightDocNet; + +/* + dotnet build QPlayer/QPlayer.csproj -p:GenerateDocumentationFile=true --configuration Release -p:DocumentationFile=$SolutionDir/api_docs.xml -p:NoWarn=1591 + */ + +internal class Program +{ + public static readonly List assemblies = []; + public static APIClass? lastClass; + private static readonly Lock logListLock = new(); + + static void Main(string[] args) + { + Assert(args.Length >= 2, "Expected usage: dotnet run StarlightDocNet api_docs.xml path/to/dst/md/"); + + string srcPath = args[0]; + string dstPath = args[1]; + + using var tr = File.OpenText(srcPath); + var doc = new XmlDocument(); + Log($"Loading xml..."); + doc.Load(tr); + Log("Parsing xml..."); + + var xml = doc.DocumentElement; + Assert(xml?.Name == "doc"); + + ParseRoot(xml!); + CreatePages(dstPath); + } + + public static void Assert(bool condition, string? msg = null, [CallerArgumentExpression(nameof(condition))] string? expr = null, [CallerMemberName] string caller = "") + { + if (condition) + return; + + if (msg != null) + Log(msg, LogLevel.Error, caller); + else + Log($"Assertion failed: {expr}", LogLevel.Error, caller); + +#if DEBUG + Debugger.Break(); +#endif + Environment.Exit(-1); + } + + public static void Log(object message, LogLevel level = LogLevel.Info, [CallerMemberName] string caller = "") + { +#if !DEBUG + if (level <= LogLevel.Debug) + return; +#endif + + lock (logListLock) + { + var time = DateTime.Now; + string messageString = message?.ToString() ?? "null"; + string msg = $"[{level}] [{time}] [{caller}] {messageString}"; + Console.WriteLine(msg); + Debug.WriteLine(msg); + } + } + + public enum LogLevel + { + Debug, + Info, + Warning, + Error + } + + private static void ParseRoot(XmlNode xml) + { + foreach (XmlNode child in xml.ChildNodes) + { + switch (child.Name) + { + case "assembly": + assemblies.Add(APIAssembly.Create(child)); + break; + case "members": + Assert(assemblies.Count > 0); + var asm = assemblies[^1]; + foreach (XmlNode xmlMember in child.ChildNodes) + { + if (xmlMember.Name == "#comment") + continue; + var mem = CreateMember(xmlMember); + if (mem != null) + asm.members.Add(mem); + else + Log($"Couldn't create member for node: {xmlMember.Name}", LogLevel.Warning); + } + break; + case "#comment": + break; + default: + Log($"Unexpected xml node in documetation: {child}", LogLevel.Warning); + break; + } + } + } + + private static APIMember? CreateMember(XmlNode xml) + { + Assert(xml.Name == "member"); + var memName = xml.Attributes?.GetNamedItem("name")?.Value; + Assert(memName != null); + Assert(memName!.Length > 0); + switch (memName[0]) + { + case 'T': + return APIClass.Create(xml, memName); + case 'M': + return APIMethod.Create(xml, memName); + case 'P': + break; + case 'F': + break; + case 'E': + break; + default: + Assert(false, $"Unrecognised member type {memName}!"); + return null; + } + return null; + } + + private static void CreatePages(string basePath) + { + foreach (var asm in assemblies) + asm.CreatePage(basePath); + } +} + +internal class APIAssembly(string name) +{ + public string name = name; + public readonly List members = []; + + public static APIAssembly Create(XmlNode xml) + { + string name = string.Empty; + foreach (XmlNode child in xml.ChildNodes) + if (child.Name == "name") + name = child.InnerText; + + return new(name); + } + + public void CreatePage(string basePath) + { + basePath = Path.Combine(basePath, name); + Directory.CreateDirectory(basePath); + var index = Path.Combine(basePath, "index.mdx"); + var sb = MDStringBuilder.Shared.Clear(); + sb.MetaHeader(name, null, -1); + File.WriteAllText(index, sb); + + foreach (var child in members) + { + child.CreatePage(basePath); + } + } +} + +internal abstract class APIMember(string name) +{ + public string name = name; + public string? type; + public string? summary; + public string? remarks; + + protected virtual void ParseMemberNode(XmlNode xml) + { + switch (xml.Name) + { + case "summary": + summary = xml.InnerText; + break; + case "remarks": + remarks = xml.InnerText; + break; + default: + Program.Log($"Unrecognised member node: {xml.Name}", Program.LogLevel.Warning); + break; + } + } + + public virtual void CreatePage(string basePath) + { + var split = name.LastIndexOf('.') + 1; + var index = Path.Combine(basePath, $"{name[split..]}.mdx"); + var sb = MDStringBuilder.Shared.Clear(); + sb.MetaHeader(name); + WriteContents(sb); + File.WriteAllText(index, sb); + } + + public virtual void WriteContents(MDStringBuilder sb) + { + if (summary != null) + { + sb.Line(summary); + } + if (remarks != null) + { + sb.H2("Remarks"); + sb.Line(remarks); + } + } +} + +internal class APIClass(string name) : APIMember(name) +{ + public readonly List members = []; + + public static APIClass Create(XmlNode xml, string name) + { + var node = new APIClass(name); + foreach (XmlNode child in xml.ChildNodes) + { + node.ParseMemberNode(child); + } + + return node; + } + + public override void CreatePage(string basePath) + { + base.CreatePage(basePath); + foreach (var child in members) + { + child.CreatePage(basePath); + } + } + + public override void WriteContents(MDStringBuilder sb) + { + base.WriteContents(sb); + + using var table = sb.Table(); + table.HeaderCell("Members"); + foreach (var mem in members) + table.Cell(mem.name); + } +} + +internal class APIMethod(string name) : APIMember(name) +{ + public readonly List @params = []; + public readonly List exceptions = []; + public APIReturns? returns; + + public static APIMethod Create(XmlNode xml, string name) + { + var node = new APIMethod(name); + foreach (XmlNode child in xml.ChildNodes) + { + node.ParseMemberNode(child); + } + + return node; + } + + protected override void ParseMemberNode(XmlNode xml) + { + switch (xml.Name) + { + case "param": + @params.Add(APIParam.Create(xml)); + break; + case "returns": + returns = new(xml.InnerText); + break; + case "exception": + exceptions.Add(new(xml.InnerText)); + break; + case "typeparam": + break; + case "inheritdoc": + break; + default: + base.ParseMemberNode(xml); + break; + } + } + + public override void WriteContents(MDStringBuilder sb) + { + base.WriteContents(sb); + + if (returns != null) + { + sb.H2("Returns"); + returns.WriteContents(sb); + } + if (exceptions.Count > 0) + { + sb.H2("Exceptions"); + using var exTab = sb.Table(); + exTab.HeaderCell("Type"); + exTab.HeaderCell("Summary"); + foreach (var ex in exceptions) + { + exTab.Cell(ex.name); + exTab.Cell(ex.summary ?? string.Empty); + } + } + sb.H2("Parameters"); + using var table = sb.Table(); + table.HeaderCell("Name"); + table.HeaderCell("Description"); + foreach (var par in @params) + { + table.Cell(par.name); + table.Cell(par.summary ?? string.Empty); + } + } +} + +internal class APIProperty(string name) : APIMember(name) +{ + +} + +internal class APIField(string name) : APIMember(name) +{ + +} + +internal class APIParam(string name) : APIMember(name) +{ + public static APIParam Create(XmlNode xml) + { + var memName = xml.Attributes?.GetNamedItem("name")?.Value ?? string.Empty; + var p = new APIParam(memName); + p.summary = xml.InnerText; + return p; + } +} + +internal class APIReturns(string name) : APIMember(name) +{ + +} + +internal class APIException(string name) : APIMember(name) +{ + +} diff --git a/StarlightDocNet/Properties/launchSettings.json b/StarlightDocNet/Properties/launchSettings.json new file mode 100644 index 0000000..f791515 --- /dev/null +++ b/StarlightDocNet/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "StarlightDocNet": { + "commandName": "Project", + "commandLineArgs": "api_docs.xml temp\\" + } + } +} \ No newline at end of file diff --git a/StarlightDocNet/README.md b/StarlightDocNet/README.md new file mode 100644 index 0000000..9ae4689 --- /dev/null +++ b/StarlightDocNet/README.md @@ -0,0 +1,10 @@ +# StarlightDocNet + +A very simple documentation generator for [Starlight](https://starlight.astro.build/) based documentation. +This is effectively an XML-doc-comment to markdown converter. + +### Usage + +```sh +dotnet run StarLightDocNet [src.xml] [path/to/place/md_files/] +``` diff --git a/StarlightDocNet/StarlightDocNet.csproj b/StarlightDocNet/StarlightDocNet.csproj new file mode 100644 index 0000000..ed9781c --- /dev/null +++ b/StarlightDocNet/StarlightDocNet.csproj @@ -0,0 +1,10 @@ + + + + Exe + net10.0 + enable + enable + + + diff --git a/docs/api_docs.xml b/docs/api_docs.xml new file mode 100644 index 0000000..6e2c2fd --- /dev/null +++ b/docs/api_docs.xml @@ -0,0 +1,3184 @@ + + + + QPlayer + + + + + Interaction logic for App.xaml + + + App + + + + + InitializeComponent + + + + + Application Entry Point. + + + + + An array of strings representing the current state of each worker thread. + + + + + The number of samples to read between each metering event. + + + + + An event raised every samples with metering information. + + + + + When building a mastering chain, use this sample provider as the source, it should never be read from directly. + + + + + Registers the given sample provider as a mastering chain, this is the last sample provider before the output. + + + + + + Creates an ISampleProvider which converts the given sample stream to one compatible with the mixer. + + This converts both Mono to Stereo and resamples the input stream. + + + + + + + + Starts the playback of a sound through the mixer. + + the sample stream to play + a callback raised when the stream is removed from the mixer + + + + Stops the playback of a sound stream. + + the sample stream to stop + + + + Gets whether a sound stream is currently playing. + + + + + + + Stops all sound sources. + + + + + Copies the desired number of samples from the delay line to the given buffer. May not entirely fill the given + buffer if the delay line doesn't contain that many samples. + + + + + + + + Pushes the span of samples into this delay buffer. + + + + + + Reads the specified number of samples from the input stream and pushes them to the delay buffer. + + + + + + + + + Reads the specified number of samples from the delay buffer with the specified amount of delay. + This should imediately preceed a call to and should read + the same number of samples the read call returned. + + + + + + + + + Applies a biquad filter to the input signal. Automatically picks a vectorised implementation if available. + + The history buffer, must be at least 4* long. + The index into the history buffer to use (this is internally multiplied by + the number of history samples the filter uses (ie: 4*)). + The number of interleaved channels in the input buffer. + The filter coefficients to apply to the signal. + The signal to filter. + + + + Applies a biquad filter to the input signal. + + The history buffer, must be at least 4* long. + The sample buffer to process. + The number of interleaved channels in the input buffer. + The index into the history buffer to use (this is internally multiplied by + the number of history samples the filter uses (ie: 4*)). + + + + + + + + + Applies a biquad filter to the input signal. + + The history buffer, must be at least 4* long. + The sample buffer to process. + The number of interleaved channels in the input buffer. + The index into the history buffer to use (this is internally multiplied by + the number of history samples the filter uses (ie: 4*)). + + + + + + + + + Applies a biquad filter to the strided input buffer. Requires FMA instructions. + + The history buffer used by the filter, must be at least 4 * channels long. + The buffer to filter. + The number of interleaved channels in the signal to filter (ie: buffer = [LRLRLRLR..], channels = 2) + The index into the history buffer to use, when chaining multiple filters + (this is the filter index, not the buffer index, so for the second iteration of filtering an index of 1 would be used). + + + + + + + + + The initial volume of the samples processed. + + + + + Starts a new fade operation, cancelling any active fade operation. + + The volume to fade to + The time to fade over in milliseconds + The type of fade to use + Optionally, an event to raise when the fade is completed. true is passed to the + event handler if the fade completed normally, false if it was cancelled. The event is invoked on the + thread that called this method. + Whether the onComplete action should be invoked using the current thread's + synchronization context. + + + + Cancels the active fade operation. + + + + + A that also provides the position within the sample stream. + + + + + The position, in samples, within the sample provider stream. + + + + + A sample provider for which handles looping and start/end time. + + + + + + The length in samples (estimate, for compressed inputs) of the input stream. + + + + + The position in samples (estimate) within the input stream. + + + + + The current playback time within the input stream. + + + + + The length in samples of the input stream, trimmed by the the and . + + + + + The length in samples of this looping sample provider (estimate, for compressed inputs). + + + + + The total diration of the looped input stream, taking into account the start and end times. + + + + + The current playback time within the looped sample, this starts at 0 at the start time and increases continuously as the input is looped. + + + + + The current playback sample position within the looped sample, this starts at 0 at the start time and increases continuously as the input is looped. + + + + + Whether this sample provider should loop the sample indefinitely. Ignores the value. + + + + + The maximum number of this sample provider can play. Use to reset the loop counter. + + + + + The current number of complete loops of the input sample that have been played since the last call to . + + + + + The time in samples to start playback from. + + + + + The time in samples to stop playback at (or the 'out' loop point of the loop). + + + + + The time to start playback from. + + + + + The time at which to stop playback (for a single loop). + + + + + An event raised at the end of each loop played. + + + + + Resets the internal loop and sample counters. Call this every time before playing the sound file. + + + + + Reads samples from the source until we reach the end of a loop (or file) or + the buffer is full (whichever happens sooner). Returns 0 if no more loops + should be played. + + + + + + + + + The number of samples to read between each metering event. + + + + + An event raised every samples with metering information. + + + + + + + + + + + Ensures the audio thread using this mixer has a sufficiently high priority. + Due to the design of NAudio, this works by setting the thread priority the + first time the method is called. + + + + + The initial volume of the samples processed. + + + + + The stereo panning applied to the processed samples. + + + + + The fade in duration in samples. + + Note that this is in mono samples so for a stereo source, this should be half the number of actual processed samples. + + + + + The fade out duration in samples. + + Note that this is in mono samples so for a stereo source, this should be half the number of actual processed samples. + + + + + The time in samples when the fade out should start. + + Note that this is in mono samples so for a stereo source, this should be half the number of actual processed samples. + + + + + A smart audio reader, which picks an appropriate decoder for the given file path, opens the file, + creates any needed stream converters to get a 32bit float sample stream, and buffers audio intelligently. + + The methods are entirely lock-free and intended to be called + from a dedicated audio thread, while all the other methods are intended to be called from the main thread. + This is with the exception of the methods which can be called from a separate + audio buffering thread (this is done automatically, if an is + passed in the constructor). Please be aware that the threading model for this class is quite complicated + (there are potentially 3+ threads with contention over this object), most methods are not reentrant unless + explicitly mentioned (or trivial). + + The lifecycle of this object is described as follows: + + MainThread: + QAudioFileReader::ctor() + \--> registers the new object with the AudioBufferingDispatcher + ... + SamplePosition.set() --> repositions the stream when needed, this blocks until the current FillBuffer operation is complete + + AudioBufferingDispatcher worker: + while true: + if audioFile.NeedsFilling: + FillBuffer() --> fills one of the internal audio buffers if needed + + AudioThread: + Read() --> gets as many samples as are available (or requested) from an audio buffer, never blocks, but may not return as many samples as requested + + + + + + The number of samples in this stream. + + + + + The position in samples within the input stream. + + + + + The starting position in samples within the input stream. Setting this clears the buffer + containing the start of the file used for seamless looping. + + + + + Gets how many samples are still available in the current buffer. + + + + + Gets whether this reader has an empty buffer waiting to be filled with . + + + + + Gets whether this reader has an empty start buffer waiting to be filled . + + + + + Releases the internal buffers used by this reader so they can be reused elsewhere. Call this + method when the audio file is not being played. + + + + + + + + Fill the specified buffer with 32 bit floating point samples. This method is not reentrant. + + + This method might not entirely fill the requested of samples if they're not available yet. + Furthermore, it may return -1 if no samples are currently available but the end of the stream hasn't been + reached yet. A return value of 0 always indicates that the stream has ended. + + The buffer to fill. + The offset into to start writing. + The number of samples requested. + When , syncronously waits for the buffer to fill before returning. + The nunber of samples read from the source. + + + + Fills the internal buffer of this reader with samples. Must be called sufficiently frequently to avoid starving the audio file reader. + This method can be called from external threads, but is not reentrant. + + + + + Fills the special 'start' buffer of this reader with samples. Must be called sufficiently frequently to avoid starving the audio file reader. + This method can be called from external threads, but is not reentrant. + + + + + + + Repeatedly reads from the until either the requested number of samples are + read, or the sample provider returns 0 samples. + + The buffer to read into. + The offset into the buffer to start writing. + How many samples to read. + Whether the returned 0 samples on the last read. + The number of samples read. + + + + Repositions the internal safely, and warms it up by reading into the junk buffer. + + + + + + Intelligently seeks this to the given sample position, reusing existing buffers if + possible. Automatically invalidates the sample buffer if needed. The underlying is not + repositioned until the next read. + + The position in samples to seek to. + + + + Aligns a position in samples to the start of the current frame. Effecitvely this rounds the input + position down to a multiple of the channel count. Note that this is only valid for positive values. + + The position in samples to align. + The aligned position in samples. + + + + This class provides a number of vectorised maths routines, which are optimised for X86 SIMD instructions. + + + + + Pretty prints an audio signal as a waveform. Based on https://github.com/sudara/melatonin_audio_sparklines/blob/main/melatonin_audio_sparklines.h + + The signal is represented as a series of dashes, with a few special characters indicated specific values: + + 0 -- a single 0 value + 0(23) -- 23 consecutive zeros + x -- a zero-crossing + N -- NaN + I -- +-Inf + S -- subnormal values + E -- outside of the -1 to 1 range + + For interleaved multi-channel signals, each chanel is displayed on it's own line. + If a signal is prepended with a + then every sample is >= 0. + + The signal to display. + The number of interleaved channels. + Whether the signal should be collapsed to skip repeated values. + Whether the signal should be normalized. + The maximum number of characters to return. + + + + + Multiplies the contents of span a by the scalar b, mutating a with the result. + + + + + + + + Multiplies the pairs of values in a by the values in b, mutating a with the result. + + + + + + + + Pans a span of interleaved stereo samples left or right. + + Lout = Lin * 1 - max(0,pan) + Rout = Rin * 1 + min(0,pan) + + + + + + + + Computes the element-wise maximum of a signal and a constant. + + + + + + + + Computes the element-wise maximum of two signals. + + + + + + + + Computes the element-wise minimum of x and y, storing the result in x. + + + + + + + + Computes the smooth-minimum of two signals using quadratic interpolation. + See: https://iquilezles.org/articles/smin/ + + + + The blending factor [0-1]. Must be > 0. + + + + + Computes the minimum value in x. + + + + + + + Computes the pair-wise minimum of x, storing the result in x. + + + + + + + Computes: ∑(x[i] * kernel[i]) + + + + + + + + Computes the gain reduction (fraction) required to clip a signal x by threshold. + + + + + + + + Computes the gain reduction (fraction) required to clip a signal x by threshold. + + + The threshold level at which to start reducing gain. + Value between 0-1, where 1 is brickwall limiting. + Value between 0-1, where 0 is a hard knee. Value must be > 0. + Gain multiplier applied to the input signal before clipping. + + + + + Multiplies two signals x and y element-wise and then clamps the resulting signal between [-c, c]. + + + + + + + + + Exactly the same as + but processes interleaved stereo samples instead. + Only processes samples tht can be vectorised, + + Resampling destination. + Resampling source. + The fractional position in the source buffer. + The increment size when sampling the source buffer. + The number of interpolated samples written. + + + + Fully managed resampler, based on Cockos WDL Resampler + + + + + Creates a new Resampler + + + + + Reset + + + + + amount of input that has been received but not yet converted to output, in seconds + + + + + Prepare + note that it is safe to call ResamplePrepare without calling ResampleOut (the next call of ResamplePrepare will function as normal) + nb inbuffer was float **, returning a place to put the in buffer, so we return a buffer and offset + + req_samples is output samples desired if !wantInputDriven, or if wantInputDriven is input samples that we have + + + + returns number of samples desired (put these into *inbuffer) + + + + if numsamples_in < the value return by ResamplePrepare(), then it will be flushed to produce all remaining valid samples + do NOT call with nframes_in greater than the value returned from resamplerprpare()! the extra samples will be ignored. + returns number of samples successfully outputted to out + + + + + This class manages the receiving and sending of MA Midi Show Control packets sent over UDP. + + + + + Asynchronously sends an MA-MSC packet. + + The message to send. + The endpoint to send the message to. + + + + + + + Subscribes an event handler to MSC messages with a given command. + + The commands to subscribe to. + The event handler to fire when a matching message is received. + + + + This is the same as a Goto command in grandMA2. It needs to be followed by a cue number. + + + + + This is the same as a Pause command in grandMA2. This can be followed by a cue number. + + + + + This will "un-plause" a cue. If a specific cue has been paused, then the cue number needs to be specified with this command. + + + + + This can be used to perform a Goto with a specific fade time. It needs both the time and the cue number - in that order. + + + + + Set can be used to set the position of faders. It needs the fader number and page followed by the position. + + + + + This can be used to trigger macros. The macro number needs to follow the command. Only macro 1 to 255 can be triggered. + + + + + This command can be used "Off" executors. This needs to followed by a cue number. + + + + + Represents an MA MSC packet. This is implemented as a union type, make sure to check the + field before reading the corresponding data field. + + + + + This is the same as a Goto command in grandMA2. It needs to be followed by a cue number. + + + + + This is the same as a Pause command in grandMA2. This can be followed by a cue number. + + + + + This will "un-plause" a cue. If a specific cue has been paused, then the cue number needs to be specified with this command. + + + + + This can be used to perform a Goto with a specific fade time. It needs both the time and the cue number - in that order. + + + + + Set can be used to set the position of faders. It needs the fader number and page followed by the position. + + + + + This can be used to trigger macros. The macro number needs to follow the command. Only macro 1 to 255 can be triggered. + + + + + This command can be used "Off" executors. This needs to followed by a cue number. + + + + + Asynchronously sends an OSC packet. + + The message to send. + The endpoint to send the message to. + + + + + + + Subscribes an event handler to OSC messages following a specified pattern. + + + Address patterns are of the form: "/foo/?/bar" +
+ Where '?' indicates a wildcard which matches any single address part. +
+ The adddress pattern to match. + The event handler to fire when a matching message is received. +
+ + + Parses a string representing an OSC message into an address and a list of arguments.
+ Arguments must be separated by spaces and are parsed automatically + Supports: + - strings -> Surrounded by double quotes + - ints + - floats + - bools + - blobs -> Surrounded by backticks +
+ + +
+ + + Stores a compact representation of the audio peaks in an audio file for faster waveform rendering. + + + + + The reduction factor of the highest resolution pyramid. + + + + + The number of bits to shift the reduction factor by between each pyramid. + + + + + The minimum number of samples in a pyramid. + + + + + Every N samples, we store the position in bytes into the file stream for efficient seeking. This is always a power of 2. + + + + + Reads and validates the metadata portion of a . + + This method does not close the stream once complete! + + The binary stream to parse + A new instance parsed from the stream. + + + + + Reads and validates from a stream. + + The binary stream to parse + A new instance parsed from the stream. + + + + Reads and validates from a stream. + + The binary stream to parse + A new instance parsed from the stream. + + + + + Loads a for the given audio file if it's valid, otherwise generates a + new for an audio file if needed. + + The path of the audio to process + The loaded or generated + + + + The exception thrown when a file of an incompatible version is loaded. + + + + + The exception thrown when a file could not be loaded due to it being corrupt. + + + + + Using this attribute on a plugin class implementing allows a custom plugin name to be specified. + + + + + + Using this attribute on a plugin class implementing allows a custom plugin name to be specified. + + + + + + Using this attribute on a plugin class implementing allows a custom plugin author to be specified. + + + + + + Using this attribute on a plugin class implementing allows a custom plugin author to be specified. + + + + + + Using this attribute on a plugin class implementing allows a custom plugin description to be specified. + + + + + + Using this attribute on a plugin class implementing allows a custom plugin description to be specified. + + + + + + Creates a main menu item which invokes this method when clicked. + + Only applicable to parameterless methods and properties on the class implementing . + + The path to the menu item to be created, eg: 'File/Save' + + + + Creates a main menu item which invokes this method when clicked. + + Only applicable to parameterless methods and properties on the class implementing . + + The path to the menu item to be created, eg: 'File/Save' + + + + Registers this class to the project settings panel. + + This class must derive from and be annotated with the + and attributes. + + The heading name for this section in the project settings panel. + + + + Registers this class to the project settings panel. + + This class must derive from and be annotated with the + and attributes. + + The heading name for this section in the project settings panel. + + + + Loads a plugin and it's dependencies in a load context to avoid depedency conflicts. + + + Taken from: https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support + + + + + + Loads a plugin and it's dependencies in a load context to avoid depedency conflicts. + + + Taken from: https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support + + + + + + Called at startup when the plugin is loaded by QPlayer. + + + + + + Called just before QPlayer exits. + + + + + Called just before QPlayer saves a show file. + + + + + + Called every time QPlayer starts a cue. + + + + + + Called every 250 ms on the UI thread. + + + + + A simple RGBA colour represented as 4 singles. Provides explicit + conversion operators to a number of formats. + + + + + This class contains the relevant code to repair and upgrade old show files. + + + + + Attempts to load a show file one field at a time, skipping any fields which can't be read. + + This method uses fairly inefficient reflection to try and deserialize as much of the show file as possible. + + The contents of show file to load. + A ShowFile, with as many parameters loaded as possible. + + + + + Attempts to load a show file one field at a time, skipping any fields which can't be read. + + This method uses fairly inefficient reflection to try and deserialize as much of the show file as possible. + + The contents of show file to load. + A ShowFile, with as many parameters loaded as possible. + + + + + Attempts to load a show file one field at a time, skipping any fields which can't be read. + + This method uses fairly inefficient reflection to try and deserialize as much of the show file as possible. + + The contents of show file to load. + A ShowFile, with as many parameters loaded as possible. + + + + + Upgrades a show file from an older version by parsing attempting to parse old data. + + The show file to merge into. + The json to parse. + + + + Upgrades a show file from an older version by parsing attempting to parse old data. + + The show file to merge into. + The json to parse. + + + + + + + Icons + + + + + InitializeComponent + + + + + A simple double-ended queue implementation. This implementation is not thread-safe. + + + + + + Points to the element at the start of the queue. + + + + + Points to the free slot at the end of the queue. + + + + + Increments the given value, wrapping on the array bounds. + + + The original value of + + + + Decrements the given value, wrapping on the array bounds. + + + The new value of + + + + Removes trailing zeros from a decimal. + + + https://stackoverflow.com/a/7983330/10874820 + + + + + Updates an item at the given index in the list, expanding the list with + default items if index larger than the size of the list. + + + + + + + + + Sets the translation component of this matrix. + + + + + + + + Synchronises a list with this collection. Note that this synchronisation only works in one direction, if the list is + modified, then the behaviour is undefined. + + + + + + + + + + Efficiently adds a collection of points to the collection. + + + + + + + Creates an array segment over a portion of this array. + + + + The index of the first element in the segment. + The number of elements to take. + A new array segment over the array. + + + + + + + An array pool which only stores arrays of a fixed size. + + + + + + Helper to raise a PropertyChanged event for the Count property + + + + + Helper to raise a PropertyChanged event for the Indexer property + + + + + A fast string-keyed dictionary. This is very similar in implementation to the .NET generic dictionary, + but it has a few specific optimisations which can be useful in some cases. Notably, it can by accessed + by string key or by of which can save unnecessary + string allocations. It also exposes methods to get values by reference which can save performance. + And it uses a slightly faster string hashing algorithm. + + The type of values stored in this dictionary. + + + + Stores references to dictionary items, index by key hashcode. Stores a 1-based index into the other arrays. + + + + + Stores the complete hashcode of an item pointed to by buckets. + + + + + Stores the index of the next item in the same bucket as the current item pointed to by buckets. 1-based index! + + + + + Stores the key of an item pointed to by buckets. + + + + + Stores the value of an item pointed to by buckets. + + + + + Optimises the dictionary for red performance and memory efficiency. + + The load factor to target. Smaller values result in faster reads at the + cost of more memory used. A good value is between 1 and 3. + Whether to compact all the entries in the slots. Saves a bit of space if many + items have been removed from the dictionary. + + + + + + + + + + Removes an item with the specified key from the dictionary, and returns the removed value. + + The key of the element to remove. + The value associated with the key which was removed. + if the item was successfully removed from the dictionary. + + + + + + + Gets the value associated with the given key. The reference is only valid so long as the dictionary is not mutated. + + The key to get the value of. + A reference to the value in the dictionary if it exists, or a null reference. + + + + Returns an enumerable of all the values with the given keys. + + The keys to search for. + An of all the values which match the given keys. + + + + A list backed by arrays from the array pool. + + + + + + Gets a span of the elements in this temporary list, valid as long as the list count isn't changed. + + + + + + Adds each element from the enumerable to the list efficiently. + + + + + + Factory class used by the collection builder to correctly initialise a . + + + + + Factory method used by the collection builder to correctly initialise a . + + + + + Sets the to a level that ensures none of the sound cues in the + cue stack will exceed 0dBfs when playing individually. + + The amount of headroom to leave in dB from full-scale, positive + values attenuate, negative values will push cues into the limiter. + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + The base class for any view model which can be bound onto a separate model instance. + + This class implements all the necessary logic to automatically synchronise changes + from a view model to a model. The behaviour of the automatic bindings can be controlled + using the various model attribtues (, + , ). + Implementing classes should be annotated with and + where applicable. + + + The default automatic binding behaviour is to bind all properties with a public getter + and setter on the ViewModel to all public fields with matching (case insensitive) names + on the Model. + + The type of the model to bind to. + + + + Binds this to the specified model instance. Automatically propagates proeprties + changes from this object to the model, but not the other way around. +
+ When using the source generator, this method is automatically implemented so long as the deriving + class defines at least one reactive property (see ). +
+ The model to bind to, or to unbind. +
+ + + Copies all bound property values on this instance from the bound model. +
+ When using the source generator, this method is automatically implemented so long as the deriving + class defines at least one reactive property (see ). +
+
+ + + Copies all bound property values on this instance to the bound model. +
+ When using the source generator, this method is automatically implemented so long as the deriving + class defines at least one reactive property (see ). +
+
+ + + When using a source generator, this method is automatically implemented and should be called in . + + + + + When using a source generator, this method is automatically implemented and should be called in . + + + + + Creates a new instance of a cue of the given type. Available cue types are those registered in . + + + + + + + Creates a new instance of a cue view model of the given type. Available cue types are those registered in . + End users should preferentially use . + + + + + + + + Creates a new instance of a cue view model for a given cue and copies all of it's properties. + + + + + + + + Creates a new instance of a cue for a given cue view modeland copies all of it's properties. + + The view model to create a model for. + to bind the to the newly created + model, to only copy it's parameter. + + + + + + The Cue is currently stopped and ready to be played + + + + + The Cue is currently waiting to start. + + + + + The duration of this cue, as received from a remote node. + + + + + This method is invoked by QPlayer when this cue is selected in the inspector. + + + + + Starts this cues after it's delay has elapsed. + + Optionally, a cue to wait for it's event before starting this cue. + + + + Starts this cue immediately. + + + + + Pauses this cue. It can be resumed again by calling Go. + + Not all cues support pausing. For unsupported cues, this should Stop(). + + + + + Stops this cue immediately. + + + + + Stops this cue without informing remote clients or executing cue specific stopping code. + This is called when a remote node needs to tell us that a cue has finished playing. + + + + + Sets the playback time of the cue to the given time, and puts it in the paused state. + + the time to start the cue at. + + + + This callback is triggered every 50 or so ms when this cue is active by the main thread. + + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + Creates a new ViewModel from the given Model, without binding it. + + the model to copy properties from + the main view model + a new ViewModel for the given Model. + + + + Copies the properties in this ViewModel to the given Model object. + + the model to copy to + + + + Copies the value of a given property to the bound Model. + + the property to copy + + + + Binds this view model to a given model, such that updates from the view model are propagated to the model (but NOT vice versa). + + the model to bind to + + + + The global instance of the audio playback manager. + + + + + An event which is fired every 250ms on the main thread. + + + + + Returns true if a non show mode command can execute. + + + + + + Opens or activates a window of the given type. + + The type of the window to open. + When , activates an existing window of the type if it already exists. + The opened/activated window. + + + + Closes a window of the given type. + + + if a window of the given type was closed. + + + + Closes all active windows, excluding the main window. + + + + + Informs the cue stack that the cue ID of a given cue view model has been changed. This should be called whenever a QID is changed. + + Note that since 's setter calls this method, users which change QID's through this + setter need not call this method. + + + + + + + + Deletes the cue at the given index from the cue stack. + + The 0-based index of the cue in the cue stack. + Whether an undo item should be recorded. + The cue which was just removed, or null if it wasn't found. + + + + Deletes the given cue from the cue stack. + + The cue instance to remove from the cue stack. + if the cue was successfully removed. + + + + Deletes the given cue from the cue stack. + + The cue instance to remove from the cue stack. + if the cue was successfully removed. + + + + Inserts an existing cue into the cue stack. This method should be used with care as + it does not check if the cue already exists in the stack. To duplicate a cue, use + . + + The index at which to insert the cue. + The cue to insert. + Whether the newly inserted cue should be selected. + Whether an undo item should be recorded. + + + + Inserts an existing cue into the cue stack according to it's qid. This method + should be used with care as it does not check if the cue already exists in the + stack. To duplicate a cue, use . + + The cue to insert in the stack. + Whether the newly inserted cue should be selected. + Whether an undo item should be recorded. + + + + Duplicates the given cue in the cue stack. + + The cue to duplicate, or to use the currently selected cue. + Whether the newly created cue should be selected. + The instance of the newly created cue, or if no cue was duplicated. + + + + Tries to find a cue view model given a cue ID. + + + The can be one of the following types: + , + , + , + , + + The cue ID to search for. + The returned cue view model if it was found. + if the cue was found. + + + + Tries to find a cue view model given a cue ID. + + The cue ID to search for. + The returned cue view model if it was found. + if the cue was found. + + + + Gets the index of a cue in the cue list. Executes in O(n) time. + + The cue instance to search for. + The index of the cue in the list or -1 if it wasn't found. + + + + Moves the given cue up or down by one, swapping position with the cue above or below it. + Renumbers the given cue to remain in order. + + The cue instance to move. + Whether the cue should be moved up or down. + Whether the cue should be reselected after it's moved. + Whether an undo item should be recorded. + if successful. + + + + Moves the given cue in the cue stack to the given cue ID, or directly after it if the + specified cue ID is already in use. + + The cue to move in the cue stack. + The cue ID to insert the cue at. + Whether the moved cue should be reselected. + + + + Moves the given cue in the cue stack to the specified index. + + The cue to move in the cue stack. + The index within the cue stack to move the cue to. + Whether the moved cue should be reselected. + Optionally, the new QID to assign to the cue once it's moved. + Otherwise, this method will choose a new QID itself (recommended). + Whether an undo item should be recorded. + if the cue was moved successfully. + + + + Moves the given cue in the cue stack to the specified index. + + + The insertion index behaves a little bit odd compared to regular insertion behaviour. + To illustrate: + + srcInd: [0] [1] [2] [3] [4] + dstInd: 0 1 2 3 4 5 + + The cue is always inserted at an index 'between' two cues, so if we want to move q1 to + before q0, we would pick index 0, but to move it after q2, we would pick index 3. + Effectively, dstInd 1 and 2 don't move the cue. + + The cue to move in the cue stack. + The index within the cue stack to move the cue to. + Whether the moved cue should be reselected. + Optionally, the new QID to assign to the cue once it's moved. + Otherwise, this method will choose a new QID itself (recommended). + Whether an undo item should be recorded. + if the cue was moved successfully. + + + + Creates a new cue of the given type and inserts it into the cue stack at the selected position. + + The type of cue to create. + Whether the new cue should be inserted before the selected cue. + Whether the new cue should be inserted at the end of the cue stack. + Whether the new cue should be selected. + Optionally, a cue to copy properties from. + The view model instance of the newly created cue. + + + + Creates a new cue of the given type and inserts it into the cue stack at the given position. + + The type of cue to create. + The index in the cue stac to insert the cue + Whether the newly created cue should be selected. + Optionally, a cue to copy properties from. + The view model instance of the newly created cue. + + + + Creates a new cue of the given type without inserting it into the cue stack. Use this method with caution as + QPlayer assumes cues are always in the cue stack. + + The type of cue to create. + Optionally, copies properties from this cue. + The view model instance of the newly created cue. + + + + Generates a QID at the given insertion point in the cue stack, renumbering cues if needed. + + The index of the cue after which to insert the new QID. + When enabled the first parameter is the index of the cue to + renumber such that it fits in between it's neighbours. + + + + + Converts a path to/from a project relative path. Only paths which are in subdirectories of the project path are made relative. + + the path to convert + whether the path should be expanded to an absolute path or made relative to the project + + + + + Checks if the project file has unsaved changes and prompts the user to save if needed. + + + Must be called on the dispatcher thread. + + false if the user decided to cancel the current operation. + + + + Checks if any cues are currently running, and if so prompts the user if they want to cancel the next operation. + + + false if the user decided to cancel the current operation. + + + + Must be called on the dispatcher thread. + + When true, executes without waiting for the dispatcher. + + + + This effectively makes sure that the data in the view model is copied to the model, just in case a change was missed. + + + + + Opens the project at the specified path. + + + Must be called on the dispatcher thread. + + + + + + + Saves the show file asynchronously. This method can be called from a worker thread. + + The path to save the project to. + Whether syncing the show file with remote clients is allowed. + Whether the internal model should be resynchronised if needed. + + + + + Saves the show file synchronously. This method must be called from the main thread. Prefer . + + + + + + Saves the project and copies all of it's referenced files to the given directory. + + The directory to pack the project into. + + + + Attempts to load an embedded resource file from the executing assembly. + + The path/filename to the file to load. + A stream of the file contents. + + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + Removes a remote node from the collection of remote nodes. + + The name of the name to remove + if the node was removed successfully. + + + + Gets a remote node by name, returning a new node and adding it, if it doesn't already + exist in the collection. + + + true if the returned node was newly added. + + + + + + + Gets whether a given remote node is currently active. + + + + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + Checks if this node is still active, and notifies the UI if it's state has changed. + + if this node has just become inactive. + + + Reactive property for + + + + Checks whether the current audio file is valid. This also checks that the underlying stream object still exists. + + + + + Fades out the current playing sound. + + The duration in seconds to fade over + The type of fade to use + + + + Fades this sound to the given volume in a given amount of time. + + The volume to fade to + The duration in seconds to fade over + The type of fade to use + + + + Stops all playing audio, stops the timers, and rewinds the audioFile to it's start time. + + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + The global undo manager, this provides methods to record actions in a way that can be undone or redone. This class is not + thread-safe and must be called from the main thread. + + + + + Registers a property change action to the undo stack. + + The path to the property being changed. + The object being changed. + The previous value. + The new value after this action has occured. + + + + Registers an action to the undo stack. + + A brief description of the action (in the past tense). + A function to call to undo the action. + A function to call to redo the action. + + + + Undoes the last action registered to the undo stack. + + + + + Redoes the last action undone by the undo manager. + + + + + Clears the undo and redo history. Necessary after drastic changes which would invalidate the undo history, + this also allows the GC to reclaim objects being kept alive by the undo history. + + + + + When used with a block, suppresses undo action recording for the scope of this function. + + + + + + Temporarily suppresses the recording of new undo actions until is called. + + + + + Stops suppressing undo recording. Counterpart of . + + + + + Forcefully stops suppressing undo recording. Counterpart of . + + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + This is the name of a special property change notification which the view listens to so that it knows to + propagate the correct width/height/cursors back to the renderer. + + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + Reactive property for + + + + Interaction logic for AboutWindow.xaml + + + AboutWindow + + + + + InitializeComponent + + + + + Interaction logic for ActiveCueControl.xaml + + + ActiveCueControl + + + + + InitializeComponent + + + + + Interaction logic for AudioLimiterControl.xaml + + + AudioLimiterControl + + + + + InitializeComponent + + + + + Interaction logic for AudioMeter.xaml + + + AudioMeter + + + + + InitializeComponent + + + + + Interaction logic for CueDataControl.xaml + + + CueDataControl + + + + + InitializeComponent + + + + Reactive property for + + + + Interaction logic for CueDataHeaderControl.xaml + + + CueDataHeaderControl + + + + + InitializeComponent + + + + + CueDataTemplates + + + + + InitializeComponent + + + + + Interaction logic for CueEditor.xaml + + + CueEditor + + + + + InitializeComponent + + + + + Interaction logic for HiddenComboBox.xaml + + + HiddenComboBox + + + + + InitializeComponent + + + + + Interaction logic for HiddenTextbox.xaml + + + HiddenTextbox + + + + + InitializeComponent + + + + + Interaction logic for Knob.xaml + + + Knob + + + + + InitializeComponent + + + + Reactive property for + + + + Displays or hides the cursor. + + + If bShow is TRUE, the display count is incremented by one. If bShow is FALSE, the display count is decremented by one. + + The return value specifies the new display counter. + + + + Interaction logic for LogWindow.xaml + + + LogWindow + + + + + InitializeComponent + + + + + A progress bar which is a little more GC friendly. This is mostly just a hack to prevent WPF from allocating so much garbage when updating this frequently. + + + + + Interaction logic for PlaybackProgressBar.xaml + + + PlaybackProgressBar + + + + + InitializeComponent + + + + Reactive property for + + + + Interaction logic for PluginManagerWindow.xaml + + + PluginManagerWindow + + + + + InitializeComponent + + + + Reactive property for + + + + Interaction logic for ProjectSettingsEditor.xaml + + + ProjectSettingsEditor + + + + + InitializeComponent + + + + + Interaction logic for RemoteNodesWindow.xaml + + + RemoteNodesWindow + + + + + InitializeComponent + + + + + Interaction logic for RemoteSetupControl.xaml + + + RemoteSetupControl + + + + + InitializeComponent + + + + + Interaction logic for SettingsWindow.xaml + + + SettingsWindow + + + + + InitializeComponent + + + + + Interaction logic for TextField.xaml + + + TextField + + + + + InitializeComponent + + + + + Interaction logic for WaveForm.xaml + + + WaveForm + + + + + InitializeComponent + + + + Reactive property for + + + + Interaction logic for WaveFormWindow.xaml + + + WaveFormWindow + + + + + InitializeComponent + + + + + Interaction logic for MainWindow.xaml + + + MainWindow + + + + + InitializeComponent + + + + + Automatically generates a property for the annotated field which automatically raised + PropertyChanged notifications when set. +
+ This attribute can also be used on existing properties to generate a reactive property for that property. + To this, the annotated property must either be partial (in which case a backing field will also be + generated), or the parameter must be specified. +
+ + If a custom property name is not specified, the generated property will take the name of field + with the first letter capitalised, or prefixed with an underscore. IE: int exampleProp -> + int ExampleProp, and int OtherExample -> int _OtherExample + + The name of the reactive property to generate. +
+ + + Automatically generates a property for the annotated field which automatically raised + PropertyChanged notifications when set. +
+ This attribute can also be used on existing properties to generate a reactive property for that property. + To this, the annotated property must either be partial (in which case a backing field will also be + generated), or the parameter must be specified. +
+ + If a custom property name is not specified, the generated property will take the name of field + with the first letter capitalised, or prefixed with an underscore. IE: int exampleProp -> + int ExampleProp, and int OtherExample -> int _OtherExample + + The name of the reactive property to generate. +
+ + + When this property is updated use a cached instance of . + + + + + By default, when this property is updated, the old value is compared to the new value using the + == operator, and only if the value are different is the setter and property change + notification invoked. This attribute skips this check, this can be useful if no == is + available or if this equality comparison would be very expensive. +
+ Requires a on this same property. +
+
+ + + When this property is updated, a property change notification for the specified property is also raised. +
+ Requires a on this same property. +
+ The name of the property to generate a change notifcation for. +
+ + + When this property is updated, a property change notification for the specified property is also raised. +
+ Requires a on this same property. +
+ The name of the property to generate a change notifcation for. +
+ + + Uses the getter and setter from the specified property as a template for this reactive property. +
+ Requires a on this same property. +
+ The name of the property to use to implement this reactive property. +
+ + + Uses the getter and setter from the specified property as a template for this reactive property. +
+ Requires a on this same property. +
+ The name of the property to use to implement this reactive property. +
+ + + Marks the setter on the generated property as private. +
+ Requires a on this same property. +
+
+ + + Specifies that, for the annotated property, the provided delegates should be called to synchronise + data to and from the model for this property. + + The name of a static method in this class to copy this property's value from this instance to the model. + The name of a static method in this class to copy this property's value from the model to this instance. + + + + Specifies that, for the annotated property, the provided delegates should be called to synchronise + data to and from the model for this property. + + The name of a static method in this class to copy this property's value from this instance to the model. + The name of a static method in this class to copy this property's value from the model to this instance. + + + + Specifies the name of the field of the model this property should be bound to. + + + + + + Specifies the name of the field of the model this property should be bound to. + + + + + + Indicates that this property should not be automatically bound to a corresponding model property. Note that + properties for read-only fields are implicitly skipped from model binding as they cannot be written too. + + This attribute also implies the . + + + + + Allows a custom getter function to be used in a property generated using a . + + A function which returns the value of the property. + When , the setter parameter expects a method name; + when , the getter parameter takes an expression which is placed inline in the generator getter. + + + + Allows a custom getter function to be used in a property generated using a . + + A function which returns the value of the property. + When , the setter parameter expects a method name; + when , the getter parameter takes an expression which is placed inline in the generator getter. + + + + Allows a custom setter function to be used in a property generated using a . + + A method which takes as input the new value to assign to the property. + When , the setter parameter expects a method name; + when , the setter parameter takes an expression which is placed inline in the generator setter. + + + + Allows a custom setter function to be used in a property generated using a . + + A method which takes as input the new value to assign to the property. + When , the setter parameter expects a method name; + when , the setter parameter takes an expression which is placed inline in the generator setter. + + + + Allows custom accessibility keywords to be used on a property generated using a . + + + [Reactive, CustomAccessibility("protected virtual")] string prop; + + The accessibility modifiers to add to the generated property. + + + + Allows custom accessibility keywords to be used on a property generated using a . + + + [Reactive, CustomAccessibility("protected virtual")] string prop; + + The accessibility modifiers to add to the generated property. + + + + Prevents undo actions from being recorded on the property generated using a . + + The accessibility modifiers to add to the generated property. + + + + Specifies the model type associated with this view model. + + + + + + Specifies the model type associated with this view model. + + + + + + Specifies the view type associated with this view model. + + + + + + Specifies the view type associated with this view model. + + + + + + Specifies the display name of a given cue type. + + + + + + Specifies the display name of a given cue type. + + + + + + Specifies the icon for a given cue type. + + The icon is defined as a in a (in xaml). + The plugin loader automatically creates an instance of the given resource dictionary and binds it to the app if one doesn't already exist. + The parameter should refer to a given x:Key="name" attribute on the in xaml. + + The key of the in the given resource dictionary to use as the icon. + The type of the resource dictionary which contains the given icon. + + + + Specifies the icon for a given cue type. + + The icon is defined as a in a (in xaml). + The plugin loader automatically creates an instance of the given resource dictionary and binds it to the app if one doesn't already exist. + The parameter should refer to a given x:Key="name" attribute on the in xaml. + + The key of the in the given resource dictionary to use as the icon. + The type of the resource dictionary which contains the given icon. + + + + When used on a class which derives from , generates an implementation + for and + based on all fields marked as []. + + Use the [] and [] to add/remove fields + from inclusion in the Clone() implementation. + + To mix both a automatically generated clone implementation with custom behaviour, the + parameter can be set. This allows the generated implementation to call a custom clone method after it has cloned all the + automatically implemented properties. The custom clone method is always called after all other fields have been cloned + and must have the following signature: + + // This method CAN be declared as private, T represents the type of this attribute is decorating. + void CustomClone(T target); + + + If a field's type declares a public T Clone(); method (or one is provided by an extension method) then this + method will be called when copying that field. This behaviour must be enabled via the + property. + + + Generates the following code: + + public partial class Label + { + public override UIElement Clone() => Clone(new Label()); + + public override UIElement Clone(UIElement target) + { + base.Clone(target); + if (target is Label t) + { + t.text = text; + t.size = size; + t.colour = colour; + // For the sake of example, if Font defined a Clone() method it would be called as shown. + t.font = font.Clone(); + } + return target; + } + } + + + When , calls a method on this + + + + When used on a class which derives from , generates an implementation + for and + based on all fields marked as []. + + Use the [] and [] to add/remove fields + from inclusion in the Clone() implementation. + + To mix both a automatically generated clone implementation with custom behaviour, the + parameter can be set. This allows the generated implementation to call a custom clone method after it has cloned all the + automatically implemented properties. The custom clone method is always called after all other fields have been cloned + and must have the following signature: + + // This method CAN be declared as private, T represents the type of this attribute is decorating. + void CustomClone(T target); + + + If a field's type declares a public T Clone(); method (or one is provided by an extension method) then this + method will be called when copying that field. This behaviour must be enabled via the + property. + + + Generates the following code: + + public partial class Label + { + public override UIElement Clone() => Clone(new Label()); + + public override UIElement Clone(UIElement target) + { + base.Clone(target); + if (target is Label t) + { + t.text = text; + t.size = size; + t.colour = colour; + // For the sake of example, if Font defined a Clone() method it would be called as shown. + t.font = font.Clone(); + } + return target; + } + } + + + When , calls a method on this + + + + Marks a field to be included for the automatic + implementation. + + + See . + + If a field's type declares a public T Clone(); method (or one is provided by + an extension method) then this method will be called when copying the annotated field. + + + + Marks a field to be included for the automatic + implementation. + + + See . + + If a field's type declares a public T Clone(); method (or one is provided by + an extension method) then this method will be called when copying the annotated field. + + + + Marks a field to be excluded from the automatic + implementation. + + + See . + + + + + Indicates to the source generator that a should be generated for this view model. +
+ By default, a view control will be generated for every public property on this class. +
+
+ + + Indicates to the source generator that a should be generated for this view model. +
+ By default, a view control will be generated for every public property on this class. +
+
+ + + Specifies the label for the generated view control for this property. + + + + + + Specifies the label for the generated view control for this property. + + + + + + Indicates that a view control should not be generated for this property. + + + + + For numeric properties, this allows the minimum, maximum, and change rate of the generated view control to be specified. + + + + + + + + + For numeric properties, this allows the minimum, maximum, and change rate of the generated view control to be specified. + + + + + + + + + Specifies that a knob control should be generated for this property (as opposed to a Spinbox). + + + + + Specifies that a slider control should be generated for this property (as opposed to a Spinbox). + + + + + Specifies that a file picker control should be generated for this property. + Only valid on string properties. + + The name of the ICommand to invoke when the file picker button is pressed. + + + + Specifies that a file picker control should be generated for this property. + Only valid on string properties. + + The name of the ICommand to invoke when the file picker button is pressed. + + + + Generates a button control in place of this property which invokes the given command. + The annotated property's value is ignored. + + The name of the ICommand to invoke when the button is pressed. + + + + Generates a button control in place of this property which invokes the given command. + The annotated property's value is ignored. + + The name of the ICommand to invoke when the button is pressed. + + + + Generates a heading label before the annotated property in the view. + + The title of the heading. + + + + Generates a heading label before the annotated property in the view. + + The title of the heading. + + + + Specifies a tooltip to display for the generated view control for this property. + + + + + + Specifies a tooltip to display for the generated view control for this property. + + + + + + Controls + + + + + InitializeComponent + + + + + GeneratedInternalTypeHelper + + + + + CreateInstance + + + + + GetPropertyValue + + + + + SetPropertyValue + + + + + CreateDelegate + + + + + AddEventHandler + + +
+
From ae42486716fdb0b9b893a57b6f086d0f6769f161 Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sat, 25 Apr 2026 05:15:21 +0100 Subject: [PATCH 2/8] DocFX experiments - more promising --- docfx.json | 51 ++++++++++++++++++++++++++++++++++++++++++++ docs/fix_api_docs.py | 10 +++++++++ dotnet-tools.json | 13 +++++++++++ 3 files changed, 74 insertions(+) create mode 100644 docfx.json create mode 100644 docs/fix_api_docs.py create mode 100644 dotnet-tools.json diff --git a/docfx.json b/docfx.json new file mode 100644 index 0000000..c8e7ed5 --- /dev/null +++ b/docfx.json @@ -0,0 +1,51 @@ +{ + "$schema": "https://raw.githubusercontent.com/dotnet/docfx/main/schemas/docfx.schema.json", + "metadata": [ + { + "src": [ + { + "src": "../QPlayer", + "files": [ + "**/*.csproj" + ] + } + ], + "output": "api", + "outputFormat": "markdown", + "categoryLayout": "nested", + "namespaceLayout": "nested", + "memberLayout": "samePage", + "enumSortOrder": "declaringOrder" + } + ], + "##build": { + "content": [ + { + "files": [ + "**/*.{md,yml}" + ], + "exclude": [ + "_site/**" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ] + } + ], + "output": "_site", + "template": [ + "default", + "modern" + ], + "globalMetadata": { + "_appName": "QPlayer-API", + "_appTitle": "QPlayer-API", + "_enableSearch": true, + "pdf": false + } + } +} \ No newline at end of file diff --git a/docs/fix_api_docs.py b/docs/fix_api_docs.py new file mode 100644 index 0000000..07bdd5b --- /dev/null +++ b/docs/fix_api_docs.py @@ -0,0 +1,10 @@ +import os +import sys + +base_path = sys.argv[1] +for p in os.listdir(base_path): + p = os.path.join(base_path, p) + with open(p, "rt") as f: + lines = f.readlines() + with open(p, "wt") as f: + f.writelines(['---\n', f'title: {p[:-3]}\n', '---\n', '\n'] + lines) \ No newline at end of file diff --git a/dotnet-tools.json b/dotnet-tools.json new file mode 100644 index 0000000..12ab7ac --- /dev/null +++ b/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "docfx": { + "version": "2.78.5", + "commands": [ + "docfx" + ], + "rollForward": false + } + } +} \ No newline at end of file From 07b15c7f18023398139c2d867a36fb449965595c Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sun, 3 May 2026 07:44:30 +0100 Subject: [PATCH 3/8] Updated StarlightDocNet to work with docfx apipage yaml files: - Rewrote StarlightDocNet - Implemented generic object deserialiser - Added docfx config - Updated astro - Updated CI - Fixed typo in docs --- .github/workflows/deploy-docs.yml | 13 + .gitignore | 1 + QPlayer.sln | 1 + StarlightDocNet/ApiPage.cs | 171 ++ StarlightDocNet/Dict2Obj.cs | 255 +++ StarlightDocNet/MDStringBuilder.cs | 89 +- StarlightDocNet/Program.cs | 308 +--- .../Properties/launchSettings.json | 2 +- StarlightDocNet/StarlightDocNet.csproj | 6 + StarlightDocNet/YML2MD.cs | 403 +++++ docfx.json | 34 +- docs/astro.config.mjs | 9 + docs/package-lock.json | 1548 ++++++++--------- docs/package.json | 4 +- docs/src/content/docs/api/.gitignore | 2 + docs/src/content/docs/api/index.mdx | 17 + docs/src/content/docs/index.mdx | 4 +- 17 files changed, 1726 insertions(+), 1141 deletions(-) create mode 100644 StarlightDocNet/ApiPage.cs create mode 100644 StarlightDocNet/Dict2Obj.cs create mode 100644 StarlightDocNet/YML2MD.cs create mode 100644 docs/src/content/docs/api/.gitignore create mode 100644 docs/src/content/docs/api/index.mdx diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 1f5046d..a50b152 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -25,6 +25,19 @@ jobs: steps: - name: Checkout your repository using git uses: actions/checkout@v4 + + # Build API docs + - uses: actions/setup-dotnet@v2 + with: + dotnet-version: 10.0.x + - name: DocFX + shell: bash + run: | + dotnet tool install docfx + dotnet docfx + dotnet run StarlightDocNet "api/" "docs/src/content/docs/api/" + + # Build the rest of the docs - name: Install, build, and upload your site output uses: withastro/action@v4 with: diff --git a/.gitignore b/.gitignore index 779165e..a57e89a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ SigningCertificate_Encoded.txt **/publish *.zip /QPlayerOld +/api diff --git a/QPlayer.sln b/QPlayer.sln index 5463275..9e33f76 100644 --- a/QPlayer.sln +++ b/QPlayer.sln @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .gitignore = .gitignore .github\workflows\deploy-docs.yml = .github\workflows\deploy-docs.yml + docfx.json = docfx.json .github\workflows\dotnet-desktop.yml = .github\workflows\dotnet-desktop.yml README.md = README.md EndProjectSection diff --git a/StarlightDocNet/ApiPage.cs b/StarlightDocNet/ApiPage.cs new file mode 100644 index 0000000..3364174 --- /dev/null +++ b/StarlightDocNet/ApiPage.cs @@ -0,0 +1,171 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using System.Text.Json.Serialization; +using OneOf; +using StarlightDocNet; + +#nullable enable + +namespace Docfx.Build.ApiPage; + +struct LinkSpan +{ + public required string text { get; init; } + public string? url { get; init; } +} + +public static class ApiPageHelpers +{ + public static int DiscrInline(object x) => (x is IList) ? 1 : 0; + public static int DiscrSpan(object x) => (x is string) ? 0 : 1; +} + +[GenerateOneOf] +[Discriminate("ApiPageHelpers.DiscrSpan")] +partial class Span : OneOfBase { } + +[GenerateOneOf] +[Discriminate("ApiPageHelpers.DiscrInline")] +partial class Inline : OneOfBase { } + +struct Markdown +{ + public required string markdown { get; init; } +} + +struct H1 +{ + public required string h1 { get; init; } + public string? id { get; init; } +} + +struct H2 +{ + public required string h2 { get; init; } + public string? id { get; init; } +} + +struct H3 +{ + public required string h3 { get; init; } + public string? id { get; init; } +} + +struct H4 +{ + public required string h4 { get; init; } + public string? id { get; init; } +} + +struct H5 +{ + public required string h5 { get; init; } + public string? id { get; init; } +} + +struct H6 +{ + public required string h6 { get; init; } + public string? id { get; init; } +} + +[GenerateOneOf] +partial class Heading : OneOfBase { } + +abstract class ApiBase +{ + public string? id { get; init; } + public OneOf? deprecated { get; init; } + public OneOf? preview { get; init; } + public string? src { get; init; } + public Dictionary? metadata { get; init; } +} + +class Api1 : ApiBase +{ + public Api1() { } + + public required string api1 { get; init; } +} + +class Api2 : ApiBase +{ + public required string api2 { get; init; } +} + +class Api3 : ApiBase +{ + public required string api3 { get; init; } +} + +class Api4 : ApiBase +{ + public required string api4 { get; init; } +} + + +[GenerateOneOf] +partial class Api : OneOfBase { } + +record struct Fact(string name, Inline value); + +struct Facts +{ + public required Fact[] facts { get; init; } +} + +struct List +{ + public required Inline[] list { get; init; } +} + +struct Inheritance +{ + public required Inline[] inheritance { get; init; } +} + +struct Code +{ + public required string code { get; init; } + public string? languageId { get; init; } +} + +class Parameter +{ + public string? name { get; init; } + public Inline? type { get; init; } + public string? @default { get; init; } + public string? description { get; init; } + public OneOf? deprecated { get; init; } + public OneOf? preview { get; init; } + public bool? optional { get; init; } +} + +struct Parameters +{ + public required Parameter[] parameters { get; init; } +} + +[GenerateOneOf] +partial class Block : OneOfBase { } + +record ApiPage +{ + public static JsonSerializerOptions JsonSerializerOptions { get; } = new() + { + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull | JsonIgnoreCondition.WhenWritingDefault, + }; + + static ApiPage() + { + // JsonSerializerOptions.Converters.Add(new OneOfJsonConverterFactory()); + } + + public required string title { get; init; } + public required Block[] body { get; init; } + + public string? languageId { get; init; } + public Dictionary>? metadata { get; init; } +} diff --git a/StarlightDocNet/Dict2Obj.cs b/StarlightDocNet/Dict2Obj.cs new file mode 100644 index 0000000..8b3828d --- /dev/null +++ b/StarlightDocNet/Dict2Obj.cs @@ -0,0 +1,255 @@ +using Docfx.Build.ApiPage; +using OneOf; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; + +namespace StarlightDocNet; + +internal static partial class Dict2ObjExtensions +{ + public static T As(this object dict) + { + if (dict is T conv) + return conv; + return Dict2Obj.Convert((IDictionary)dict); + } + + public static T As(this IDictionary dict) => Dict2Obj.Convert(dict); + public static T[] AsArray(this object list) => [.. ((IList)list).Select(x => Convert(x))]; + public static T[] AsArray(this IList list) => [.. list.Select(x => Convert(x))]; + + private static bool StrEquals(object? a, object? b) + { + if (a is string aStr && b is string bStr) + return aStr.Equals(bStr); + return false; + } + + private static IEnumerable> ConvertKVP(IEnumerable> src) + { + foreach (var kvp in src) + yield return new KeyValuePair((T1)kvp.Key, (T2)kvp.Value); + } + + private static T[] ConvertArray(object src) => [.. ((IList)src).Select(x => Convert(x))]; + + private static T Convert(object src) + { + if (src is T conv) + return conv; + if (typeof(T).IsAssignableTo(typeof(IOneOf))) + return Obj2OneOf.Convert(src); + if (typeof(T).IsArray) + return List2Obj.Convert(src); + return Dict2Obj.Convert((IDictionary)src); + } +} + +internal static class List2Obj +{ + public delegate T ConvertDelegate(object src); + private readonly static ConvertDelegate convertFunc; + + static List2Obj() + { + var type = typeof(T); + var elemt = type.GetElementType()!; + var convMeth = typeof(Dict2ObjExtensions).GetMethod("ConvertArray", BindingFlags.NonPublic | BindingFlags.Static); + convMeth = convMeth!.MakeGenericMethod(elemt); + + var src = Expression.Parameter(typeof(object), "src"); + var result = Expression.Variable(typeof(T), "result"); + Expression body = Expression.Call(convMeth, src); + + convertFunc = Expression.Lambda(body, src).Compile(); + } + + public static T Convert(object src) => convertFunc(src); +} + +internal static class Obj2OneOf +// where T : IOneOf +{ + public delegate T ConvertDelegate(object src); + private readonly static ConvertDelegate convertFunc; + + static Obj2OneOf() + { + var type = typeof(T); + var types = type.BaseType!.GetGenericArguments(); + var oneoft = typeof(IOneOf).Assembly.GetType($"OneOf.OneOf`{types.Length}")!; + oneoft = oneoft.MakeGenericType(types); + var ctor = type.GetConstructor([oneoft])!; + + var src = Expression.Parameter(typeof(object), "src"); + var result = Expression.Variable(typeof(T), "result"); + Expression body = Expression.Empty(); + + if (type.GetCustomAttribute() is DiscriminateAttribute discr) + { + var split = discr.Discriminator.Split('.'); + var dt = type.Assembly.GetType(type.Namespace + "." + split[0])!; + var dm = dt.GetMethod(split[1], BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)!; + var selT = Expression.Call(dm, src); + List tSwitchCases = []; + for (int i = 0; i < types.Length; i++) + { + var from = oneoft.GetMethod($"FromT{i}", BindingFlags.Public | BindingFlags.Static)!; + var convMeth = typeof(Dict2ObjExtensions).GetMethod("Convert", BindingFlags.Static | BindingFlags.NonPublic); + convMeth = convMeth!.MakeGenericMethod(types[i]); + tSwitchCases.Add(Expression.SwitchCase(Expression.Block( + Expression.Assign(result, + Expression.New(ctor, Expression.Call(from, Expression.Call(convMeth, src)))) + , Expression.Empty()), Expression.Constant(i))); + } + body = Expression.Switch(selT, null, null, tSwitchCases); + } + else + { + for (int i = 0; i < types.Length; i++) + { + var from = oneoft.GetMethod($"FromT{i}", BindingFlags.Public | BindingFlags.Static)!; + body = Expression.IfThenElse(Expression.Call(Expression.Constant(types[i]), "IsAssignableFrom", null, Expression.Call(src, "GetType", null)), + Expression.Assign(result, Expression.New(ctor, + Expression.Call(from, Expression.Convert(src, types[i])))), + body); + } + } + + var block = Expression.Block(typeof(T), [result], result, body, result); + convertFunc = Expression.Lambda(block, src).Compile(); + } + + public static T Convert(object src) => convertFunc(src); +} + +internal static class Dict2Obj +// where T : new() +{ + public delegate T ConvertDelegate(IDictionary src); + private readonly static ConvertDelegate convertFunc; + + static Dict2Obj() + { + // Linq expression magic to generate code to convert a string-keyed + // dictionary into a proper object. Using expressions means we only + // bear the cost of reflection once at startup and then very efficient + // IL is generated. This is all kind of vibe-coded, and when I say + // vibe-coded, I mean I was kind of just vibing as I typed this and + // didn't give it too much thought (no ai here lol); it's a bit of a + // complicated mess lol. + var props = typeof(T).GetProperties(); + var dictType = typeof(IDictionary); + + if (typeof(T).IsAssignableTo(dictType)) + { + convertFunc = x => (T)x; + return; + } + + var src = Expression.Parameter(dictType, "src"); + var result = Expression.Variable(typeof(T), "result"); + var it = Expression.Variable(typeof(IEnumerator>), "it"); + var item = Expression.Variable(typeof(KeyValuePair), "item"); + var val = Expression.Variable(typeof(object), "val"); + var valType = Expression.Variable(typeof(Type), "valType"); + + if (typeof(T).IsAssignableTo(typeof(IDictionary))) + { + //Dictionary o = new(); + //Dictionary d = new(o.Select(x => new KeyValuePair((string)x.Key, (string)x.Value))); + var kvt = typeof(T).GenericTypeArguments; + var kvpm = typeof(KeyValuePair).GetMethod("Create", BindingFlags.Static | BindingFlags.Public)!.MakeGenericMethod(kvt); + var kvpt = kvpm.ReturnType; + var kvpCtor = kvpt.GetConstructor(kvt)!; + var enumt = typeof(IEnumerable<>).MakeGenericType(kvpt); + var ctor = typeof(T).GetConstructor([enumt])!; + var conv = typeof(Dict2ObjExtensions).GetMethod("ConvertKVP", BindingFlags.Static | BindingFlags.NonPublic)!; + conv = conv.MakeGenericMethod(kvt); + var convParam = Expression.Parameter(dictType, "src"); + var convFunc = Expression.New(ctor, Expression.Call(conv, convParam)); + + convertFunc = Expression.Lambda(convFunc, convParam).Compile(); + return; + } + + var getEnumMeth = typeof(IEnumerable>).GetMethod("GetEnumerator")!; + var moveNextMeth = typeof(IEnumerator).GetMethod("MoveNext")!; + var strEqMeth = typeof(Dict2ObjExtensions).GetMethod("StrEquals", BindingFlags.Static | BindingFlags.NonPublic); + var convArrayMeth = typeof(Dict2ObjExtensions).GetMethod("AsArray", BindingFlags.Static | BindingFlags.Public, [typeof(object)])!; + + var breakLab = Expression.Label(); + List statements = []; + + statements.Add(Expression.Assign(result, Expression.New(typeof(T)))); + statements.Add(Expression.Assign(it, Expression.Call(src, getEnumMeth))); + + List loopCont = []; + loopCont.Add(Expression.IfThen(Expression.Not(Expression.Call(it, moveNextMeth)), + Expression.Break(breakLab))); + loopCont.Add(Expression.Assign(item, Expression.Property(it, "Current"))); + loopCont.Add(Expression.Assign(val, Expression.Property(item, "Value"))); + loopCont.Add(Expression.Assign(valType, Expression.Call(val, "GetType", null))); + + List cases = []; + foreach (var prop in props) + { + if (!prop.CanRead || !prop.CanWrite) + continue; + + var propType = prop.PropertyType; + var propTypeExpr = Expression.Constant(propType); + + Expression switchContents; + if (propType.IsAssignableTo(typeof(IOneOf))) + { + // result.prop = Obj2OneOf.Convert(val); + var obj2oneoft = typeof(Obj2OneOf<>).MakeGenericType(propType); + var convertMeth = obj2oneoft.GetMethod("Convert", BindingFlags.Static | BindingFlags.Public)!; + switchContents = Expression.Block(Expression.Assign(Expression.Property(result, prop), Expression.Call(convertMeth, val)), Expression.Empty()); + } + else if (propType.IsArray) + { + // result.prop = ExtensionMethods.ToArray(val); + var elemType = propType.GetElementType()!; + var toArray = convArrayMeth.MakeGenericMethod(elemType); + switchContents = Expression.Block(Expression.Assign(Expression.Property(result, prop), Expression.Call(toArray, val)), Expression.Empty()); + } + else + { + var d2oProp = typeof(Dict2Obj<>).MakeGenericType(propType).GetMethod("Convert", BindingFlags.Static | BindingFlags.Public); + switchContents = + Expression.IfThenElse(Expression.Call(valType, "IsAssignableTo", null, propTypeExpr), + Expression.Assign(Expression.Property(result, prop), Expression.Convert(val, propType)), + Expression.IfThen(Expression.Call(valType, "IsAssignableTo", null, Expression.Constant(dictType)), + Expression.Assign(Expression.Property(result, prop), Expression.Call(null, d2oProp!, Expression.Convert(val, dictType))) + )); + } + cases.Add(Expression.SwitchCase(switchContents, Expression.Constant(prop.Name))); + } + + loopCont.Add(Expression.Switch(Expression.Property(item, "Key"), null, strEqMeth, cases)); + statements.Add(Expression.Loop(Expression.Block(loopCont), breakLab)); + statements.Add(result); + + var block = Expression.Block(typeof(T), [result, it, item, val, valType], statements); +#if DEBUG && false + var dbgView = typeof(Expression).GetProperty("DebugView", BindingFlags.Instance | BindingFlags.NonPublic)!; + Debug.WriteLine($"### Generated Dict2Obj<{typeof(T).Name}> : \n{dbgView.GetValue(block)}\n"); +#endif + convertFunc = Expression.Lambda(block, src).Compile(); + } + + public static T Convert(IDictionary src) => convertFunc(src); +} + +[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] +public sealed class DiscriminateAttribute(string discriminator) : Attribute +{ + public string Discriminator => discriminator; +} \ No newline at end of file diff --git a/StarlightDocNet/MDStringBuilder.cs b/StarlightDocNet/MDStringBuilder.cs index 5f1e534..fb20ebd 100644 --- a/StarlightDocNet/MDStringBuilder.cs +++ b/StarlightDocNet/MDStringBuilder.cs @@ -7,9 +7,20 @@ namespace StarlightDocNet; public class MDStringBuilder { protected readonly StringBuilder sb = new(); + public readonly string localURLRoot; public readonly static MDStringBuilder Shared = new(); + public MDStringBuilder() + { + localURLRoot = "/"; + } + + public MDStringBuilder(string localURLRoot) + { + this.localURLRoot = localURLRoot; + } + public MDStringBuilder Clear() { sb.Clear(); @@ -29,9 +40,10 @@ public MDStringBuilder Add(char c) return this; } - public MDStringBuilder Add(string s) + public MDStringBuilder Add(string? s) { - sb.Append(s); + if (s != null) + sb.Append(s); return this; } @@ -83,6 +95,20 @@ public MDStringBuilder Line(ref StringBuilder.AppendInterpolatedStringHandler s) return this; } + public MDStringBuilder Para() + { + if (sb[^1] != Environment.NewLine[^1]) + sb.AppendLine(); + sb.AppendLine(); + return this; + } + + public MDStringBuilder Break() + { + sb.AppendLine(" "); + return this; + } + public MDStringBuilder H1(string s) { sb.Append("# ").AppendLine(s); @@ -103,7 +129,7 @@ public MDStringBuilder H3(string s) public MDStringBuilder H4(string s) { - sb.Append("### ").AppendLine(s); + sb.Append("#### ").AppendLine(s); return this; } @@ -163,6 +189,8 @@ public MDStringBuilder MetaHeader(string title, string? description = null, int? public CodeBlockBuilder CodeBlock(string? language = null) => new(sb, language); + public AsideBuilder Aside(string? type = null) => new(sb, type); + public TableBuilder Table() => new(this); public readonly struct CodeBlockBuilder : IDisposable @@ -184,6 +212,25 @@ public readonly void Dispose() } } + public readonly struct AsideBuilder : IDisposable + { + private readonly StringBuilder sb; + + public AsideBuilder(StringBuilder sb, string? type) + { + this.sb = sb; + if (type == null) + sb.AppendLine(":::"); + else + sb.Append(":::").Append(type).AppendLine(); + } + + public readonly void Dispose() + { + sb.AppendLine(":::"); + } + } + public struct TableBuilder : IDisposable { private readonly MDStringBuilder md; @@ -207,7 +254,7 @@ public MDStringBuilder HeaderCell(string s) return md; } - public MDStringBuilder Cell(string s) + public MDStringBuilder Cell(string? s = null) { if (firstRow) { @@ -218,7 +265,37 @@ public MDStringBuilder Cell(string s) sb.Append("---|"); sb.AppendLine(); } - sb.Append(" | ").Append(s); + sb.Append(" | "); + if (s != null) + sb.Append(s); + col++; + if (col == nCols) + { + col = 0; + sb.AppendLine(" | "); + } + + return md; + } + + public MDStringBuilder BeginCell() + { + if (firstRow) + { + firstRow = false; + sb.AppendLine(" | "); + sb.Append(" |"); + for (int i = 0; i < nCols; i++) + sb.Append("---|"); + sb.AppendLine(); + } + sb.Append(" | "); + + return md; + } + + public MDStringBuilder EndCell() + { col++; if (col == nCols) { @@ -231,7 +308,7 @@ public MDStringBuilder Cell(string s) public void Dispose() { - for (; col < nCols;) + while (firstRow || col > 0) Cell(" "); sb.AppendLine(); } diff --git a/StarlightDocNet/Program.cs b/StarlightDocNet/Program.cs index 0c721cb..9346858 100644 --- a/StarlightDocNet/Program.cs +++ b/StarlightDocNet/Program.cs @@ -1,37 +1,27 @@ using System.Diagnostics; using System.Runtime.CompilerServices; -using System.Xml; namespace StarlightDocNet; -/* - dotnet build QPlayer/QPlayer.csproj -p:GenerateDocumentationFile=true --configuration Release -p:DocumentationFile=$SolutionDir/api_docs.xml -p:NoWarn=1591 - */ - internal class Program { - public static readonly List assemblies = []; - public static APIClass? lastClass; private static readonly Lock logListLock = new(); static void Main(string[] args) { - Assert(args.Length >= 2, "Expected usage: dotnet run StarlightDocNet api_docs.xml path/to/dst/md/"); + Assert(args.Length >= 2, "Expected usage: dotnet run StarlightDocNet path/to/api_yml/ path/to/dst/md/"); string srcPath = args[0]; string dstPath = args[1]; - using var tr = File.OpenText(srcPath); - var doc = new XmlDocument(); - Log($"Loading xml..."); - doc.Load(tr); - Log("Parsing xml..."); - - var xml = doc.DocumentElement; - Assert(xml?.Name == "doc"); - - ParseRoot(xml!); - CreatePages(dstPath); + Stopwatch sw = Stopwatch.StartNew(); + foreach (var path in Directory.EnumerateFiles(srcPath)) + { + YML2MD yml2md = new(); + yml2md.Process(path, dstPath); + } + sw.Stop(); + Log($"Completed it {sw}!"); } public static void Assert(bool condition, string? msg = null, [CallerArgumentExpression(nameof(condition))] string? expr = null, [CallerMemberName] string caller = "") @@ -74,284 +64,4 @@ public enum LogLevel Warning, Error } - - private static void ParseRoot(XmlNode xml) - { - foreach (XmlNode child in xml.ChildNodes) - { - switch (child.Name) - { - case "assembly": - assemblies.Add(APIAssembly.Create(child)); - break; - case "members": - Assert(assemblies.Count > 0); - var asm = assemblies[^1]; - foreach (XmlNode xmlMember in child.ChildNodes) - { - if (xmlMember.Name == "#comment") - continue; - var mem = CreateMember(xmlMember); - if (mem != null) - asm.members.Add(mem); - else - Log($"Couldn't create member for node: {xmlMember.Name}", LogLevel.Warning); - } - break; - case "#comment": - break; - default: - Log($"Unexpected xml node in documetation: {child}", LogLevel.Warning); - break; - } - } - } - - private static APIMember? CreateMember(XmlNode xml) - { - Assert(xml.Name == "member"); - var memName = xml.Attributes?.GetNamedItem("name")?.Value; - Assert(memName != null); - Assert(memName!.Length > 0); - switch (memName[0]) - { - case 'T': - return APIClass.Create(xml, memName); - case 'M': - return APIMethod.Create(xml, memName); - case 'P': - break; - case 'F': - break; - case 'E': - break; - default: - Assert(false, $"Unrecognised member type {memName}!"); - return null; - } - return null; - } - - private static void CreatePages(string basePath) - { - foreach (var asm in assemblies) - asm.CreatePage(basePath); - } -} - -internal class APIAssembly(string name) -{ - public string name = name; - public readonly List members = []; - - public static APIAssembly Create(XmlNode xml) - { - string name = string.Empty; - foreach (XmlNode child in xml.ChildNodes) - if (child.Name == "name") - name = child.InnerText; - - return new(name); - } - - public void CreatePage(string basePath) - { - basePath = Path.Combine(basePath, name); - Directory.CreateDirectory(basePath); - var index = Path.Combine(basePath, "index.mdx"); - var sb = MDStringBuilder.Shared.Clear(); - sb.MetaHeader(name, null, -1); - File.WriteAllText(index, sb); - - foreach (var child in members) - { - child.CreatePage(basePath); - } - } -} - -internal abstract class APIMember(string name) -{ - public string name = name; - public string? type; - public string? summary; - public string? remarks; - - protected virtual void ParseMemberNode(XmlNode xml) - { - switch (xml.Name) - { - case "summary": - summary = xml.InnerText; - break; - case "remarks": - remarks = xml.InnerText; - break; - default: - Program.Log($"Unrecognised member node: {xml.Name}", Program.LogLevel.Warning); - break; - } - } - - public virtual void CreatePage(string basePath) - { - var split = name.LastIndexOf('.') + 1; - var index = Path.Combine(basePath, $"{name[split..]}.mdx"); - var sb = MDStringBuilder.Shared.Clear(); - sb.MetaHeader(name); - WriteContents(sb); - File.WriteAllText(index, sb); - } - - public virtual void WriteContents(MDStringBuilder sb) - { - if (summary != null) - { - sb.Line(summary); - } - if (remarks != null) - { - sb.H2("Remarks"); - sb.Line(remarks); - } - } -} - -internal class APIClass(string name) : APIMember(name) -{ - public readonly List members = []; - - public static APIClass Create(XmlNode xml, string name) - { - var node = new APIClass(name); - foreach (XmlNode child in xml.ChildNodes) - { - node.ParseMemberNode(child); - } - - return node; - } - - public override void CreatePage(string basePath) - { - base.CreatePage(basePath); - foreach (var child in members) - { - child.CreatePage(basePath); - } - } - - public override void WriteContents(MDStringBuilder sb) - { - base.WriteContents(sb); - - using var table = sb.Table(); - table.HeaderCell("Members"); - foreach (var mem in members) - table.Cell(mem.name); - } -} - -internal class APIMethod(string name) : APIMember(name) -{ - public readonly List @params = []; - public readonly List exceptions = []; - public APIReturns? returns; - - public static APIMethod Create(XmlNode xml, string name) - { - var node = new APIMethod(name); - foreach (XmlNode child in xml.ChildNodes) - { - node.ParseMemberNode(child); - } - - return node; - } - - protected override void ParseMemberNode(XmlNode xml) - { - switch (xml.Name) - { - case "param": - @params.Add(APIParam.Create(xml)); - break; - case "returns": - returns = new(xml.InnerText); - break; - case "exception": - exceptions.Add(new(xml.InnerText)); - break; - case "typeparam": - break; - case "inheritdoc": - break; - default: - base.ParseMemberNode(xml); - break; - } - } - - public override void WriteContents(MDStringBuilder sb) - { - base.WriteContents(sb); - - if (returns != null) - { - sb.H2("Returns"); - returns.WriteContents(sb); - } - if (exceptions.Count > 0) - { - sb.H2("Exceptions"); - using var exTab = sb.Table(); - exTab.HeaderCell("Type"); - exTab.HeaderCell("Summary"); - foreach (var ex in exceptions) - { - exTab.Cell(ex.name); - exTab.Cell(ex.summary ?? string.Empty); - } - } - sb.H2("Parameters"); - using var table = sb.Table(); - table.HeaderCell("Name"); - table.HeaderCell("Description"); - foreach (var par in @params) - { - table.Cell(par.name); - table.Cell(par.summary ?? string.Empty); - } - } -} - -internal class APIProperty(string name) : APIMember(name) -{ - -} - -internal class APIField(string name) : APIMember(name) -{ - -} - -internal class APIParam(string name) : APIMember(name) -{ - public static APIParam Create(XmlNode xml) - { - var memName = xml.Attributes?.GetNamedItem("name")?.Value ?? string.Empty; - var p = new APIParam(memName); - p.summary = xml.InnerText; - return p; - } -} - -internal class APIReturns(string name) : APIMember(name) -{ - -} - -internal class APIException(string name) : APIMember(name) -{ - } diff --git a/StarlightDocNet/Properties/launchSettings.json b/StarlightDocNet/Properties/launchSettings.json index f791515..590aa82 100644 --- a/StarlightDocNet/Properties/launchSettings.json +++ b/StarlightDocNet/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "StarlightDocNet": { "commandName": "Project", - "commandLineArgs": "api_docs.xml temp\\" + "commandLineArgs": "\"C:\\Users\\Thoma\\OneDrive\\Computer Sync\\visual studio 2015\\Projects\\QPlayer\\api\" \r\n\"C:\\Users\\Thoma\\OneDrive\\Computer Sync\\visual studio 2015\\Projects\\QPlayer\\docs\\src\\content\\docs\\api\"" } } } \ No newline at end of file diff --git a/StarlightDocNet/StarlightDocNet.csproj b/StarlightDocNet/StarlightDocNet.csproj index ed9781c..1b23ff5 100644 --- a/StarlightDocNet/StarlightDocNet.csproj +++ b/StarlightDocNet/StarlightDocNet.csproj @@ -7,4 +7,10 @@ enable + + + + + + diff --git a/StarlightDocNet/YML2MD.cs b/StarlightDocNet/YML2MD.cs new file mode 100644 index 0000000..748acc6 --- /dev/null +++ b/StarlightDocNet/YML2MD.cs @@ -0,0 +1,403 @@ +using Docfx.Build.ApiPage; +using System; +using System.Buffers; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Text; +using YamlDotNet.Core; +using YamlDotNet.Serialization; +using static StarlightDocNet.Program; + +namespace StarlightDocNet; + +internal class YML2MD +{ + public void Process(string srcPath, string dstDir) + { + // File path stuff + var fname = Path.GetFileNameWithoutExtension(srcPath); + int prefixInd = fname.LastIndexOf('.'); + var subdir = prefixInd != -1 ? fname[..prefixInd] : string.Empty; + var shortName = prefixInd != -1 ? fname[(prefixInd + 1)..] : fname; + subdir = subdir.Replace('.', Path.DirectorySeparatorChar); + var dstPath = Path.Combine(dstDir, subdir, shortName + ".md"); + var apiDocRootInd = dstDir.LastIndexOf("docs"); + var apiDocRoot = "/"; + if (apiDocRootInd != -1) + apiDocRoot = dstDir[(apiDocRootInd + 4)..].Replace(Path.DirectorySeparatorChar, '/'); + if (!apiDocRoot.EndsWith('/')) + apiDocRoot += '/'; + + if (fname == "toc") + return; + Log($"Processing {fname}..."); + + using var tr = File.OpenText(srcPath); + var parser = new Parser(tr); + var ser = new Deserializer(); + + var doc = ser.Deserialize(tr) as IDictionary; + Assert(doc != null); + + var md = new MDStringBuilder(apiDocRoot); + + var title = ((string)doc!["title"]).Split(' '); + var docType = title[0] switch + { + "Class" => DocType.Class, + "Namespace" => DocType.Namespace, + "Enum" => DocType.Enum, + "Struct" => DocType.Struct, + "Interface" => DocType.Interface, + "Delegate" => DocType.Delegate, + _ => throw new Exception() + }; + + md.MetaHeader(title[1], null, docType == DocType.Namespace ? 0 : 10); + + var body = doc["body"].AsArray>(); + int i = 0; + var apiDoc = body[i++]; + var api = apiDoc.As(); + md.H1("Definition"); + if (api.src != null) + md.SrcLink(api.src); + + if (body[i].ContainsKey("facts")) + { + var facts = body[1].As(); + foreach (var fact in facts.facts) + md.Italic(fact.name).Add(": ").Add(fact.value).Break(); + md.Para(); + i++; + } + + if (body[i].ContainsKey("code")) + { + md.CodeBlock(body[i].As()); + i++; + } + + bool injectSummary = true; + for (; i < body.Length; i++) + { + var item = body[i]; + foreach (var key in item.Keys) + { + switch (key) + { + case "h1": md.H1((string)item["h1"]); break; + case "h2": + if (injectSummary) + { + injectSummary = false; + CreateSummary(md, body, i); + } + md.H2((string)item["h2"]); + break; + case "h3": md.H3((string)item["h3"]); break; + case "h4": md.H4((string)item["h4"]); break; + case "markdown": md.Line((string)item["markdown"]); break; + + case "inheritance": md.Add(item.As()); break; + case "list": md.Add(item.As()); break; + case "api2": md.Add(item.As()); break; + case "api3": md.Add(item.As()); break; + case "api4": md.Add(item.As()); break; + case "code": md.CodeBlock(item.As()); break; + case "parameters": md.Add(item.As()); break; + + default: break; + } + } + } + + var dstFinalDir = Path.GetDirectoryName(dstPath)!; + if (!Directory.Exists(dstFinalDir)) + Directory.CreateDirectory(dstFinalDir); + File.WriteAllText(dstPath, md.ToString()); + } + + private static void CreateSummary(MDStringBuilder md, IDictionary[] body, int ind) + { + md.H2("Summary"); + using var table = md.Table(); + table.HeaderCell("Type"); + table.HeaderCell("Name"); + table.HeaderCell("Description"); + string nextItemName = string.Empty; + string? nextDesc = null; + for (int i = ind; i < body.Length; i++) + { + var item = body[i]; + if (item.TryGetValue("h2", out var h2)) + { + WriteSummaryItem(); + table.BeginCell(); + md.Bold(h2.ToString()?.ToUpperInvariant() ?? string.Empty); + table.EndCell(); + table.Cell(); + table.Cell(); + } + else if (item.ContainsKey("api3")) + { + WriteSummaryItem(); + var api3 = item.As(); + nextItemName = api3.api3; + nextDesc = null; + } + else if (item.TryGetValue("markdown", out var desc)) + { + nextDesc = desc.ToString()?.Without('\n', '\r'); + } + } + WriteSummaryItem(); + + void WriteSummaryItem() + { + if (nextItemName == string.Empty) + return; + + var itemSlug = '#' + nextItemName.Without(',', '<', '>', '(', ')', '[', ']', '@', '#', '^', '`') + .Replace(' ', '-').ToLowerInvariant(); + + table.Cell(); + table.BeginCell(); + md.Link(itemSlug, nextItemName.EscapeLink()); + table.EndCell(); + table.Cell(nextDesc); + nextDesc = null; + nextItemName = string.Empty; + } + } + + enum DocType + { + Namespace, + Class, + Interface, + Struct, + Enum, + Delegate + } +} + +public static partial class ExtensionMethods +{ + [ThreadStatic] + private static StringBuilder? sbInst; + internal static string Without(this string str, params Span toRemove) + { + sbInst ??= new(); + sbInst.Clear(); + sbInst.EnsureCapacity(str.Length); + + foreach (var c in str) + if (!toRemove.Contains(c)) + sbInst.Append(c); + + return sbInst.ToString(); + } + + internal static string EscapeLink(this string str) + { + sbInst ??= new(); + sbInst.Clear(); + sbInst.EnsureCapacity(str.Length); + + foreach (var c in str) + { + if (c == '[' || c == ']') + sbInst.Append('\\'); + sbInst.Append(c); + } + + return sbInst.ToString(); + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Inline? inline) + { + if (inline == null) + return md; + if (inline.IsT0) + { + md.Add(inline.AsT0); + return md; + } + else + { + var arr = inline.AsT1; + if (arr.Length == 0) + return md; + + md.Add(arr[0]); + for (int i = 1; i < arr.Length; i++) + md/*.Add(", ")*/.Add(arr[i]); + + return md; + } + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Span span) + { + if (span.IsT0) + { + md.Add(span.AsT0); + return md; + } + else + { + var link = span.AsT1; + var url = link.url ?? string.Empty; + if (!url.StartsWith("http")) + { + if (url.EndsWith(".html")) + url = url[..^5]; + url = url.Replace('.', '/'); + url = md.localURLRoot + url; + url = url.ToLowerInvariant(); + } + md.Link(url, link.text); + return md; + } + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Markdown val) + { + var str = val.markdown; + // TODO: Replace + md.Add(str); + return md; + } + + internal static MDStringBuilder CodeBlock(this MDStringBuilder md, Code code) + { + using (md.CodeBlock(code.languageId ?? "cs")) + md.Line(code.code); + return md; + } + + internal static MDStringBuilder Code(this MDStringBuilder md, Code code) + { + md.Code(code.code); + return md; + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Inheritance val) + { + md.Add("> "); + if (val.inheritance.Length > 0) + md.Add(val.inheritance[0]); + for (int i = 1; i < val.inheritance.Length; i++) + md.Add(" → ").Add(val.inheritance[i]); + md.Para(); + return md; + } + + internal static MDStringBuilder Add(this MDStringBuilder md, List val) + { + md.Add("> "); + var vals = val.list; + if (vals.Length > 0) + md.Add(vals[0]); + for (int i = 1; i < vals.Length; i++) + md.Add(", ").Add(vals[i]); + md.Para(); + return md; + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Api2 val) + { + md.H2(val.api2); + if (val.src != null) + md.SrcLink(val.src); + if (val.deprecated != null) + md.Bold("DEPRECATED").Para(); + if (val.preview != null) + md.Bold("EXPERIMENTAL").Para(); + md.Para(); + return md; + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Api3 val) + { + md.H3(val.api3); + if (val.src != null) + md.SrcLink(val.src); + if (val.deprecated != null) + md.Bold("DEPRECATED").Para(); + if (val.preview != null) + md.Bold("EXPERIMENTAL").Para(); + md.Para(); + return md; + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Api4 val) + { + md.H4(val.api4); + if (val.src != null) + md.SrcLink(val.src); + if (val.deprecated != null) + md.Bold("DEPRECATED").Para(); + if (val.preview != null) + md.Bold("EXPERIMENTAL").Para(); + md.Para(); + return md; + } + + internal static MDStringBuilder SrcLink(this MDStringBuilder md, string src) + { + md.Italic("Source:").Add(' ').Link(src, src[(src.LastIndexOf('/') + 1)..src.LastIndexOf('#')]).Break(); + return md; + } + + internal static MDStringBuilder Add(this MDStringBuilder md, Parameters vals) + { + var arr = vals.parameters; + if (arr.Length == 0) + return md; + if (arr[0].name != null) + { + using var table = md.Table(); + table.HeaderCell("Type"); + table.HeaderCell("Name"); + table.HeaderCell("Description"); + foreach (var item in arr) + { + table.BeginCell().Add(item.type); table.EndCell(); + table.Cell(item.name ?? string.Empty); + table.BeginCell(); + if (item.preview != null) + md.Italic("EXPERIMENTAL "); + if (item.deprecated != null) + md.Italic("DEPRECATED "); + //if (item.optional ?? false) + // md.Italic("Optional, "); + md.Add(item.description?.Without('\n', '\r')); + table.EndCell(); + } + } + else + { + using var table = md.Table(); + table.HeaderCell("Type"); + table.HeaderCell("Description"); + foreach (var item in arr) + { + table.BeginCell().Add(item.type); table.EndCell(); + table.BeginCell(); + if (item.preview != null) + md.Italic("EXPERIMENTAL "); + if (item.deprecated != null) + md.Italic("DEPRECATED "); + //if (item.optional ?? false) + // md.Italic("Optional, "); + md.Add(item.description?.Without('\n', '\r')); + table.EndCell(); + } + } + return md; + } +} diff --git a/docfx.json b/docfx.json index c8e7ed5..08a4f4a 100644 --- a/docfx.json +++ b/docfx.json @@ -11,41 +11,11 @@ } ], "output": "api", - "outputFormat": "markdown", + "outputFormat": "apiPage", "categoryLayout": "nested", "namespaceLayout": "nested", "memberLayout": "samePage", "enumSortOrder": "declaringOrder" } - ], - "##build": { - "content": [ - { - "files": [ - "**/*.{md,yml}" - ], - "exclude": [ - "_site/**" - ] - } - ], - "resource": [ - { - "files": [ - "images/**" - ] - } - ], - "output": "_site", - "template": [ - "default", - "modern" - ], - "globalMetadata": { - "_appName": "QPlayer-API", - "_appTitle": "QPlayer-API", - "_enableSearch": true, - "pdf": false - } - } + ] } \ No newline at end of file diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 2ce86c5..9f9b427 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -61,6 +61,15 @@ export default defineConfig({ label: 'Reference', autogenerate: { directory: 'reference' }, }, + { + label: 'API', + autogenerate: { directory: 'api' }, + collapsed: true, + badge: { + class: 'warning', + text: 'For Developers' + }, + } ], customCss: [ // Relative path to your custom CSS file diff --git a/docs/package-lock.json b/docs/package-lock.json index e48e445..b43413d 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -8,8 +8,8 @@ "name": "qplayer-docs", "version": "0.0.1", "dependencies": { - "@astrojs/starlight": "^0.37.6", - "astro": "^5.17.1", + "@astrojs/starlight": "^0.38.4", + "astro": "^6.2.1", "sharp": "^0.34.5", "starlight-auto-sidebar": "^0.1.0", "starlight-giscus": "^0.8.1", @@ -17,29 +17,31 @@ } }, "node_modules/@astrojs/compiler": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-2.13.0.tgz", - "integrity": "sha512-mqVORhUJViA28fwHYaWmsXSzLO9osbdZ5ImUfxBarqsYdMlPbqAqGJCxsNzvppp1BEzc1mJNjOVvQqeDN8Vspw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@astrojs/compiler/-/compiler-4.0.0.tgz", + "integrity": "sha512-eouss7G8ygdZqHuke033VMcVw5HTZUu+PXd/h06DGDUg/jt5btPYPqh66ENWw/mU78rBrf/oeC4oqoBwMtDMNA==", "license": "MIT" }, "node_modules/@astrojs/internal-helpers": { - "version": "0.7.5", - "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.7.5.tgz", - "integrity": "sha512-vreGnYSSKhAjFJCWAwe/CNhONvoc5lokxtRoZims+0wa3KbHBdPHSSthJsKxPd8d/aic6lWKpRTYGY/hsgK6EA==", - "license": "MIT" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@astrojs/internal-helpers/-/internal-helpers-0.9.0.tgz", + "integrity": "sha512-GdYkzR26re8izmyYlBqf4z2s7zNngmWLFuxw0UKiPNqHraZGS6GKWIwSHgS22RDlu2ePFJ8bzmpBcUszut/SDg==", + "license": "MIT", + "dependencies": { + "picomatch": "^4.0.4" + } }, "node_modules/@astrojs/markdown-remark": { - "version": "6.3.10", - "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-6.3.10.tgz", - "integrity": "sha512-kk4HeYR6AcnzC4QV8iSlOfh+N8TZ3MEStxPyenyCtemqn8IpEATBFMTJcfrNW32dgpt6MY3oCkMM/Tv3/I4G3A==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@astrojs/markdown-remark/-/markdown-remark-7.1.1.tgz", + "integrity": "sha512-C6e9BnLGlbdv6bV8MYGeHpHxsUHrCrB4OuRLqi5LI7oiBVcBcqfUN06zpwFQdHgV48QCCrMmLpyqBr7VqC+swA==", "license": "MIT", "dependencies": { - "@astrojs/internal-helpers": "0.7.5", - "@astrojs/prism": "3.3.0", + "@astrojs/internal-helpers": "0.9.0", + "@astrojs/prism": "4.0.1", "github-slugger": "^2.0.0", "hast-util-from-html": "^2.0.3", "hast-util-to-text": "^4.0.2", - "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "mdast-util-definitions": "^6.0.0", "rehype-raw": "^7.0.0", @@ -48,25 +50,125 @@ "remark-parse": "^11.0.0", "remark-rehype": "^11.1.2", "remark-smartypants": "^3.0.2", - "shiki": "^3.19.0", - "smol-toml": "^1.5.2", + "retext-smartypants": "^6.2.0", + "shiki": "^4.0.0", + "smol-toml": "^1.6.0", "unified": "^11.0.5", "unist-util-remove-position": "^5.0.0", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "unist-util-visit-parents": "^6.0.2", "vfile": "^6.0.3" } }, + "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/core": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz", + "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.0.2", + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-javascript": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz", + "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/engine-oniguruma": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz", + "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/langs": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz", + "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/themes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz", + "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/@shikijs/types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", + "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@astrojs/markdown-remark/node_modules/shiki": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz", + "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.0.2", + "@shikijs/engine-javascript": "4.0.2", + "@shikijs/engine-oniguruma": "4.0.2", + "@shikijs/langs": "4.0.2", + "@shikijs/themes": "4.0.2", + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@astrojs/mdx": { - "version": "4.3.13", - "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-4.3.13.tgz", - "integrity": "sha512-IHDHVKz0JfKBy3//52JSiyWv089b7GVSChIXLrlUOoTLWowG3wr2/8hkaEgEyd/vysvNQvGk+QhysXpJW5ve6Q==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-5.0.4.tgz", + "integrity": "sha512-tSbuuYueNODiFAFaME7pjHY5lOLoxBYJi1cKd6scw9+a4ZO7C7UGdafEoVAQvOV2eO8a6RaHSAJYGVPL1w8BPA==", "license": "MIT", "dependencies": { - "@astrojs/markdown-remark": "6.3.10", + "@astrojs/markdown-remark": "7.1.1", "@mdx-js/mdx": "^3.1.1", - "acorn": "^8.15.0", - "es-module-lexer": "^1.7.0", + "acorn": "^8.16.0", + "es-module-lexer": "^2.0.0", "estree-util-visit": "^2.0.0", "hast-util-to-html": "^9.0.5", "piccolore": "^0.1.3", @@ -74,54 +176,53 @@ "remark-gfm": "^4.0.1", "remark-smartypants": "^3.0.2", "source-map": "^0.7.6", - "unist-util-visit": "^5.0.0", + "unist-util-visit": "^5.1.0", "vfile": "^6.0.3" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": ">=22.12.0" }, "peerDependencies": { - "astro": "^5.0.0" + "astro": "^6.0.0" } }, "node_modules/@astrojs/prism": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.3.0.tgz", - "integrity": "sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-4.0.1.tgz", + "integrity": "sha512-nksZQVjlferuWzhPsBpQ1JE5XuKAf1id1/9Hj4a9KG4+ofrlzxUUwX4YGQF/SuDiuiGKEnzopGOt38F3AnVWsQ==", "license": "MIT", "dependencies": { "prismjs": "^1.30.0" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0" + "node": ">=22.12.0" } }, "node_modules/@astrojs/sitemap": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.0.tgz", - "integrity": "sha512-+qxjUrz6Jcgh+D5VE1gKUJTA3pSthuPHe6Ao5JCxok794Lewx8hBFaWHtOnN0ntb2lfOf7gvOi9TefUswQ/ZVA==", + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/@astrojs/sitemap/-/sitemap-3.7.2.tgz", + "integrity": "sha512-PqkzkcZTb5ICiyIR8VoKbIAP/laNRXi5tw616N1Ckk+40oNB8Can1AzVV56lrbC5GKSZFCyJYUVYqVivMisvpA==", "license": "MIT", "dependencies": { - "sitemap": "^8.0.2", + "sitemap": "^9.0.0", "stream-replace-string": "^2.0.0", - "zod": "^3.25.76" + "zod": "^4.3.6" } }, "node_modules/@astrojs/starlight": { - "version": "0.37.6", - "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.37.6.tgz", - "integrity": "sha512-wQrKwH431q+8FsLBnNQeG+R36TMtEGxTQ2AuiVpcx9APcazvL3n7wVW8mMmYyxX0POjTnxlcWPkdMGR3Yj1L+w==", + "version": "0.38.4", + "resolved": "https://registry.npmjs.org/@astrojs/starlight/-/starlight-0.38.4.tgz", + "integrity": "sha512-TGFIr2aVC+gcZCPQzJOO4ZnA/yL3jRnsUDcKlVdEhxhxaOQnWr9lZ9MRScg9zU6uh3HVeZAmmjkLCdTlHdcaZA==", "license": "MIT", - "peer": true, "dependencies": { - "@astrojs/markdown-remark": "^6.3.1", - "@astrojs/mdx": "^4.2.3", - "@astrojs/sitemap": "^3.3.0", + "@astrojs/markdown-remark": "^7.0.0", + "@astrojs/mdx": "^5.0.0", + "@astrojs/sitemap": "^3.7.1", "@pagefind/default-ui": "^1.3.0", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", "@types/mdast": "^4.0.4", - "astro-expressive-code": "^0.41.1", + "astro-expressive-code": "^0.41.6", "bcp-47": "^2.1.0", "hast-util-from-html": "^2.0.1", "hast-util-select": "^6.0.2", @@ -144,21 +245,20 @@ "vfile": "^6.0.2" }, "peerDependencies": { - "astro": "^5.5.0" + "astro": "^6.0.0" } }, "node_modules/@astrojs/telemetry": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.0.tgz", - "integrity": "sha512-UFBgfeldP06qu6khs/yY+q1cDAaArM2/7AEIqQ9Cuvf7B1hNLq0xDrZkct+QoIGyjq56y8IaE2I3CTvG99mlhQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@astrojs/telemetry/-/telemetry-3.3.1.tgz", + "integrity": "sha512-7fcIxXS9J4ls5tr8b3ww9rbAIz2+HrhNJYZdkAhhB4za/I5IZ/60g+Bs8q7zwG0tOIZfNB4JWhVJ1Qkl/OrNCw==", "license": "MIT", "dependencies": { - "ci-info": "^4.2.0", - "debug": "^4.4.0", + "ci-info": "^4.4.0", "dlv": "^1.1.3", "dset": "^3.1.4", - "is-docker": "^3.0.0", - "is-wsl": "^3.1.0", + "is-docker": "^4.0.0", + "is-wsl": "^3.1.1", "which-pm-runs": "^1.1.0" }, "engines": { @@ -184,9 +284,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.3.tgz", + "integrity": "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -232,6 +332,34 @@ "node": ">=18" } }, + "node_modules/@clack/core": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-1.3.0.tgz", + "integrity": "sha512-xJPHpAmEQUBrXSLx0gF+q5K/IyihXpsHZcha+jB+tyahsKRK3Dxo4D0coZDewHo12NhiuzC3dTtMPbm53GEAAA==", + "license": "MIT", + "dependencies": { + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, + "node_modules/@clack/prompts": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.3.0.tgz", + "integrity": "sha512-GgcWwRCs/xPtaqlMy8qRhPnZf9vlWcWZNHAitnVQ3yk7JmSralSiq5q07yaffYE8SogtDm7zFeKccx1QNVARpw==", + "license": "MIT", + "dependencies": { + "@clack/core": "1.3.0", + "fast-string-width": "^3.0.2", + "fast-wrap-ansi": "^0.2.0", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 20.12.0" + } + }, "node_modules/@ctrl/tinycolor": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", @@ -252,9 +380,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.7.tgz", + "integrity": "sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==", "cpu": [ "ppc64" ], @@ -268,9 +396,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.7.tgz", + "integrity": "sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==", "cpu": [ "arm" ], @@ -284,9 +412,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.7.tgz", + "integrity": "sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==", "cpu": [ "arm64" ], @@ -300,9 +428,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.7.tgz", + "integrity": "sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==", "cpu": [ "x64" ], @@ -316,9 +444,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.7.tgz", + "integrity": "sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==", "cpu": [ "arm64" ], @@ -332,9 +460,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.7.tgz", + "integrity": "sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==", "cpu": [ "x64" ], @@ -348,9 +476,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.7.tgz", + "integrity": "sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==", "cpu": [ "arm64" ], @@ -364,9 +492,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.7.tgz", + "integrity": "sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==", "cpu": [ "x64" ], @@ -380,9 +508,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.7.tgz", + "integrity": "sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==", "cpu": [ "arm" ], @@ -396,9 +524,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.7.tgz", + "integrity": "sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==", "cpu": [ "arm64" ], @@ -412,9 +540,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.7.tgz", + "integrity": "sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==", "cpu": [ "ia32" ], @@ -428,9 +556,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.7.tgz", + "integrity": "sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==", "cpu": [ "loong64" ], @@ -444,9 +572,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.7.tgz", + "integrity": "sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==", "cpu": [ "mips64el" ], @@ -460,9 +588,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.7.tgz", + "integrity": "sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==", "cpu": [ "ppc64" ], @@ -476,9 +604,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.7.tgz", + "integrity": "sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==", "cpu": [ "riscv64" ], @@ -492,9 +620,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.7.tgz", + "integrity": "sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==", "cpu": [ "s390x" ], @@ -508,9 +636,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.7.tgz", + "integrity": "sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==", "cpu": [ "x64" ], @@ -524,9 +652,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.7.tgz", + "integrity": "sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==", "cpu": [ "arm64" ], @@ -540,9 +668,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.7.tgz", + "integrity": "sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==", "cpu": [ "x64" ], @@ -556,9 +684,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.7.tgz", + "integrity": "sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==", "cpu": [ "arm64" ], @@ -572,9 +700,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.7.tgz", + "integrity": "sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==", "cpu": [ "x64" ], @@ -588,9 +716,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.7.tgz", + "integrity": "sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==", "cpu": [ "arm64" ], @@ -604,9 +732,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.7.tgz", + "integrity": "sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==", "cpu": [ "x64" ], @@ -620,9 +748,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.7.tgz", + "integrity": "sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==", "cpu": [ "arm64" ], @@ -636,9 +764,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.7.tgz", + "integrity": "sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==", "cpu": [ "ia32" ], @@ -652,9 +780,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.7.tgz", + "integrity": "sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==", "cpu": [ "x64" ], @@ -1339,9 +1467,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.57.1.tgz", - "integrity": "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", "cpu": [ "arm" ], @@ -1352,9 +1480,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.57.1.tgz", - "integrity": "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", "cpu": [ "arm64" ], @@ -1365,9 +1493,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.57.1.tgz", - "integrity": "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", "cpu": [ "arm64" ], @@ -1378,9 +1506,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.57.1.tgz", - "integrity": "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", "cpu": [ "x64" ], @@ -1391,9 +1519,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.57.1.tgz", - "integrity": "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", "cpu": [ "arm64" ], @@ -1404,9 +1532,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.57.1.tgz", - "integrity": "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", "cpu": [ "x64" ], @@ -1417,9 +1545,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.57.1.tgz", - "integrity": "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", "cpu": [ "arm" ], @@ -1430,9 +1558,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.57.1.tgz", - "integrity": "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", "cpu": [ "arm" ], @@ -1443,9 +1571,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.57.1.tgz", - "integrity": "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", "cpu": [ "arm64" ], @@ -1456,9 +1584,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.57.1.tgz", - "integrity": "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", "cpu": [ "arm64" ], @@ -1469,9 +1597,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.57.1.tgz", - "integrity": "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", "cpu": [ "loong64" ], @@ -1482,9 +1610,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.57.1.tgz", - "integrity": "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", "cpu": [ "loong64" ], @@ -1495,9 +1623,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.57.1.tgz", - "integrity": "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", "cpu": [ "ppc64" ], @@ -1508,9 +1636,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.57.1.tgz", - "integrity": "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", "cpu": [ "ppc64" ], @@ -1521,9 +1649,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.57.1.tgz", - "integrity": "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", "cpu": [ "riscv64" ], @@ -1534,9 +1662,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.57.1.tgz", - "integrity": "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", "cpu": [ "riscv64" ], @@ -1547,9 +1675,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.57.1.tgz", - "integrity": "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", "cpu": [ "s390x" ], @@ -1560,9 +1688,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.57.1.tgz", - "integrity": "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", "cpu": [ "x64" ], @@ -1573,9 +1701,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.57.1.tgz", - "integrity": "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", "cpu": [ "x64" ], @@ -1586,9 +1714,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.57.1.tgz", - "integrity": "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", "cpu": [ "x64" ], @@ -1599,9 +1727,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.57.1.tgz", - "integrity": "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", "cpu": [ "arm64" ], @@ -1612,9 +1740,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.57.1.tgz", - "integrity": "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", "cpu": [ "arm64" ], @@ -1625,9 +1753,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.57.1.tgz", - "integrity": "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", "cpu": [ "ia32" ], @@ -1638,9 +1766,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.57.1.tgz", - "integrity": "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", "cpu": [ "x64" ], @@ -1651,9 +1779,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.57.1.tgz", - "integrity": "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", "cpu": [ "x64" ], @@ -1705,6 +1833,33 @@ "@shikijs/types": "3.22.0" } }, + "node_modules/@shikijs/primitive": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/primitive/-/primitive-4.0.2.tgz", + "integrity": "sha512-M6UMPrSa3fN5ayeJwFVl9qWofl273wtK1VG8ySDZ1mQBfhCpdd8nEx7nPZ/tk7k+TYcpqBZzj/AnwxT9lO+HJw==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@shikijs/primitive/node_modules/@shikijs/types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", + "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@shikijs/themes": { "version": "3.22.0", "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.22.0.tgz", @@ -1800,9 +1955,9 @@ } }, "node_modules/@types/node": { - "version": "25.2.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.2.0.tgz", - "integrity": "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w==", + "version": "24.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz", + "integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -1830,11 +1985,10 @@ "license": "ISC" }, "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1851,80 +2005,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/ansi-align": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", - "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", - "license": "ISC", - "dependencies": { - "string-width": "^4.1.0" - } - }, - "node_modules/ansi-align/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==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-align/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==", - "license": "MIT" - }, - "node_modules/ansi-align/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==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-align/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==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -1939,9 +2019,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "license": "MIT", "engines": { "node": ">=8.6" @@ -1991,81 +2071,71 @@ } }, "node_modules/astro": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/astro/-/astro-5.17.1.tgz", - "integrity": "sha512-oD3tlxTaVWGq/Wfbqk6gxzVRz98xa/rYlpe+gU2jXJMSD01k6sEDL01ZlT8mVSYB/rMgnvIOfiQQ3BbLdN237A==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/astro/-/astro-6.2.1.tgz", + "integrity": "sha512-3g1sYNly+QAkuO5ErNEQBYvsxorNDSCUNIeStBs+kcXGchvKQl1Q9EuDNOvSg010XLlHJFLVFZs9LV18Jjp4Hg==", "license": "MIT", - "peer": true, "dependencies": { - "@astrojs/compiler": "^2.13.0", - "@astrojs/internal-helpers": "0.7.5", - "@astrojs/markdown-remark": "6.3.10", - "@astrojs/telemetry": "3.3.0", + "@astrojs/compiler": "^4.0.0", + "@astrojs/internal-helpers": "0.9.0", + "@astrojs/markdown-remark": "7.1.1", + "@astrojs/telemetry": "3.3.1", "@capsizecss/unpack": "^4.0.0", + "@clack/prompts": "^1.1.0", "@oslojs/encoding": "^1.1.0", "@rollup/pluginutils": "^5.3.0", - "acorn": "^8.15.0", "aria-query": "^5.3.2", "axobject-query": "^4.1.0", - "boxen": "8.0.1", - "ci-info": "^4.3.1", + "ci-info": "^4.4.0", "clsx": "^2.1.1", - "common-ancestor-path": "^1.0.1", + "common-ancestor-path": "^2.0.0", "cookie": "^1.1.1", - "cssesc": "^3.0.0", - "debug": "^4.4.3", - "deterministic-object-hash": "^2.0.2", - "devalue": "^5.6.2", + "devalue": "^5.6.3", "diff": "^8.0.3", - "dlv": "^1.1.3", "dset": "^3.1.4", - "es-module-lexer": "^1.7.0", - "esbuild": "^0.25.0", - "estree-walker": "^3.0.3", + "es-module-lexer": "^2.0.0", + "esbuild": "^0.27.3", "flattie": "^1.1.1", - "fontace": "~0.4.0", + "fontace": "~0.4.1", "github-slugger": "^2.0.0", "html-escaper": "3.0.3", "http-cache-semantics": "^4.2.0", - "import-meta-resolve": "^4.2.0", "js-yaml": "^4.1.1", "magic-string": "^0.30.21", - "magicast": "^0.5.1", + "magicast": "^0.5.2", "mrmime": "^2.0.1", "neotraverse": "^0.6.18", - "p-limit": "^6.2.0", - "p-queue": "^8.1.1", + "obug": "^2.1.1", + "p-limit": "^7.3.0", + "p-queue": "^9.1.0", "package-manager-detector": "^1.6.0", "piccolore": "^0.1.3", - "picomatch": "^4.0.3", - "prompts": "^2.4.2", + "picomatch": "^4.0.4", "rehype": "^13.0.2", - "semver": "^7.7.3", - "shiki": "^3.21.0", + "semver": "^7.7.4", + "shiki": "^4.0.2", "smol-toml": "^1.6.0", - "svgo": "^4.0.0", - "tinyexec": "^1.0.2", + "svgo": "^4.0.1", + "tinyclip": "^0.1.12", + "tinyexec": "^1.0.4", "tinyglobby": "^0.2.15", "tsconfck": "^3.1.6", "ultrahtml": "^1.6.0", - "unifont": "~0.7.3", - "unist-util-visit": "^5.0.0", - "unstorage": "^1.17.4", + "unifont": "~0.7.4", + "unist-util-visit": "^5.1.0", + "unstorage": "^1.17.5", "vfile": "^6.0.3", - "vite": "^6.4.1", - "vitefu": "^1.1.1", + "vite": "^7.3.2", + "vitefu": "^1.1.2", "xxhash-wasm": "^1.1.0", - "yargs-parser": "^21.1.1", - "yocto-spinner": "^0.2.3", - "zod": "^3.25.76", - "zod-to-json-schema": "^3.25.1", - "zod-to-ts": "^1.2.0" + "yargs-parser": "^22.0.0", + "zod": "^4.3.6" }, "bin": { - "astro": "astro.js" + "astro": "bin/astro.mjs" }, "engines": { - "node": "18.20.8 || ^20.3.0 || >=22.0.0", + "node": ">=22.12.0", "npm": ">=9.6.5", "pnpm": ">=7.1.0" }, @@ -2089,6 +2159,105 @@ "astro": "^4.0.0-beta || ^5.0.0-beta || ^3.3.0 || ^6.0.0-beta" } }, + "node_modules/astro/node_modules/@shikijs/core": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-4.0.2.tgz", + "integrity": "sha512-hxT0YF4ExEqB8G/qFdtJvpmHXBYJ2lWW7qTHDarVkIudPFE6iCIrqdgWxGn5s+ppkGXI0aEGlibI0PAyzP3zlw==", + "license": "MIT", + "dependencies": { + "@shikijs/primitive": "4.0.2", + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4", + "hast-util-to-html": "^9.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/astro/node_modules/@shikijs/engine-javascript": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-4.0.2.tgz", + "integrity": "sha512-7PW0Nm49DcoUIQEXlJhNNBHyoGMjalRETTCcjMqEaMoJRLljy1Bi/EGV3/qLBgLKQejdspiiYuHGQW6dX94Nag==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "oniguruma-to-es": "^4.3.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/astro/node_modules/@shikijs/engine-oniguruma": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-4.0.2.tgz", + "integrity": "sha512-UpCB9Y2sUKlS9z8juFSKz7ZtysmeXCgnRF0dlhXBkmQnek7lAToPte8DkxmEYGNTMii72zU/lyXiCB6StuZeJg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/astro/node_modules/@shikijs/langs": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-4.0.2.tgz", + "integrity": "sha512-KaXby5dvoeuZzN0rYQiPMjFoUrz4hgwIE+D6Du9owcHcl6/g16/yT5BQxSW5cGt2MZBz6Hl0YuRqf12omRfUUg==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/astro/node_modules/@shikijs/themes": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-4.0.2.tgz", + "integrity": "sha512-mjCafwt8lJJaVSsQvNVrJumbnnj1RI8jbUKrPKgE6E3OvQKxnuRoBaYC51H4IGHePsGN/QtALglWBU7DoKDFnA==", + "license": "MIT", + "dependencies": { + "@shikijs/types": "4.0.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/astro/node_modules/@shikijs/types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-4.0.2.tgz", + "integrity": "sha512-qzbeRooUTPnLE+sHD/Z8DStmaDgnbbc/pMrU203950aRqjX/6AFHeDYT+j00y2lPdz0ywJKx7o/7qnqTivtlXg==", + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/astro/node_modules/shiki": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-4.0.2.tgz", + "integrity": "sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==", + "license": "MIT", + "dependencies": { + "@shikijs/core": "4.0.2", + "@shikijs/engine-javascript": "4.0.2", + "@shikijs/engine-oniguruma": "4.0.2", + "@shikijs/langs": "4.0.2", + "@shikijs/themes": "4.0.2", + "@shikijs/types": "4.0.2", + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2108,12 +2277,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/base-64": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz", - "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==", - "license": "MIT" - }, "node_modules/bcp-47": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz", @@ -2145,40 +2308,6 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, - "node_modules/boxen": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-8.0.1.tgz", - "integrity": "sha512-F3PH5k5juxom4xktynS7MoFY+NUWH5LC4CnH11YB8NPew+HLpmBLCybSAEyb2F+4pRXhuhWqFesoQd6DAyc2hw==", - "license": "MIT", - "dependencies": { - "ansi-align": "^3.0.1", - "camelcase": "^8.0.0", - "chalk": "^5.3.0", - "cli-boxes": "^3.0.0", - "string-width": "^7.2.0", - "type-fest": "^4.21.0", - "widest-line": "^5.0.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/camelcase": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", - "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/ccount": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", @@ -2189,18 +2318,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", @@ -2271,18 +2388,6 @@ "node": ">=8" } }, - "node_modules/cli-boxes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", - "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -2322,10 +2427,13 @@ } }, "node_modules/common-ancestor-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "license": "ISC" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-2.0.0.tgz", + "integrity": "sha512-dnN3ibLeoRf2HNC+OlCiNc5d2zxbLJXOtiZUudNFSXZrNSydxcCsSpRzXwfu7BBWCIfHPw+xTayeBvJCP/D8Ng==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } }, "node_modules/cookie": { "version": "1.1.1", @@ -2341,9 +2449,9 @@ } }, "node_modules/cookie-es": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz", - "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.3.tgz", + "integrity": "sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==", "license": "MIT" }, "node_modules/crossws": { @@ -2388,13 +2496,13 @@ "license": "MIT" }, "node_modules/css-tree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "license": "MIT", "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" @@ -2488,9 +2596,9 @@ } }, "node_modules/defu": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz", - "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", "license": "MIT" }, "node_modules/dequal": { @@ -2517,22 +2625,10 @@ "node": ">=8" } }, - "node_modules/deterministic-object-hash": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/deterministic-object-hash/-/deterministic-object-hash-2.0.2.tgz", - "integrity": "sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==", - "license": "MIT", - "dependencies": { - "base-64": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/devalue": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.6.2.tgz", - "integrity": "sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.8.0.tgz", + "integrity": "sha512-2zA9pFEsnp7vWBZbXF5JAgAq0fsUIt/1XPbRiAmRV3lp/2C3upzH+sADiyy66aFCihoLEsrQHxNM5w1gIDfsBg==", "license": "MIT" }, "node_modules/devlop": { @@ -2652,12 +2748,6 @@ "node": ">=4" } }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "license": "MIT" - }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -2671,9 +2761,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", "license": "MIT" }, "node_modules/esast-util-from-estree": { @@ -2709,9 +2799,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "version": "0.27.7", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.7.tgz", + "integrity": "sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -2721,32 +2811,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" + "@esbuild/aix-ppc64": "0.27.7", + "@esbuild/android-arm": "0.27.7", + "@esbuild/android-arm64": "0.27.7", + "@esbuild/android-x64": "0.27.7", + "@esbuild/darwin-arm64": "0.27.7", + "@esbuild/darwin-x64": "0.27.7", + "@esbuild/freebsd-arm64": "0.27.7", + "@esbuild/freebsd-x64": "0.27.7", + "@esbuild/linux-arm": "0.27.7", + "@esbuild/linux-arm64": "0.27.7", + "@esbuild/linux-ia32": "0.27.7", + "@esbuild/linux-loong64": "0.27.7", + "@esbuild/linux-mips64el": "0.27.7", + "@esbuild/linux-ppc64": "0.27.7", + "@esbuild/linux-riscv64": "0.27.7", + "@esbuild/linux-s390x": "0.27.7", + "@esbuild/linux-x64": "0.27.7", + "@esbuild/netbsd-arm64": "0.27.7", + "@esbuild/netbsd-x64": "0.27.7", + "@esbuild/openbsd-arm64": "0.27.7", + "@esbuild/openbsd-x64": "0.27.7", + "@esbuild/openharmony-arm64": "0.27.7", + "@esbuild/sunos-x64": "0.27.7", + "@esbuild/win32-arm64": "0.27.7", + "@esbuild/win32-ia32": "0.27.7", + "@esbuild/win32-x64": "0.27.7" } }, "node_modules/escape-string-regexp": { @@ -2876,6 +2966,30 @@ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.0.tgz", + "integrity": "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==", + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, "node_modules/fdir": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", @@ -2937,18 +3051,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/github-slugger": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", @@ -2956,14 +3058,14 @@ "license": "ISC" }, "node_modules/h3": { - "version": "1.15.5", - "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.5.tgz", - "integrity": "sha512-xEyq3rSl+dhGX2Lm0+eFQIAzlDN6Fs0EcC4f7BNUmzaRX/PTzeuM+Tr2lHB8FoXggsQIeXLj8EDVgs5ywxyxmg==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.11.tgz", + "integrity": "sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==", "license": "MIT", "dependencies": { - "cookie-es": "^1.2.2", + "cookie-es": "^1.2.3", "crossws": "^0.3.5", - "defu": "^6.1.4", + "defu": "^6.1.6", "destr": "^2.0.5", "iron-webcrypto": "^1.2.1", "node-mock-http": "^1.0.4", @@ -3392,16 +3494,6 @@ "@babel/runtime": "^7.23.2" } }, - "node_modules/import-meta-resolve": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", - "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } - }, "node_modules/inline-style-parser": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz", @@ -3452,29 +3544,20 @@ } }, "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-4.0.0.tgz", + "integrity": "sha512-LHE+wROyG/Y/0ZnbktRCoTix2c1RhgWaZraMZ8o1Q7zCh0VSrICJQO5oqIIISrcSBtrXv0o233w1IYwsWCjTzA==", "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/is-hexadecimal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz", @@ -3503,6 +3586,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-inside-container/node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -3516,9 +3614,9 @@ } }, "node_modules/is-wsl": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", - "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", "license": "MIT", "dependencies": { "is-inside-container": "^1.0.0" @@ -3542,15 +3640,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/klona": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", @@ -3571,9 +3660,9 @@ } }, "node_modules/lru-cache": { - "version": "11.2.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.5.tgz", - "integrity": "sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==", + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -3589,13 +3678,13 @@ } }, "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", + "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", "source-map-js": "^1.2.1" } }, @@ -3945,9 +4034,9 @@ } }, "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "license": "CC0-1.0" }, "node_modules/micromark": { @@ -4774,6 +4863,16 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/ofetch": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.5.1.tgz", @@ -4809,43 +4908,43 @@ } }, "node_modules/p-limit": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", - "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-7.3.0.tgz", + "integrity": "sha512-7cIXg/Z0M5WZRblrsOla88S4wAK+zOQQWeBYfV3qJuJXMr+LnbYjaadrFaS0JILfEDPVqHyKnZ1Z/1d6J9VVUw==", "license": "MIT", "dependencies": { - "yocto-queue": "^1.1.1" + "yocto-queue": "^1.2.1" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-queue": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", - "integrity": "sha512-aNZ+VfjobsWryoiPnEApGGmf5WmNsCo9xu8dfaYamG5qaLP7ClhLN6NgsFe6SwJ2UbLEBK5dv9x8Mn5+RVhMWQ==", + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-9.2.0.tgz", + "integrity": "sha512-dWgLE8AH0HjQ9fe74pUkKkvzzYT18Inp4zra3lKHnnwqGvcfcUBrvF2EAVX+envufDNBOzpPq/IBUONDbI7+3g==", "license": "MIT", "dependencies": { - "eventemitter3": "^5.0.1", - "p-timeout": "^6.1.2" + "eventemitter3": "^5.0.4", + "p-timeout": "^7.0.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-timeout": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", - "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-7.0.1.tgz", + "integrity": "sha512-AxTM2wDGORHGEkPCt8yqxOTMgpfbEHqF51f/5fJCmwFC3C/zNcGT63SymH2ttOAaiIws2zVg4+izQCjrakcwHg==", "license": "MIT", "engines": { - "node": ">=14.16" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4942,9 +5041,9 @@ "license": "ISC" }, "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -4972,7 +5071,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -5029,19 +5127,6 @@ "node": ">=6" } }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "license": "MIT", - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/property-information": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", @@ -5434,11 +5519,10 @@ } }, "node_modules/rollup": { - "version": "4.57.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.57.1.tgz", - "integrity": "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A==", + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -5450,47 +5534,47 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.57.1", - "@rollup/rollup-android-arm64": "4.57.1", - "@rollup/rollup-darwin-arm64": "4.57.1", - "@rollup/rollup-darwin-x64": "4.57.1", - "@rollup/rollup-freebsd-arm64": "4.57.1", - "@rollup/rollup-freebsd-x64": "4.57.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", - "@rollup/rollup-linux-arm-musleabihf": "4.57.1", - "@rollup/rollup-linux-arm64-gnu": "4.57.1", - "@rollup/rollup-linux-arm64-musl": "4.57.1", - "@rollup/rollup-linux-loong64-gnu": "4.57.1", - "@rollup/rollup-linux-loong64-musl": "4.57.1", - "@rollup/rollup-linux-ppc64-gnu": "4.57.1", - "@rollup/rollup-linux-ppc64-musl": "4.57.1", - "@rollup/rollup-linux-riscv64-gnu": "4.57.1", - "@rollup/rollup-linux-riscv64-musl": "4.57.1", - "@rollup/rollup-linux-s390x-gnu": "4.57.1", - "@rollup/rollup-linux-x64-gnu": "4.57.1", - "@rollup/rollup-linux-x64-musl": "4.57.1", - "@rollup/rollup-openbsd-x64": "4.57.1", - "@rollup/rollup-openharmony-arm64": "4.57.1", - "@rollup/rollup-win32-arm64-msvc": "4.57.1", - "@rollup/rollup-win32-ia32-msvc": "4.57.1", - "@rollup/rollup-win32-x64-gnu": "4.57.1", - "@rollup/rollup-win32-x64-msvc": "4.57.1", + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", "fsevents": "~2.3.2" } }, "node_modules/sax": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", - "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "license": "BlueOak-1.0.0", "engines": { "node": ">=11.0.0" } }, "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -5566,34 +5650,28 @@ "license": "MIT" }, "node_modules/sitemap": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.2.tgz", - "integrity": "sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-9.0.1.tgz", + "integrity": "sha512-S6hzjGJSG3d6if0YoF5kTyeRJvia6FSTBroE5fQ0bu1QNxyJqhhinfUsXi9fH3MgtXODWvwo2BDyQSnhPQ88uQ==", "license": "MIT", "dependencies": { - "@types/node": "^17.0.5", + "@types/node": "^24.9.2", "@types/sax": "^1.2.1", "arg": "^5.0.0", "sax": "^1.4.1" }, "bin": { - "sitemap": "dist/cli.js" + "sitemap": "dist/esm/cli.js" }, "engines": { - "node": ">=14.0.0", - "npm": ">=6.0.0" + "node": ">=20.19.5", + "npm": ">=10.8.2" } }, - "node_modules/sitemap/node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", - "license": "MIT" - }, "node_modules/smol-toml": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.0.tgz", - "integrity": "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.6.1.tgz", + "integrity": "sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==", "license": "BSD-3-Clause", "engines": { "node": ">= 18" @@ -5675,23 +5753,6 @@ "integrity": "sha512-TlnjJ1C0QrmxRNrON00JvaFFlNh5TTG00APw23j74ET7gkQpTASi6/L2fuiav8pzK715HXtUeClpBTw2NPSn6w==", "license": "MIT" }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -5706,21 +5767,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/style-to-js": { "version": "1.1.21", "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.21.tgz", @@ -5740,9 +5786,9 @@ } }, "node_modules/svgo": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz", - "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz", + "integrity": "sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==", "license": "MIT", "dependencies": { "commander": "^11.1.0", @@ -5751,7 +5797,7 @@ "css-what": "^6.1.0", "csso": "^5.0.5", "picocolors": "^1.1.1", - "sax": "^1.4.1" + "sax": "^1.5.0" }, "bin": { "svgo": "bin/svgo.js" @@ -5770,23 +5816,32 @@ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==", "license": "MIT" }, + "node_modules/tinyclip": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/tinyclip/-/tinyclip-0.1.12.tgz", + "integrity": "sha512-Ae3OVUqifDw0wBriIBS7yVaW44Dp6eSHQcyq4Igc7eN2TJH/2YsicswaW+J/OuMvhpDPOKEgpAZCjkb4hpoyeA==", + "license": "MIT", + "engines": { + "node": "^16.14.0 || >= 17.3.0" + } + }, "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.2.tgz", + "integrity": "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==", "license": "MIT", "engines": { "node": ">=18" } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -5842,36 +5897,10 @@ "license": "0BSD", "optional": true }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, "node_modules/ufo": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.3.tgz", - "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", "license": "MIT" }, "node_modules/ultrahtml": { @@ -5912,9 +5941,9 @@ } }, "node_modules/unifont": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.3.tgz", - "integrity": "sha512-b0GtQzKCyuSHGsfj5vyN8st7muZ6VCI4XD4vFlr7Uy1rlWVYxC3npnfk8MyreHxJYrz1ooLDqDzFe9XqQTlAhA==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/unifont/-/unifont-0.7.4.tgz", + "integrity": "sha512-oHeis4/xl42HUIeHuNZRGEvxj5AaIKR+bHPNegRq5LV1gdc3jundpONbjglKpihmJf+dswygdMJn3eftGIMemg==", "license": "MIT", "dependencies": { "css-tree": "^3.1.0", @@ -6059,16 +6088,16 @@ } }, "node_modules/unstorage": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.4.tgz", - "integrity": "sha512-fHK0yNg38tBiJKp/Vgsq4j0JEsCmgqH58HAn707S7zGkArbZsVr/CwINoi+nh3h98BRCwKvx1K3Xg9u3VV83sw==", + "version": "1.17.5", + "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.5.tgz", + "integrity": "sha512-0i3iqvRfx29hkNntHyQvJTpf5W9dQ9ZadSoRU8+xVlhVtT7jAX57fazYO9EHvcRCfBCyi5YRya7XCDOsbTgkPg==", "license": "MIT", "dependencies": { "anymatch": "^3.1.3", "chokidar": "^5.0.0", "destr": "^2.0.5", - "h3": "^1.15.5", - "lru-cache": "^11.2.0", + "h3": "^1.15.10", + "lru-cache": "^11.2.7", "node-fetch-native": "^1.6.7", "ofetch": "^1.5.1", "ufo": "^1.6.3" @@ -6203,24 +6232,23 @@ } }, "node_modules/vite": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", - "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", + "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", "license": "MIT", - "peer": true, "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.4", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.13" + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -6229,14 +6257,14 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@types/node": "^20.19.0 || >=22.12.0", "jiti": ">=1.21.0", - "less": "*", + "less": "^4.0.0", "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" @@ -6278,9 +6306,9 @@ } }, "node_modules/vitefu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz", - "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.3.tgz", + "integrity": "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==", "license": "MIT", "workspaces": [ "tests/deps/*", @@ -6288,7 +6316,7 @@ "tests/projects/workspace/packages/*" ], "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "vite": { @@ -6315,38 +6343,6 @@ "node": ">=4" } }, - "node_modules/widest-line": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-5.0.0.tgz", - "integrity": "sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==", - "license": "MIT", - "dependencies": { - "string-width": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/xxhash-wasm": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/xxhash-wasm/-/xxhash-wasm-1.1.0.tgz", @@ -6354,12 +6350,12 @@ "license": "MIT" }, "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==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "license": "ISC", "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yocto-queue": { @@ -6374,61 +6370,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yocto-spinner": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/yocto-spinner/-/yocto-spinner-0.2.3.tgz", - "integrity": "sha512-sqBChb33loEnkoXte1bLg45bEBsOP9N1kzQh5JZNKj/0rik4zAPTNSAVPj3uQAdc6slYJ0Ksc403G2XgxsJQFQ==", - "license": "MIT", - "dependencies": { - "yoctocolors": "^2.1.1" - }, - "engines": { - "node": ">=18.19" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yoctocolors": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz", - "integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.2.tgz", + "integrity": "sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } }, - "node_modules/zod-to-json-schema": { - "version": "3.25.1", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz", - "integrity": "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25 || ^4" - } - }, - "node_modules/zod-to-ts": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/zod-to-ts/-/zod-to-ts-1.2.0.tgz", - "integrity": "sha512-x30XE43V+InwGpvTySRNz9kB7qFU8DlyEy7BsSTCHPH1R0QasMmHWZDCzYm6bVXtj/9NNJAZF3jW8rzFvH5OFA==", - "peerDependencies": { - "typescript": "^4.9.4 || ^5.0.2", - "zod": "^3" - } - }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/docs/package.json b/docs/package.json index 5f4782b..c2ca407 100644 --- a/docs/package.json +++ b/docs/package.json @@ -10,8 +10,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/starlight": "^0.37.6", - "astro": "^5.17.1", + "@astrojs/starlight": "^0.38.4", + "astro": "^6.2.1", "sharp": "^0.34.5", "starlight-auto-sidebar": "^0.1.0", "starlight-giscus": "^0.8.1", diff --git a/docs/src/content/docs/api/.gitignore b/docs/src/content/docs/api/.gitignore new file mode 100644 index 0000000..a214ee7 --- /dev/null +++ b/docs/src/content/docs/api/.gitignore @@ -0,0 +1,2 @@ +# API docs are considered temporary artifacts and should be regenerated by the CI +**/*.md diff --git a/docs/src/content/docs/api/index.mdx b/docs/src/content/docs/api/index.mdx new file mode 100644 index 0000000..202e12c --- /dev/null +++ b/docs/src/content/docs/api/index.mdx @@ -0,0 +1,17 @@ +--- +title: QPlayer API Reference +description: The reference manual for the QPlayer programming API. +order: 0 +--- + +This section of the manual contains the complete API reference for the latest pre-release of +QPlayer. This API reference is automatically generated from the source code by the build +system using [DocFX](https://dotnet.github.io/docfx/) and our own custom post-processor: +*StarlightDocNet*. Being auto-generated, it's possible for this reference to be incomplete +or innacurate at times, as always the ultimate source of truth is the source code. + +Please read the [Writing Plugins](#) guide for information about extending QPlayer. + +:::note +This section is intended for developers seeking write plugins or add new functionality to QPlayer. +::: diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index 8b5ff90..cb60b01 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -22,11 +22,11 @@ import { Card, CardGrid } from '@astrojs/starlight/components'; - QPlayer is free now and forever, thanks to it's permissive MIT license, + QPlayer is free now and forever, thanks to it's permissive GPL license, you are free to use and adapt QPlayer however you like! - Supports playback of many common file formats, including: WAV, MP3, etc... + Supports playback of many common file formats, including: WAV, MP3, FLAC, etc... Cues containing media files, stop cues, fade cues, and more, are all added to one cue stack From abba21692aa3a48d8258cda3eb454383f26acb09 Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sun, 3 May 2026 07:48:08 +0100 Subject: [PATCH 4/8] Remove redundant file --- docs/api_docs.xml | 3184 --------------------------------------------- 1 file changed, 3184 deletions(-) delete mode 100644 docs/api_docs.xml diff --git a/docs/api_docs.xml b/docs/api_docs.xml deleted file mode 100644 index 6e2c2fd..0000000 --- a/docs/api_docs.xml +++ /dev/null @@ -1,3184 +0,0 @@ - - - - QPlayer - - - - - Interaction logic for App.xaml - - - App - - - - - InitializeComponent - - - - - Application Entry Point. - - - - - An array of strings representing the current state of each worker thread. - - - - - The number of samples to read between each metering event. - - - - - An event raised every samples with metering information. - - - - - When building a mastering chain, use this sample provider as the source, it should never be read from directly. - - - - - Registers the given sample provider as a mastering chain, this is the last sample provider before the output. - - - - - - Creates an ISampleProvider which converts the given sample stream to one compatible with the mixer. - - This converts both Mono to Stereo and resamples the input stream. - - - - - - - - Starts the playback of a sound through the mixer. - - the sample stream to play - a callback raised when the stream is removed from the mixer - - - - Stops the playback of a sound stream. - - the sample stream to stop - - - - Gets whether a sound stream is currently playing. - - - - - - - Stops all sound sources. - - - - - Copies the desired number of samples from the delay line to the given buffer. May not entirely fill the given - buffer if the delay line doesn't contain that many samples. - - - - - - - - Pushes the span of samples into this delay buffer. - - - - - - Reads the specified number of samples from the input stream and pushes them to the delay buffer. - - - - - - - - - Reads the specified number of samples from the delay buffer with the specified amount of delay. - This should imediately preceed a call to and should read - the same number of samples the read call returned. - - - - - - - - - Applies a biquad filter to the input signal. Automatically picks a vectorised implementation if available. - - The history buffer, must be at least 4* long. - The index into the history buffer to use (this is internally multiplied by - the number of history samples the filter uses (ie: 4*)). - The number of interleaved channels in the input buffer. - The filter coefficients to apply to the signal. - The signal to filter. - - - - Applies a biquad filter to the input signal. - - The history buffer, must be at least 4* long. - The sample buffer to process. - The number of interleaved channels in the input buffer. - The index into the history buffer to use (this is internally multiplied by - the number of history samples the filter uses (ie: 4*)). - - - - - - - - - Applies a biquad filter to the input signal. - - The history buffer, must be at least 4* long. - The sample buffer to process. - The number of interleaved channels in the input buffer. - The index into the history buffer to use (this is internally multiplied by - the number of history samples the filter uses (ie: 4*)). - - - - - - - - - Applies a biquad filter to the strided input buffer. Requires FMA instructions. - - The history buffer used by the filter, must be at least 4 * channels long. - The buffer to filter. - The number of interleaved channels in the signal to filter (ie: buffer = [LRLRLRLR..], channels = 2) - The index into the history buffer to use, when chaining multiple filters - (this is the filter index, not the buffer index, so for the second iteration of filtering an index of 1 would be used). - - - - - - - - - The initial volume of the samples processed. - - - - - Starts a new fade operation, cancelling any active fade operation. - - The volume to fade to - The time to fade over in milliseconds - The type of fade to use - Optionally, an event to raise when the fade is completed. true is passed to the - event handler if the fade completed normally, false if it was cancelled. The event is invoked on the - thread that called this method. - Whether the onComplete action should be invoked using the current thread's - synchronization context. - - - - Cancels the active fade operation. - - - - - A that also provides the position within the sample stream. - - - - - The position, in samples, within the sample provider stream. - - - - - A sample provider for which handles looping and start/end time. - - - - - - The length in samples (estimate, for compressed inputs) of the input stream. - - - - - The position in samples (estimate) within the input stream. - - - - - The current playback time within the input stream. - - - - - The length in samples of the input stream, trimmed by the the and . - - - - - The length in samples of this looping sample provider (estimate, for compressed inputs). - - - - - The total diration of the looped input stream, taking into account the start and end times. - - - - - The current playback time within the looped sample, this starts at 0 at the start time and increases continuously as the input is looped. - - - - - The current playback sample position within the looped sample, this starts at 0 at the start time and increases continuously as the input is looped. - - - - - Whether this sample provider should loop the sample indefinitely. Ignores the value. - - - - - The maximum number of this sample provider can play. Use to reset the loop counter. - - - - - The current number of complete loops of the input sample that have been played since the last call to . - - - - - The time in samples to start playback from. - - - - - The time in samples to stop playback at (or the 'out' loop point of the loop). - - - - - The time to start playback from. - - - - - The time at which to stop playback (for a single loop). - - - - - An event raised at the end of each loop played. - - - - - Resets the internal loop and sample counters. Call this every time before playing the sound file. - - - - - Reads samples from the source until we reach the end of a loop (or file) or - the buffer is full (whichever happens sooner). Returns 0 if no more loops - should be played. - - - - - - - - - The number of samples to read between each metering event. - - - - - An event raised every samples with metering information. - - - - - - - - - - - Ensures the audio thread using this mixer has a sufficiently high priority. - Due to the design of NAudio, this works by setting the thread priority the - first time the method is called. - - - - - The initial volume of the samples processed. - - - - - The stereo panning applied to the processed samples. - - - - - The fade in duration in samples. - - Note that this is in mono samples so for a stereo source, this should be half the number of actual processed samples. - - - - - The fade out duration in samples. - - Note that this is in mono samples so for a stereo source, this should be half the number of actual processed samples. - - - - - The time in samples when the fade out should start. - - Note that this is in mono samples so for a stereo source, this should be half the number of actual processed samples. - - - - - A smart audio reader, which picks an appropriate decoder for the given file path, opens the file, - creates any needed stream converters to get a 32bit float sample stream, and buffers audio intelligently. - - The methods are entirely lock-free and intended to be called - from a dedicated audio thread, while all the other methods are intended to be called from the main thread. - This is with the exception of the methods which can be called from a separate - audio buffering thread (this is done automatically, if an is - passed in the constructor). Please be aware that the threading model for this class is quite complicated - (there are potentially 3+ threads with contention over this object), most methods are not reentrant unless - explicitly mentioned (or trivial). - - The lifecycle of this object is described as follows: - - MainThread: - QAudioFileReader::ctor() - \--> registers the new object with the AudioBufferingDispatcher - ... - SamplePosition.set() --> repositions the stream when needed, this blocks until the current FillBuffer operation is complete - - AudioBufferingDispatcher worker: - while true: - if audioFile.NeedsFilling: - FillBuffer() --> fills one of the internal audio buffers if needed - - AudioThread: - Read() --> gets as many samples as are available (or requested) from an audio buffer, never blocks, but may not return as many samples as requested - - - - - - The number of samples in this stream. - - - - - The position in samples within the input stream. - - - - - The starting position in samples within the input stream. Setting this clears the buffer - containing the start of the file used for seamless looping. - - - - - Gets how many samples are still available in the current buffer. - - - - - Gets whether this reader has an empty buffer waiting to be filled with . - - - - - Gets whether this reader has an empty start buffer waiting to be filled . - - - - - Releases the internal buffers used by this reader so they can be reused elsewhere. Call this - method when the audio file is not being played. - - - - - - - - Fill the specified buffer with 32 bit floating point samples. This method is not reentrant. - - - This method might not entirely fill the requested of samples if they're not available yet. - Furthermore, it may return -1 if no samples are currently available but the end of the stream hasn't been - reached yet. A return value of 0 always indicates that the stream has ended. - - The buffer to fill. - The offset into to start writing. - The number of samples requested. - When , syncronously waits for the buffer to fill before returning. - The nunber of samples read from the source. - - - - Fills the internal buffer of this reader with samples. Must be called sufficiently frequently to avoid starving the audio file reader. - This method can be called from external threads, but is not reentrant. - - - - - Fills the special 'start' buffer of this reader with samples. Must be called sufficiently frequently to avoid starving the audio file reader. - This method can be called from external threads, but is not reentrant. - - - - - - - Repeatedly reads from the until either the requested number of samples are - read, or the sample provider returns 0 samples. - - The buffer to read into. - The offset into the buffer to start writing. - How many samples to read. - Whether the returned 0 samples on the last read. - The number of samples read. - - - - Repositions the internal safely, and warms it up by reading into the junk buffer. - - - - - - Intelligently seeks this to the given sample position, reusing existing buffers if - possible. Automatically invalidates the sample buffer if needed. The underlying is not - repositioned until the next read. - - The position in samples to seek to. - - - - Aligns a position in samples to the start of the current frame. Effecitvely this rounds the input - position down to a multiple of the channel count. Note that this is only valid for positive values. - - The position in samples to align. - The aligned position in samples. - - - - This class provides a number of vectorised maths routines, which are optimised for X86 SIMD instructions. - - - - - Pretty prints an audio signal as a waveform. Based on https://github.com/sudara/melatonin_audio_sparklines/blob/main/melatonin_audio_sparklines.h - - The signal is represented as a series of dashes, with a few special characters indicated specific values: - - 0 -- a single 0 value - 0(23) -- 23 consecutive zeros - x -- a zero-crossing - N -- NaN - I -- +-Inf - S -- subnormal values - E -- outside of the -1 to 1 range - - For interleaved multi-channel signals, each chanel is displayed on it's own line. - If a signal is prepended with a + then every sample is >= 0. - - The signal to display. - The number of interleaved channels. - Whether the signal should be collapsed to skip repeated values. - Whether the signal should be normalized. - The maximum number of characters to return. - - - - - Multiplies the contents of span a by the scalar b, mutating a with the result. - - - - - - - - Multiplies the pairs of values in a by the values in b, mutating a with the result. - - - - - - - - Pans a span of interleaved stereo samples left or right. - - Lout = Lin * 1 - max(0,pan) - Rout = Rin * 1 + min(0,pan) - - - - - - - - Computes the element-wise maximum of a signal and a constant. - - - - - - - - Computes the element-wise maximum of two signals. - - - - - - - - Computes the element-wise minimum of x and y, storing the result in x. - - - - - - - - Computes the smooth-minimum of two signals using quadratic interpolation. - See: https://iquilezles.org/articles/smin/ - - - - The blending factor [0-1]. Must be > 0. - - - - - Computes the minimum value in x. - - - - - - - Computes the pair-wise minimum of x, storing the result in x. - - - - - - - Computes: ∑(x[i] * kernel[i]) - - - - - - - - Computes the gain reduction (fraction) required to clip a signal x by threshold. - - - - - - - - Computes the gain reduction (fraction) required to clip a signal x by threshold. - - - The threshold level at which to start reducing gain. - Value between 0-1, where 1 is brickwall limiting. - Value between 0-1, where 0 is a hard knee. Value must be > 0. - Gain multiplier applied to the input signal before clipping. - - - - - Multiplies two signals x and y element-wise and then clamps the resulting signal between [-c, c]. - - - - - - - - - Exactly the same as - but processes interleaved stereo samples instead. - Only processes samples tht can be vectorised, - - Resampling destination. - Resampling source. - The fractional position in the source buffer. - The increment size when sampling the source buffer. - The number of interpolated samples written. - - - - Fully managed resampler, based on Cockos WDL Resampler - - - - - Creates a new Resampler - - - - - Reset - - - - - amount of input that has been received but not yet converted to output, in seconds - - - - - Prepare - note that it is safe to call ResamplePrepare without calling ResampleOut (the next call of ResamplePrepare will function as normal) - nb inbuffer was float **, returning a place to put the in buffer, so we return a buffer and offset - - req_samples is output samples desired if !wantInputDriven, or if wantInputDriven is input samples that we have - - - - returns number of samples desired (put these into *inbuffer) - - - - if numsamples_in < the value return by ResamplePrepare(), then it will be flushed to produce all remaining valid samples - do NOT call with nframes_in greater than the value returned from resamplerprpare()! the extra samples will be ignored. - returns number of samples successfully outputted to out - - - - - This class manages the receiving and sending of MA Midi Show Control packets sent over UDP. - - - - - Asynchronously sends an MA-MSC packet. - - The message to send. - The endpoint to send the message to. - - - - - - - Subscribes an event handler to MSC messages with a given command. - - The commands to subscribe to. - The event handler to fire when a matching message is received. - - - - This is the same as a Goto command in grandMA2. It needs to be followed by a cue number. - - - - - This is the same as a Pause command in grandMA2. This can be followed by a cue number. - - - - - This will "un-plause" a cue. If a specific cue has been paused, then the cue number needs to be specified with this command. - - - - - This can be used to perform a Goto with a specific fade time. It needs both the time and the cue number - in that order. - - - - - Set can be used to set the position of faders. It needs the fader number and page followed by the position. - - - - - This can be used to trigger macros. The macro number needs to follow the command. Only macro 1 to 255 can be triggered. - - - - - This command can be used "Off" executors. This needs to followed by a cue number. - - - - - Represents an MA MSC packet. This is implemented as a union type, make sure to check the - field before reading the corresponding data field. - - - - - This is the same as a Goto command in grandMA2. It needs to be followed by a cue number. - - - - - This is the same as a Pause command in grandMA2. This can be followed by a cue number. - - - - - This will "un-plause" a cue. If a specific cue has been paused, then the cue number needs to be specified with this command. - - - - - This can be used to perform a Goto with a specific fade time. It needs both the time and the cue number - in that order. - - - - - Set can be used to set the position of faders. It needs the fader number and page followed by the position. - - - - - This can be used to trigger macros. The macro number needs to follow the command. Only macro 1 to 255 can be triggered. - - - - - This command can be used "Off" executors. This needs to followed by a cue number. - - - - - Asynchronously sends an OSC packet. - - The message to send. - The endpoint to send the message to. - - - - - - - Subscribes an event handler to OSC messages following a specified pattern. - - - Address patterns are of the form: "/foo/?/bar" -
- Where '?' indicates a wildcard which matches any single address part. -
- The adddress pattern to match. - The event handler to fire when a matching message is received. -
- - - Parses a string representing an OSC message into an address and a list of arguments.
- Arguments must be separated by spaces and are parsed automatically - Supports: - - strings -> Surrounded by double quotes - - ints - - floats - - bools - - blobs -> Surrounded by backticks -
- - -
- - - Stores a compact representation of the audio peaks in an audio file for faster waveform rendering. - - - - - The reduction factor of the highest resolution pyramid. - - - - - The number of bits to shift the reduction factor by between each pyramid. - - - - - The minimum number of samples in a pyramid. - - - - - Every N samples, we store the position in bytes into the file stream for efficient seeking. This is always a power of 2. - - - - - Reads and validates the metadata portion of a . - - This method does not close the stream once complete! - - The binary stream to parse - A new instance parsed from the stream. - - - - - Reads and validates from a stream. - - The binary stream to parse - A new instance parsed from the stream. - - - - Reads and validates from a stream. - - The binary stream to parse - A new instance parsed from the stream. - - - - - Loads a for the given audio file if it's valid, otherwise generates a - new for an audio file if needed. - - The path of the audio to process - The loaded or generated - - - - The exception thrown when a file of an incompatible version is loaded. - - - - - The exception thrown when a file could not be loaded due to it being corrupt. - - - - - Using this attribute on a plugin class implementing allows a custom plugin name to be specified. - - - - - - Using this attribute on a plugin class implementing allows a custom plugin name to be specified. - - - - - - Using this attribute on a plugin class implementing allows a custom plugin author to be specified. - - - - - - Using this attribute on a plugin class implementing allows a custom plugin author to be specified. - - - - - - Using this attribute on a plugin class implementing allows a custom plugin description to be specified. - - - - - - Using this attribute on a plugin class implementing allows a custom plugin description to be specified. - - - - - - Creates a main menu item which invokes this method when clicked. - - Only applicable to parameterless methods and properties on the class implementing . - - The path to the menu item to be created, eg: 'File/Save' - - - - Creates a main menu item which invokes this method when clicked. - - Only applicable to parameterless methods and properties on the class implementing . - - The path to the menu item to be created, eg: 'File/Save' - - - - Registers this class to the project settings panel. - - This class must derive from and be annotated with the - and attributes. - - The heading name for this section in the project settings panel. - - - - Registers this class to the project settings panel. - - This class must derive from and be annotated with the - and attributes. - - The heading name for this section in the project settings panel. - - - - Loads a plugin and it's dependencies in a load context to avoid depedency conflicts. - - - Taken from: https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support - - - - - - Loads a plugin and it's dependencies in a load context to avoid depedency conflicts. - - - Taken from: https://learn.microsoft.com/en-us/dotnet/core/tutorials/creating-app-with-plugin-support - - - - - - Called at startup when the plugin is loaded by QPlayer. - - - - - - Called just before QPlayer exits. - - - - - Called just before QPlayer saves a show file. - - - - - - Called every time QPlayer starts a cue. - - - - - - Called every 250 ms on the UI thread. - - - - - A simple RGBA colour represented as 4 singles. Provides explicit - conversion operators to a number of formats. - - - - - This class contains the relevant code to repair and upgrade old show files. - - - - - Attempts to load a show file one field at a time, skipping any fields which can't be read. - - This method uses fairly inefficient reflection to try and deserialize as much of the show file as possible. - - The contents of show file to load. - A ShowFile, with as many parameters loaded as possible. - - - - - Attempts to load a show file one field at a time, skipping any fields which can't be read. - - This method uses fairly inefficient reflection to try and deserialize as much of the show file as possible. - - The contents of show file to load. - A ShowFile, with as many parameters loaded as possible. - - - - - Attempts to load a show file one field at a time, skipping any fields which can't be read. - - This method uses fairly inefficient reflection to try and deserialize as much of the show file as possible. - - The contents of show file to load. - A ShowFile, with as many parameters loaded as possible. - - - - - Upgrades a show file from an older version by parsing attempting to parse old data. - - The show file to merge into. - The json to parse. - - - - Upgrades a show file from an older version by parsing attempting to parse old data. - - The show file to merge into. - The json to parse. - - - - - - - Icons - - - - - InitializeComponent - - - - - A simple double-ended queue implementation. This implementation is not thread-safe. - - - - - - Points to the element at the start of the queue. - - - - - Points to the free slot at the end of the queue. - - - - - Increments the given value, wrapping on the array bounds. - - - The original value of - - - - Decrements the given value, wrapping on the array bounds. - - - The new value of - - - - Removes trailing zeros from a decimal. - - - https://stackoverflow.com/a/7983330/10874820 - - - - - Updates an item at the given index in the list, expanding the list with - default items if index larger than the size of the list. - - - - - - - - - Sets the translation component of this matrix. - - - - - - - - Synchronises a list with this collection. Note that this synchronisation only works in one direction, if the list is - modified, then the behaviour is undefined. - - - - - - - - - - Efficiently adds a collection of points to the collection. - - - - - - - Creates an array segment over a portion of this array. - - - - The index of the first element in the segment. - The number of elements to take. - A new array segment over the array. - - - - - - - An array pool which only stores arrays of a fixed size. - - - - - - Helper to raise a PropertyChanged event for the Count property - - - - - Helper to raise a PropertyChanged event for the Indexer property - - - - - A fast string-keyed dictionary. This is very similar in implementation to the .NET generic dictionary, - but it has a few specific optimisations which can be useful in some cases. Notably, it can by accessed - by string key or by of which can save unnecessary - string allocations. It also exposes methods to get values by reference which can save performance. - And it uses a slightly faster string hashing algorithm. - - The type of values stored in this dictionary. - - - - Stores references to dictionary items, index by key hashcode. Stores a 1-based index into the other arrays. - - - - - Stores the complete hashcode of an item pointed to by buckets. - - - - - Stores the index of the next item in the same bucket as the current item pointed to by buckets. 1-based index! - - - - - Stores the key of an item pointed to by buckets. - - - - - Stores the value of an item pointed to by buckets. - - - - - Optimises the dictionary for red performance and memory efficiency. - - The load factor to target. Smaller values result in faster reads at the - cost of more memory used. A good value is between 1 and 3. - Whether to compact all the entries in the slots. Saves a bit of space if many - items have been removed from the dictionary. - - - - - - - - - - Removes an item with the specified key from the dictionary, and returns the removed value. - - The key of the element to remove. - The value associated with the key which was removed. - if the item was successfully removed from the dictionary. - - - - - - - Gets the value associated with the given key. The reference is only valid so long as the dictionary is not mutated. - - The key to get the value of. - A reference to the value in the dictionary if it exists, or a null reference. - - - - Returns an enumerable of all the values with the given keys. - - The keys to search for. - An of all the values which match the given keys. - - - - A list backed by arrays from the array pool. - - - - - - Gets a span of the elements in this temporary list, valid as long as the list count isn't changed. - - - - - - Adds each element from the enumerable to the list efficiently. - - - - - - Factory class used by the collection builder to correctly initialise a . - - - - - Factory method used by the collection builder to correctly initialise a . - - - - - Sets the to a level that ensures none of the sound cues in the - cue stack will exceed 0dBfs when playing individually. - - The amount of headroom to leave in dB from full-scale, positive - values attenuate, negative values will push cues into the limiter. - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - The base class for any view model which can be bound onto a separate model instance. - - This class implements all the necessary logic to automatically synchronise changes - from a view model to a model. The behaviour of the automatic bindings can be controlled - using the various model attribtues (, - , ). - Implementing classes should be annotated with and - where applicable. - - - The default automatic binding behaviour is to bind all properties with a public getter - and setter on the ViewModel to all public fields with matching (case insensitive) names - on the Model. - - The type of the model to bind to. - - - - Binds this to the specified model instance. Automatically propagates proeprties - changes from this object to the model, but not the other way around. -
- When using the source generator, this method is automatically implemented so long as the deriving - class defines at least one reactive property (see ). -
- The model to bind to, or to unbind. -
- - - Copies all bound property values on this instance from the bound model. -
- When using the source generator, this method is automatically implemented so long as the deriving - class defines at least one reactive property (see ). -
-
- - - Copies all bound property values on this instance to the bound model. -
- When using the source generator, this method is automatically implemented so long as the deriving - class defines at least one reactive property (see ). -
-
- - - When using a source generator, this method is automatically implemented and should be called in . - - - - - When using a source generator, this method is automatically implemented and should be called in . - - - - - Creates a new instance of a cue of the given type. Available cue types are those registered in . - - - - - - - Creates a new instance of a cue view model of the given type. Available cue types are those registered in . - End users should preferentially use . - - - - - - - - Creates a new instance of a cue view model for a given cue and copies all of it's properties. - - - - - - - - Creates a new instance of a cue for a given cue view modeland copies all of it's properties. - - The view model to create a model for. - to bind the to the newly created - model, to only copy it's parameter. - - - - - - The Cue is currently stopped and ready to be played - - - - - The Cue is currently waiting to start. - - - - - The duration of this cue, as received from a remote node. - - - - - This method is invoked by QPlayer when this cue is selected in the inspector. - - - - - Starts this cues after it's delay has elapsed. - - Optionally, a cue to wait for it's event before starting this cue. - - - - Starts this cue immediately. - - - - - Pauses this cue. It can be resumed again by calling Go. - - Not all cues support pausing. For unsupported cues, this should Stop(). - - - - - Stops this cue immediately. - - - - - Stops this cue without informing remote clients or executing cue specific stopping code. - This is called when a remote node needs to tell us that a cue has finished playing. - - - - - Sets the playback time of the cue to the given time, and puts it in the paused state. - - the time to start the cue at. - - - - This callback is triggered every 50 or so ms when this cue is active by the main thread. - - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - Creates a new ViewModel from the given Model, without binding it. - - the model to copy properties from - the main view model - a new ViewModel for the given Model. - - - - Copies the properties in this ViewModel to the given Model object. - - the model to copy to - - - - Copies the value of a given property to the bound Model. - - the property to copy - - - - Binds this view model to a given model, such that updates from the view model are propagated to the model (but NOT vice versa). - - the model to bind to - - - - The global instance of the audio playback manager. - - - - - An event which is fired every 250ms on the main thread. - - - - - Returns true if a non show mode command can execute. - - - - - - Opens or activates a window of the given type. - - The type of the window to open. - When , activates an existing window of the type if it already exists. - The opened/activated window. - - - - Closes a window of the given type. - - - if a window of the given type was closed. - - - - Closes all active windows, excluding the main window. - - - - - Informs the cue stack that the cue ID of a given cue view model has been changed. This should be called whenever a QID is changed. - - Note that since 's setter calls this method, users which change QID's through this - setter need not call this method. - - - - - - - - Deletes the cue at the given index from the cue stack. - - The 0-based index of the cue in the cue stack. - Whether an undo item should be recorded. - The cue which was just removed, or null if it wasn't found. - - - - Deletes the given cue from the cue stack. - - The cue instance to remove from the cue stack. - if the cue was successfully removed. - - - - Deletes the given cue from the cue stack. - - The cue instance to remove from the cue stack. - if the cue was successfully removed. - - - - Inserts an existing cue into the cue stack. This method should be used with care as - it does not check if the cue already exists in the stack. To duplicate a cue, use - . - - The index at which to insert the cue. - The cue to insert. - Whether the newly inserted cue should be selected. - Whether an undo item should be recorded. - - - - Inserts an existing cue into the cue stack according to it's qid. This method - should be used with care as it does not check if the cue already exists in the - stack. To duplicate a cue, use . - - The cue to insert in the stack. - Whether the newly inserted cue should be selected. - Whether an undo item should be recorded. - - - - Duplicates the given cue in the cue stack. - - The cue to duplicate, or to use the currently selected cue. - Whether the newly created cue should be selected. - The instance of the newly created cue, or if no cue was duplicated. - - - - Tries to find a cue view model given a cue ID. - - - The can be one of the following types: - , - , - , - , - - The cue ID to search for. - The returned cue view model if it was found. - if the cue was found. - - - - Tries to find a cue view model given a cue ID. - - The cue ID to search for. - The returned cue view model if it was found. - if the cue was found. - - - - Gets the index of a cue in the cue list. Executes in O(n) time. - - The cue instance to search for. - The index of the cue in the list or -1 if it wasn't found. - - - - Moves the given cue up or down by one, swapping position with the cue above or below it. - Renumbers the given cue to remain in order. - - The cue instance to move. - Whether the cue should be moved up or down. - Whether the cue should be reselected after it's moved. - Whether an undo item should be recorded. - if successful. - - - - Moves the given cue in the cue stack to the given cue ID, or directly after it if the - specified cue ID is already in use. - - The cue to move in the cue stack. - The cue ID to insert the cue at. - Whether the moved cue should be reselected. - - - - Moves the given cue in the cue stack to the specified index. - - The cue to move in the cue stack. - The index within the cue stack to move the cue to. - Whether the moved cue should be reselected. - Optionally, the new QID to assign to the cue once it's moved. - Otherwise, this method will choose a new QID itself (recommended). - Whether an undo item should be recorded. - if the cue was moved successfully. - - - - Moves the given cue in the cue stack to the specified index. - - - The insertion index behaves a little bit odd compared to regular insertion behaviour. - To illustrate: - - srcInd: [0] [1] [2] [3] [4] - dstInd: 0 1 2 3 4 5 - - The cue is always inserted at an index 'between' two cues, so if we want to move q1 to - before q0, we would pick index 0, but to move it after q2, we would pick index 3. - Effectively, dstInd 1 and 2 don't move the cue. - - The cue to move in the cue stack. - The index within the cue stack to move the cue to. - Whether the moved cue should be reselected. - Optionally, the new QID to assign to the cue once it's moved. - Otherwise, this method will choose a new QID itself (recommended). - Whether an undo item should be recorded. - if the cue was moved successfully. - - - - Creates a new cue of the given type and inserts it into the cue stack at the selected position. - - The type of cue to create. - Whether the new cue should be inserted before the selected cue. - Whether the new cue should be inserted at the end of the cue stack. - Whether the new cue should be selected. - Optionally, a cue to copy properties from. - The view model instance of the newly created cue. - - - - Creates a new cue of the given type and inserts it into the cue stack at the given position. - - The type of cue to create. - The index in the cue stac to insert the cue - Whether the newly created cue should be selected. - Optionally, a cue to copy properties from. - The view model instance of the newly created cue. - - - - Creates a new cue of the given type without inserting it into the cue stack. Use this method with caution as - QPlayer assumes cues are always in the cue stack. - - The type of cue to create. - Optionally, copies properties from this cue. - The view model instance of the newly created cue. - - - - Generates a QID at the given insertion point in the cue stack, renumbering cues if needed. - - The index of the cue after which to insert the new QID. - When enabled the first parameter is the index of the cue to - renumber such that it fits in between it's neighbours. - - - - - Converts a path to/from a project relative path. Only paths which are in subdirectories of the project path are made relative. - - the path to convert - whether the path should be expanded to an absolute path or made relative to the project - - - - - Checks if the project file has unsaved changes and prompts the user to save if needed. - - - Must be called on the dispatcher thread. - - false if the user decided to cancel the current operation. - - - - Checks if any cues are currently running, and if so prompts the user if they want to cancel the next operation. - - - false if the user decided to cancel the current operation. - - - - Must be called on the dispatcher thread. - - When true, executes without waiting for the dispatcher. - - - - This effectively makes sure that the data in the view model is copied to the model, just in case a change was missed. - - - - - Opens the project at the specified path. - - - Must be called on the dispatcher thread. - - - - - - - Saves the show file asynchronously. This method can be called from a worker thread. - - The path to save the project to. - Whether syncing the show file with remote clients is allowed. - Whether the internal model should be resynchronised if needed. - - - - - Saves the show file synchronously. This method must be called from the main thread. Prefer . - - - - - - Saves the project and copies all of it's referenced files to the given directory. - - The directory to pack the project into. - - - - Attempts to load an embedded resource file from the executing assembly. - - The path/filename to the file to load. - A stream of the file contents. - - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - Removes a remote node from the collection of remote nodes. - - The name of the name to remove - if the node was removed successfully. - - - - Gets a remote node by name, returning a new node and adding it, if it doesn't already - exist in the collection. - - - true if the returned node was newly added. - - - - - - - Gets whether a given remote node is currently active. - - - - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - Checks if this node is still active, and notifies the UI if it's state has changed. - - if this node has just become inactive. - - - Reactive property for - - - - Checks whether the current audio file is valid. This also checks that the underlying stream object still exists. - - - - - Fades out the current playing sound. - - The duration in seconds to fade over - The type of fade to use - - - - Fades this sound to the given volume in a given amount of time. - - The volume to fade to - The duration in seconds to fade over - The type of fade to use - - - - Stops all playing audio, stops the timers, and rewinds the audioFile to it's start time. - - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - The global undo manager, this provides methods to record actions in a way that can be undone or redone. This class is not - thread-safe and must be called from the main thread. - - - - - Registers a property change action to the undo stack. - - The path to the property being changed. - The object being changed. - The previous value. - The new value after this action has occured. - - - - Registers an action to the undo stack. - - A brief description of the action (in the past tense). - A function to call to undo the action. - A function to call to redo the action. - - - - Undoes the last action registered to the undo stack. - - - - - Redoes the last action undone by the undo manager. - - - - - Clears the undo and redo history. Necessary after drastic changes which would invalidate the undo history, - this also allows the GC to reclaim objects being kept alive by the undo history. - - - - - When used with a block, suppresses undo action recording for the scope of this function. - - - - - - Temporarily suppresses the recording of new undo actions until is called. - - - - - Stops suppressing undo recording. Counterpart of . - - - - - Forcefully stops suppressing undo recording. Counterpart of . - - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - This is the name of a special property change notification which the view listens to so that it knows to - propagate the correct width/height/cursors back to the renderer. - - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - Reactive property for - - - - Interaction logic for AboutWindow.xaml - - - AboutWindow - - - - - InitializeComponent - - - - - Interaction logic for ActiveCueControl.xaml - - - ActiveCueControl - - - - - InitializeComponent - - - - - Interaction logic for AudioLimiterControl.xaml - - - AudioLimiterControl - - - - - InitializeComponent - - - - - Interaction logic for AudioMeter.xaml - - - AudioMeter - - - - - InitializeComponent - - - - - Interaction logic for CueDataControl.xaml - - - CueDataControl - - - - - InitializeComponent - - - - Reactive property for - - - - Interaction logic for CueDataHeaderControl.xaml - - - CueDataHeaderControl - - - - - InitializeComponent - - - - - CueDataTemplates - - - - - InitializeComponent - - - - - Interaction logic for CueEditor.xaml - - - CueEditor - - - - - InitializeComponent - - - - - Interaction logic for HiddenComboBox.xaml - - - HiddenComboBox - - - - - InitializeComponent - - - - - Interaction logic for HiddenTextbox.xaml - - - HiddenTextbox - - - - - InitializeComponent - - - - - Interaction logic for Knob.xaml - - - Knob - - - - - InitializeComponent - - - - Reactive property for - - - - Displays or hides the cursor. - - - If bShow is TRUE, the display count is incremented by one. If bShow is FALSE, the display count is decremented by one. - - The return value specifies the new display counter. - - - - Interaction logic for LogWindow.xaml - - - LogWindow - - - - - InitializeComponent - - - - - A progress bar which is a little more GC friendly. This is mostly just a hack to prevent WPF from allocating so much garbage when updating this frequently. - - - - - Interaction logic for PlaybackProgressBar.xaml - - - PlaybackProgressBar - - - - - InitializeComponent - - - - Reactive property for - - - - Interaction logic for PluginManagerWindow.xaml - - - PluginManagerWindow - - - - - InitializeComponent - - - - Reactive property for - - - - Interaction logic for ProjectSettingsEditor.xaml - - - ProjectSettingsEditor - - - - - InitializeComponent - - - - - Interaction logic for RemoteNodesWindow.xaml - - - RemoteNodesWindow - - - - - InitializeComponent - - - - - Interaction logic for RemoteSetupControl.xaml - - - RemoteSetupControl - - - - - InitializeComponent - - - - - Interaction logic for SettingsWindow.xaml - - - SettingsWindow - - - - - InitializeComponent - - - - - Interaction logic for TextField.xaml - - - TextField - - - - - InitializeComponent - - - - - Interaction logic for WaveForm.xaml - - - WaveForm - - - - - InitializeComponent - - - - Reactive property for - - - - Interaction logic for WaveFormWindow.xaml - - - WaveFormWindow - - - - - InitializeComponent - - - - - Interaction logic for MainWindow.xaml - - - MainWindow - - - - - InitializeComponent - - - - - Automatically generates a property for the annotated field which automatically raised - PropertyChanged notifications when set. -
- This attribute can also be used on existing properties to generate a reactive property for that property. - To this, the annotated property must either be partial (in which case a backing field will also be - generated), or the parameter must be specified. -
- - If a custom property name is not specified, the generated property will take the name of field - with the first letter capitalised, or prefixed with an underscore. IE: int exampleProp -> - int ExampleProp, and int OtherExample -> int _OtherExample - - The name of the reactive property to generate. -
- - - Automatically generates a property for the annotated field which automatically raised - PropertyChanged notifications when set. -
- This attribute can also be used on existing properties to generate a reactive property for that property. - To this, the annotated property must either be partial (in which case a backing field will also be - generated), or the parameter must be specified. -
- - If a custom property name is not specified, the generated property will take the name of field - with the first letter capitalised, or prefixed with an underscore. IE: int exampleProp -> - int ExampleProp, and int OtherExample -> int _OtherExample - - The name of the reactive property to generate. -
- - - When this property is updated use a cached instance of . - - - - - By default, when this property is updated, the old value is compared to the new value using the - == operator, and only if the value are different is the setter and property change - notification invoked. This attribute skips this check, this can be useful if no == is - available or if this equality comparison would be very expensive. -
- Requires a on this same property. -
-
- - - When this property is updated, a property change notification for the specified property is also raised. -
- Requires a on this same property. -
- The name of the property to generate a change notifcation for. -
- - - When this property is updated, a property change notification for the specified property is also raised. -
- Requires a on this same property. -
- The name of the property to generate a change notifcation for. -
- - - Uses the getter and setter from the specified property as a template for this reactive property. -
- Requires a on this same property. -
- The name of the property to use to implement this reactive property. -
- - - Uses the getter and setter from the specified property as a template for this reactive property. -
- Requires a on this same property. -
- The name of the property to use to implement this reactive property. -
- - - Marks the setter on the generated property as private. -
- Requires a on this same property. -
-
- - - Specifies that, for the annotated property, the provided delegates should be called to synchronise - data to and from the model for this property. - - The name of a static method in this class to copy this property's value from this instance to the model. - The name of a static method in this class to copy this property's value from the model to this instance. - - - - Specifies that, for the annotated property, the provided delegates should be called to synchronise - data to and from the model for this property. - - The name of a static method in this class to copy this property's value from this instance to the model. - The name of a static method in this class to copy this property's value from the model to this instance. - - - - Specifies the name of the field of the model this property should be bound to. - - - - - - Specifies the name of the field of the model this property should be bound to. - - - - - - Indicates that this property should not be automatically bound to a corresponding model property. Note that - properties for read-only fields are implicitly skipped from model binding as they cannot be written too. - - This attribute also implies the . - - - - - Allows a custom getter function to be used in a property generated using a . - - A function which returns the value of the property. - When , the setter parameter expects a method name; - when , the getter parameter takes an expression which is placed inline in the generator getter. - - - - Allows a custom getter function to be used in a property generated using a . - - A function which returns the value of the property. - When , the setter parameter expects a method name; - when , the getter parameter takes an expression which is placed inline in the generator getter. - - - - Allows a custom setter function to be used in a property generated using a . - - A method which takes as input the new value to assign to the property. - When , the setter parameter expects a method name; - when , the setter parameter takes an expression which is placed inline in the generator setter. - - - - Allows a custom setter function to be used in a property generated using a . - - A method which takes as input the new value to assign to the property. - When , the setter parameter expects a method name; - when , the setter parameter takes an expression which is placed inline in the generator setter. - - - - Allows custom accessibility keywords to be used on a property generated using a . - - - [Reactive, CustomAccessibility("protected virtual")] string prop; - - The accessibility modifiers to add to the generated property. - - - - Allows custom accessibility keywords to be used on a property generated using a . - - - [Reactive, CustomAccessibility("protected virtual")] string prop; - - The accessibility modifiers to add to the generated property. - - - - Prevents undo actions from being recorded on the property generated using a . - - The accessibility modifiers to add to the generated property. - - - - Specifies the model type associated with this view model. - - - - - - Specifies the model type associated with this view model. - - - - - - Specifies the view type associated with this view model. - - - - - - Specifies the view type associated with this view model. - - - - - - Specifies the display name of a given cue type. - - - - - - Specifies the display name of a given cue type. - - - - - - Specifies the icon for a given cue type. - - The icon is defined as a in a (in xaml). - The plugin loader automatically creates an instance of the given resource dictionary and binds it to the app if one doesn't already exist. - The parameter should refer to a given x:Key="name" attribute on the in xaml. - - The key of the in the given resource dictionary to use as the icon. - The type of the resource dictionary which contains the given icon. - - - - Specifies the icon for a given cue type. - - The icon is defined as a in a (in xaml). - The plugin loader automatically creates an instance of the given resource dictionary and binds it to the app if one doesn't already exist. - The parameter should refer to a given x:Key="name" attribute on the in xaml. - - The key of the in the given resource dictionary to use as the icon. - The type of the resource dictionary which contains the given icon. - - - - When used on a class which derives from , generates an implementation - for and - based on all fields marked as []. - - Use the [] and [] to add/remove fields - from inclusion in the Clone() implementation. - - To mix both a automatically generated clone implementation with custom behaviour, the - parameter can be set. This allows the generated implementation to call a custom clone method after it has cloned all the - automatically implemented properties. The custom clone method is always called after all other fields have been cloned - and must have the following signature: - - // This method CAN be declared as private, T represents the type of this attribute is decorating. - void CustomClone(T target); - - - If a field's type declares a public T Clone(); method (or one is provided by an extension method) then this - method will be called when copying that field. This behaviour must be enabled via the - property. - - - Generates the following code: - - public partial class Label - { - public override UIElement Clone() => Clone(new Label()); - - public override UIElement Clone(UIElement target) - { - base.Clone(target); - if (target is Label t) - { - t.text = text; - t.size = size; - t.colour = colour; - // For the sake of example, if Font defined a Clone() method it would be called as shown. - t.font = font.Clone(); - } - return target; - } - } - - - When , calls a method on this - - - - When used on a class which derives from , generates an implementation - for and - based on all fields marked as []. - - Use the [] and [] to add/remove fields - from inclusion in the Clone() implementation. - - To mix both a automatically generated clone implementation with custom behaviour, the - parameter can be set. This allows the generated implementation to call a custom clone method after it has cloned all the - automatically implemented properties. The custom clone method is always called after all other fields have been cloned - and must have the following signature: - - // This method CAN be declared as private, T represents the type of this attribute is decorating. - void CustomClone(T target); - - - If a field's type declares a public T Clone(); method (or one is provided by an extension method) then this - method will be called when copying that field. This behaviour must be enabled via the - property. - - - Generates the following code: - - public partial class Label - { - public override UIElement Clone() => Clone(new Label()); - - public override UIElement Clone(UIElement target) - { - base.Clone(target); - if (target is Label t) - { - t.text = text; - t.size = size; - t.colour = colour; - // For the sake of example, if Font defined a Clone() method it would be called as shown. - t.font = font.Clone(); - } - return target; - } - } - - - When , calls a method on this - - - - Marks a field to be included for the automatic - implementation. - - - See . - - If a field's type declares a public T Clone(); method (or one is provided by - an extension method) then this method will be called when copying the annotated field. - - - - Marks a field to be included for the automatic - implementation. - - - See . - - If a field's type declares a public T Clone(); method (or one is provided by - an extension method) then this method will be called when copying the annotated field. - - - - Marks a field to be excluded from the automatic - implementation. - - - See . - - - - - Indicates to the source generator that a should be generated for this view model. -
- By default, a view control will be generated for every public property on this class. -
-
- - - Indicates to the source generator that a should be generated for this view model. -
- By default, a view control will be generated for every public property on this class. -
-
- - - Specifies the label for the generated view control for this property. - - - - - - Specifies the label for the generated view control for this property. - - - - - - Indicates that a view control should not be generated for this property. - - - - - For numeric properties, this allows the minimum, maximum, and change rate of the generated view control to be specified. - - - - - - - - - For numeric properties, this allows the minimum, maximum, and change rate of the generated view control to be specified. - - - - - - - - - Specifies that a knob control should be generated for this property (as opposed to a Spinbox). - - - - - Specifies that a slider control should be generated for this property (as opposed to a Spinbox). - - - - - Specifies that a file picker control should be generated for this property. - Only valid on string properties. - - The name of the ICommand to invoke when the file picker button is pressed. - - - - Specifies that a file picker control should be generated for this property. - Only valid on string properties. - - The name of the ICommand to invoke when the file picker button is pressed. - - - - Generates a button control in place of this property which invokes the given command. - The annotated property's value is ignored. - - The name of the ICommand to invoke when the button is pressed. - - - - Generates a button control in place of this property which invokes the given command. - The annotated property's value is ignored. - - The name of the ICommand to invoke when the button is pressed. - - - - Generates a heading label before the annotated property in the view. - - The title of the heading. - - - - Generates a heading label before the annotated property in the view. - - The title of the heading. - - - - Specifies a tooltip to display for the generated view control for this property. - - - - - - Specifies a tooltip to display for the generated view control for this property. - - - - - - Controls - - - - - InitializeComponent - - - - - GeneratedInternalTypeHelper - - - - - CreateInstance - - - - - GetPropertyValue - - - - - SetPropertyValue - - - - - CreateDelegate - - - - - AddEventHandler - - -
-
From 1c72c9f7e3c1e056bd4f9222f4e1009cbbc7257b Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sun, 3 May 2026 07:50:28 +0100 Subject: [PATCH 5/8] CI fix --- .github/workflows/deploy-docs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index a50b152..b883fdf 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -22,6 +22,8 @@ concurrency: jobs: build: runs-on: ubuntu-latest + env: + EnableWindowsTargeting: true steps: - name: Checkout your repository using git uses: actions/checkout@v4 From f93fd279b71d21552c421a41eef00dea8708bfff Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sun, 3 May 2026 07:52:22 +0100 Subject: [PATCH 6/8] Fix CI --- .github/workflows/deploy-docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index b883fdf..592c607 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -36,6 +36,7 @@ jobs: shell: bash run: | dotnet tool install docfx + dotnet build -c Release dotnet docfx dotnet run StarlightDocNet "api/" "docs/src/content/docs/api/" From defdd66aae216421f4f1c34013bbc9e39e62eea1 Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sun, 3 May 2026 07:54:42 +0100 Subject: [PATCH 7/8] Fix CI --- .github/workflows/deploy-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index 592c607..c75b372 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -36,7 +36,7 @@ jobs: shell: bash run: | dotnet tool install docfx - dotnet build -c Release + dotnet build -c Release QPlayer/QPlayer.csproj dotnet docfx dotnet run StarlightDocNet "api/" "docs/src/content/docs/api/" From 01fcceb6f032637ddaae88aa12a9bba8919e3ec1 Mon Sep 17 00:00:00 2001 From: Thomas Mathieson Date: Sun, 3 May 2026 07:58:14 +0100 Subject: [PATCH 8/8] Fix CI --- .github/workflows/deploy-docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-docs.yml b/.github/workflows/deploy-docs.yml index c75b372..62bebb7 100644 --- a/.github/workflows/deploy-docs.yml +++ b/.github/workflows/deploy-docs.yml @@ -38,7 +38,7 @@ jobs: dotnet tool install docfx dotnet build -c Release QPlayer/QPlayer.csproj dotnet docfx - dotnet run StarlightDocNet "api/" "docs/src/content/docs/api/" + dotnet run -c Release --project StarlightDocNet "api/" "docs/src/content/docs/api/" # Build the rest of the docs - name: Install, build, and upload your site output