From 487fdcc77b1954b588d988a14f843d4218d265eb Mon Sep 17 00:00:00 2001 From: qwsdcvghyu89 <61093706+qwsdcvghyu89@users.noreply.github.com> Date: Wed, 25 Jun 2025 22:09:59 +0300 Subject: [PATCH] ``` feat: add PuppetConfig and integrate with CLI Introduced a new PuppetConfig class in the Puppeteer namespace to manage Puppeteer configurations. Updated the CLI project to reference the Puppeteer project and added a new method in DownloadBuilder for using a Puppet manipulator. This change enables better configuration management for Puppeteer within the CLI. ``` --- Beam.Puppeteer/PuppetConfig.cs | 10 + Beam.Temporary.Cli/Beam.Temporary.Cli.csproj | 3 + Beam.Temporary.Cli/DownloadBuilder.cs | 1 + Beam/SourceLinkBuilder.cs | 236 +++++++++++++++++-- aeqw89.Beam/aeqw89.Beam.csproj | 2 +- 5 files changed, 232 insertions(+), 20 deletions(-) create mode 100644 Beam.Puppeteer/PuppetConfig.cs diff --git a/Beam.Puppeteer/PuppetConfig.cs b/Beam.Puppeteer/PuppetConfig.cs new file mode 100644 index 0000000..d77c275 --- /dev/null +++ b/Beam.Puppeteer/PuppetConfig.cs @@ -0,0 +1,10 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Beam.Puppeteer { + internal class PuppetConfig { + } +} diff --git a/Beam.Temporary.Cli/Beam.Temporary.Cli.csproj b/Beam.Temporary.Cli/Beam.Temporary.Cli.csproj index 4015cee..b80d122 100644 --- a/Beam.Temporary.Cli/Beam.Temporary.Cli.csproj +++ b/Beam.Temporary.Cli/Beam.Temporary.Cli.csproj @@ -23,6 +23,9 @@ all + + all + all diff --git a/Beam.Temporary.Cli/DownloadBuilder.cs b/Beam.Temporary.Cli/DownloadBuilder.cs index def26f8..9c0fdce 100644 --- a/Beam.Temporary.Cli/DownloadBuilder.cs +++ b/Beam.Temporary.Cli/DownloadBuilder.cs @@ -55,6 +55,7 @@ namespace Beam.Temporary.Cli { IContextStage WithRetryReporter(IProgress reporter); DownloadEnumerable Build(); IContextStage UseFragments(); + IContextStage UsePuppet(AsyncManipulator manipulator); } /* ────────────────────────── Implementation ────────────────────────── */ diff --git a/Beam/SourceLinkBuilder.cs b/Beam/SourceLinkBuilder.cs index 8a8c21e..5e7e68c 100644 --- a/Beam/SourceLinkBuilder.cs +++ b/Beam/SourceLinkBuilder.cs @@ -5,116 +5,290 @@ using System.Text; using System.Threading.Tasks; namespace Beam { + /// + /// Describes where a token should be inserted relative to the run‑time value + /// that ultimately replaces it when building a . + /// [Flags] public enum Position { - Before = 0b01, - After = 0b10, - BeforeAndAfter = 0b11 + /// + /// The parameter name is written before its run‑time value + /// (e.g. id42 when the name is id and the value is 42). + /// + Before = 0b01, + + /// + /// The parameter name is written after its run‑time value + /// (e.g. 42id). + /// + After = 0b10, + + /// + /// The parameter name is written both before and after the value + /// (e.g. id42id). + /// + BeforeAndAfter = 0b11 } + /// + /// Represents a single placeholder that will be substituted when a link is built. + /// + /// Identifier that appears in the final link according to . + /// Controls whether is written before, after, or on both sides of the value. public class Parameter(string name, Position position = Position.Before) { + /// + /// Gets or sets the identifier that frames the value when the link is rendered. + /// public string Name { get; set; } = name; + + /// + /// Gets or sets the position at which is emitted relative to the run‑time value. + /// public Position Position { get; set; } = position; + + /// + /// Creates a shallow copy whose mutable members are detached from the original instance. + /// + /// A new with identical and . + public Parameter Clone() + => new(Name, Position); } + /// + /// Describes one path segment of a URL and the collection of tokens that belong to it. + /// + /// Literal part of the segment that precedes the parameters (may be empty). + /// Optional string placed between adjacent parameters when more than one is present. + /// Optional string appended after the last parameter in the segment. public class LinkSegment(string name, string separator = "", string suffix = "") { + /// + /// Gets or sets the literal path component for this segment. + /// public string Name { get; set; } = name; + + /// + /// Gets or sets the collection of parameters that appear within the segment. + /// public List Parameters { get; set; } = []; + + /// + /// Gets or sets the string inserted between parameters when the segment is rendered. + /// public string Separator { get; set; } = separator; + + /// + /// Gets or sets the string appended after the last parameter when the segment is rendered. + /// public string Suffix { get; set; } = suffix; + /// + /// Produces a deep copy whose list contains cloned objects. + /// + public LinkSegment Clone() + => new LinkSegment(Name, Separator, Suffix) { + Parameters = [.. Parameters.Select(static x => x.Clone())] + }; + + /// + /// Replaces with a new set whose items all use . + /// + /// Parameter identifiers to add. + /// This instance for fluent calls. public LinkSegment WithParameters(params string[] parameters) { - Parameters = parameters.Select((x) => new Parameter(x)).ToList(); + Parameters = parameters.Select(static x => new Parameter(x)).ToList(); return this; } + /// + /// Replaces with a new set using explicit name/position tuples. + /// + /// Tuples of parameter identifier and desired position. + /// This instance for fluent calls. public LinkSegment WithParameters(params (string, Position)[] parameters) { - Parameters = parameters.Select((x) => new Parameter(x.Item1, x.Item2)).ToList(); + Parameters = parameters.Select(static x => new Parameter(x.Item1, x.Item2)).ToList(); return this; } } + /// + /// Fluent helper for composing strongly‑typed, template‑driven source links. + /// + /// + /// The builder captures a static template (protocol, host, path segments and their parameters) and is later supplied with + /// a flat array of values that populate all parameters in left‑to‑right order. + /// + /// DNS host name (e.g. api.example.com). + /// Transport protocol; defaults to https. public class SourceLinkBuilder(string host, string protocol = "https") { + /// + /// Gets or sets the scheme part of the URL (e.g. https, http). + /// public string Protocol { get; set; } = protocol; + + /// + /// Gets or sets the host portion of the URL. + /// public string Host { get; set; } = host; + + /// + /// Gets or sets the ordered collection of path segments. + /// public List Segments { get; set; } = []; + /// + /// Produces a deep copy whose and contained collections are detached from the original. + /// + public SourceLinkBuilder Clone() + => new SourceLinkBuilder(Protocol, Host) { + Segments = [.. Segments.Select(static x => x.Clone())] + }; + + #region Helpers – suffix & separator + /// + /// Returns the suffix of the ‑th segment. + /// + /// Zero‑based segment index. + /// If is outside the valid range. public string GetSuffix(int segmentIndex) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(segmentIndex, Segments.Count); ArgumentOutOfRangeException.ThrowIfNegative(segmentIndex); return Segments[segmentIndex].Suffix; } + /// + /// Returns the suffix of the last segment. + /// public string GetSuffix() => GetSuffix(Segments.Count - 1); + /// + /// Returns the separator used by the ‑th segment. + /// + /// Zero‑based segment index. + /// If is outside the valid range. public string GetSeparator(int segmentIndex) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(segmentIndex, Segments.Count); ArgumentOutOfRangeException.ThrowIfNegative(segmentIndex); return Segments[segmentIndex].Separator; } + /// + /// Returns the separator of the last segment. + /// public string GetSeparator() => GetSeparator(Segments.Count - 1); + /// + /// Assigns a new suffix to the ‑th segment. + /// + /// Zero‑based segment index. + /// String appended after the segment's parameters. + /// If is outside the valid range. public void SetSuffix(int segmentIndex, string suffix) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(segmentIndex, Segments.Count); ArgumentOutOfRangeException.ThrowIfNegative(segmentIndex); - var seg = Segments[segmentIndex]; - seg.Suffix = suffix; + Segments[segmentIndex].Suffix = suffix; } + /// + /// Assigns a new suffix to the last segment. + /// public void SetSuffix(string suffix) => SetSuffix(Segments.Count - 1, suffix); + /// + /// Assigns a new separator to the ‑th segment. + /// + /// Zero‑based segment index. + /// String inserted between parameters belonging to the same segment. + /// If is outside the valid range. public void SetSeparator(int segmentIndex, string separator) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(segmentIndex, Segments.Count); ArgumentOutOfRangeException.ThrowIfNegative(segmentIndex); - var seg = Segments[segmentIndex]; - seg.Separator = separator; + Segments[segmentIndex].Separator = separator; } + /// + /// Assigns a new separator to the last segment. + /// public void SetSeparator(string separator) => SetSeparator(Segments.Count - 1, separator); + #endregion + #region Segment manipulation + /// + /// Appends a new segment. + /// + /// Literal portion of the segment. + /// Optional separator for subsequent parameters; keeps the current default. + /// If is , empty, or whitespace. public void AddSegment(string name, string? separator = null) { ArgumentException.ThrowIfNullOrWhiteSpace(name); Segments.Add(new LinkSegment(name, separator)); } + /// + /// Replaces the whole collection with the supplied , each represented as a . + /// + /// This instance for fluent calls. public SourceLinkBuilder WithSegments(params IEnumerable segments) { - Segments = segments.Select((x) => new LinkSegment(x)).ToList(); + Segments = segments.Select(static x => new LinkSegment(x)).ToList(); return this; } + /// + /// Replaces the collection with empty segments. + /// + /// Number of segments to create. public SourceLinkBuilder WithSegments(int count) => WithSegments(Enumerable.Repeat("", count)); + #endregion + #region Parameter manipulation (fluent) + /// + /// Replaces parameters of the ‑th segment using the supplied identifiers. + /// public SourceLinkBuilder WithParameters(int i, params string[] parameters) { - Segments[i] - .WithParameters(parameters); + Segments[i].WithParameters(parameters); return this; } + /// + /// Replaces parameters of the ‑th segment using explicit name/position tuples. + /// public SourceLinkBuilder WithParameters(int i, params (string, Position)[] parameters) { - Segments[i] - .WithParameters(parameters); + Segments[i].WithParameters(parameters); return this; } + #endregion + #region Parameter manipulation (imperative) + /// + /// Adds new parameters to the specified segment without clearing existing ones. + /// + /// Zero‑based segment index. + /// Identifiers of parameters to add. + /// If is invalid. + /// If any parameter identifier is , empty or whitespace. public void AddParameters(int segmentIndex, params string[] parameters) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(segmentIndex, Segments.Count); ArgumentOutOfRangeException.ThrowIfNegative(segmentIndex); var seg = Segments[segmentIndex]; - foreach(var parameter in parameters) { + foreach (var parameter in parameters) { ArgumentException.ThrowIfNullOrWhiteSpace(parameter); seg.Parameters.Add(new Parameter(parameter)); } } - public void AddParameters(params string[] parameters) + /// + /// Adds parameters to the last segment. + /// + public void AddParameters(params string[] parameters) => AddParameters(Segments.Count - 1, parameters); + /// + /// Replaces the entire parameter list of the specified segment. + /// public void SetParameters(int segmentIndex, params string[] parameters) { ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(segmentIndex, Segments.Count); ArgumentOutOfRangeException.ThrowIfNegative(segmentIndex); @@ -123,21 +297,38 @@ namespace Beam { AddParameters(segmentIndex, parameters); } + /// + /// Replaces the parameter list of the last segment. + /// public void SetParameters(params string[] parameters) => SetParameters(Segments.Count - 1, parameters); + #endregion + /// + /// Returns the total number of tokens across all segments. + /// public int GetParameterCount() { int count = 0; - foreach(var segment in Segments) { + foreach (var segment in Segments) { count += segment.Parameters.Count; } - return count; } + #region Build + /// + /// Produces a concrete using values from an external object. + /// + /// Object providing positional values. public SourceLink Build(State parameterValues) => Build(parameterValues.GetState()); + /// + /// Produces a concrete by substituting into the template. + /// + /// Flat array of values that will be written in the order that parameters appear when segments are enumerated left‑to‑right. + /// The completed . + /// If the supplied value count does not match (). public SourceLink Build(params object[] parameterValues) { ArgumentOutOfRangeException.ThrowIfNotEqual(parameterValues.Length, GetParameterCount()); @@ -145,22 +336,29 @@ namespace Beam { link.Append(Protocol); link.Append("://"); link.Append(Host); + int pvC = 0; - foreach(var segment in Segments) { + foreach (var segment in Segments) { link.Append('/'); link.Append(segment.Name); for (int i = 0; i < segment.Parameters.Count; i++) { if (segment.Parameters[i].Position.HasFlag(Position.Before)) link.Append(segment.Parameters[i].Name); + link.Append(parameterValues[pvC++]); + if (segment.Parameters[i].Position.HasFlag(Position.After)) link.Append(segment.Parameters[i].Name); + if (i + 1 < segment.Parameters.Count && segment.Separator is not null) link.Append(segment.Separator); } + + link.Append(segment.Suffix); } return new SourceLink(link.ToString()); } + #endregion } } diff --git a/aeqw89.Beam/aeqw89.Beam.csproj b/aeqw89.Beam/aeqw89.Beam.csproj index 1a517c6..9f5b57b 100644 --- a/aeqw89.Beam/aeqw89.Beam.csproj +++ b/aeqw89.Beam/aeqw89.Beam.csproj @@ -7,7 +7,7 @@ Beam aeqw89 qwsdcvghyu - 1.3.0 + 1.3.2 A library for downloading internet resources https://github.com/qwsdcvghyu89/Beam https://github.com/qwsdcvghyu89/Beam