public Variable(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : this(super) { var Child = elem.Elements(); foreach (XElement e in Child) { switch (e.Name.LocalName) { case "ident": this.Name = e.Attribute("text").Value; break; case "question": this.Optional = true; break; case "type": this.Type = Tool.NewType(e, context); break; case "k_export": this.Public = true; break; case "k_static": this.Static = true; break; case "string": this.hasString = true; break; } } }
public FunctionType(XElement elem, TypeScriptDefContext context) : this() { var Params = elem.Element("paramlist"); if (Params != null) { var ParamListElem = Params.Elements(); bool Spread = false; foreach (XElement e in ParamListElem) { if (e.Name.LocalName == "spreadop") { Spread = true; } else { Param p = new Param(e, null, false, context); p.Spread = Spread; this.Params.Add(p); Spread = false; } } } this.ReturnType = Tool.NewType(elem.Element("type"), context); }
public AnonymousType(XElement elem, TypeScriptDefContext context) : this() { this.Class = new Class(elem, null, context); this.Class.Name = "AnonymousType" + AnonID++; this.Class.AddContent(elem, context); //this.Class.Super = new Namespace(); //this.Class.Super.Name = "AnonymousTypes"; context.CurrentGeneratedFiles.Add(context.OutputDirectory + "AnonymousTypes\\" + this.Class.Name + ".cs"); }
// The Namespace is the only Model element where we don't parse it into the constructor // This is to avoid duplicating a same Namespace public Namespace(XElement elem, Namespace super, string name, TypeScriptDefContext context) : this(super, context) { this.Super = super; this.Name = name; // The static class is always named [NamespaceNames]Class this.StaticClass.Name = name + "Class"; if (elem != null) { this.AddContent(elem.Element("namespacecontent"), context); } }
// Create if needed a namespace // If there is already ns1.ns2 in this namespace // and you call it with ns1.ns2.ns3.ns4 // it will only create ns3 and ns4 and add the content into ns4 public void AddChildNamespace(XElement elem, TypeScriptDefContext context) { // Get the full name of the added namespace (ex: "ns1.ns2") var Name = Tool.GetIdent(elem); // Split the full name into an array var name = Name.Split('.'); // Temporary variables Container <Declaration> tmp = this; Class cls = null; Namespace ns = null; // While there are names in the array while (name.Count() > 0) { // Check if there is a class in tmp matching the first remaining name cls = tmp.OfType <Class>().FirstOrDefault(t => t.Name == name[0] ); // If there is one, it means the added namespace references one // of its child classes, so tmp become this class if (cls != null) { tmp = cls; } // If there is no matching class and tmp is a namespace else if (tmp is Namespace) { // Search for a matching namespace in tmp ns = tmp.OfType <Namespace>().FirstOrDefault(n => n.Name == name[0] ); // If there isn't one if (ns == null) { // Create it ns = new Namespace(null, (Namespace)tmp, name[0], context); ((Namespace)tmp).Declarations.Add(ns); } // Now we are sure that the namespace exists, so tmp become this one tmp = ns; } // We remove the first name (the one we created if needed) name = name.Skip(1).ToArray(); } // Now that there is no more name in the array // tmp is either the class referenced by the added namespace // or the added namespace itself // In either case we add its content tmp.AddContent(elem.Element("namespacecontent"), context); }
public Class(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : base(elem, super, context) { this.InitProperties(); this.Name = Tool.GetIdent(elem); if (this.Name == null) { this.Name = ""; } // Split based on '\\' is done if the interface has name based on the .t.ds or xml file // if this file is in subfolder, it's name will include some '\\' (or '/', that's the same here) // But this doesn't seems to work right now, need to fix it string[] path = this.Name.Split('\\'); // Name is in fact the last element of the path this.Name = path.Last(); // We remove the name from the path path = path.Take(path.Count() - 1).ToArray(); // Prefix is now the first file path (without the name) if (path.Count() > 0) { this.Prefix = string.Join("\\", path) + "\\"; } else { this.Prefix = ""; } // Parsing the "extends" parts (inheritance) //var Extends = elem.Element("extends"); //if (Extends != null) //{ // foreach (XElement e in Extends.Elements()) // { // if (e.Name.LocalName == "dotident") // { // var b = new BasicType(e); // if (b.ToString(this.Super) != "object") // this.Inherit.Add(b.ToString(this.Super)); // } // else if (e.Name.LocalName == "generic") // { // var g = new Generic(e, context); // this.Inherit.Add(g.ToString(this.Super)); // } // } //} }
// Parse and add content to this namespace public void AddContent(XElement content, TypeScriptDefContext context) { #if LOG_VERBOSE context.Logger.WriteMessage("AddContent: '" + this.Name + "'"); #endif foreach (XElement elem in content.Elements()) { switch (elem.Name.LocalName) { case "import": this.Imports.Add(new Import(elem)); break; case "namespace": this.AddChildNamespace(elem, context); // We don't add it directly because maybe the namespace already exists break; // Variable directly in the namespace case "variable": this.StaticClass.Properties.Add(new Property(elem, this.StaticClass, context) { Static = true }); break; // Function directly in the namespace case "function": this.StaticClass.Methods.Add(new Method(elem, this.StaticClass, context) { Static = true }); break; case "enum": this.Declarations.Add(TypeDeclaration.New(elem, this, context)); break; case "interface": this.Declarations.Add(TypeDeclaration.New(elem, this, context)); break; case "class": this.Declarations.Add(TypeDeclaration.New(elem, this, context)); break; } } }
// This is simply boring XML parsing, should've used deserialization but at this time I was a noob sorry public GlobalProgram(XDocument doc, string name, TypeScriptDefContext context) : this(context) { this.Name = name; var Child = doc.Root.Elements(); string[] path = name.Split('.'); this.StaticClass.Name = path.Last() + "Class"; foreach (XElement elem in Child) { switch (elem.Name.LocalName) { case "import": this.Imports.Add(new Import(elem)); break; case "namespace": this.AddChildNamespace(elem, context); // We don't add it directly because maybe the namespace already exists break; // Variable directly in the namespace case "variable": this.StaticClass.Properties.Add(new Property(elem, this.StaticClass, context) { Static = true }); break; // Function directly in the namespace case "function": this.StaticClass.Methods.Add(new Method(elem, this.StaticClass, context) { Static = true }); break; case "interface": this.Declarations.Add(TypeDeclaration.New(elem, this, context)); break; case "class": this.Declarations.Add(TypeDeclaration.New(elem, this, context)); break; } } }
// Parse and add content to this class public void AddContent(XElement content, TypeScriptDefContext context) { foreach (XElement e in content.Elements()) { switch (e.Name.LocalName) { // Properties case "variable": this.AddProperty(new Property(e, this, context)); break; // Methods case "function": Method m = new Method(e, this, context); if (!m.HasString) { this.AddMethod(m); } if (m.Name == "constructor" && m.Params.Count == 0) { this.HasParameterlessConstructor = true; } break; // If the class is a generic and has some "generic arguments" case "generic_arg": this.GenericArg = e.Attribute("text").Value; break; // Nested interfaces case "interface": this.AddTypeDeclaration(TypeDeclaration.New(e, this, context)); break; // Nested classes case "class": this.AddTypeDeclaration(TypeDeclaration.New(e, this, context)); break; // Nested enums case "enum": this.AddTypeDeclaration(TypeDeclaration.New(e, this, context)); break; } } }
public Namespace(Namespace super, TypeScriptDefContext context) : base(super) { this.Declarations = new HashSet <Declaration>(); this.Imports = new List <Import>(); this.StaticClass = new Class(this) { Static = true }; // Those are basic usings to allow good working this.Imports.Add(new Import() { Alias = "CSHTML5", Name = "CSHTML5" }); // Allow Interop calls this.Imports.Add(new Import() { Alias = "System", Name = "System" }); this.Imports.Add(new Import() { Alias = "System.Collections.Generic", Name = "System.Collections.Generic" }); // Those are usings that can be useful here this.Imports.Add(new Import() { Alias = "AnonymousTypes", Name = "AnonymousTypes" }); this.Imports.Add(new Import() { Alias = "ToJavaScriptObjectExtender", Name = "ToJavaScriptObjectExtender" }); this.Imports.Add(new Import() { Alias = "TypeScriptDefinitionsSupport", Name = "TypeScriptDefinitionsSupport" }); // Those are aliases that are needed to compile, but they can also be added in the CSHTML5.Core //this.Imports.Add(new Import() { Alias = "EventListenerOrEventListenerObject", Name = "UnionType<webworker_generated.EventListener, webworker_generated.EventListenerObject>" }); //this.Imports.Add(new Import() { Alias = "AlgorithmIdentifier", Name = "UnionType<System.String, webworker_generated.Algorithm>" }); //this.Imports.Add(new Import() { Alias = "IDBKeyPath", Name = "System.String" }); //this.Imports.Add(new Import() { Alias = "IDBValidKey", Name = "UnionType<System.Int32, System.Double, System.String, System.DateTime, webworker_generated.IDBArrayKey>" }); //this.Imports.Add(new Import() { Alias = "BufferSource", Name = "System.Collections.Generic.List<object>" }); }
public Generic(XElement elem, TypeScriptDefContext context) : this() { this.Name = elem.Element("generic").Attribute("text").Value; if (elem.Element("type") != null) { var types = Tool.NewType(elem.Element("type"), context); if (types is UnionTypeModel) { this.TypeList = ((UnionTypeModel)types).Types; } else { this.TypeList.Add((TSType)types); } } }
public Enum(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : base(elem, super, context) { this.InitProperties(); foreach (XElement e in elem.Elements()) { if (e.Name.LocalName != "ident") { throw new Exception(); } if (this.Name == null) { this.Name = e.Attribute("text").Value; } else { this.Values.Add(e.Attribute("text").Value); } } }
// Exports each children list public override void Export(TypeScriptDefContext context) { #if LOG_VERBOSE context.Logger.WriteMessage("Namespace Export: '" + this.FullName(".") + "'"); #endif foreach (Declaration d in this.Declarations) { #if LOG_VERBOSE if (d is Class) { context.Logger.WriteMessage("Class: '" + this.FullName(".") + "." + d.Name + "'"); } #endif d.Export(context); } // Export the static class only if there is at least a property or a method if (StaticClass.Properties.Any() || StaticClass.Methods.Any()) { StaticClass.Export(context); } }
public void AddContent(XElement content, TypeScriptDefContext context) { int spread = 0; foreach (XElement e in content.Elements()) { if (e.Name.LocalName == "variable") { Param p = new Param(e, this, spread == 1, context); if (p.hasString) { this.HasString = true; } this.Params.Add(p); } else if (e.Name.LocalName == "spreadop") { spread = 2; } spread--; } }
// Exporting a Class create a new file (like exporting Interface or Enum) public override void Export(TypeScriptDefContext context) { var res = new StringBuilder(); // Get the imports of the Super Namespace and it's parents var imports = this.FirstAncestor <Namespace>().GetImportList(); // Join them with a NewLine as separator (overrided imports.ToString() format it as needed) res.Append(string.Join(Environment.NewLine, imports)); // If there was is at least an import, we add a NewLine (useless but pretty) if (imports.Any()) { res.AppendLine(Environment.NewLine); } // Put the class in the good namespace (with full namespace's name) res.Append("namespace ") .AppendLine(this.Super.FullName(".")) .AppendLine("{"); // Write the class and close the namespace res.Append(this.ToString()) .AppendLine("}"); // Get the destination path (namespace structure) string path = context.OutputDirectory + this.Super.FullName("\\") + "\\" + this.Prefix; // If needed, create the destination folder Directory.CreateDirectory(path); string fileName = path + this.Name + ".cs"; File.WriteAllText(fileName, Tool.ReIndent(res.ToString())); if (context.CurrentGeneratedFiles != null) { context.CurrentGeneratedFiles.Add(fileName); } }
public override void Export(TypeScriptDefContext context) { var res = new StringBuilder(); var imports = this.FirstAncestor <Namespace>().GetImportList(); res.Append(string.Join(Environment.NewLine, imports)); if (imports.Any()) { res.AppendLine(Environment.NewLine); } res.Append("namespace ") .AppendLine(Super.FullName(".")) .AppendLine("{"); res.Append(this.ToString()) .AppendLine("}"); // Get the destination path (namespace structure) string path = Super.FullName("\\") + "\\"; // Get the full relative file path string fullPath = context.OutputDirectory + path + this.Name + ".cs"; // Split the full path string[] tmp = fullPath.Split('\\'); // Remove the filename from the path tmp = tmp.Take(tmp.Count() - 1).ToArray(); // If needed, create the destination folder #if LOG_VERBOSE context.Logger.WriteMessage("enum: " + fullPath); #endif Directory.CreateDirectory(string.Join("\\", tmp)); File.WriteAllText(fullPath, Tool.ReIndent(res.ToString())); context.CurrentGeneratedFiles.Add(fullPath); }
public Function(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : this(super) { this.Name = elem.Element("function").Attribute("text").Value; while (this.Name.Length > 0 && this.Name[this.Name.Length - 1] == ' ') { this.Name = this.Name.Remove(this.Name.Length - 1); } if (this.Name.Length > 0 && this.Name[this.Name.Length - 1] == '?') { this.Optional = true; this.Name = this.Name.Remove(this.Name.Length - 1); } var paramlist = elem.Element("paramlist"); if (paramlist != null) { this.AddContent(paramlist, context); } this.ReturnType = Tool.NewType(elem.Element("type"), context); }
public void Export(TypeScriptDefContext context) { this.Class.Export(context); }
// Return the TypeDeclaration instance associated with a given XML type declaration, // or a newly created one that is added to the dictionary if it doesn't exist private static TypeDeclaration GetInstance(XElement elem, Container <Declaration> super, TypeScriptDefContext context) { Type typeDeclarationClass = TypeDeclaration.GetClass(elem); string typeDeclarationName = TypeDeclaration.GetFullName(elem); try { var inst = TypeDeclaration.Instances[typeDeclarationName]; // We update the declaration's Super if it wasn't specified previously // (needed for type declarations instanciated because of a variable of that type) if (inst.Super == null) { inst.Super = super; } return(inst); } catch (KeyNotFoundException) { var inst = (TypeDeclaration)Activator.CreateInstance(typeDeclarationClass, elem, super, context); TypeDeclaration.Instances[typeDeclarationName] = inst; // We add content after updating the dictionary to avoid cycles // when declarations refer to their ancestors if (inst is Container <Declaration> ) { ((Container <Declaration>)inst).AddContent(elem, context); } return(inst); } }
// Check if a given type name is declared somewhere in a given XML subtree, // and return the associated TypeDeclaration instance if it is, null otherwise private static TypeDeclaration New(string[] name, XElement root, Container <Declaration> super, TypeScriptDefContext context) { // We create a list of the elements we're going to inspect var elems = new List <XElement>(); // First we inspect the root itself (except if it is the global namespace) if (root.Name.LocalName != "start") { elems.Add(root); } // If there is no declaration directly in the root, we inspect its children IEnumerable <XElement> children; // We need to handle the special case of namespace elements, // which do not hold their declarations as direct children if (root.Name.LocalName == "namespace") { children = root.Element("namespacecontent").Elements(); } else { children = root.Elements(); } elems.AddRange(children); // Then for each element in the list foreach (XElement e in elems) { // First we make sure that it correponds either to a TypeDeclaration or a Container<TypeDeclaration> Type typeDeclarationClass = TypeDeclaration.GetClass(e); bool isTypeDeclarationContainer = TypeDeclaration.IsTypeDeclarationContainer(e); if (typeDeclarationClass != null || isTypeDeclarationContainer) { // The element identifier must be at most as long as the type name string[] ident = Tool.GetIdent(e).Split('.'); if (ident.Length <= name.Length) { // If the hole identifier matches the beginning of the name int match = ident.ToList().FirstMismatchIndex(name.ToList()); if (match == ident.Length) { // Either the beginning is actually the type (local) name... if (name.Length == 1) { // ...and if the element is associated with a TypeDeclaration class, // it means we have found a valid declaration, so we return an instance of said class if (typeDeclarationClass != null) { return(TypeDeclaration.GetInstance(e, super, context)); } } // Or the beginning is just the name of an ancestor container... else if (isTypeDeclarationContainer) { // ...and therefore we call the method recursively on the element var res = TypeDeclaration.New(name.Skip(match).ToArray(), e, super, context); // If we found a valid declaration during the recursive call, we return it if (res != null) { return(res); } // Otherwise there might be another container with the same name, so we keep searching. // For example it is possible that class a.b does not contain the declaration, // while namespace a.b, which is going to be merged with class a.b by the compiler, does contain it. } } } } } // If there is no element containing a declaration, we return null return(null); }
// Take either an XML type declaration or a type.dotident element, and return the associated // TypeDeclaration instance if it is declared somewhere in the XML, null otherwise public static TypeDeclaration New(XElement elem, Container <Declaration> super, TypeScriptDefContext context) { // If the argument passed is an XML type declaration, we don't search // in the XML and directly return the associated instance if (TypeDeclaration.GetClass(elem) != null) { return(TypeDeclaration.GetInstance(elem, super, context)); } string[] name = elem.Attribute("text").Value.Split('.'); XElement parent; TypeDeclaration typeDeclaration = null; do { // We check if there is a declaration in the current namespace parent = elem.Ancestors().FirstOrDefault(e => TypeDeclaration.IsTypeDeclarationContainer(e)); if (parent != null) { typeDeclaration = TypeDeclaration.New(name, parent, super, context); elem = parent; } } // If not, we check in the parent namespace, and if not in the parent of the parent, // and so on until we reach the root namespace while (typeDeclaration == null && parent != null); return(typeDeclaration); }
public Property(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : base(elem, super, context) { }
public GlobalProgram(TypeScriptDefContext context) : base(null, context) { }
public Param(XElement elem, Container <Declaration> super, bool spread, TypeScriptDefContext context) : base(elem, super, context) { this.Spread = spread; }
public Method(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : base(elem, super, context) { this.IsConstructor = (this.Name == "constructor"); }
public TypeDeclaration(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : this(super) { ((TSType)this).Name = TypeDeclaration.GetFullName(elem); }
public Namespace(XElement elem, Namespace super, TypeScriptDefContext context) : this(elem, super, Tool.GetIdent(elem), context) { }
public Signature(XElement elem, Container <Declaration> super, TypeScriptDefContext context) : base(elem, super, context) { }
public virtual void Export(TypeScriptDefContext context) { throw new NotImplementedException(); }