private IEnumerable <ModuleTree> GetChildrenExcludingNodeModules(ModuleTree moduleTree) { if (moduleTree == null) { return(Enumerable.Empty <ModuleTree>()); } //Children.Values returns an IEnumerable // The process of resolving modules can lead us to add entries into the underlying array // doing so results in exceptions b/c the array has changed under the enumerable // To avoid this, we call .ToArray() to create a copy of the array locally which we then Enumerate return(moduleTree.Children.Values.ToArray().Where(mod => !String.Equals(mod.Name, AnalysisConstants.NodeModulesFolder, StringComparison.OrdinalIgnoreCase))); }
private static void AppendPath(StringBuilder res, ModuleTree moduleTree) { if (moduleTree.Parent != null) { AppendPath(res, moduleTree.Parent); } if (!String.IsNullOrEmpty(moduleTree.Name)) { res.Append(moduleTree.Name); res.Append('\\'); } }
public ModuleTree GetChild(string name, AnalysisUnit unit) { ModuleTree tree; if (!Children.TryGetValue(name, out tree)) { Children[name] = tree = new ModuleTree(this, name); } if (unit != null) { tree.AddDependency(unit); } return(tree); }
private void GetChildModules(List <MemberResult> res, ModuleTree moduleTree, string projectRelative) { foreach (var child in GetChildrenExcludingNodeModules(moduleTree)) { Debug.Assert(child.Name != AnalysisConstants.NodeModulesFolder); if (child.ProjectEntry == null) { GetChildModules(res, child, projectRelative + child.Name + "/"); } else { res.Add(MakeProjectMemberResult(projectRelative + child.Name)); } } }
/// <summary> /// Gets the exports object from the module, or if we currently point to /// a folder resolves to the default package.json. /// </summary> private IAnalysisSet GetExports(Node node, AnalysisUnit unit, ModuleTree curTree) { if (curTree != null) { if (curTree.ProjectEntry != null) { var module = curTree.ProjectEntry.GetModule(unit); if (module != null) { return(module.Get( node, unit, "exports" )); } } else if (curTree.Parent != null) { // No ModuleReference, this is a folder, check and see // if we have the default package file (either index.js // or the file specified in package.json) // we need to check for infinite recursion // if someone setup two package.json's which // point the main file at each other. if (_recursionCheck == null) { _recursionCheck = new HashSet <ModuleRecursion>(); } var recCheck = new ModuleRecursion(curTree.DefaultPackage, curTree); if (_recursionCheck.Add(recCheck)) { try { return(RequireModule( node, unit, curTree.DefaultPackage, curTree )); } finally { _recursionCheck.Remove(recCheck); } } } } return(AnalysisSet.Empty); }
private static ModuleTree ResolveModule(ModuleTree parentTree, string relativeName, AnalysisUnit unit) { ModuleTree curTree = parentTree; var components = ModuleTable.GetPathComponents(relativeName); for (int i = 0; i < components.Length; i++) { var comp = components[i]; if (curTree == null) { return(null); } if (comp == "." || comp == "") { continue; } else if (comp == "..") { curTree = curTree.Parent; continue; } ModuleTree nextTree; if (i == components.Length - 1) { nextTree = curTree.GetChild(comp + ".js", unit); if (nextTree.ProjectEntry != null) { return(nextTree); } } nextTree = curTree.GetChild(comp, unit); if (nextTree.Children.Count > 0 || nextTree.ProjectEntry != null) { curTree = nextTree; continue; } return(null); } return(curTree); }
public ModuleTree GetModuleTree(string name) { lock (_lock) { var curTree = _modules; foreach (var comp in GetPathComponents(name)) { ModuleTree nextTree; if (!curTree.Children.TryGetValue(comp, out nextTree)) { curTree.Children[comp] = nextTree = new ModuleTree(curTree, comp); } curTree = nextTree; } _modulesByFilename[name] = curTree; return(curTree); } }
// Visibility rules: // My peers can see my assignments/I can see my peers assignments // Everything up to the next node_modules and terminating at child node_modules // folders is a set of peers. They can easily require each other using relative // paths. We make all of the assignments made by these modules available to // see by all the other modules. // // My parent and its peers can see my assignments // A folder which contains node_modules is presumably using those modules. ANy // peers within that folder structure can see all of the changes by the children // in node_modules. // // We share hashsets of visible nodes. They're stored in the ModuleTree and when a // new module is added we assign it's _visibleEntries field to the one shared by all // of it's peers. We then update the relevant entries with the new values. internal void AddVisibility(ModuleTree tree, ProjectEntry newModule) { // My peers can see my assignments/I can see my peers assignments. Update // ourselves and our peers so we can see each others writes. var curTree = tree; while (curTree.Parent != null && curTree.Parent.Name != AnalysisConstants.NodeModulesFolder) { curTree = curTree.Parent; } if (curTree.VisibleEntries == null) { curTree.VisibleEntries = new HashSet <ProjectEntry>(); curTree.VisibleEntries.Add(newModule.Analyzer._builtinEntry); } curTree.VisibleEntries.Add(newModule); newModule._visibleEntries = curTree.VisibleEntries; // My parent and its peers can see my assignments. Update existing parents // so they can see the newly added modules writes. if (curTree.Parent != null) { Debug.Assert(curTree.Parent.Name == AnalysisConstants.NodeModulesFolder); var grandParent = curTree.Parent.Parent; if (grandParent != null) { while (grandParent.Parent != null && !String.Equals(grandParent.Parent.Name, AnalysisConstants.NodeModulesFolder, StringComparison.OrdinalIgnoreCase)) { grandParent = grandParent.Parent; } if (grandParent.VisibleEntries == null) { grandParent.VisibleEntries = new HashSet <ProjectEntry>(); } grandParent.VisibleEntries.Add(newModule); } } }
internal ModuleTree RequireModule(AnalysisUnit unit, string moduleName, ModuleTree relativeTo) { ModuleTree curTree = null; if (moduleName.StartsWith("./") || moduleName.StartsWith("../")) { // search relative to our declaring module. curTree = ResolveModule(relativeTo, moduleName, unit); } else { // must be in node_modules, search in the current directory // and up through our parents do { var nodeModules = relativeTo.GetChild(AnalysisConstants.NodeModulesFolder, unit); curTree = ResolveModule(nodeModules, moduleName, unit); relativeTo = relativeTo.Parent; } while (relativeTo != null && curTree == null); } return(curTree); }
public ModuleTree(ModuleTree parent, string name) { Parent = parent; Name = name; }
public bool TryGetValue(string name, out ModuleTree moduleTree) { lock (_lock) { return(_modulesByFilename.TryGetValue(name, out moduleTree)); } }
public ModuleRecursion(string name, ModuleTree module) { Name = name; Module = module; }
public TreeUpdateAnalysis(ModuleTree tree) { _tree = tree; }
private IAnalysisSet RequireModule(Node node, AnalysisUnit unit, string moduleName, ModuleTree relativeTo) { ModuleTree tree = RequireModule(unit, moduleName, relativeTo); if (node != null) { return(GetExports(node, unit, tree)); } return(AnalysisSet.Empty); }
private IAnalysisSet RequireModule(Node node, AnalysisUnit unit, string moduleName, ModuleTree relativeTo) { if (moduleName.StartsWith("./") || moduleName.StartsWith("../")) { // search relative to our declaring module. return(GetExports( node, unit, ResolveModule(relativeTo, moduleName, unit) )); } else { // must be in node_modules, search in the current directory // and up through our parents do { var nodeModules = relativeTo.GetChild(AnalysisConstants.NodeModulesFolder, unit); var curTree = ResolveModule(nodeModules, moduleName, unit); if (curTree != null) { return(GetExports(node, unit, curTree)); } relativeTo = relativeTo.Parent; } while (relativeTo != null); } return(AnalysisSet.Empty); }
internal IEnumerable <MemberResult> GetModules() { //TODO - Handle require('../a/b/c.js' List <MemberResult> res = new List <MemberResult>(); //Add the builtIns foreach (var m in ProjectState.Modules.BuiltinModules) { res.Add(new MemberResult( m.ModuleName, m.Module.Documentation, JsMemberType.Module)); } ModuleTree moduleTree = ProjectState.Modules.GetModuleTree(ModuleName); if (moduleTree == null || moduleTree.Parent == null) { return(res); } ModuleTree parentMT = moduleTree.Parent; //Walk up the tree looking for node_modules do { ModuleTree nodeModules; if (parentMT.Children.TryGetValue(AnalysisConstants.NodeModulesFolder, out nodeModules)) { foreach (var child in GetChildrenExcludingNodeModules(nodeModules)) { var module = ModuleTable.ResolveModule(child.Parent, child.Name); if (module != null) { res.Add(MakeProjectMemberResult(module.Name)); } } } parentMT = parentMT.Parent; } while (parentMT != null); foreach (var sibling in GetChildrenExcludingNodeModules(moduleTree.Parent)) { if (sibling == moduleTree) { //Don't let us require ourself continue; } if (sibling.ProjectEntry != null) { res.Add(MakeProjectMemberResult("./" + sibling.Name)); } else { //We're looking at a folder include the children GetChildModules(res, sibling, "./" + sibling.Name + "/"); } } return(res); }
public static ModuleTree ResolveModule(ModuleTree parentTree, string relativeName) { return(ResolveModule(parentTree, relativeName, null)); }
public TreeUpdateAnalysis(ModuleTree tree, IEnumerable <RequireAnalysisUnit> requireAnalysisUnits = null) { _tree = tree; _requireAnalysisUnits = requireAnalysisUnits; }