diff --git a/src/Framework/Framework/Compilation/Javascript/JavascriptTranslatableMethodCollection.cs b/src/Framework/Framework/Compilation/Javascript/JavascriptTranslatableMethodCollection.cs index ad843b4789..21dabf13e4 100644 --- a/src/Framework/Framework/Compilation/Javascript/JavascriptTranslatableMethodCollection.cs +++ b/src/Framework/Framework/Compilation/Javascript/JavascriptTranslatableMethodCollection.cs @@ -175,6 +175,7 @@ public void AddDefaultMethodTranslators() AddMethodTranslator(() => default(ICollection)!.Count, lengthMethod); AddMethodTranslator(() => default(ICollection)!.Count, lengthMethod); AddMethodTranslator(() => default(IReadOnlyCollection)!.Count, lengthMethod); + AddMethodTranslator(() => default(ImmutableArray)!.Length, lengthMethod); AddMethodTranslator(() => "".Length, lengthMethod); AddMethodTranslator(() => Enums.GetNames(), new EnumGetNamesMethodTranslator()); var identityTranslator = new GenericMethodCompiler(a => a[1]); @@ -538,9 +539,15 @@ bool IsDelegateReturnTypeEnum(Type type) string GetDelegateReturnTypeHash(Type type) => type.GetGenericArguments().Last().GetTypeHash(); - AddMethodTranslator(() => Enumerable.All(Enumerable.Empty(), _ => false), new GenericMethodCompiler(args => args[1].Member("every").Invoke(args[2]))); - AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty()), new GenericMethodCompiler(args => args[1].Member("some").Invoke(returnTrueFunc.Clone()))); - AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty(), _ => 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(), _ => false), all); + AddMethodTranslator(() => ImmutableArrayExtensions.All(default(ImmutableArray), _ => false), all); + var any = new GenericMethodCompiler(args => args[1].Member("length").Binary(BinaryOperatorType.Greater, new JsLiteral(0))); + AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty()), any); + AddMethodTranslator(() => ImmutableArrayExtensions.Any(default(ImmutableArray)), any); + var anyPred = new GenericMethodCompiler(args => args[1].Member("some").Invoke(args[2])); + AddMethodTranslator(() => Enumerable.Any(Enumerable.Empty(), _ => false), anyPred); + AddMethodTranslator(() => ImmutableArrayExtensions.Any(default(ImmutableArray), _ => false), anyPred); AddMethodTranslator(() => Enumerable.Concat(Enumerable.Empty(), Enumerable.Empty()), new GenericMethodCompiler(args => args[1].Member("concat").Invoke(args[2]))); AddMethodTranslator(() => Enumerable.Count(Enumerable.Empty()), new GenericMethodCompiler(args => args[1].Member("length"))); AddMethodTranslator(() => Enumerable.Empty().Distinct(), new GenericMethodCompiler(args => new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("distinct").Invoke(args[1]), @@ -548,17 +555,27 @@ string GetDelegateReturnTypeHash(Type type) AddMethodTranslator(() => Enumerable.Empty().ElementAt(0), new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method))); + AddMethodTranslator(() => Enumerable.Empty().ElementAtOrDefault(0), + new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method))); + AddMethodTranslator(() => ImmutableArrayExtensions.ElementAt(default(ImmutableArray), 0), + new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method))); + AddMethodTranslator(() => ImmutableArrayExtensions.ElementAtOrDefault(default(ImmutableArray), 0), + new GenericMethodCompiler((args, method) => BuildIndexer(args[1], args[2], method))); - AddMethodTranslator(() => Enumerable.Empty().FirstOrDefault(), new GenericMethodCompiler((args, m) => - args[1].Indexer(0) - .WithAnnotation(new VMPropertyInfoAnnotation(m.ReturnType)).WithAnnotation(MayBeNullAnnotation.Instance))); - AddMethodTranslator(() => Enumerable.Empty().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().LastOrDefault(), new GenericMethodCompiler(args => - new JsIdentifierExpression("dotvvm").Member("translations").Member("array").Member("lastOrDefault").Invoke(args[1], returnTrueFunc.Clone()).WithAnnotation(MayBeNullAnnotation.Instance))); - AddMethodTranslator(() => Enumerable.Empty().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().FirstOrDefault(), new GenericMethodCompiler((args, m) => BuildIndexer(args[1], new JsLiteral(0), m))); + AddMethodTranslator(() => ImmutableArrayExtensions.FirstOrDefault(default(ImmutableArray)), 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().FirstOrDefault(_ => true), firstOrDefaultPred); + AddMethodTranslator(() => ImmutableArrayExtensions.FirstOrDefault(default(ImmutableArray), _ => true), firstOrDefaultPred); + + var lastOrDefault = new GenericMethodCompiler(args => args[1].Member("at").Invoke(new JsLiteral(-1)).WithAnnotation(MayBeNullAnnotation.Instance)); + AddMethodTranslator(() => Enumerable.Empty().LastOrDefault(), lastOrDefault); + AddMethodTranslator(() => ImmutableArrayExtensions.LastOrDefault(default(ImmutableArray)), 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().LastOrDefault(_ => false), lastOrDefaultPred); + AddMethodTranslator(() => ImmutableArrayExtensions.LastOrDefault(default(ImmutableArray), _ => false), lastOrDefaultPred); AddMethodTranslator(() => Enumerable.Empty().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)), @@ -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().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().Select(_ => Generic.Enum.Something), select); + AddMethodTranslator(() => ImmutableArrayExtensions.Select(default(ImmutableArray), _ => Generic.Enum.Something), select); AddMethodTranslator(() => Enumerable.Empty().Skip(0), new GenericMethodCompiler(args => args[1].Member("slice").Invoke(args[2]))); AddMethodTranslator(() => Enumerable.Empty().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().Where(_ => true), where); + AddMethodTranslator(() => ImmutableArrayExtensions.Where(default(ImmutableArray), _ => true), where); + AddMethodTranslator(() => Enumerable.Empty().ToArray(), new GenericMethodCompiler(args => args[1])); AddMethodTranslator(() => Enumerable.Empty().ToList(), new GenericMethodCompiler(args => args[1])); + AddMethodTranslator(() => Enumerable.Empty().ToHashSet(), new GenericMethodCompiler(args => args[1])); + AddMethodTranslator(() => Enumerable.AsEnumerable(Enumerable.Empty()), new GenericMethodCompiler(args => args[1])); + + AddMethodTranslator(() => ImmutableArray.ToImmutableArray(Enumerable.Empty()), new GenericMethodCompiler(args => args[1])); + AddMethodTranslator(() => ImmutableList.ToImmutableList(Enumerable.Empty()), new GenericMethodCompiler(args => args[1])); + AddMethodTranslator(() => ImmutableArrayExtensions.ToArray(ImmutableArray.Empty), new GenericMethodCompiler(args => args[1])); - AddMethodTranslator(() => Enumerable.Empty().Where(_ => true), new GenericMethodCompiler(args => args[1].Member("filter").Invoke(args[2]))); + AddMethodTranslator(() => Enumerable.Empty(), new GenericMethodCompiler(args => new JsArrayExpression())); + AddMethodTranslator(() => Array.Empty(), new GenericMethodCompiler(args => new JsArrayExpression())); AddDefaultNumericEnumerableTranslations(); } diff --git a/src/Framework/Framework/Diagnostics/CompilationPage.dothtml b/src/Framework/Framework/Diagnostics/CompilationPage.dothtml index 6f545a8557..6270e1b1a7 100644 --- a/src/Framework/Framework/Diagnostics/CompilationPage.dothtml +++ b/src/Framework/Framework/Diagnostics/CompilationPage.dothtml @@ -34,10 +34,14 @@ Text="Master pages" class="nav" Class-active="{value: ActiveTab == 2}" /> +
-
+

Routes

@@ -52,15 +56,19 @@ - {{value: Url}} + {{value: Url == "" ? "" : Url}} - + {{value: Url}} + HeaderText="Virtual Path"> + + + +
-
+

Controls

@@ -89,7 +97,11 @@ HeaderCssClass="fit" CssClass="fit" /> - + + + + +
-
+

Master pages

@@ -112,11 +124,15 @@ Class-success="{value: Status == 'CompletedSuccessfully'}" /> - + + + + + + CssClass="fit status"/> @@ -127,6 +143,67 @@
+
+

Errors

+ +

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. +

+ + + + + + + + + r.Status == 'CompilationFailed')} WrapperTagName=tbody > + + + + + + + + + r.Status == 'CompilationFailed')} WrapperTagName=tbody > + + + + + + + + + r.Status == 'CompilationFailed')} WrapperTagName=tbody > + + + + + + + + + + +
TypeNameFile pathStatusActions
Route {RouteName}"}> + + {{value: RouteName}} + + + {{value: RouteName}} + + {{value: VirtualPath}}{{value: Status}} + +
Control + {{value: $"{TagPrefix}:{TagName}"}} + {{value: VirtualPath}}{{value: Status}} + +
Master page{{value: VirtualPath}}{{value: Status}} + +
+

diff --git a/src/Framework/Framework/Diagnostics/CompilationPageViewModel.cs b/src/Framework/Framework/Diagnostics/CompilationPageViewModel.cs index cfe6c388ec..c6007f36fc 100644 --- a/src/Framework/Framework/Diagnostics/CompilationPageViewModel.cs +++ b/src/Framework/Framework/Diagnostics/CompilationPageViewModel.cs @@ -15,6 +15,7 @@ public class CompilationPageViewModel : DotvvmViewModelBase public ImmutableArray MasterPages => viewCompilationService.GetMasterPages(); public ImmutableArray Controls => viewCompilationService.GetControls(); public int ActiveTab { get; set; } = 0; + public string PathBase => Context.TranslateVirtualPath("~/"); public CompilationPageViewModel(IDotvvmViewCompilationService viewCompilationService) { diff --git a/src/Tests/Binding/JavascriptCompilationTests.cs b/src/Tests/Binding/JavascriptCompilationTests.cs index f86d57076a..0afcb96536 100644 --- a/src/Tests/Binding/JavascriptCompilationTests.cs +++ b/src/Tests/Binding/JavascriptCompilationTests.cs @@ -562,9 +562,10 @@ public void JsTranslator_DictionaryRemove() [TestMethod] [DataRow("Enumerable.Where(LongArray, (long item) => item % 2 == 0)", DisplayName = "Regular call of Enumerable.Where")] [DataRow("LongArray.Where((long item) => item % 2 == 0)", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().Where((long item) => item % 2 == 0)", DisplayName = "Immutable array - extension method")] public void JsTranslator_EnumerableWhere(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("LongArray().filter((item)=>ko.unwrap(item)%2==0)", result); } @@ -579,18 +580,21 @@ public void JsTranslator_NestedEnumerableMethods() [TestMethod] [DataRow("Enumerable.Select(LongArray, (long item) => -item)", DisplayName = "Regular call of Enumerable.Select")] [DataRow("LongArray.Select((long item) => -item)", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().Select((long item) => -item)", DisplayName = "Immutable array - extension method")] + [DataRow("LongArray.ToImmutableList().Select((long item) => -item)", DisplayName = "Immutable list - extension method")] public void JsTranslator_EnumerableSelect(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("LongArray().map((item)=>-ko.unwrap(item))", result); } [TestMethod] [DataRow("Enumerable.Concat(LongArray, LongArray)", DisplayName = "Regular call of Enumerable.Concat")] [DataRow("LongArray.Concat(LongArray)", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().Concat(LongArray.ToImmutableArray())", DisplayName = "Immutable arrays")] public void JsTranslator_EnumerableConcat(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("LongArray().concat(LongArray())", result); } @@ -636,18 +640,20 @@ public void JsTranslator_ListAddRange() [TestMethod] [DataRow("Enumerable.All(LongArray, (long item) => item > 0)", DisplayName = "Regular call of Enumerable.All")] [DataRow("LongArray.All((long item) => item > 0)", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().All((long item) => item > 0)", DisplayName = "Immutable array - extension method")] public void JsTranslator_EnumerableAll(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("LongArray().every((item)=>ko.unwrap(item)>0)", result); } [TestMethod] [DataRow("Enumerable.Any(LongArray, (long item) => item > 0)", DisplayName = "Regular call of Enumerable.Any")] [DataRow("LongArray.Any((long item) => item > 0)", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().Any((long item) => item > 0)", DisplayName = "Immutable array - extension method")] public void JsTranslator_EnumerableAny(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("LongArray().some((item)=>ko.unwrap(item)>0)", result); } @@ -665,21 +671,35 @@ public void JsTranslator_ICollectionClear() Assert.AreEqual("dotvvm.translations.array.clear(TestViewModel2().Collection)", result); } + [TestMethod] + [DataRow("Enumerable.Empty()")] + [DataRow("Array.Empty()")] + [DataRow("ImmutableArray.Empty")] + [DataRow("ImmutableList.Empty")] + public void JsTranslator_EnumerableEmpty(string binding) + { + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); + Assert.AreEqual("[]", result); + } + + [TestMethod] [DataRow("Enumerable.FirstOrDefault(LongArray)", DisplayName = "Regular call of Enumerable.FirstOrDefault")] [DataRow("LongArray.FirstOrDefault()", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().FirstOrDefault()", DisplayName = "Immutable array - extension method")] public void JsTranslator_EnumerableFirstOrDefault(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("LongArray()[0]", result); } [TestMethod] [DataRow("Enumerable.FirstOrDefault(LongArray, (long item) => item > 0)", DisplayName = "Regular call of Enumerable.FirstOrDefault")] [DataRow("LongArray.FirstOrDefault((long item) => item > 0)", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().FirstOrDefault((long item) => item > 0)", DisplayName = "Immutable array - extension method")] public void JsTranslator_EnumerableFirstOrDefaultParametrized(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("dotvvm.translations.array.firstOrDefault(LongArray(),(item)=>ko.unwrap(item)>0)", result); } @@ -718,10 +738,11 @@ public void JsTranslator_ICollectionContains() [TestMethod] [DataRow("Enumerable.LastOrDefault(LongArray)", DisplayName = "Regular call of Enumerable.LastOrDefault")] [DataRow("LongArray.LastOrDefault()", DisplayName = "Syntax sugar - extension method")] + [DataRow("LongArray.ToImmutableArray().LastOrDefault()", DisplayName = "Immutable array - extension method")] public void JsTranslator_EnumerableLastOrDefault(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); - Assert.AreEqual("dotvvm.translations.array.lastOrDefault(LongArray(),()=>true)", result); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); + Assert.AreEqual("LongArray().at(-1)", result); } [TestMethod] @@ -729,7 +750,7 @@ public void JsTranslator_EnumerableLastOrDefault(string binding) [DataRow("LongArray.LastOrDefault((long item) => item > 0)", DisplayName = "Syntax sugar - extension method")] public void JsTranslator_EnumerableLastOrDefaultParametrized(string binding) { - var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq") }, new[] { typeof(TestViewModel) }); + var result = CompileBinding(binding, new[] { new NamespaceImport("System.Linq"), new NamespaceImport("System.Collections.Immutable") }, new[] { typeof(TestViewModel) }); Assert.AreEqual("dotvvm.translations.array.lastOrDefault(LongArray(),(item)=>ko.unwrap(item)>0)", result); }