mirror of
https://github.com/k1tbyte/Wand-Enhancer.git
synced 2026-08-29 22:01:18 +00:00
6716da5c80
Anchor each patch on a stable string (API endpoint, IPC channel, method name) and walk the delimiter structure via JsCursor to the edit site, reading minified identifiers out of the located region. Move injected JavaScript into WandEnhancer/Patches/*.js as embedded resources. Declare patches as PatchEntry rows in EnhancerConfig with CandidateFileNames, SearchHints and optional CapabilityHints. Recognise keyword-preceded regex literals in JsCursor so `return/re/.test(x)` no longer desynchronises the scan. Require the remote setValue anchor to match exactly once; Wand ships sibling call sites for other sources. Require both backup halves in IsPatched so a partial backup no longer blocks patch and restore at the same time. Chain inner exceptions when unpack or pack fails. Rename Common to ProcessTerminator and Utils.Extensions to WeModInstalls.
64 lines
2.4 KiB
C#
64 lines
2.4 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace WandEnhancer.Core.Js
|
|
{
|
|
/// <summary>
|
|
/// Loads injected JavaScript from embedded <c>Patches/*.js</c> files so payloads stay
|
|
/// lintable source rather than escaped C# string literals.
|
|
/// </summary>
|
|
internal static class PatchPayload
|
|
{
|
|
private const string ResourcePrefix = "patches/";
|
|
|
|
private static readonly ConcurrentDictionary<string, string> Cache =
|
|
new ConcurrentDictionary<string, string>(StringComparer.Ordinal);
|
|
|
|
private static readonly Regex Placeholder = new Regex(@"\$\{(?<name>\w+)\}");
|
|
|
|
/// <summary>
|
|
/// Loads a payload, replacing each <c>${name}</c> placeholder from alternating name/value pairs.
|
|
/// Substitution is a single pass, so injected bundle text is never rescanned for placeholders.
|
|
/// Unknown placeholders are left intact for the caller's own regex replacement to resolve.
|
|
/// </summary>
|
|
public static string Load(string name, params string[] placeholders)
|
|
{
|
|
if (placeholders.Length % 2 != 0)
|
|
{
|
|
throw new ArgumentException("Placeholders must be name/value pairs", nameof(placeholders));
|
|
}
|
|
|
|
var values = new Dictionary<string, string>(StringComparer.Ordinal);
|
|
for (int index = 0; index < placeholders.Length; index += 2)
|
|
{
|
|
values[placeholders[index]] = placeholders[index + 1];
|
|
}
|
|
|
|
return Placeholder.Replace(
|
|
Cache.GetOrAdd(name, ReadResource),
|
|
match => values.TryGetValue(match.Groups["name"].Value, out var value) ? value : match.Value);
|
|
}
|
|
|
|
private static string ReadResource(string name)
|
|
{
|
|
string resourceName = $"{ResourcePrefix}{name}.js";
|
|
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName))
|
|
{
|
|
if (stream == null)
|
|
{
|
|
throw new FileNotFoundException($"Embedded patch payload not found: {resourceName}");
|
|
}
|
|
|
|
using (var reader = new StreamReader(stream))
|
|
{
|
|
return reader.ReadToEnd().Trim();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|