public void JsImportWriter() { var writer = new JsImportWriter(); var mainClass = new JsClass { Name = "Main", FilePath = Path.Combine(Environment.CurrentDirectory, "Main.js") }; var dependencyNested = new JsClass { Name = "Dep1", FilePath = Path.Combine(Environment.CurrentDirectory, "subfolder", "Dep1.js") }; var dependencyAbove = new JsClass { Name = "Dep2", FilePath = Path.Combine(Environment.CurrentDirectory, "../", "Dep2.js") }; var statementNested = writer.Write(mainClass, dependencyNested); var statementAbove = writer.Write(mainClass, dependencyAbove); Assert.Equal("import Dep1 from './subfolder/Dep1.js';", statementNested); Assert.Equal("import Dep2 from '../Dep2.js';", statementAbove); }
private void AddCompiledConstructorToType(JsClass jsClass, IMethod constructor, ConstructorScriptSemantics options, JsFunctionDefinitionExpression jsConstructor) { switch (options.Type) { case ConstructorScriptSemantics.ImplType.UnnamedConstructor: if (jsClass.UnnamedConstructor != null) { _errorReporter.Region = constructor.Region; _errorReporter.Message(7501, constructor.DeclaringType.FullName); } else { jsClass.UnnamedConstructor = jsConstructor; } break; case ConstructorScriptSemantics.ImplType.NamedConstructor: jsClass.NamedConstructors.Add(new JsNamedConstructor(options.Name, jsConstructor)); break; case ConstructorScriptSemantics.ImplType.StaticMethod: jsClass.StaticMethods.Add(new JsMethod(constructor, options.Name, new string[0], jsConstructor)); break; } }
public static void CreateInstanceImpl(JsClass klass) { var func = new JsFunction(null); func.Body.Add(klass.Type.New().Return()); klass.ExtendPrototype(func, "CreateInstance"); }
public static void ExtendPrototype(this JsClass klass, JsFunction func, string name) { var type = klass.Type; var typeName = type.IsString() ? "String" : type.JsFullName(); var fullName = typeName + ".prototype." + name; klass.Add(new JsGeneratedMethod(fullName, func)); }
private void AddInstanceInitStatements(JsClass jsClass, IEnumerable <JsStatement> statements) { List <JsStatement> l; if (!_instanceInitStatements.TryGetValue(jsClass, out l)) { _instanceInitStatements[jsClass] = l = new List <JsStatement>(); } l.AddRange(statements); }
private void MaybeCompileAndAddConstructorToType(JsClass jsClass, ConstructorDeclaration node, IMethod constructor, ConstructorScriptSemantics options) { if (options.GenerateCode) { var mc = CreateMethodCompiler(); var compiled = mc.CompileConstructor(node, constructor, TryGetInstanceInitStatements(jsClass), options); OnMethodCompiled(constructor, compiled, mc); AddCompiledConstructorToType(jsClass, constructor, options, compiled); } }
public string Write(JsClass mainClass, JsClass dependency) { var relativePath = new Uri(mainClass.FilePath).MakeRelativeUri(new Uri(dependency.FilePath)).ToString(); if (!relativePath.StartsWith("../")) { relativePath = $"./{relativePath}"; } return($"import {dependency.Name} from '{relativePath}';"); }
private void AddDefaultFieldInitializerToType(JsClass jsClass, string fieldName, IMember member, IType fieldType, ITypeDefinition owningType, bool isStatic) { if (isStatic) { jsClass.StaticInitStatements.AddRange(CreateMethodCompiler().CompileDefaultFieldInitializer(member.Region, JsExpression.Member(_runtimeLibrary.InstantiateType(Utils.SelfParameterize(owningType), this), fieldName), fieldType, member.DeclaringTypeDefinition)); } else { AddInstanceInitStatements(jsClass, CreateMethodCompiler().CompileDefaultFieldInitializer(member.Region, JsExpression.Member(JsExpression.This, fieldName), fieldType, member.DeclaringTypeDefinition)); } }
private JsStatement GenerateResourcesClass(JsClass c) { var fields = c.StaticInitStatements .OfType <JsExpressionStatement>() .Select(s => s.Expression) .OfType <JsBinaryExpression>() .Where(expr => expr.NodeType == ExpressionNodeType.Assign && expr.Left is JsMemberAccessExpression) .Select(expr => new { Name = ((JsMemberAccessExpression)expr.Left).MemberName, Value = expr.Right }); return(new JsVariableDeclarationStatement(_namer.GetTypeVariableName(_metadataImporter.GetTypeSemantics(c.CSharpTypeDefinition).Name), JsExpression.ObjectLiteral(fields.Select(f => new JsObjectLiteralProperty(f.Name, f.Value))))); }
private void AddCompiledMethodToType(JsClass jsClass, IMethod method, MethodScriptSemantics options, JsMethod jsMethod) { if ((options.Type == MethodScriptSemantics.ImplType.NormalMethod && method.IsStatic) || options.Type == MethodScriptSemantics.ImplType.StaticMethodWithThisAsFirstArgument) { jsClass.StaticMethods.Add(jsMethod); } else { jsClass.InstanceMethods.Add(jsMethod); } }
private void AddDefaultFieldInitializerToType(JsClass jsClass, string fieldName, IMember member, IType fieldType, ITypeDefinition owningType, bool isStatic) { if (isStatic) { jsClass.StaticInitStatements.AddRange(CreateMethodCompiler().CompileDefaultFieldInitializer(member.Region, JsExpression.Member(_runtimeLibrary.GetScriptType(owningType, TypeContext.UseStaticMember), fieldName), fieldType)); } else { AddInstanceInitStatements(jsClass, CreateMethodCompiler().CompileDefaultFieldInitializer(member.Region, JsExpression.Member(JsExpression.This, fieldName), fieldType)); } }
private void CompileAndAddFieldInitializerToType(JsClass jsClass, string fieldName, IMember member, Expression initializer, bool isStatic) { if (isStatic) { jsClass.StaticInitStatements.AddRange(CreateMethodCompiler().CompileFieldInitializer(initializer.GetRegion(), _runtimeLibrary.InstantiateType(Utils.SelfParameterize(member.DeclaringTypeDefinition), this), fieldName, member, initializer)); } else { AddInstanceInitStatements(jsClass, CreateMethodCompiler().CompileFieldInitializer(initializer.GetRegion(), JsExpression.This, fieldName, member, initializer)); } }
private JsStatement GenerateResourcesClass(JsClass c) { var fields = c.StaticInitStatements .OfType <JsExpressionStatement>() .Select(s => s.Expression) .OfType <JsBinaryExpression>() .Where(expr => expr.NodeType == ExpressionNodeType.Assign && expr.Left is JsMemberAccessExpression) .Select(expr => new { Name = ((JsMemberAccessExpression)expr.Left).Member, Value = expr.Right }); return(new JsExpressionStatement(JsExpression.Assign(new JsTypeReferenceExpression(c.CSharpTypeDefinition.ParentAssembly, c.Name), JsExpression.ObjectLiteral(fields.Select(f => new JsObjectLiteralProperty(f.Name, f.Value)))))); }
private void CompileAndAddFieldInitializerToType(JsClass jsClass, string fieldName, ITypeDefinition owningType, Expression initializer, bool isStatic) { if (isStatic) { jsClass.StaticInitStatements.AddRange(CreateMethodCompiler().CompileFieldInitializer(initializer.GetRegion(), JsExpression.MemberAccess(_runtimeLibrary.GetScriptType(owningType, TypeContext.UseStaticMember), fieldName), initializer)); } else { AddInstanceInitStatements(jsClass, CreateMethodCompiler().CompileFieldInitializer(initializer.GetRegion(), JsExpression.MemberAccess(JsExpression.This, fieldName), initializer)); } }
private JsExpression CreateInitInterfaceCall(JsClass type, string ctorName, IList <JsExpression> interfaces) { var args = new List <JsExpression> { JsExpression.Identifier(ctorName), _linker.CurrentAssemblyExpression, CreateInstanceMembers(type, null) }; if (interfaces.Count > 0) { args.Add(JsExpression.ArrayLiteral(interfaces)); } return(JsExpression.Invocation(JsExpression.Member(_systemScript, InitInterface), args)); }
private void MaybeAddDefaultConstructorToType(JsClass jsClass, IMethod constructor) { var options = _metadataImporter.GetConstructorSemantics(constructor); if (options.GenerateCode) { var mc = CreateMethodCompiler(); var compiled = mc.CompileDefaultConstructor(constructor, TryGetInstanceInitStatements(jsClass), options); OnMethodCompiled(constructor, compiled, mc); AddCompiledConstructorToType(jsClass, constructor, options, compiled); } }
private JsType ConvertType(JsClass type) { if (type.InstanceMethods.Any(m => m.Name == "runTests")) { _errorReporter.Region = type.CSharpTypeDefinition.Region; _errorReporter.Message(MessageSeverity.Error, 7019, string.Format("The type {0} cannot define a method named 'runTests' because it has a [TestFixtureAttribute].", type.CSharpTypeDefinition.FullName)); return(type); } var instanceMethods = new List <JsMethod>(); var tests = new List <Tuple <string, string, bool, int?, JsFunctionDefinitionExpression> >(); foreach (var method in type.InstanceMethods) { var testAttr = _attributeStore.AttributesFor(method.CSharpMember).GetAttribute <TestAttribute>(); if (testAttr != null) { if (!method.CSharpMember.IsPublic || !method.CSharpMember.ReturnType.IsKnownType(KnownTypeCode.Void) || ((IMethod)method.CSharpMember).Parameters.Count > 0 || ((IMethod)method.CSharpMember).TypeParameters.Count > 0) { _errorReporter.Region = method.CSharpMember.Region; _errorReporter.Message(MessageSeverity.Error, 7020, string.Format("Method {0}: Methods decorated with a [TestAttribute] must be public, non-generic, parameterless instance methods that return void.", method.CSharpMember.FullName)); } tests.Add(Tuple.Create(testAttr.Description ?? method.CSharpMember.Name, testAttr.Category, testAttr.IsAsync, testAttr.ExpectedAssertionCount >= 0 ? (int?)testAttr.ExpectedAssertionCount : null, method.Definition)); } else { instanceMethods.Add(method); } } var testInvocations = new List <JsExpression>(); foreach (var category in tests.GroupBy(t => t.Item2).Select(g => new { Category = g.Key, Tests = g.Select(x => new { Description = x.Item1, IsAsync = x.Item3, ExpectedAssertionCount = x.Item4, Function = x.Item5 }) }).OrderBy(x => x.Category)) { if (category.Category != null) { testInvocations.Add(JsExpression.Invocation(JsExpression.Member(JsExpression.Identifier("QUnit"), "module"), JsExpression.String(category.Category))); } testInvocations.AddRange(category.Tests.Select(t => JsExpression.Invocation(JsExpression.Identifier(t.IsAsync ? "asyncTest" : "test"), t.ExpectedAssertionCount != null ? new JsExpression[] { JsExpression.String(t.Description), JsExpression.Number(t.ExpectedAssertionCount.Value), _runtimeLibrary.Bind(t.Function, JsExpression.This, this) } : new JsExpression[] { JsExpression.String(t.Description), _runtimeLibrary.Bind(t.Function, JsExpression.This, this) }))); } instanceMethods.Add(new JsMethod(null, "runTests", null, JsExpression.FunctionDefinition(new string[0], JsStatement.Block(testInvocations.Select(t => (JsStatement)t))))); var result = type.Clone(); result.InstanceMethods.Clear(); foreach (var m in instanceMethods) { result.InstanceMethods.Add(m); } return(result); }
private void CompileAndAddAutoEventMethodsToType(JsClass jsClass, EventDeclaration node, IEvent evt, EventScriptSemantics options, string backingFieldName) { if (options.AddMethod != null && options.AddMethod.GeneratedMethodName != null) { var compiled = CreateMethodCompiler().CompileAutoEventAdder(evt, options, backingFieldName); AddCompiledMethodToType(jsClass, evt.AddAccessor, options.AddMethod, new JsMethod(evt.AddAccessor, options.AddMethod.GeneratedMethodName, new string[0], compiled)); } if (options.RemoveMethod != null && options.RemoveMethod.GeneratedMethodName != null) { var compiled = CreateMethodCompiler().CompileAutoEventRemover(evt, options, backingFieldName); AddCompiledMethodToType(jsClass, evt.RemoveAccessor, options.RemoveMethod, new JsMethod(evt.RemoveAccessor, options.RemoveMethod.GeneratedMethodName, new string[0], compiled)); } }
private void CompileAndAddAutoPropertyMethodsToType(JsClass jsClass, IProperty property, PropertyScriptSemantics options, string backingFieldName) { if (options.GetMethod != null && options.GetMethod.GeneratedMethodName != null) { var compiled = CreateMethodCompiler().CompileAutoPropertyGetter(property, options, backingFieldName); AddCompiledMethodToType(jsClass, property.Getter, options.GetMethod, new JsMethod(property.Getter, options.GetMethod.GeneratedMethodName, new string[0], compiled)); } if (options.SetMethod != null && options.SetMethod.GeneratedMethodName != null) { var compiled = CreateMethodCompiler().CompileAutoPropertySetter(property, options, backingFieldName); AddCompiledMethodToType(jsClass, property.Setter, options.SetMethod, new JsMethod(property.Setter, options.SetMethod.GeneratedMethodName, new string[0], compiled)); } }
private List <JsStatement> TryGetInstanceInitStatements(JsClass jsClass) { List <JsStatement> l; if (_instanceInitStatements.TryGetValue(jsClass, out l)) { return(l); } else { return(new List <JsStatement>()); } }
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) { Contract.Requires(typeDeclaration != null); // Is this a class but not a test fixture? if (IsClass(typeDeclaration) && !HasTestFixtureAttribute(typeDeclaration)) { var parent = new JsClass() { Name = typeDeclaration.Name, Properties = new List <JsProperty>() }; if (typeDeclaration.Attributes.Count > 0) { foreach (var attribute in typeDeclaration.Attributes) { var jsAttributes = new List <JsAttribute>(); var a = attribute.Attributes[0]; jsAttributes.Add(new JsAttribute() { Name = a.Name }); parent.Attributes = jsAttributes; } } if (Model == null) { Model = new JsFile(); } if (Model.Files == null) { Model.Files = new List <JsClass>(); } Model.Files.Add(parent); CurrentParent = parent; } // Visit children (E.g. MethodDeclarion objects) typeDeclaration.AcceptChildren(this, data); return(null); }
private JsClass GetJsClass(ITypeDefinition typeDefinition) { JsClass result; if (!_types.TryGetValue(typeDefinition, out result)) { if (typeDefinition.Kind == TypeKind.Struct && !_allowUserDefinedStructs) { var oldRegion = _errorReporter.Region; _errorReporter.Region = typeDefinition.Region; _errorReporter.Message(7998, "user-defined value type (struct)"); _errorReporter.Region = oldRegion; } var semantics = _metadataImporter.GetTypeSemantics(typeDefinition); if (semantics.GenerateCode) { var unusableTypes = Utils.FindUsedUnusableTypes(typeDefinition.GetAllBaseTypes(), _metadataImporter).ToList(); if (unusableTypes.Count > 0) { foreach (var ut in unusableTypes) { var oldRegion = _errorReporter.Region; _errorReporter.Region = typeDefinition.Region; _errorReporter.Message(7500, ut.FullName, typeDefinition.FullName); _errorReporter.Region = oldRegion; } result = new JsClass(typeDefinition, "X", ConvertClassType(typeDefinition.Kind), new string[0], null, null); } else { var baseTypes = typeDefinition.GetAllBaseTypes().Where(t => _runtimeLibrary.GetScriptType(t, TypeContext.GenericArgument) != null).ToList(); var baseClass = typeDefinition.Kind != TypeKind.Interface ? _runtimeLibrary.GetScriptType(baseTypes.Last(t => !t.GetDefinition().Equals(typeDefinition) && t.Kind == TypeKind.Class), TypeContext.Inheritance) : null; // NRefactory bug/feature: Interfaces are reported as having System.Object as their base type. var interfaces = baseTypes.Where(t => !t.GetDefinition().Equals(typeDefinition) && t.Kind == TypeKind.Interface).Select(t => _runtimeLibrary.GetScriptType(t, TypeContext.Inheritance)).Where(t => t != null).ToList(); var typeArgNames = semantics.IgnoreGenericArguments ? null : typeDefinition.TypeParameters.Select(a => _namer.GetTypeParameterName(a)).ToList(); result = new JsClass(typeDefinition, semantics.Name, ConvertClassType(typeDefinition.Kind), typeArgNames, baseClass, interfaces); } } else { result = null; } _types[typeDefinition] = result; } return(result); }
private HashSet <ITypeDefinition> GetStaticInitializationDependencies(JsClass c, int pass) { // Consider the following reference locations: // Pass 1: static init statements, static methods, instance methods, constructors // Pass 2: static init statements, static methods // Pass 3: static init statements only var result = new HashSet <ITypeDefinition>(); switch (pass) { case 1: foreach (var r in c.InstanceMethods.Where(m => m.Definition != null).SelectMany(m => TypeReferenceFinder.Analyze(m.Definition))) { result.Add(r); } foreach (var r in c.NamedConstructors.Where(m => m.Definition != null).SelectMany(m => TypeReferenceFinder.Analyze(m.Definition))) { result.Add(r); } if (c.UnnamedConstructor != null) { foreach (var r in TypeReferenceFinder.Analyze(c.UnnamedConstructor)) { result.Add(r); } } goto case 2; case 2: foreach (var r in c.StaticMethods.Where(m => m.Definition != null).SelectMany(m => TypeReferenceFinder.Analyze(m.Definition))) { result.Add(r); } goto case 3; case 3: foreach (var r in TypeReferenceFinder.Analyze(c.StaticInitStatements)) { result.Add(r); } break; default: throw new ArgumentException("pass"); } return(result); }
private JsExpression CreateInitClassCall(JsClass type, string ctorName, JsExpression baseClass, IList <JsExpression> interfaces) { var args = new List <JsExpression> { JsExpression.Identifier(ctorName), CreateInstanceMembers(type) }; if (baseClass != null || interfaces.Count > 0) { args.Add(baseClass ?? JsExpression.Null); } if (interfaces.Count > 0) { args.Add(JsExpression.ArrayLiteral(interfaces)); } return(JsExpression.Invocation(JsExpression.Member(_systemScript, InitClass), args)); }
private JsExpression CreateInstanceMembers(JsClass c, string typeVariableName) { var members = c.InstanceMethods.Select(m => new JsObjectLiteralProperty(m.Name, m.Definition != null ? RewriteMethod(m) : JsExpression.Null)); if (c.CSharpTypeDefinition.Kind == TypeKind.Struct) { if (!c.InstanceMethods.Any(m => m.Name == "getHashCode")) { members = members.Concat(new[] { new JsObjectLiteralProperty("getHashCode", GenerateStructGetHashCodeMethod(c.CSharpTypeDefinition)) }); } if (!c.InstanceMethods.Any(m => m.Name == "equals")) { members = members.Concat(new[] { new JsObjectLiteralProperty("equals", GenerateStructEqualsMethod(c.CSharpTypeDefinition, typeVariableName)) }); } } return(JsExpression.ObjectLiteral(members)); }
private void MaybeCompileAndAddMethodToType(JsClass jsClass, EntityDeclaration node, BlockStatement body, IMethod method, MethodScriptSemantics options) { if (options.GeneratedMethodName != null) { var typeParamNames = options.IgnoreGenericArguments ? (IEnumerable <string>) new string[0] : method.TypeParameters.Select(tp => _namer.GetTypeParameterName(tp)).ToList(); JsMethod jsMethod; if (method.IsAbstract) { jsMethod = new JsMethod(method, options.GeneratedMethodName, typeParamNames, null); } else { var compiled = CompileMethod(node, body, method, options); jsMethod = new JsMethod(method, options.GeneratedMethodName, typeParamNames, compiled); } AddCompiledMethodToType(jsClass, method, options, jsMethod); } }
public void DefaultDependencyResolver() { var dependencyClass = new JsClass { OriginalType = typeof(string) }; var resolvingClass = new JsClass { Dependencies = new List <Type> { typeof(string) } }; var classes = new List <JsClass> { dependencyClass, resolvingClass }; var resolver = new JsClassDependencyResolver(classes); var resolved = resolver.Resolve(resolvingClass); Assert.Contains(resolved, a => a.OriginalType == typeof(string)); }
private JsClass GetJsClass(ITypeDefinition typeDefinition) { JsClass result; if (!_types.TryGetValue(typeDefinition, out result)) { if (typeDefinition.Kind == TypeKind.Struct && !_allowUserDefinedStructs) { var oldRegion = _errorReporter.Region; _errorReporter.Region = typeDefinition.Region; _errorReporter.Message(Messages._7998, "user-defined value type (struct)"); _errorReporter.Region = oldRegion; } var semantics = _metadataImporter.GetTypeSemantics(typeDefinition); if (semantics.GenerateCode) { var unusableTypes = Utils.FindUsedUnusableTypes(typeDefinition.GetAllBaseTypes(), _metadataImporter).ToList(); if (unusableTypes.Count > 0) { foreach (var ut in unusableTypes) { var oldRegion = _errorReporter.Region; _errorReporter.Region = typeDefinition.Region; _errorReporter.Message(Messages._7500, ut.FullName, typeDefinition.FullName); _errorReporter.Region = oldRegion; } } result = new JsClass(typeDefinition); } else { result = null; } _types[typeDefinition] = result; } return(result); }
public string Write(JsClass jsClass) { var dependencies = DependencyResolver.Resolve(jsClass).ToList(); var stringBuilder = new StringBuilder(); stringBuilder.AppendLine("//CSharpToJs: auto"); foreach (var dependency in dependencies) { stringBuilder.AppendLine(JsImportWriter.Write(jsClass, dependency)); } stringBuilder.Append($"class {jsClass.Name} "); //TODO: Not sure if this is the right place to decide if it's a derived class var inherits = dependencies.SingleOrDefault(a => a.OriginalType == jsClass.OriginalType.BaseType); if (inherits != null) { stringBuilder.Append($"extends {inherits.Name}"); } stringBuilder.AppendLine(" {"); stringBuilder.AppendLine("\tconstructor() {"); foreach (var jsProperty in jsClass.Properties.Where(a => a.PropertyInfo.DeclaringType == jsClass.OriginalType)) { stringBuilder.AppendLine($"\t\t{JsPropertyWriter.Write(jsProperty)};"); } stringBuilder.AppendLine("\t}"); stringBuilder.AppendLine("}"); stringBuilder.Append($"export default {jsClass.Name};"); return(stringBuilder.ToString()); }
private JsClass GetJsClass(ITypeDefinition typeDefinition) { JsClass result; if (!_types.TryGetValue(typeDefinition, out result)) { var semantics = _metadataImporter.GetTypeSemantics(typeDefinition); if (semantics.GenerateCode) { var errors = Utils.FindTypeUsageErrors(typeDefinition.GetAllBaseTypes(), _metadataImporter); if (errors.HasErrors) { var oldRegion = _errorReporter.Region; try { _errorReporter.Region = typeDefinition.Region; foreach (var ut in errors.UsedUnusableTypes) { _errorReporter.Message(Messages._7500, ut.FullName, typeDefinition.FullName); } foreach (var t in errors.MutableValueTypesBoundToTypeArguments) { _errorReporter.Message(Messages._7539, t.FullName); } } finally { _errorReporter.Region = oldRegion; } } result = new JsClass(typeDefinition); } else { result = null; } _types[typeDefinition] = result; } return(result); }