public override void ConvertToJavascript(JavascriptConversionContext context) { var initExpr = context.Node as MemberInitExpression; if (initExpr == null) { return; } var typeOk1 = this.NewObjectTypes?.Contains(initExpr.Type) ?? false; var typeOk2 = this.TypePredicate?.Invoke(initExpr.Type) ?? false; var typeOk3 = this.NewObjectTypes == null && this.TypePredicate == null; if (!typeOk1 && !typeOk2 && !typeOk3) { return; } if (initExpr.NewExpression.Arguments.Count > 0) { return; } if (initExpr.Bindings.Any(mb => mb.BindingType != MemberBindingType.Assignment)) { return; } context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(0)) { writer.Write('{'); var posStart = writer.Length; foreach (var assignExpr in initExpr.Bindings.Cast <MemberAssignment>()) { if (writer.Length > posStart) { writer.Write(','); } var metadataProvider = context.Options.GetMetadataProvider(); var meta = metadataProvider.GetMemberMetadata(assignExpr.Member); var memberName = meta?.MemberName; Debug.Assert(!string.IsNullOrEmpty(memberName), "!string.IsNullOrEmpty(memberName)"); if (Regex.IsMatch(memberName, @"^\w[\d\w]*$")) { writer.Write(memberName); } else { writer.WriteLiteral(memberName); } writer.Write(':'); context.Visitor.Visit(assignExpr.Expression); } writer.Write('}'); } }
public override void ConvertToJavascript(JavascriptConversionContext context) { var cte = context.Node as ConstantExpression; if (cte != null && cte.Type.GetTypeInfo().IsEnum) { context.PreventDefault(); var writer = context.GetWriter(); long remaining = Convert.ToInt64(cte.Value); var flagsAsString = (this.opts & EnumOptions.FlagsAsStringWithSeparator) != 0; var flagsAsOrs = (this.opts & EnumOptions.FlagsAsNumericOrs) != 0; var flagsAsArray = (this.opts & EnumOptions.FlagsAsArray) != 0; var isFlags = cte.Type.GetTypeInfo().IsDefined(typeof(FlagsAttribute), false); // when value is zero if (remaining == 0 && (!isFlags || !(flagsAsString || flagsAsOrs || flagsAsArray))) { if (WriteSingleEnumItem(context, writer, 0, cte.Value, false)) { return; } } // reading enum composition var values = Enum.GetValues(cte.Type); var selected = new List <int>(); for (int itV = 0; itV < values.Length; itV++) { var val = Convert.ToInt64(values.GetValue(values.Length - itV - 1)); if ((val & remaining) == val) { remaining &= ~val; selected.Add(values.Length - itV - 1); if (!isFlags) { break; } } } // selecting enum case if (isFlags) { var cnt = selected.Count + (remaining != 0 ? 1 : 0); PrecedenceController xpto = null; string start = ""; string separator = ""; string end = ""; if (flagsAsString) { xpto = writer.Operation(JavascriptOperationTypes.Literal); start = "\""; separator = "|"; end = "\""; } else if (flagsAsArray) { xpto = writer.Operation(0); start = "["; separator = ","; end = "]"; } else if (flagsAsOrs && cnt > 1) { xpto = writer.Operation(JavascriptOperationTypes.Or); start = ""; separator = "|"; end = ""; } else if (cnt > 1) { throw new NotSupportedException("When converting flags enums to JavaScript, a flags option must be specified."); } using (xpto) { writer.Write(start); var pos0 = writer.Length; for (int itIdx = 0; itIdx < selected.Count; itIdx++) { if (pos0 != writer.Length) { writer.Write(separator); } var index = selected[itIdx]; var enumVal = values.GetValue(index); var val = Convert.ToInt64(enumVal); WriteSingleEnumItem(context, writer, val, enumVal, flagsAsString); } if (remaining != 0) { if (pos0 != writer.Length) { writer.Write(separator); } WriteSingleEnumItem(context, writer, remaining, remaining, flagsAsString); } writer.Write(end); } } else { if (remaining != 0) { var enumVal = cte.Value; var val = Convert.ToInt64(cte.Value); WriteSingleEnumItem(context, writer, val, enumVal, false); } else { foreach (var index in selected) { var enumVal = values.GetValue(index); var val = Convert.ToInt64(enumVal); WriteSingleEnumItem(context, writer, val, enumVal, false); } } } } }
public override void ConvertToJavascript(JavascriptConversionContext context) { var methodCall = context.Node as MethodCallExpression; if (methodCall != null) { if (methodCall.Method.DeclaringType == typeof(Enumerable)) { switch (methodCall.Method.Name) { case "Select": { context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(JavascriptOperationTypes.Call)) { using (writer.Operation(JavascriptOperationTypes.IndexerProperty)) { // public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector) // public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector) var pars = methodCall.Method.GetParameters(); if (pars.Length != 2) { throw new NotSupportedException("The `Enumerable.Select` method must have 2 parameters."); } context.Visitor.Visit(methodCall.Arguments[0]); writer.Write(".map"); } writer.Write('('); // separator using (writer.Operation(0)) context.Visitor.Visit(methodCall.Arguments[1]); writer.Write(')'); } return; } case "Where": { context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(JavascriptOperationTypes.Call)) { using (writer.Operation(JavascriptOperationTypes.IndexerProperty)) { // public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) // public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, int, bool> predicate) var pars = methodCall.Method.GetParameters(); if (pars.Length != 2) { throw new NotSupportedException("The `Enumerable.Where` method must have 2 parameters."); } context.Visitor.Visit(methodCall.Arguments[0]); writer.Write(".filter"); } writer.Write('('); // separator using (writer.Operation(0)) context.Visitor.Visit(methodCall.Arguments[1]); writer.Write(')'); } return; } case "ToArray": { // Ecma Script 6+: use spread operator // Other: use array `slice` if (context.Options.ScriptVersion.Supports(JavascriptSyntaxFeature.ArraySpread)) { context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(0)) { writer.Write('['); writer.Write("..."); using (writer.Operation(JavascriptOperationTypes.ParamIsolatedLhs)) context.Visitor.Visit(methodCall.Arguments[0]); writer.Write(']'); } } else { context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(JavascriptOperationTypes.Call)) { using (writer.Operation(JavascriptOperationTypes.IndexerProperty)) { context.Visitor.Visit(methodCall.Arguments[0]); writer.Write(".slice"); } writer.Write('('); writer.Write(')'); } } return; } } } } }
public override void ConvertToJavascript(JavascriptConversionContext context) { var methodCall = context.Node as MethodCallExpression; if (methodCall != null) { if (methodCall.Method.DeclaringType == typeof(string)) { switch (methodCall.Method.Name) { case "Concat": { context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(JavascriptOperationTypes.Concat)) { if (methodCall.Arguments.Count == 0) { writer.Write("''"); } else { if (GetTypeOfExpression(methodCall.Arguments[0]) != typeof(string)) { writer.Write("''+"); } context.WriteMany('+', methodCall.Arguments); } } return; } case "Join": { context.PreventDefault(); var writer = context.GetWriter(); using (writer.Operation(JavascriptOperationTypes.Call)) { using (writer.Operation(JavascriptOperationTypes.IndexerProperty)) { var pars = methodCall.Method.GetParameters(); if (pars.Length == 4 && pars[1].ParameterType.IsArray && pars[2].ParameterType == typeof(int) && pars[3].ParameterType == typeof(int)) { throw new NotSupportedException("The `String.Join` method with start and count paramaters is not supported."); } if (pars.Length != 2 || !TypeHelpers.IsEnumerableType(pars[1].ParameterType)) { throw new NotSupportedException("This `String.Join` method is not supported."); } // if second parameter is an enumerable, render it directly context.Visitor.Visit(methodCall.Arguments[1]); writer.Write(".join"); } writer.Write('('); // separator using (writer.Operation(0)) context.Visitor.Visit(methodCall.Arguments[0]); writer.Write(')'); } return; } } } } }
public override void ConvertToJavascript(JavascriptConversionContext context) { var methodCall = context.Node as MethodCallExpression; if (methodCall != null) { if (methodCall.Method.DeclaringType == typeof(Math)) { NameLength jsInfo; if (membersMap.TryGetValue(methodCall.Method.Name, out jsInfo)) { if (methodCall.Arguments.Count == jsInfo.length) { context.PreventDefault(); using (context.Operation(JavascriptOperationTypes.Call)) { using (context.Operation(JavascriptOperationTypes.IndexerProperty)) context.Write("Math." + jsInfo.name); context.WriteManyIsolated('(', ')', ',', methodCall.Arguments); } return; } else if (methodCall.Method.Name == "Log" && methodCall.Arguments.Count == 2) { // JavaScript does not support `Math.log` with 2 parameters, // But it is easy enough for us to give a little help! context.PreventDefault(); using (context.Operation(JavascriptOperationTypes.MulDivMod)) { using (context.Operation(JavascriptOperationTypes.Call)) { using (context.Operation(JavascriptOperationTypes.IndexerProperty)) context.Write("Math.log"); context.Write('('); using (context.Operation(0)) context.Write(methodCall.Arguments[0]); context.Write(')'); } context.Write('/'); using (context.Operation(JavascriptOperationTypes.Call)) { using (context.Operation(JavascriptOperationTypes.IndexerProperty)) context.Write("Math.log"); context.Write('('); using (context.Operation(0)) context.Write(methodCall.Arguments[1]); context.Write(')'); } } return; } else if (methodCall.Method.Name == "Round" && methodCall.Arguments.Count == 2 && TypeHelpers.IsNumericType(methodCall.Arguments[1].Type)) { // We won't support `Math.Round` with two parameters by default. // To do it, we'd have to repeat an input value in the expression (unacceptable): // Math.Round(A, B) => Math.round(A * Math.pow(10, B)) / Math.pow(10, B) // Or start helping with hacky things (acceptable, but not by default): // Math.Round(A, B) => (function(a, b) { return Math.round(a * b) / b; })(A, Math.pow(10, B)); if (this.round2) { context.PreventDefault(); using (context.Operation(JavascriptOperationTypes.Call)) { context.WriteLambda <Func <double, double, double> >((a, b) => Math.Round(a * b) / b); context.Write('('); using (context.Operation(0)) context.Write(methodCall.Arguments[0]); context.Write(','); using (context.Operation(0)) using (context.Operation(JavascriptOperationTypes.Call)) { using (context.Operation(JavascriptOperationTypes.IndexerProperty)) context.Write("Math.pow"); context.Write('('); context.Write("10"); context.Write(','); using (context.Operation(0)) context.Write(methodCall.Arguments[1]); context.Write(')'); } context.Write(')'); return; } } } } } } // E and PI are constant values, they will never result in // a member access expression. We will have to catch the // exact numbers, and convert them instead. var constVal = context.Node as ConstantExpression; if (constVal != null) { if (constVal.Value.Equals(Math.E)) { context.PreventDefault(); using (context.Operation(JavascriptOperationTypes.IndexerProperty)) context.Write("Math.E"); } else if (constVal.Value.Equals(Math.PI)) { context.PreventDefault(); using (context.Operation(JavascriptOperationTypes.IndexerProperty)) context.Write("Math.PI"); } } }