Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime warnings: include markup line number of nearest ancestor #1739

Merged
merged 3 commits into from
Dec 1, 2023
Merged
Changes from 1 commit
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
60 changes: 43 additions & 17 deletions src/Framework/Framework/Controls/DotvvmBindableObjectHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,26 @@ static string ValueDebugString(object? value)
return toStringed;
}

private static (string? prefix, string tagName) FormatControlName(DotvvmBindableObject control, DotvvmConfiguration? config = null)
{
var type = control.GetType();
if (type == typeof(HtmlGenericControl))
return (null, ((HtmlGenericControl)control).TagName!);
var reg = config?.Markup.Controls.FirstOrDefault(c => c.Namespace == type.Namespace && Type.GetType(c.Namespace + "." + type.Name + ", " + c.Assembly) == type) ??
config?.Markup.Controls.FirstOrDefault(c => c.Namespace == type.Namespace) ??
config?.Markup.Controls.FirstOrDefault(c => c.Assembly == type.Assembly.GetName().Name);
var ns = reg?.TagPrefix ?? type.Namespace switch {
"DotVVM.Framework.Controls" => "dot",
"DotVVM.AutoUI.Controls" => "auto",
"DotVVM.BusinessPack.Controls" or "DotVVM.BusinessPack.PostBackHandlers" => "bp",
"DotVVM.BusinessPack.Controls.FilterOperators" => "op",
"DotVVM.BusinessPack.Controls.FilterBuilderFields" => "fp",
_ => "_"
};
var optionsAttribute = type.GetCustomAttribute<ControlMarkupOptionsAttribute>();
return (ns, optionsAttribute?.PrimaryName ?? type.Name);
}

/// <summary> Returns somewhat readable string representing this dotvvm control. </summary>
public static string DebugString(this DotvvmBindableObject control, DotvvmConfiguration? config = null, bool multiline = true, bool useHtml = false)
{
Expand All @@ -506,25 +526,30 @@ public static string DebugString(this DotvvmBindableObject control, DotvvmConfig
select new { p, className, propName = name.propName, memberName = name.memberName, croppedValue, value, isAttached }
).ToArray();

var location = (file: control.TryGetValue(Internal.MarkupFileNameProperty) as string, line: control.TryGetValue(Internal.MarkupLineNumberProperty) as int? ?? -1);
var reg = config?.Markup.Controls.FirstOrDefault(c => c.Namespace == type.Namespace && Type.GetType(c.Namespace + "." + type.Name + ", " + c.Assembly) == type) ??
config?.Markup.Controls.FirstOrDefault(c => c.Namespace == type.Namespace) ??
config?.Markup.Controls.FirstOrDefault(c => c.Assembly == type.Assembly.GetName().Name);
var ns = reg?.TagPrefix ?? type.Namespace switch {
"DotVVM.Framework.Controls" => "dot",
"DotVVM.BusinessPack.Controls" or "DotVVM.BusinessPack.PostBackHandlers" => "bp",
"DotVVM.BusinessPack.Controls.FilterOperators" => "op",
"DotVVM.BusinessPack.Controls.FilterBuilderFields" => "fp",
_ => "_"
};

var location = (
file: control.TryGetValue(Internal.MarkupFileNameProperty) as string,
line: control.TryGetValue(Internal.MarkupLineNumberProperty) as int? ?? -1,
nearestControlInMarkup: (string?)null
);
if (location.line < 0 && location.file is {})
{
// line is not normally inherited, but we can find it manually in an ancestor control
var ancestor = control.GetAllAncestors().FirstOrDefault(c => c.TryGetValue(Internal.MarkupLineNumberProperty) is int line && line >= 0);
if (ancestor is {} && location.file.Equals(ancestor.TryGetValue(Internal.MarkupFileNameProperty)))
{
location.line = (int)ancestor.TryGetValue(Internal.MarkupLineNumberProperty)!;
var ancestorName = FormatControlName(ancestor);
location.nearestControlInMarkup = ancestorName.prefix is null ? ancestorName.tagName : $"{ancestorName.prefix}:{ancestorName.tagName}";
}
}

var cname = FormatControlName(control, config);
string dothtmlString;
if (useHtml)
{
var tagName = type == typeof(HtmlGenericControl) ?
$"<span class='tag-name'>{((HtmlGenericControl)control).TagName}</span>" :
$"<span class='tag-prefix'>{WebUtility.HtmlEncode(ns)}</span>:<span class='control-name'>{WebUtility.HtmlEncode(type.Name)}</span>";
var tagName = cname.prefix is null ?
$"<span class='tag-name'>{cname.tagName}</span>" :
tomasherceg marked this conversation as resolved.
Show resolved Hide resolved
$"<span class='tag-prefix'>{WebUtility.HtmlEncode(cname.prefix)}</span>:<span class='control-name'>{WebUtility.HtmlEncode(cname.tagName)}</span>";
dothtmlString = $"&lt;<span class='tag' title='{WebUtility.HtmlEncode(type.ToCode())}'>{tagName}</span> ";
var prefixLength = dothtmlString.Length;

Expand All @@ -547,7 +572,7 @@ public static string DebugString(this DotvvmBindableObject control, DotvvmConfig
}
else
{
var tagName = type == typeof(HtmlGenericControl) ? ((HtmlGenericControl)control).TagName : ns + ":" + type.Name;
var tagName = cname.prefix is null ? cname.tagName : cname.prefix + ":" + cname.tagName;
dothtmlString = $"<{tagName} ";
var prefixLength = dothtmlString.Length;

Expand All @@ -567,7 +592,8 @@ public static string DebugString(this DotvvmBindableObject control, DotvvmConfig
}

var fileLocation = (location.file)
+ (location.line >= 0 ? ":" + location.line : "");
+ (location.line >= 0 ? ":" + location.line : "")
+ (location.nearestControlInMarkup is null && multiline ? "" : $" (nearest dothtml control is <{location.nearestControlInMarkup}>)");

if (useHtml)
{
Expand Down
Loading