@@ -131,13 +131,59 @@ public JSMarshaller()
131131 /// </summary>
132132 public bool AutoCamelCase { get ; set ; }
133133
134- private string ToCamelCase ( string name )
134+ public static string ToCamelCase ( string name )
135135 {
136- if ( ! AutoCamelCase ) return name ;
136+ if ( name . Length == 0 )
137+ {
138+ return name ;
139+ }
140+
141+ // Skip leading underscores.
142+ int firstLetterIndex = 0 ;
143+ while ( name [ firstLetterIndex ] == '_' )
144+ {
145+ firstLetterIndex ++ ;
146+ if ( firstLetterIndex == name . Length )
147+ {
148+ // Only underscores.
149+ return name ;
150+ }
151+ }
152+
153+ // Only convert if it looks like title-case. (Avoid converting ALLCAPS.)
154+ if ( char . IsUpper ( name [ firstLetterIndex ] ) )
155+ {
156+ for ( int i = firstLetterIndex + 1 ; i < name . Length ; i ++ )
157+ {
158+ if ( char . IsLower ( name [ i ] ) )
159+ {
160+ // Found at least one lowercase letter. Convert to camel-case and return.
161+ char [ ] chars = name . ToCharArray ( ) ;
162+ chars [ firstLetterIndex ] = char . ToLower ( name [ firstLetterIndex ] ) ;
163+ return new string ( chars ) ;
164+ }
165+ }
166+ }
167+
168+ return name ;
169+ }
170+
171+ private UnaryExpression JSMemberNameExpression ( MemberInfo member )
172+ {
173+ string name = member . Name ;
174+ int lastDotIndex = name . LastIndexOf ( '.' ) ;
175+ if ( lastDotIndex > 0 )
176+ {
177+ // For explicit interface implementations, use the simple name.
178+ name = name . Substring ( lastDotIndex + 1 ) ;
179+ }
180+
181+ string jsName = AutoCamelCase ? ToCamelCase ( name ) : name ;
137182
138- StringBuilder sb = new ( name ) ;
139- sb [ 0 ] = char . ToLowerInvariant ( sb [ 0 ] ) ;
140- return sb . ToString ( ) ;
183+ return Expression . Convert (
184+ Expression . Constant ( jsName ) ,
185+ typeof ( JSValue ) ,
186+ typeof ( JSValue ) . GetImplicitConversion ( typeof ( string ) , typeof ( JSValue ) ) ) ;
141187 }
142188
143189 /// <summary>
@@ -603,14 +649,7 @@ public LambdaExpression BuildToJSMethodExpression(MethodInfo method)
603649 * }
604650 */
605651
606- // If the method is an explicit interface implementation, parse off the simple name.
607- // Then convert to JSValue for use as a JS property name.
608- int dotIndex = method. Name. LastIndexOf( '. ') ;
609- Expression methodName = Expression. Convert(
610- Expression . Constant ( ToCamelCase (
611- dotIndex >= 0 ? method. Name . Substring ( dotIndex + 1 ) : method. Name ) ) ,
612- typeof ( JSValue ) ,
613- typeof ( JSValue ) . GetImplicitConversion ( typeof ( string ) , typeof ( JSValue ) ) ) ;
652+ Expression methodName = JSMemberNameExpression( method ) ;
614653
615654 Expression ParameterToJSValue( int index ) => InlineOrInvoke(
616655 GetToJSValueExpression ( methodParameters [ index ] . ParameterType ) ,
@@ -1114,10 +1153,7 @@ public LambdaExpression BuildToJSPropertyGetExpression(PropertyInfo property)
11141153 * }
11151154 */
11161155
1117- Expression propertyName = Expression. Convert(
1118- Expression. Constant( ToCamelCase( property. Name) ) ,
1119- typeof ( JSValue) ,
1120- typeof ( JSValue) . GetImplicitConversion( typeof ( string ) , typeof ( JSValue) ) ) ;
1156+ Expression propertyName = JSMemberNameExpression( property ) ;
11211157
11221158 Expression getStatement = Expression . Assign (
11231159 resultVariable ,
@@ -1189,10 +1225,7 @@ public LambdaExpression BuildToJSPropertySetExpression(PropertyInfo property)
11891225 * }
11901226 */
11911227
1192- Expression propertyName = Expression. Convert(
1193- Expression. Constant( ToCamelCase( property. Name) ) ,
1194- typeof ( JSValue) ,
1195- typeof ( JSValue) . GetImplicitConversion( typeof ( string ) , typeof ( JSValue) ) ) ;
1228+ Expression propertyName = JSMemberNameExpression( property) ;
11961229
11971230 Expression convertStatement = Expression. Assign(
11981231 jsValueVariable ,
@@ -2962,7 +2995,8 @@ private IEnumerable<Expression> BuildFromJSToStructExpressions(
29622995 continue ;
29632996 }
29642997
2965- Expression propertyName = Expression. Constant( ToCamelCase( property. Name) ) ;
2998+ Expression propertyName = Expression. Constant(
2999+ AutoCamelCase ? ToCamelCase( property. Name) : property. Name) ;
29663000 memberBindings. Add( Expression. Bind( property, InlineOrInvoke (
29673001 GetFromJSValueExpression ( property . PropertyType ) ,
29683002 Expression . Property ( valueVariable , s_valueItem , propertyName ) ,
@@ -3021,7 +3055,8 @@ private IEnumerable<Expression> BuildToJSFromStructExpressions(
30213055 continue ;
30223056 }
30233057
3024- Expression propertyName = Expression. Constant( ToCamelCase( property. Name) ) ;
3058+ Expression propertyName = Expression. Constant(
3059+ AutoCamelCase ? ToCamelCase( property. Name) : property. Name) ;
30253060 yield return Expression. Assign(
30263061 Expression. Property( jsValueVariable, s_valueItem , propertyName ) ,
30273062 InlineOrInvoke (
0 commit comments