/// <summary> /// Writes a property accessor. /// </summary> /// <param name="context"></param> /// <param name="propertyName">The property to access. Anything that can be converted to a string.</param> /// <returns></returns> /// <exception cref="ArgumentNullException"></exception> public static JavascriptConversionContext WriteAccessor( [NotNull] this JavascriptConversionContext context, [NotNull] string propertyName) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (propertyName == null) { throw new ArgumentNullException(nameof(propertyName)); } if (Regex.IsMatch(propertyName, @"^\w[\d\w]*$")) { context.GetWriter().Write('.'); context.GetWriter().Write(propertyName); } else if (Regex.IsMatch(propertyName, @"^\d+$")) { context.GetWriter().Write('['); context.GetWriter().Write(propertyName); context.GetWriter().Write(']'); } else { context.GetWriter().Write('['); context.GetWriter().WriteLiteral(propertyName); context.GetWriter().Write(']'); } return(context); }
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('}'); } }
/// <summary> /// Writes a single character. /// </summary> /// <param name="context">The Javascript conversion context.</param> /// <param name="ch">Character to write.</param> /// <returns>The Javascript conversion context itself, to allow fluent style rendering.</returns> public static JavascriptConversionContext Write(this JavascriptConversionContext context, char ch) { var writer = context.GetWriter(); writer.Write(ch); return(context); }
/// <summary> /// Writes many expressions isolated from outer and inner operations by opening, closing and separator characters. /// </summary> /// <param name="context">The Javascript conversion context.</param> /// <param name="opening">First character to render, isolating from outer operation.</param> /// <param name="closing">Last character to render, isolating from outer operation.</param> /// <param name="separator">Separator character to render, isolating one parameter from the other.</param> /// <param name="nodes">Nodes to render.</param> public static JavascriptConversionContext WriteManyIsolated( this JavascriptConversionContext context, char opening, char closing, char separator, IEnumerable <Expression> nodes) { var writer = context.GetWriter(); writer.Write(opening); using (writer.Operation(0)) context.WriteMany(separator, nodes); writer.Write(closing); return(context); }
/// <summary> /// Writes many expression nodes, separated by the given separator. /// </summary> /// <param name="context">The Javascript conversion context.</param> /// <param name="separator">Separator to be used.</param> /// <param name="nodes">A list of nodes to write.</param> /// <returns>The Javascript conversion context itself, to allow fluent style rendering.</returns> public static JavascriptConversionContext WriteMany( this JavascriptConversionContext context, char separator, IEnumerable <Expression> nodes) { var writer = context.GetWriter(); int count = 0; foreach (var node in nodes) { if (count++ > 0) { writer.Write(separator); } context.Visitor.Visit(node); } return(context); }
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": { 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": { 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(JavascriptSyntax.ArraySpread)) { 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 { 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 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(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 static JavascriptConversionContext WriteFormat(this JavascriptConversionContext context, string format, params object[] values) { context.GetWriter().WriteFormat(format, values); return(context); }
/// <summary> /// Writes a string to the output. /// </summary> /// <param name="context">The Javascript conversion context.</param> /// <param name="str">String to write.</param> /// <returns>The Javascript conversion context itself, to allow fluent style rendering.</returns> public static JavascriptConversionContext Write(this JavascriptConversionContext context, string str) { context.GetWriter().Write(str); return(context); }
/// <summary> /// Encloses the following write calls in an operation context, /// that will automatically write precedence operators '(' and ')' if needed, /// depening on the operations stack. /// <para> /// For example, a sum (+) /// inside a multiplication (*) requires the precedence operators. /// </para> /// <para> /// To isolate operations, you can pass 0 to the <paramref name="op"/> parameter, /// making neither the current nor the inner operation need precedence operators. /// </para> /// </summary> /// <param name="context">Context of the conversion.</param> /// <param name="op">The operation that you want to render in the scope.</param> /// <returns>A disposable object that renders the ending ')' when needed.</returns> public static IDisposable Operation( this JavascriptConversionContext context, JavascriptOperationTypes op) { return(context.GetWriter().Operation(op)); }