/// <summary> /// Extract documentation from XML included in ASDocs-enriched SWCs /// </summary> /// <param name="rawDocs"></param> private static void ParseDocumentation(ContentParser parser) { if (parser.Catalog != null) { MxmlFilter.AddCatalog(parser.Filename, parser.Catalog); } if (parser.Docs.Count > 0) foreach (string docFile in parser.Docs.Keys) { if (docFile.EndsWith(".dita.xml")) continue; try { Match m = reDocFile.Match(docFile); if (!m.Success) continue; string package = m.Groups[1].Value; Dictionary<string, ASDocItem> packageDocs = Docs.ContainsKey(package) ? Docs[package] : new Dictionary<string, ASDocItem>(); byte[] rawDoc = parser.Docs[docFile]; ASDocsReader dr = new ASDocsReader(rawDoc); dr.ExcludedASDocs = ExcludedASDocs; dr.Parse(packageDocs); Docs[package] = packageDocs; } catch (Exception) { } } }
/// <summary> /// Create virtual FileModel objects from Abc bytecode /// </summary> /// <param name="abcs"></param> /// <param name="path"></param> /// <param name="context"></param> public static void Convert(ContentParser parser, PathModel path, IASContext context) { inSWF = Path.GetExtension(path.Path).ToLower() == ".swf"; // extract documentation ParseDocumentation(parser); // extract models Dictionary<string, FileModel> models = new Dictionary<string, FileModel>(); FileModel privateClasses = new FileModel(Path.Combine(path.Path, "__Private.as")); privateClasses.Version = 3; privateClasses.Package = "private"; genericTypes = new Dictionary<string, FileModel>(); imports = new Dictionary<string, string>(); conflicts = new Dictionary<string, string>(); foreach (Abc abc in parser.Abcs) { // types foreach (Traits trait in abc.classes) { Traits instance = trait.itraits; if (instance == null) continue; imports.Clear(); conflicts.Clear(); FileModel model = new FileModel(""); model.Context = context; model.Package = reSafeChars.Replace(instance.name.uri, "_"); model.HasPackage = true; string filename = reSafeChars.Replace(trait.name.ToString(), "_").TrimEnd('$'); filename = Path.Combine(model.Package.Replace('.', Path.DirectorySeparatorChar), filename); model.FileName = Path.Combine(path.Path, filename); model.Version = 3; ClassModel type = new ClassModel(); model.Classes = new List<ClassModel>(); model.Classes.Add(type); type.InFile = model; type.Type = instance.name.ToTypeString(); type.Name = instance.name.localName; type.Flags = FlagType.Class; conflicts.Add(type.Name, type.QualifiedName); if (instance.flags == TraitMember.Function) type.Flags |= FlagType.Interface; thisDocs = GetDocs(model.Package); if (thisDocs != null) { docPath = (model.Package.Length > 0 ? model.Package + ":" : "globalClassifier:") + type.Name; if (thisDocs.ContainsKey(docPath)) { ASDocItem doc = thisDocs[docPath]; applyASDoc(doc, type); if (doc.Meta != null) model.MetaDatas = doc.Meta; } if (model.Package.Length == 0) docPath = type.Name; } if (instance.baseName.uri == model.Package) type.ExtendsType = ImportType(instance.baseName.localName); else type.ExtendsType = ImportType(instance.baseName); if (instance.interfaces != null && instance.interfaces.Length > 0) { type.Implements = new List<string>(); foreach (QName name in instance.interfaces) type.Implements.Add(ImportType(name)); } if (model.Package == "private") { model.Package = ""; type.Access = Visibility.Private; type.Namespace = "private"; } else if (model.Package == "__AS3__.vec") { model.Package = ""; type.Access = Visibility.Private; type.Namespace = "private"; string genType = type.Name; if (type.Name.IndexOf("$") > 0) { string[] itype = type.Name.Split('$'); genType = itype[0]; type.Name = itype[0] + "$" + itype[1]; type.IndexType = itype[1]; } if (genericTypes.ContainsKey(genType)) { model.Classes.Clear(); type.InFile = genericTypes[genType]; genericTypes[genType].Classes.Add(type); } else genericTypes[genType] = model; } else if (type.Name.StartsWith("_")) { type.Access = Visibility.Private; type.Namespace = "private"; } else { type.Access = Visibility.Public; type.Namespace = "public"; } type.Members = GetMembers(trait.members, FlagType.Static, instance.name); type.Members.Add(GetMembers(instance.members, FlagType.Dynamic, instance.name)); if ((type.Flags & FlagType.Interface) > 0) { // TODO properly support interface multiple inheritance type.ExtendsType = null; if (type.Implements != null && type.Implements.Count > 0) { type.ExtendsType = type.Implements[0]; type.Implements.RemoveAt(0); if (type.Implements.Count == 0) type.Implements = null; } foreach (MemberModel member in type.Members) { member.Access = Visibility.Public; member.Namespace = ""; } } // constructor if (instance.init != null && (type.Flags & FlagType.Interface) == 0) { List<MemberInfo> temp = new List<MemberInfo>(new MemberInfo[] { instance.init }); MemberList result = GetMembers(temp, 0, instance.name); if (result.Count > 0) { MemberModel ctor = result[0]; ctor.Flags |= FlagType.Constructor; ctor.Access = Visibility.Public; ctor.Type = type.Type; ctor.Namespace = "public"; type.Members.Merge(result); type.Constructor = ctor.Name; } result = null; temp = null; } else type.Constructor = type.Name; if (type.Access == Visibility.Private) { model = privateClasses; type.InFile = model; } if (model.Classes.Count > 0 || model.Members.Count > 0) { AddImports(model, imports); models[model.FileName] = model; } } // packages if (abc.scripts == null) continue; foreach (Traits trait in abc.scripts) { FileModel model = null; foreach (MemberInfo info in trait.members) { if (info.kind == TraitMember.Class) continue; MemberModel member = GetMember(info, 0); if (member == null) continue; if (model == null || model.Package != info.name.uri) { AddImports(model, imports); string package = info.name.uri ?? ""; string filename = package.Length > 0 ? "package.as" : "toplevel.as"; filename = Path.Combine(package.Replace('.', Path.DirectorySeparatorChar), filename); filename = Path.Combine(path.Path, filename); if (models.ContainsKey(filename)) model = models[filename]; else { model = new FileModel(""); model.Context = context; model.Package = package; model.HasPackage = true; model.FileName = filename; model.Version = 3; models[filename] = model; } } thisDocs = GetDocs(model.Package); if (thisDocs != null) { docPath = "globalOperation:" + (model.Package.Length > 0 ? model.Package + ":" : "") + member.Name; if (member.Access == Visibility.Public && !String.IsNullOrEmpty(member.Namespace) && member.Namespace != "public") docPath += member.Namespace + ":"; if ((member.Flags & FlagType.Setter) > 0) docPath += ":set"; else if ((member.Flags & FlagType.Getter) > 0) docPath += ":get"; if (thisDocs.ContainsKey(docPath)) applyASDoc(thisDocs[docPath], member); } member.InFile = model; member.IsPackageLevel = true; model.Members.Add(member); } AddImports(model, imports); } } if (privateClasses.Classes.Count > 0) models[privateClasses.FileName] = privateClasses; // some SWCs need manual fixes CustomFixes(path.Path, models); // fake SWC (like 'playerglobal_rb.swc', only provides documentation) if (models.Keys.Count == 1) { foreach (FileModel model in models.Values) if (model.GetPublicClass().QualifiedName == "Empty") { models.Clear(); break; } } path.SetFiles(models); }
private bool OpenVirtualFileModel(string virtualPath) { int p = virtualPath.IndexOf("::"); if (p < 0) return false; string container = virtualPath.Substring(0, p); string ext = Path.GetExtension(container).ToLower(); if (ext != ".swf" && ext != ".swc" && ext != ".ane") return false; if (!File.Exists(container)) return false; string fileName = Path.Combine(container, virtualPath.Substring(p + 2).Replace('.', Path.DirectorySeparatorChar)); PathModel path = new PathModel(container, contextInstance); ContentParser parser = new ContentParser(path.Path); parser.Run(); AbcConverter.Convert(parser, path, contextInstance); if (path.HasFile(fileName)) { FileModel model = path.GetFile(fileName); ASComplete.OpenVirtualFile(model); return true; } int split = fileName.LastIndexOf(Path.DirectorySeparatorChar) + 1; fileName = fileName.Substring(0, split) + "package.as"; if (path.HasFile(fileName)) { FileModel model = path.GetFile(fileName); ASComplete.OpenVirtualFile(model); return true; } fileName = fileName.Substring(0, split) + "toplevel.as"; if (path.HasFile(fileName)) { FileModel model = path.GetFile(fileName); ASComplete.OpenVirtualFile(model); return true; } return false; }
/// <summary> /// Parse a packaged library file /// </summary> /// <param name="path">Models owner</param> public override void ExploreVirtualPath(PathModel path) { if (path.WasExplored) { if (MxmlFilter.HasCatalog(path.Path)) MxmlFilter.AddCatalog(path.Path); if (path.FilesCount != 0) // already parsed return; } try { if (File.Exists(path.Path) && !path.WasExplored) { bool isRefresh = path.FilesCount > 0; //TraceManager.AddAsync("parse " + path.Path); lock (path) { path.WasExplored = true; ContentParser parser = new ContentParser(path.Path); parser.Run(); AbcConverter.Convert(parser, path, this); } // reset FCSH if (isRefresh) { EventManager.DispatchEvent(this, new DataEvent(EventType.Command, "ProjectManager.RestartFlexShell", path.Path)); } } } catch (Exception ex) { string message = TextHelper.GetString("Info.ExceptionWhileParsing"); TraceManager.AddAsync(message + " " + path.Path); TraceManager.AddAsync(ex.Message); TraceManager.AddAsync(ex.StackTrace); } }