Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 62 additions & 8 deletions uSync.Core/Versions/18.0/SyncLocalLinkProcessor.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;

using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Templates;

namespace uSync.Core.Versions._18._0;

Expand All @@ -18,19 +19,27 @@ public interface ISyncTypedLocalLinkProcessor
public Func<object?, Func<object?, bool>, Func<string, string>, bool> Process { get; }
}


public class SyncLocalLinkProcessor
/// <summary>
/// Finds and replaces the legacy {localLink:x} syntax within values, mapping ids/UDIs to keys.
/// </summary>
/// <remarks>
/// Umbraco's own <c>HtmlLocalLinkParser.FindLegacyLocalLinkIds</c> (and its <c>LocalLinkTag</c> model)
/// are obsolete and scheduled for removal in Umbraco 18, but uSync still needs to detect these
/// legacy (un-migrated) links when mapping content, so the parsing logic lives here instead.
/// </remarks>
public partial class SyncLocalLinkProcessor
{
private readonly HtmlLocalLinkParser _localLinkParser;
// copied from Umbraco.Cms.Core.Templates.HtmlLocalLinkParser.LocalLinkPattern
[GeneratedRegex(@"href=['""](?<locallink>\/?(?:\{|\%7B)localLink:(?<guid>[a-zA-Z0-9-://]+)(?:\}|\%7D))", RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.IgnorePatternWhitespace, "en-GB")]
private static partial Regex LegacyLocalLinkPattern();

private readonly IIdKeyMap _idKeyMap;
private readonly IEnumerable<ISyncTypedLocalLinkProcessor> _localLinkProcessors;

public SyncLocalLinkProcessor(
HtmlLocalLinkParser localLinkParser,
IIdKeyMap idKeyMap,
IEnumerable<ISyncTypedLocalLinkProcessor> localLinkProcessors)
{
_localLinkParser = localLinkParser;
_idKeyMap = idKeyMap;
_localLinkProcessors = localLinkProcessors;
}
Expand All @@ -49,9 +58,9 @@ public bool ProcessToEditorValue(object? editorValue)
public string ProcessStringValue(string input)
{
// find all legacy tags
var tags = _localLinkParser.FindLegacyLocalLinkIds(input).ToList();
var tags = FindLegacyLocalLinkIds(input).ToList();

foreach (HtmlLocalLinkParser.LocalLinkTag tag in tags)
foreach (LocalLinkTag tag in tags)
{
string newTagHref;
if (tag.Udi is not null)
Expand Down Expand Up @@ -101,4 +110,49 @@ public string ProcessStringValue(string input)
return null;
}

// copied from Umbraco.Cms.Core.Templates.HtmlLocalLinkParser.FindLegacyLocalLinkIds
private static IEnumerable<LocalLinkTag> FindLegacyLocalLinkIds(string text)
{
MatchCollection tags = LegacyLocalLinkPattern().Matches(text);
foreach (Match tag in tags)
{
if (tag.Groups.Count <= 0)
{
continue;
}

var id = tag.Groups["guid"].Value;

// The id could be an int or a UDI
if (UdiParser.TryParse(id, out Udi? udi))
{
if (udi is GuidUdi guidUdi)
{
yield return new LocalLinkTag(null, guidUdi, tag.Groups["locallink"].Value);
}
}

if (int.TryParse(id, NumberStyles.Integer, CultureInfo.InvariantCulture, out var intId))
{
yield return new LocalLinkTag(intId, null, tag.Groups["locallink"].Value);
}
}
}

// copied from Umbraco.Cms.Core.Templates.HtmlLocalLinkParser.LocalLinkTag
private sealed class LocalLinkTag
{
public LocalLinkTag(int? intId, GuidUdi? udi, string tagHref)
{
IntId = intId;
Udi = udi;
TagHref = tagHref;
}

public int? IntId { get; }

public GuidUdi? Udi { get; }

public string TagHref { get; }
}
}
Loading