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