Skip to content

Commit

Permalink
Merge pull request #1713 from riganti/js-translations-immutablearray
Browse files Browse the repository at this point in the history
support Linq methods on ImmutableArray + added Errors tab to Compilation Page
  • Loading branch information
tomasherceg authored Oct 22, 2023
2 parents 5fd4088 + b5ca605 commit c5ef35b
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ public void AddDefaultMethodTranslators()
AddMethodTranslator(() => default(ICollection)!.Count, lengthMethod);
AddMethodTranslator(() => default(ICollection<Generic.T>)!.Count, lengthMethod);
AddMethodTranslator(() => default(IReadOnlyCollection<Generic.T>)!.Count, lengthMethod);
AddMethodTranslator(() => default(ImmutableArray<Generic.T>)!.Length, lengthMethod);
AddMethodTranslator(() => "".Length, lengthMethod);
AddMethodTranslator(() => Enums.GetNames<Generic.Enum>(), new EnumGetNamesMethodTranslator());
var identityTranslator = new GenericMethodCompiler(a => a[1]);
Expand Down Expand Up @@ -538,27 +539,43 @@ bool IsDelegateReturnTypeEnum(Type type)
string GetDelegateReturnTypeHash(Type type)
=> type.GetGenericArguments().Last().GetTypeHash();

AddMethodTranslator(() => Enumerable.All(Enumerable.Empty<Generic.T>(), _ => false), new GenericMethodCompiler(args => args[1].Member("every").Invoke(args[2])));
AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty<Generic.T>()), new GenericMethodCompiler(args => args[1].Member("some").Invoke(returnTrueFunc.Clone())));
AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty<Generic.T>(), _ => false), new GenericMethodCompiler(args => args[1].Member("some").Invoke(args[2])));
var all = new GenericMethodCompiler(args => args[1].Member("every").Invoke(args[2]));
AddMethodTranslator(() => Enumerable.All(Enumerable.Empty<Generic.T>(), _ => false), all);
AddMethodTranslator(() => ImmutableArrayExtensions.All(default(ImmutableArray<Generic.T>), _ => false), all);
var any = new GenericMethodCompiler(args => args[1].Member("length").Binary(BinaryOperatorType.Greater, new JsLiteral(0)));
AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty<Generic.T>()), any);
AddMethodTranslator(() => ImmutableArrayExtensions.Any(default(ImmutableArray<Generic.T>)), any);
var anyPred = new GenericMethodCompiler(args => args[1].Member("some").Invoke(args[2]));
AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty<Generic.T>(), _ => false), anyPred);
AddMethodTranslator(() => ImmutableArrayExtensions.Any(default(ImmutableArray<Generic.T>), _ => false), anyPred);
AddMethodTranslator(() => Enumerable.Concat(Enumerable.Empty<Generic.T>(), Enumerable.Empty<Generic.T>()), new GenericMethodCompiler(args => args[1].Member("concat").Invoke(args[2])));
AddMethodTranslator(() => Enumerable.Count(Enumerable.Empty<Generic.T>()), new GenericMethodCompiler(args => args[1].Member("length")));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Distinct(), new GenericMethodCompiler(args => new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("distinct").Invoke(args[1]),
check: (method, target, arguments) => EnsureIsComparableInJavascript(method, ReflectionUtils.GetEnumerableType(arguments.First().Type).NotNull())));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().ElementAt(0),
new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method)));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().ElementAtOrDefault(0),
new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method)));
AddMethodTranslator(() => ImmutableArrayExtensions.ElementAt(default(ImmutableArray<Generic.T>), 0),
new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method)));
AddMethodTranslator(() => ImmutableArrayExtensions.ElementAtOrDefault(default(ImmutableArray<Generic.T>), 0),
new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method)));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().FirstOrDefault(), new GenericMethodCompiler((args, m) =>
args[1].Indexer(0)
.WithAnnotation(new VMPropertyInfoAnnotation(m.ReturnType)).WithAnnotation(MayBeNullAnnotation.Instance)));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().FirstOrDefault(_ => true), new GenericMethodCompiler(args =>
new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("firstOrDefault").Invoke(args[1], args[2]).WithAnnotation(MayBeNullAnnotation.Instance)));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().LastOrDefault(), new GenericMethodCompiler(args =>
new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("lastOrDefault").Invoke(args[1], returnTrueFunc.Clone()).WithAnnotation(MayBeNullAnnotation.Instance)));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().LastOrDefault(_ => false), new GenericMethodCompiler(args =>
new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("lastOrDefault").Invoke(args[1], args[2]).WithAnnotation(MayBeNullAnnotation.Instance)));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().FirstOrDefault(), new GenericMethodCompiler((args, m) => BuildIndexer(args[1], new JsLiteral(0), m)));
AddMethodTranslator(() => ImmutableArrayExtensions.FirstOrDefault(default(ImmutableArray<Generic.T>)), new GenericMethodCompiler((args, m) => BuildIndexer(args[1], new JsLiteral(0), m)));
var firstOrDefaultPred = new GenericMethodCompiler(args =>
new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("firstOrDefault").Invoke(args[1], args[2]).WithAnnotation(MayBeNullAnnotation.Instance));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().FirstOrDefault(_ => true), firstOrDefaultPred);
AddMethodTranslator(() => ImmutableArrayExtensions.FirstOrDefault(default(ImmutableArray<Generic.T>), _ => true), firstOrDefaultPred);

var lastOrDefault = new GenericMethodCompiler(args => args[1].Member("at").Invoke(new JsLiteral(-1)).WithAnnotation(MayBeNullAnnotation.Instance));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().LastOrDefault(), lastOrDefault);
AddMethodTranslator(() => ImmutableArrayExtensions.LastOrDefault(default(ImmutableArray<Generic.T>)), lastOrDefault);
var lastOrDefaultPred = new GenericMethodCompiler(args =>
new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("lastOrDefault").Invoke(args[1], args[2]).WithAnnotation(MayBeNullAnnotation.Instance));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().LastOrDefault(_ => false), lastOrDefaultPred);
AddMethodTranslator(() => ImmutableArrayExtensions.LastOrDefault(default(ImmutableArray<Generic.T>), _ => false), lastOrDefaultPred);

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().OrderBy(_ => Generic.Enum.Something), new GenericMethodCompiler((jArgs, dArgs) => new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("orderBy")
.Invoke(jArgs[1], jArgs[2], new JsLiteral((IsDelegateReturnTypeEnum(dArgs.Last().Type)) ? GetDelegateReturnTypeHash(dArgs.Last().Type) : null)),
Expand All @@ -567,17 +584,30 @@ string GetDelegateReturnTypeHash(Type type)
.Invoke(jArgs[1], jArgs[2], new JsLiteral((IsDelegateReturnTypeEnum(dArgs.Last().Type)) ? GetDelegateReturnTypeHash(dArgs.Last().Type) : null)),
check: (method, _, arguments) => EnsureIsComparableInJavascript(method, arguments.Last().Type.GetGenericArguments().Last())));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Select(_ => Generic.Enum.Something),
translator: new GenericMethodCompiler(args => args[1].Member("map").Invoke(args[2])));
var select = new GenericMethodCompiler(args => args[1].Member("map").Invoke(args[2]));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Select(_ => Generic.Enum.Something), select);
AddMethodTranslator(() => ImmutableArrayExtensions.Select(default(ImmutableArray<Generic.T>), _ => Generic.Enum.Something), select);
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Skip(0), new GenericMethodCompiler(args => args[1].Member("slice").Invoke(args[2])));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Take(0), new GenericMethodCompiler(args =>
args[1].Member("slice").Invoke(new JsLiteral(0), args[2])));

var where = new GenericMethodCompiler(args => args[1].Member("filter").Invoke(args[2]));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Where(_ => true), where);
AddMethodTranslator(() => ImmutableArrayExtensions.Where(default(ImmutableArray<Generic.T>), _ => true), where);

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().ToArray(), new GenericMethodCompiler(args => args[1]));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().ToList(), new GenericMethodCompiler(args => args[1]));
AddMethodTranslator(() => Enumerable.Empty<Generic.T>().ToHashSet(), new GenericMethodCompiler(args => args[1]));
AddMethodTranslator(() => Enumerable.AsEnumerable(Enumerable.Empty<Generic.T>()), new GenericMethodCompiler(args => args[1]));

AddMethodTranslator(() => ImmutableArray.ToImmutableArray(Enumerable.Empty<Generic.T>()), new GenericMethodCompiler(args => args[1]));
AddMethodTranslator(() => ImmutableList.ToImmutableList(Enumerable.Empty<Generic.T>()), new GenericMethodCompiler(args => args[1]));
AddMethodTranslator(() => ImmutableArrayExtensions.ToArray(ImmutableArray<Generic.T>.Empty), new GenericMethodCompiler(args => args[1]));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>().Where(_ => true), new GenericMethodCompiler(args => args[1].Member("filter").Invoke(args[2])));

AddMethodTranslator(() => Enumerable.Empty<Generic.T>(), new GenericMethodCompiler(args => new JsArrayExpression()));
AddMethodTranslator(() => Array.Empty<Generic.T>(), new GenericMethodCompiler(args => new JsArrayExpression()));
AddDefaultNumericEnumerableTranslations();
}

Expand Down
95 changes: 86 additions & 9 deletions src/Framework/Framework/Diagnostics/CompilationPage.dothtml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@
Text="Master pages"
class="nav"
Class-active="{value: ActiveTab == 2}" />
<dot:Button Click="{staticCommand: ActiveTab = 3}"
Text="Errors"
class="nav"
Class-active="{value: ActiveTab == 3}" />
</nav>
<hr />
<main>
<section Visible="{value: ActiveTab == 0}">
<section IncludeInPage="{value: ActiveTab == 0}">
<h2>Routes</h2>
<dot:GridView DataSource="{value: Routes}" class="nowrap">
<RowDecorators>
Expand All @@ -52,15 +56,19 @@
<dot:GridViewTemplateColumn HeaderText="Url">
<ContentTemplate>
<span IncludeInPage={value: !HasParameters}>
<a href="{value: "/" + Url}">{{value: Url}}</a>
<a href="{value: _root.PathBase + Url}">{{value: Url == "" ? "<Empty>" : Url}}</a>
</span>
<span IncludeInPage={value: HasParameters}>
<span IncludeInPage={value: HasParameters} title={value: Url}>
{{value: Url}}
</span>
</ContentTemplate>
</dot:GridViewTemplateColumn>
<dot:GridViewTextColumn ValueBinding="{value: VirtualPath}"
HeaderText="Virtual Path" />
HeaderText="Virtual Path">
<CellDecorators>
<dot:Decorator title={value: VirtualPath} />
</CellDecorators>
</dot:GridViewTextColumn>
<dot:GridViewTextColumn ValueBinding="{value: Status}"
HeaderText="Status"
HeaderCssClass="fit"
Expand All @@ -76,7 +84,7 @@
</dot:GridView>
</section>

<section Visible="{value: ActiveTab == 1}">
<section IncludeInPage="{value: ActiveTab == 1}" Visible={value: _page.EvaluatingOnClient}>
<h2>Controls</h2>
<dot:GridView DataSource="{value: Controls}" class="nowrap">
<RowDecorators>
Expand All @@ -89,7 +97,11 @@
HeaderCssClass="fit"
CssClass="fit" />
<dot:GridViewTextColumn ValueBinding="{value: TagName}" HeaderText="Tag" />
<dot:GridViewTextColumn ValueBinding="{value: VirtualPath}" HeaderText="Virtual Path" />
<dot:GridViewTextColumn ValueBinding="{value: VirtualPath}" HeaderText="Virtual Path">
<CellDecorators>
<dot:Decorator title={value: VirtualPath} />
</CellDecorators>
</dot:GridViewTextColumn>
<dot:GridViewTextColumn ValueBinding="{value: Status}"
HeaderText="Status"
HeaderCssClass="fit"
Expand All @@ -103,7 +115,7 @@
</dot:GridView>
</section>

<section Visible="{value: ActiveTab == 2}">
<section IncludeInPage="{value: ActiveTab == 2}" Visible={value: _page.EvaluatingOnClient}>
<h2>Master pages</h2>
<dot:GridView DataSource="{value: MasterPages}" class="nowrap">

Expand All @@ -112,11 +124,15 @@
Class-success="{value: Status == 'CompletedSuccessfully'}" />
</RowDecorators>
<Columns>
<dot:GridViewTextColumn ValueBinding="{value: VirtualPath}" HeaderText="Virtual Path" />
<dot:GridViewTextColumn ValueBinding="{value: VirtualPath}" HeaderText="Virtual Path">
<CellDecorators>
<dot:Decorator title={value: VirtualPath} />
</CellDecorators>
</dot:GridViewTextColumn>
<dot:GridViewTextColumn ValueBinding="{value: Status}"
HeaderText="Status"
HeaderCssClass="fit"
CssClass="fit status" />
CssClass="fit status"/>
<dot:GridViewTemplateColumn HeaderText="Actions" HeaderCssClass="fit" CssClass="fit">
<ContentTemplate>
<span Visible="{value: Status != CompilationState.NonCompilable}">
Expand All @@ -127,6 +143,67 @@
</Columns>
</dot:GridView>
</section>
<section IncludeInPage={value: ActiveTab == 3} Visible={value: _page.EvaluatingOnClient} >
<h2>Errors</h2>

<p IncludeInPage={value: MasterPages.AsEnumerable().Any(m => m.Status == 'None') || Controls.AsEnumerable().Any(m => m.Status == 'None') || Routes.AsEnumerable().Any(m => m.Status == 'None')}
style="color: var(--error-dark-color)">
Some files have not been compiled yet. Please press the "Compile all" button to make the list of errors complete.
</p>
<table>
<thead>
<th>Type</th>
<th>Name</th>
<th>File path</th>
<th>Status</th>
<th>Actions</th>
</thead>
<dot:Repeater DataSource={value: Routes.Where(r => r.Status == 'CompilationFailed')} WrapperTagName=tbody >
<tr class="failure">
<td>Route</td>
<td title={value: $"{Url} -> {RouteName}"}>
<span IncludeInPage={value: !HasParameters}>
<a href="{value: _root.PathBase + Url}">{{value: RouteName}}</a>
</span>
<span IncludeInPage={value: HasParameters}>
{{value: RouteName}}
</span>
</td>
<td title={value: VirtualPath}>{{value: VirtualPath}}</td>
<td>{{value: Status}}</td>
<td>
<dot:LinkButton Click="{command: _root.BuildView(_this)}" Text="Recompile" class="execute" />
</td>
</tr>
</dot:Repeater>
<dot:Repeater DataSource={value: Controls.Where(r => r.Status == 'CompilationFailed')} WrapperTagName=tbody >
<tr class="failure">
<td>Control</td>
<td>
{{value: $"{TagPrefix}:{TagName}"}}
</td>
<td title={value: VirtualPath}>{{value: VirtualPath}}</td>
<td>{{value: Status}}</td>
<td>
<dot:LinkButton Click="{command: _root.BuildView(_this)}" Text="Recompile" class="execute" />
</td>
</tr>
</dot:Repeater>
<dot:Repeater DataSource={value: MasterPages.Where(r => r.Status == 'CompilationFailed')} WrapperTagName=tbody >
<tr class="failure">
<td>Master page</td>
<td></td>
<td title={value: VirtualPath}>{{value: VirtualPath}}</td>
<td>{{value: Status}}</td>
<td>
<dot:LinkButton Click="{command: _root.BuildView(_this)}" Text="Recompile" class="execute" />
</td>
</tr>
</dot:Repeater>


</table>
</section>
</main>
<hr />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public class CompilationPageViewModel : DotvvmViewModelBase
public ImmutableArray<DotHtmlFileInfo> MasterPages => viewCompilationService.GetMasterPages();
public ImmutableArray<DotHtmlFileInfo> Controls => viewCompilationService.GetControls();
public int ActiveTab { get; set; } = 0;
public string PathBase => Context.TranslateVirtualPath("~/");

public CompilationPageViewModel(IDotvvmViewCompilationService viewCompilationService)
{
Expand Down
Loading

0 comments on commit c5ef35b

Please sign in to comment.