@hanseltime/esm-interop-tools 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -124,6 +124,17 @@ async function getESMPackages(pkgGraph) {
124
124
  }
125
125
  let pkgInfos = packagePathsMap[currentNode.value.name];
126
126
  if (pkgInfos) {
127
+ // Cache layer to speed up processing when we've already see a package
128
+ const pkgInfo = pkgInfos.find((info)=>info.packageJsonPath === jsonPath);
129
+ if (pkgInfo) {
130
+ return [
131
+ {
132
+ optionalDependencies: pkgInfo.optionalDependencies,
133
+ parentPkgPath: pkgInfo.packageJsonPath
134
+ },
135
+ false
136
+ ];
137
+ }
127
138
  if (pkgInfos.some((info)=>info.packageJsonPath === jsonPath)) {
128
139
  return [
129
140
  {},
@@ -138,7 +149,8 @@ async function getESMPackages(pkgGraph) {
138
149
  const json = JSON.parse(contents.toString());
139
150
  pkgInfos.push({
140
151
  packageJsonPath: jsonPath,
141
- isModule: json.type === "module"
152
+ isModule: json.type === "module",
153
+ optionalDependencies: json.optionalDependencies
142
154
  });
143
155
  return [
144
156
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/operations/getESMPackages.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport resolvePackagePath from \"resolve-package-path\";\nimport {\n\tPackageGraph,\n\tPackageInfo,\n\tNode,\n\tPackageInfoKey,\n} from \"../packageGraphs\";\nimport { join } from \"path\";\nimport { fsOpenFiles } from \"systeminformation\";\n\nfunction resolvePkgPath(\n\tpkgDir: string,\n\tpkgName: string,\n\toptions: {\n\t\toptionalDepsFromParent?: {\n\t\t\t[dep: string]: string;\n\t\t};\n\t\t// If this was a patch, we probably can't find a package.json (or at least, I didn't solve this)\n\t\tisPatch: boolean;\n\t\tisRoot: boolean;\n\t},\n) {\n\tconst { optionalDepsFromParent, isPatch, isRoot } = options;\n\tconst path = resolvePackagePath(pkgName, pkgDir);\n\tif (!path && !optionalDepsFromParent?.[pkgName] && !isPatch) {\n\t\tif (isRoot) {\n\t\t\t// Accounts for an unresolvable root project since we're in it\n\t\t\treturn join(pkgDir, \"package.json\");\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Non-optional dependency could not be found: ${pkgName} when looking from ${pkgDir}`,\n\t\t);\n\t}\n\treturn path;\n}\n// options: {\n// /**\n// * Depending on the integrity of your packages, you may get failures due to some packages saying\n// */\n// ignorePackages: string[]\n// }\ninterface VisitReturn {\n\t/**\n\t * The resolved path of the package.json that's requesting this. This is specifically for multi-version resolutions\n\t */\n\tparentPkgPath?: string;\n\toptionalDependencies?: {\n\t\t[dep: string]: string;\n\t};\n}\n\ninterface PkgInfo {\n\tpackageJsonPath: string;\n\tisModule: boolean;\n}\n\nclass FileReadBatcher {\n\tprivate batch: Promise<void>[] = [];\n\tprivate semaphore: Promise<void> | undefined;\n\treadonly max: number;\n\tconstructor(max: number) {\n\t\tthis.max = max;\n\t}\n\n\tasync read(file: string): Promise<Buffer> {\n\t\tdo {\n\t\t\tif (this.semaphore) {\n\t\t\t\tawait this.semaphore;\n\t\t\t}\n\t\t} while (this.batch.length > this.max);\n\n\t\tconst read = readFile(file);\n\t\tthis.batch.push(\n\t\t\tread.then(() => {\n\t\t\t\treturn undefined;\n\t\t\t}),\n\t\t);\n\t\tif (this.batch.length === this.max) {\n\t\t\tthis.semaphore = (async () => {\n\t\t\t\tawait Promise.all(this.batch);\n\t\t\t\tthis.semaphore = undefined;\n\t\t\t\tthis.batch.length = 0;\n\t\t\t})();\n\t\t}\n\n\t\treturn await read;\n\t}\n}\n\n/**\n * Returns the esm packages from a PackageGraph - Assumes we can read package.json (may not work with yarn plug'n'play)\n * @param pkgGraph\n * @returns\n */\nexport async function getESMPackages(pkgGraph: PackageGraph) {\n\tconst packagePathsMap: {\n\t\t// Since packages can be multiply referenced via nested modules, we can have multiple of these\n\t\t[pkgName: string]: PkgInfo[];\n\t} = {};\n\t// Types are wrong\n\tconst openInfo = (await fsOpenFiles()) as unknown as {\n\t\tavailable: number;\n\t} | null;\n\tlet available: number;\n\tif (!openInfo || openInfo.available == null) {\n\t\tavailable = 400;\n\t} else {\n\t\tavailable = openInfo.available > 400 ? 400 : openInfo.available;\n\t}\n\tif (available === 0) {\n\t\tthrow new Error(\n\t\t\t\"There are 0 available file handles to open so getESMPackages cannot read package.json's\",\n\t\t);\n\t}\n\tconst fileReadBatcher = new FileReadBatcher(available);\n\n\t// We need to resolve the packageJsons and are fine with optional dependencies missing since we can't tell if we need them\n\tasync function resolvePackageJsons(\n\t\tcurrentNode: Node<PackageInfo, PackageInfoKey>,\n\t\tpreviousOptions?: VisitReturn,\n\t): Promise<[VisitReturn, boolean]> {\n\t\t// Look up the package.json\n\t\tconst jsonPath = resolvePkgPath(\n\t\t\tpreviousOptions?.parentPkgPath ?? pkgGraph.pkgDir,\n\t\t\tcurrentNode.value.name,\n\t\t\t{\n\t\t\t\toptionalDepsFromParent: previousOptions?.optionalDependencies,\n\t\t\t\tisPatch: currentNode.value.isPatch,\n\t\t\t\tisRoot: currentNode.value.isRoot,\n\t\t\t},\n\t\t);\n\t\t// If we didn't throw any resolution errors, then we can assume this was optional - we shouldn't resolve down that path\n\t\tif (!jsonPath) {\n\t\t\treturn [{}, true];\n\t\t}\n\t\tlet pkgInfos: PkgInfo[] | undefined =\n\t\t\tpackagePathsMap[currentNode.value.name];\n\t\tif (pkgInfos) {\n\t\t\tif (pkgInfos.some((info) => info.packageJsonPath === jsonPath)) {\n\t\t\t\treturn [{}, false];\n\t\t\t}\n\t\t} else {\n\t\t\tpkgInfos = [] as PkgInfo[];\n\t\t\tpackagePathsMap[currentNode.value.name] = pkgInfos;\n\t\t}\n\n\t\tconst contents = await fileReadBatcher.read(jsonPath);\n\t\tconst json = JSON.parse(contents.toString());\n\t\tpkgInfos.push({\n\t\t\tpackageJsonPath: jsonPath,\n\t\t\tisModule: json.type === \"module\",\n\t\t});\n\t\treturn [\n\t\t\t{\n\t\t\t\toptionalDependencies: json.optionalDependencies,\n\t\t\t\tparentPkgPath: jsonPath,\n\t\t\t},\n\t\t\tfalse,\n\t\t];\n\t}\n\n\t// Iterate the packages and resolve all non-optional packages and existing optionals\n\tawait pkgGraph.topDownVisitAsync(resolvePackageJsons);\n\n\treturn Array.from(\n\t\tObject.keys(packagePathsMap).reduce((mods, p) => {\n\t\t\tconst infos = packagePathsMap[p];\n\t\t\tinfos.forEach((info) => {\n\t\t\t\tif (info.isModule) {\n\t\t\t\t\tmods.add(p);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn mods;\n\t\t}, new Set<string>()),\n\t);\n}\n"],"names":["getESMPackages","resolvePkgPath","pkgDir","pkgName","options","optionalDepsFromParent","isPatch","isRoot","path","resolvePackagePath","join","Error","FileReadBatcher","read","file","semaphore","batch","length","max","readFile","push","then","undefined","Promise","all","constructor","pkgGraph","packagePathsMap","openInfo","fsOpenFiles","available","fileReadBatcher","resolvePackageJsons","currentNode","previousOptions","jsonPath","parentPkgPath","value","name","optionalDependencies","pkgInfos","some","info","packageJsonPath","contents","json","JSON","parse","toString","isModule","type","topDownVisitAsync","Array","from","Object","keys","reduce","mods","p","infos","forEach","add","Set"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/operations/getESMPackages.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport resolvePackagePath from \"resolve-package-path\";\nimport {\n\tPackageGraph,\n\tPackageInfo,\n\tNode,\n\tPackageInfoKey,\n} from \"../packageGraphs\";\nimport { join } from \"path\";\nimport { fsOpenFiles } from \"systeminformation\";\n\nfunction resolvePkgPath(\n\tpkgDir: string,\n\tpkgName: string,\n\toptions: {\n\t\toptionalDepsFromParent?: {\n\t\t\t[dep: string]: string;\n\t\t};\n\t\t// If this was a patch, we probably can't find a package.json (or at least, I didn't solve this)\n\t\tisPatch: boolean;\n\t\tisRoot: boolean;\n\t},\n) {\n\tconst { optionalDepsFromParent, isPatch, isRoot } = options;\n\tconst path = resolvePackagePath(pkgName, pkgDir);\n\tif (!path && !optionalDepsFromParent?.[pkgName] && !isPatch) {\n\t\tif (isRoot) {\n\t\t\t// Accounts for an unresolvable root project since we're in it\n\t\t\treturn join(pkgDir, \"package.json\");\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Non-optional dependency could not be found: ${pkgName} when looking from ${pkgDir}`,\n\t\t);\n\t}\n\treturn path;\n}\n// options: {\n// /**\n// * Depending on the integrity of your packages, you may get failures due to some packages saying\n// */\n// ignorePackages: string[]\n// }\ninterface VisitReturn {\n\t/**\n\t * The resolved path of the package.json that's requesting this. This is specifically for multi-version resolutions\n\t */\n\tparentPkgPath?: string;\n\toptionalDependencies?: {\n\t\t[dep: string]: string;\n\t};\n}\n\ninterface PkgInfo {\n\tpackageJsonPath: string;\n\tisModule: boolean;\n\toptionalDependencies?: {\n\t\t[dep: string]: string;\n\t};\n}\n\nclass FileReadBatcher {\n\tprivate batch: Promise<void>[] = [];\n\tprivate semaphore: Promise<void> | undefined;\n\treadonly max: number;\n\tconstructor(max: number) {\n\t\tthis.max = max;\n\t}\n\n\tasync read(file: string): Promise<Buffer> {\n\t\tdo {\n\t\t\tif (this.semaphore) {\n\t\t\t\tawait this.semaphore;\n\t\t\t}\n\t\t} while (this.batch.length > this.max);\n\n\t\tconst read = readFile(file);\n\t\tthis.batch.push(\n\t\t\tread.then(() => {\n\t\t\t\treturn undefined;\n\t\t\t}),\n\t\t);\n\t\tif (this.batch.length === this.max) {\n\t\t\tthis.semaphore = (async () => {\n\t\t\t\tawait Promise.all(this.batch);\n\t\t\t\tthis.semaphore = undefined;\n\t\t\t\tthis.batch.length = 0;\n\t\t\t})();\n\t\t}\n\n\t\treturn await read;\n\t}\n}\n\n/**\n * Returns the esm packages from a PackageGraph - Assumes we can read package.json (may not work with yarn plug'n'play)\n * @param pkgGraph\n * @returns\n */\nexport async function getESMPackages(pkgGraph: PackageGraph) {\n\tconst packagePathsMap: {\n\t\t// Since packages can be multiply referenced via nested modules, we can have multiple of these\n\t\t[pkgName: string]: PkgInfo[];\n\t} = {};\n\t// Types are wrong\n\tconst openInfo = (await fsOpenFiles()) as unknown as {\n\t\tavailable: number;\n\t} | null;\n\tlet available: number;\n\tif (!openInfo || openInfo.available == null) {\n\t\tavailable = 400;\n\t} else {\n\t\tavailable = openInfo.available > 400 ? 400 : openInfo.available;\n\t}\n\tif (available === 0) {\n\t\tthrow new Error(\n\t\t\t\"There are 0 available file handles to open so getESMPackages cannot read package.json's\",\n\t\t);\n\t}\n\tconst fileReadBatcher = new FileReadBatcher(available);\n\n\t// We need to resolve the packageJsons and are fine with optional dependencies missing since we can't tell if we need them\n\tasync function resolvePackageJsons(\n\t\tcurrentNode: Node<PackageInfo, PackageInfoKey>,\n\t\tpreviousOptions?: VisitReturn,\n\t): Promise<[VisitReturn, boolean]> {\n\t\t// Look up the package.json\n\t\tconst jsonPath = resolvePkgPath(\n\t\t\tpreviousOptions?.parentPkgPath ?? pkgGraph.pkgDir,\n\t\t\tcurrentNode.value.name,\n\t\t\t{\n\t\t\t\toptionalDepsFromParent: previousOptions?.optionalDependencies,\n\t\t\t\tisPatch: currentNode.value.isPatch,\n\t\t\t\tisRoot: currentNode.value.isRoot,\n\t\t\t},\n\t\t);\n\t\t// If we didn't throw any resolution errors, then we can assume this was optional - we shouldn't resolve down that path\n\t\tif (!jsonPath) {\n\t\t\treturn [{}, true];\n\t\t}\n\t\tlet pkgInfos: PkgInfo[] | undefined =\n\t\t\tpackagePathsMap[currentNode.value.name];\n\t\tif (pkgInfos) {\n\t\t\t// Cache layer to speed up processing when we've already see a package\n\t\t\tconst pkgInfo = pkgInfos.find(\n\t\t\t\t(info) => info.packageJsonPath === jsonPath,\n\t\t\t);\n\t\t\tif (pkgInfo) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\toptionalDependencies: pkgInfo.optionalDependencies,\n\t\t\t\t\t\tparentPkgPath: pkgInfo.packageJsonPath,\n\t\t\t\t\t},\n\t\t\t\t\tfalse,\n\t\t\t\t];\n\t\t\t}\n\t\t\tif (pkgInfos.some((info) => info.packageJsonPath === jsonPath)) {\n\t\t\t\treturn [{}, false];\n\t\t\t}\n\t\t} else {\n\t\t\tpkgInfos = [] as PkgInfo[];\n\t\t\tpackagePathsMap[currentNode.value.name] = pkgInfos;\n\t\t}\n\n\t\tconst contents = await fileReadBatcher.read(jsonPath);\n\t\tconst json = JSON.parse(contents.toString());\n\t\tpkgInfos.push({\n\t\t\tpackageJsonPath: jsonPath,\n\t\t\tisModule: json.type === \"module\",\n\t\t\toptionalDependencies: json.optionalDependencies,\n\t\t});\n\t\treturn [\n\t\t\t{\n\t\t\t\toptionalDependencies: json.optionalDependencies,\n\t\t\t\tparentPkgPath: jsonPath,\n\t\t\t},\n\t\t\tfalse,\n\t\t];\n\t}\n\n\t// Iterate the packages and resolve all non-optional packages and existing optionals\n\tawait pkgGraph.topDownVisitAsync(resolvePackageJsons);\n\n\treturn Array.from(\n\t\tObject.keys(packagePathsMap).reduce((mods, p) => {\n\t\t\tconst infos = packagePathsMap[p];\n\t\t\tinfos.forEach((info) => {\n\t\t\t\tif (info.isModule) {\n\t\t\t\t\tmods.add(p);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn mods;\n\t\t}, new Set<string>()),\n\t);\n}\n"],"names":["getESMPackages","resolvePkgPath","pkgDir","pkgName","options","optionalDepsFromParent","isPatch","isRoot","path","resolvePackagePath","join","Error","FileReadBatcher","read","file","semaphore","batch","length","max","readFile","push","then","undefined","Promise","all","constructor","pkgGraph","packagePathsMap","openInfo","fsOpenFiles","available","fileReadBatcher","resolvePackageJsons","currentNode","previousOptions","jsonPath","parentPkgPath","value","name","optionalDependencies","pkgInfos","pkgInfo","find","info","packageJsonPath","some","contents","json","JSON","parse","toString","isModule","type","topDownVisitAsync","Array","from","Object","keys","reduce","mods","p","infos","forEach","add","Set"],"mappings":"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"}
@@ -84,7 +84,7 @@ let Graph = class Graph {
84
84
  * @param visit
85
85
  * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters
86
86
  * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node
87
- * it is coming from
87
+ * it is coming from - note guestbook is deprecated due to needing to late check optional dependencies
88
88
  */ async topDownVisitAsync(visit, firstArrivalOnly) {
89
89
  const guestBook = firstArrivalOnly ? new Set() : undefined;
90
90
  for (const noFrom of this.noFrom){
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/packageGraphs/Graph.ts"],"sourcesContent":["// TODO: it would be nice to split this into a package for reuse\n\n/**\n * Describes a node in a graph that has a value of a specific type\n * and then points to values of others nodes\n */\nexport interface Node<T, NodeKey> {\n\tself: NodeKey;\n\tfrom: NodeKey[];\n\tto: NodeKey[];\n\tvalue: T;\n}\n\n/**\n * A node that we only know where it goes to at the moment\n */\nexport interface DownstreamNode<T, NodeKey> {\n\tself: NodeKey;\n\tvalue: T;\n\tto: NodeKey[];\n}\n\n/**\n * If using a compound node key, then we require a node key serializer to get a base string out of it\n */\ntype NodeKeySerializer<T> = T extends string ? undefined : (t: T) => string;\n\n/**\n * Mnimal \"graph\" class that takes in a bunch of nodes and then allows you to visit them in a particular order.\n *\n * The value of the node <T> is used as the unique node key for referencing other nodes.\n */\nexport class Graph<\n\tT,\n\tNodeKey,\n\tNKSerializer extends NodeKeySerializer<NodeKey> = NodeKeySerializer<NodeKey>,\n> {\n\t// This map is partially filled so we allow undefined values internally\n\treadonly map = new Map<string, Node<T | undefined, NodeKey>>();\n\tprivate readonly noFrom = new Set<string>();\n\treadonly keySerializer: NKSerializer;\n\n\t/**\n\t *\n\t * @param keySerializer - if the graph has a compound key, then you must supply a function that converts a compound key to a string\n\t */\n\tconstructor(keySerializer: NKSerializer) {\n\t\tthis.keySerializer = keySerializer;\n\t}\n\n\tprivate getNodeKeyStr(nodeKey: NodeKey): string {\n\t\treturn this.keySerializer\n\t\t\t? this.keySerializer(nodeKey)\n\t\t\t: (nodeKey as string);\n\t}\n\n\taddDownstreamNode(node: DownstreamNode<T, NodeKey>) {\n\t\tconst nodeKeyStr = this.getNodeKeyStr(node.self);\n\n\t\t// If a previous node prestubbed in the next node, we add it here\n\t\tif (this.map.has(nodeKeyStr)) {\n\t\t\tconst preStubbedNode = this.map.get(nodeKeyStr)!;\n\t\t\tif (preStubbedNode.value !== undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Already added a downstream node of same key: ${nodeKeyStr} - Can't add ${JSON.stringify(node)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tpreStubbedNode.to.push(...node.to);\n\t\t\tpreStubbedNode.value = node.value;\n\t\t} else {\n\t\t\tthis.map.set(nodeKeyStr, {\n\t\t\t\tfrom: [],\n\t\t\t\t...node,\n\t\t\t});\n\t\t\tthis.noFrom.add(nodeKeyStr);\n\t\t}\n\n\t\t// Add to or pre-stub some nodes\n\t\tnode.to.forEach((n) => {\n\t\t\tconst nkStr = this.getNodeKeyStr(n);\n\t\t\tif (this.map.has(nkStr)) {\n\t\t\t\tconst existingNode = this.map.get(nkStr)!;\n\t\t\t\texistingNode.from.push(node.self);\n\t\t\t\tif (existingNode.from.length === 1) {\n\t\t\t\t\t// We were wrong about this package\n\t\t\t\t\tthis.noFrom.delete(nkStr);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.map.set(nkStr, {\n\t\t\t\t\tself: n,\n\t\t\t\t\tfrom: [node.self],\n\t\t\t\t\tto: [],\n\t\t\t\t\tvalue: undefined,\n\t\t\t\t} as Node<T | undefined, NodeKey>);\n\t\t\t}\n\t\t});\n\t}\n\n\tvalidate() {\n\t\tconst errors = [];\n\t\tfor (let [k, node] of this.map.entries()) {\n\t\t\tif (!node.value) {\n\t\t\t\terrors.push(\n\t\t\t\t\t`Unregistered node: ${k}! Node was pointed to by: ${JSON.stringify(node.from)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(errors.join(\"\\n\"));\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param visit\n\t * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters\n\t * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node\n\t * it is coming from\n\t */\n\tasync topDownVisitAsync<R>(\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tfirstArrivalOnly?: boolean,\n\t) {\n\t\tconst guestBook = firstArrivalOnly ? new Set<string>() : undefined;\n\t\tfor (const noFrom of this.noFrom) {\n\t\t\tconst node = this.map.get(noFrom)!;\n\t\t\tawait this.visitDownNodeAsync(node as Node<T, NodeKey>, visit, guestBook);\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param nodeKey - the key that we used to retrieve this node\n\t * @param node - the node itself\n\t * @param visit - the visit function\n\t * @param guestBook - This is used to track if we have already visited the node - note this means we don't expect the visit function to change results\n\t * regardless of the node that we come from\n\t * @param prevResult - the result of the last node that got here\n\t * @returns\n\t */\n\tasync visitDownNodeAsync<R>(\n\t\tnode: Node<T, NodeKey>,\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tguestBook?: Set<string>,\n\t\tprevResult?: R,\n\t) {\n\t\tif (guestBook?.has(this.getNodeKeyStr(node.self))) {\n\t\t\t// We already visited this node\n\t\t\treturn;\n\t\t}\n\t\tconst [result, stop] = await visit(node, prevResult);\n\t\tif (stop) {\n\t\t\t// We let the visitor control travel\n\t\t\treturn;\n\t\t}\n\t\tawait Promise.all(\n\t\t\tnode.to.map((n) => {\n\t\t\t\treturn this.visitDownNodeAsync(\n\t\t\t\t\tthis.map.get(this.getNodeKeyStr(n))! as Node<T, NodeKey>,\n\t\t\t\t\tvisit,\n\t\t\t\t\tguestBook,\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n}\n\ntype StopVisiting = boolean;\n\n/**\n * This function will be called for each visit while traversing along the \"to\" nodes. You can return\n * a result from the visit function that will be provided to any of the \"to\" visitors as the previous result.\n *\n * Additionally, if you return a boolean value in the second tuple, it can stop any further downstream visits from this\n * particular visitor function. (Keep in mind that a visitor can only stop further travel from itself, so if there are\n * multiple visits from multiple nodes each visitor will need to stop further travel. If you do use a guestbook, in a\n * visiting function, that would stop travel fromm the visitor function that first calls stop.)\n */\ntype VisitFunction<Node, R> = (\n\tcurrentNode: Node,\n\tpreviousResult?: R,\n) => Promise<[R, StopVisiting]>;\n"],"names":["Graph","getNodeKeyStr","nodeKey","keySerializer","addDownstreamNode","node","nodeKeyStr","self","map","has","preStubbedNode","get","value","undefined","Error","JSON","stringify","to","push","set","from","noFrom","add","forEach","n","nkStr","existingNode","length","delete","validate","errors","k","entries","join","topDownVisitAsync","visit","firstArrivalOnly","guestBook","Set","visitDownNodeAsync","prevResult","result","stop","Promise","all","constructor","Map"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/packageGraphs/Graph.ts"],"sourcesContent":["// TODO: it would be nice to split this into a package for reuse\n\n/**\n * Describes a node in a graph that has a value of a specific type\n * and then points to values of others nodes\n */\nexport interface Node<T, NodeKey> {\n\tself: NodeKey;\n\tfrom: NodeKey[];\n\tto: NodeKey[];\n\tvalue: T;\n}\n\n/**\n * A node that we only know where it goes to at the moment\n */\nexport interface DownstreamNode<T, NodeKey> {\n\tself: NodeKey;\n\tvalue: T;\n\tto: NodeKey[];\n}\n\n/**\n * If using a compound node key, then we require a node key serializer to get a base string out of it\n */\ntype NodeKeySerializer<T> = T extends string ? undefined : (t: T) => string;\n\n/**\n * Mnimal \"graph\" class that takes in a bunch of nodes and then allows you to visit them in a particular order.\n *\n * The value of the node <T> is used as the unique node key for referencing other nodes.\n */\nexport class Graph<\n\tT,\n\tNodeKey,\n\tNKSerializer extends NodeKeySerializer<NodeKey> = NodeKeySerializer<NodeKey>,\n> {\n\t// This map is partially filled so we allow undefined values internally\n\treadonly map = new Map<string, Node<T | undefined, NodeKey>>();\n\tprivate readonly noFrom = new Set<string>();\n\treadonly keySerializer: NKSerializer;\n\n\t/**\n\t *\n\t * @param keySerializer - if the graph has a compound key, then you must supply a function that converts a compound key to a string\n\t */\n\tconstructor(keySerializer: NKSerializer) {\n\t\tthis.keySerializer = keySerializer;\n\t}\n\n\tprivate getNodeKeyStr(nodeKey: NodeKey): string {\n\t\treturn this.keySerializer\n\t\t\t? this.keySerializer(nodeKey)\n\t\t\t: (nodeKey as string);\n\t}\n\n\taddDownstreamNode(node: DownstreamNode<T, NodeKey>) {\n\t\tconst nodeKeyStr = this.getNodeKeyStr(node.self);\n\n\t\t// If a previous node prestubbed in the next node, we add it here\n\t\tif (this.map.has(nodeKeyStr)) {\n\t\t\tconst preStubbedNode = this.map.get(nodeKeyStr)!;\n\t\t\tif (preStubbedNode.value !== undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Already added a downstream node of same key: ${nodeKeyStr} - Can't add ${JSON.stringify(node)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tpreStubbedNode.to.push(...node.to);\n\t\t\tpreStubbedNode.value = node.value;\n\t\t} else {\n\t\t\tthis.map.set(nodeKeyStr, {\n\t\t\t\tfrom: [],\n\t\t\t\t...node,\n\t\t\t});\n\t\t\tthis.noFrom.add(nodeKeyStr);\n\t\t}\n\n\t\t// Add to or pre-stub some nodes\n\t\tnode.to.forEach((n) => {\n\t\t\tconst nkStr = this.getNodeKeyStr(n);\n\t\t\tif (this.map.has(nkStr)) {\n\t\t\t\tconst existingNode = this.map.get(nkStr)!;\n\t\t\t\texistingNode.from.push(node.self);\n\t\t\t\tif (existingNode.from.length === 1) {\n\t\t\t\t\t// We were wrong about this package\n\t\t\t\t\tthis.noFrom.delete(nkStr);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.map.set(nkStr, {\n\t\t\t\t\tself: n,\n\t\t\t\t\tfrom: [node.self],\n\t\t\t\t\tto: [],\n\t\t\t\t\tvalue: undefined,\n\t\t\t\t} as Node<T | undefined, NodeKey>);\n\t\t\t}\n\t\t});\n\t}\n\n\tvalidate() {\n\t\tconst errors = [];\n\t\tfor (let [k, node] of this.map.entries()) {\n\t\t\tif (!node.value) {\n\t\t\t\terrors.push(\n\t\t\t\t\t`Unregistered node: ${k}! Node was pointed to by: ${JSON.stringify(node.from)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(errors.join(\"\\n\"));\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param visit\n\t * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters\n\t * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node\n\t * it is coming from - note guestbook is deprecated due to needing to late check optional dependencies\n\t */\n\tasync topDownVisitAsync<R>(\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tfirstArrivalOnly?: boolean,\n\t) {\n\t\tconst guestBook = firstArrivalOnly ? new Set<string>() : undefined;\n\t\tfor (const noFrom of this.noFrom) {\n\t\t\tconst node = this.map.get(noFrom)!;\n\t\t\tawait this.visitDownNodeAsync(node as Node<T, NodeKey>, visit, guestBook);\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param nodeKey - the key that we used to retrieve this node\n\t * @param node - the node itself\n\t * @param visit - the visit function\n\t * @param guestBook - This is used to track if we have already visited the node - note this means we don't expect the visit function to change results\n\t * regardless of the node that we come from\n\t * @param prevResult - the result of the last node that got here\n\t * @returns\n\t */\n\tasync visitDownNodeAsync<R>(\n\t\tnode: Node<T, NodeKey>,\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tguestBook?: Set<string>,\n\t\tprevResult?: R,\n\t) {\n\t\tif (guestBook?.has(this.getNodeKeyStr(node.self))) {\n\t\t\t// We already visited this node\n\t\t\treturn;\n\t\t}\n\t\tconst [result, stop] = await visit(node, prevResult);\n\t\tif (stop) {\n\t\t\t// We let the visitor control travel\n\t\t\treturn;\n\t\t}\n\t\tawait Promise.all(\n\t\t\tnode.to.map((n) => {\n\t\t\t\treturn this.visitDownNodeAsync(\n\t\t\t\t\tthis.map.get(this.getNodeKeyStr(n))! as Node<T, NodeKey>,\n\t\t\t\t\tvisit,\n\t\t\t\t\tguestBook,\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n}\n\ntype StopVisiting = boolean;\n\n/**\n * This function will be called for each visit while traversing along the \"to\" nodes. You can return\n * a result from the visit function that will be provided to any of the \"to\" visitors as the previous result.\n *\n * Additionally, if you return a boolean value in the second tuple, it can stop any further downstream visits from this\n * particular visitor function. (Keep in mind that a visitor can only stop further travel from itself, so if there are\n * multiple visits from multiple nodes each visitor will need to stop further travel. If you do use a guestbook, in a\n * visiting function, that would stop travel fromm the visitor function that first calls stop.)\n */\ntype VisitFunction<Node, R> = (\n\tcurrentNode: Node,\n\tpreviousResult?: R,\n) => Promise<[R, StopVisiting]>;\n"],"names":["Graph","getNodeKeyStr","nodeKey","keySerializer","addDownstreamNode","node","nodeKeyStr","self","map","has","preStubbedNode","get","value","undefined","Error","JSON","stringify","to","push","set","from","noFrom","add","forEach","n","nkStr","existingNode","length","delete","validate","errors","k","entries","join","topDownVisitAsync","visit","firstArrivalOnly","guestBook","Set","visitDownNodeAsync","prevResult","result","stop","Promise","all","constructor","Map"],"mappings":"AAAA,gEAAgE;AAEhE;;;CAGC;;;;+BA2BYA;;;eAAAA;;;;;;;;;;;;;;;;AAAN,IAAA,AAAMA,QAAN,MAAMA;IAkBJC,cAAcC,OAAgB,EAAU;QAC/C,OAAO,IAAI,CAACC,aAAa,GACtB,IAAI,CAACA,aAAa,CAACD,WAClBA;IACL;IAEAE,kBAAkBC,IAAgC,EAAE;QACnD,MAAMC,aAAa,IAAI,CAACL,aAAa,CAACI,KAAKE,IAAI;QAE/C,iEAAiE;QACjE,IAAI,IAAI,CAACC,GAAG,CAACC,GAAG,CAACH,aAAa;YAC7B,MAAMI,iBAAiB,IAAI,CAACF,GAAG,CAACG,GAAG,CAACL;YACpC,IAAII,eAAeE,KAAK,KAAKC,WAAW;gBACvC,MAAM,IAAIC,MACT,CAAC,6CAA6C,EAAER,WAAW,aAAa,EAAES,KAAKC,SAAS,CAACX,OAAO;YAElG;YACAK,eAAeO,EAAE,CAACC,IAAI,IAAIb,KAAKY,EAAE;YACjCP,eAAeE,KAAK,GAAGP,KAAKO,KAAK;QAClC,OAAO;YACN,IAAI,CAACJ,GAAG,CAACW,GAAG,CAACb,YAAY;gBACxBc,MAAM,EAAE;gBACR,GAAGf,IAAI;YACR;YACA,IAAI,CAACgB,MAAM,CAACC,GAAG,CAAChB;QACjB;QAEA,gCAAgC;QAChCD,KAAKY,EAAE,CAACM,OAAO,CAAC,CAACC;YAChB,MAAMC,QAAQ,IAAI,CAACxB,aAAa,CAACuB;YACjC,IAAI,IAAI,CAAChB,GAAG,CAACC,GAAG,CAACgB,QAAQ;gBACxB,MAAMC,eAAe,IAAI,CAAClB,GAAG,CAACG,GAAG,CAACc;gBAClCC,aAAaN,IAAI,CAACF,IAAI,CAACb,KAAKE,IAAI;gBAChC,IAAImB,aAAaN,IAAI,CAACO,MAAM,KAAK,GAAG;oBACnC,mCAAmC;oBACnC,IAAI,CAACN,MAAM,CAACO,MAAM,CAACH;gBACpB;YACD,OAAO;gBACN,IAAI,CAACjB,GAAG,CAACW,GAAG,CAACM,OAAO;oBACnBlB,MAAMiB;oBACNJ,MAAM;wBAACf,KAAKE,IAAI;qBAAC;oBACjBU,IAAI,EAAE;oBACNL,OAAOC;gBACR;YACD;QACD;IACD;IAEAgB,WAAW;QACV,MAAMC,SAAS,EAAE;QACjB,KAAK,IAAI,CAACC,GAAG1B,KAAK,IAAI,IAAI,CAACG,GAAG,CAACwB,OAAO,GAAI;YACzC,IAAI,CAAC3B,KAAKO,KAAK,EAAE;gBAChBkB,OAAOZ,IAAI,CACV,CAAC,mBAAmB,EAAEa,EAAE,2BAA2B,EAAEhB,KAAKC,SAAS,CAACX,KAAKe,IAAI,GAAG;YAElF;QACD;QACA,IAAIU,OAAOH,MAAM,GAAG,GAAG;YACtB,MAAM,IAAIb,MAAMgB,OAAOG,IAAI,CAAC;QAC7B;IACD;IAEA;;;;;;EAMC,GACD,MAAMC,kBACLC,KAAyC,EACzCC,gBAA0B,EACzB;QACD,MAAMC,YAAYD,mBAAmB,IAAIE,QAAgBzB;QACzD,KAAK,MAAMQ,UAAU,IAAI,CAACA,MAAM,CAAE;YACjC,MAAMhB,OAAO,IAAI,CAACG,GAAG,CAACG,GAAG,CAACU;YAC1B,MAAM,IAAI,CAACkB,kBAAkB,CAAClC,MAA0B8B,OAAOE;QAChE;IACD;IAEA;;;;;;;;;EASC,GACD,MAAME,mBACLlC,IAAsB,EACtB8B,KAAyC,EACzCE,SAAuB,EACvBG,UAAc,EACb;QACD,IAAIH,WAAW5B,IAAI,IAAI,CAACR,aAAa,CAACI,KAAKE,IAAI,IAAI;YAClD,+BAA+B;YAC/B;QACD;QACA,MAAM,CAACkC,QAAQC,KAAK,GAAG,MAAMP,MAAM9B,MAAMmC;QACzC,IAAIE,MAAM;YACT,oCAAoC;YACpC;QACD;QACA,MAAMC,QAAQC,GAAG,CAChBvC,KAAKY,EAAE,CAACT,GAAG,CAAC,CAACgB;YACZ,OAAO,IAAI,CAACe,kBAAkB,CAC7B,IAAI,CAAC/B,GAAG,CAACG,GAAG,CAAC,IAAI,CAACV,aAAa,CAACuB,KAChCW,OACAE,WACAI;QAEF;IAEF;IA3HA;;;EAGC,GACDI,YAAY1C,aAA2B,CAAE;QATzC,uEAAuE;QACvE,uBAASK,OAAM,IAAIsC;QACnB,uBAAiBzB,UAAS,IAAIiB;QAC9B,uBAASnC,iBAAT,KAAA;QAOC,IAAI,CAACA,aAAa,GAAGA;IACtB;AAsHD"}
@@ -130,6 +130,17 @@ function _getESMPackages() {
130
130
  }
131
131
  let pkgInfos = packagePathsMap[currentNode.value.name];
132
132
  if (pkgInfos) {
133
+ // Cache layer to speed up processing when we've already see a package
134
+ const pkgInfo = pkgInfos.find((info)=>info.packageJsonPath === jsonPath);
135
+ if (pkgInfo) {
136
+ return [
137
+ {
138
+ optionalDependencies: pkgInfo.optionalDependencies,
139
+ parentPkgPath: pkgInfo.packageJsonPath
140
+ },
141
+ false
142
+ ];
143
+ }
133
144
  if (pkgInfos.some((info)=>info.packageJsonPath === jsonPath)) {
134
145
  return [
135
146
  {},
@@ -144,7 +155,8 @@ function _getESMPackages() {
144
155
  const json = JSON.parse(contents.toString());
145
156
  pkgInfos.push({
146
157
  packageJsonPath: jsonPath,
147
- isModule: json.type === "module"
158
+ isModule: json.type === "module",
159
+ optionalDependencies: json.optionalDependencies
148
160
  });
149
161
  return [
150
162
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/operations/getESMPackages.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport resolvePackagePath from \"resolve-package-path\";\nimport {\n\tPackageGraph,\n\tPackageInfo,\n\tNode,\n\tPackageInfoKey,\n} from \"../packageGraphs\";\nimport { join } from \"path\";\nimport { fsOpenFiles } from \"systeminformation\";\n\nfunction resolvePkgPath(\n\tpkgDir: string,\n\tpkgName: string,\n\toptions: {\n\t\toptionalDepsFromParent?: {\n\t\t\t[dep: string]: string;\n\t\t};\n\t\t// If this was a patch, we probably can't find a package.json (or at least, I didn't solve this)\n\t\tisPatch: boolean;\n\t\tisRoot: boolean;\n\t},\n) {\n\tconst { optionalDepsFromParent, isPatch, isRoot } = options;\n\tconst path = resolvePackagePath(pkgName, pkgDir);\n\tif (!path && !optionalDepsFromParent?.[pkgName] && !isPatch) {\n\t\tif (isRoot) {\n\t\t\t// Accounts for an unresolvable root project since we're in it\n\t\t\treturn join(pkgDir, \"package.json\");\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Non-optional dependency could not be found: ${pkgName} when looking from ${pkgDir}`,\n\t\t);\n\t}\n\treturn path;\n}\n// options: {\n// /**\n// * Depending on the integrity of your packages, you may get failures due to some packages saying\n// */\n// ignorePackages: string[]\n// }\ninterface VisitReturn {\n\t/**\n\t * The resolved path of the package.json that's requesting this. This is specifically for multi-version resolutions\n\t */\n\tparentPkgPath?: string;\n\toptionalDependencies?: {\n\t\t[dep: string]: string;\n\t};\n}\n\ninterface PkgInfo {\n\tpackageJsonPath: string;\n\tisModule: boolean;\n}\n\nclass FileReadBatcher {\n\tprivate batch: Promise<void>[] = [];\n\tprivate semaphore: Promise<void> | undefined;\n\treadonly max: number;\n\tconstructor(max: number) {\n\t\tthis.max = max;\n\t}\n\n\tasync read(file: string): Promise<Buffer> {\n\t\tdo {\n\t\t\tif (this.semaphore) {\n\t\t\t\tawait this.semaphore;\n\t\t\t}\n\t\t} while (this.batch.length > this.max);\n\n\t\tconst read = readFile(file);\n\t\tthis.batch.push(\n\t\t\tread.then(() => {\n\t\t\t\treturn undefined;\n\t\t\t}),\n\t\t);\n\t\tif (this.batch.length === this.max) {\n\t\t\tthis.semaphore = (async () => {\n\t\t\t\tawait Promise.all(this.batch);\n\t\t\t\tthis.semaphore = undefined;\n\t\t\t\tthis.batch.length = 0;\n\t\t\t})();\n\t\t}\n\n\t\treturn await read;\n\t}\n}\n\n/**\n * Returns the esm packages from a PackageGraph - Assumes we can read package.json (may not work with yarn plug'n'play)\n * @param pkgGraph\n * @returns\n */\nexport async function getESMPackages(pkgGraph: PackageGraph) {\n\tconst packagePathsMap: {\n\t\t// Since packages can be multiply referenced via nested modules, we can have multiple of these\n\t\t[pkgName: string]: PkgInfo[];\n\t} = {};\n\t// Types are wrong\n\tconst openInfo = (await fsOpenFiles()) as unknown as {\n\t\tavailable: number;\n\t} | null;\n\tlet available: number;\n\tif (!openInfo || openInfo.available == null) {\n\t\tavailable = 400;\n\t} else {\n\t\tavailable = openInfo.available > 400 ? 400 : openInfo.available;\n\t}\n\tif (available === 0) {\n\t\tthrow new Error(\n\t\t\t\"There are 0 available file handles to open so getESMPackages cannot read package.json's\",\n\t\t);\n\t}\n\tconst fileReadBatcher = new FileReadBatcher(available);\n\n\t// We need to resolve the packageJsons and are fine with optional dependencies missing since we can't tell if we need them\n\tasync function resolvePackageJsons(\n\t\tcurrentNode: Node<PackageInfo, PackageInfoKey>,\n\t\tpreviousOptions?: VisitReturn,\n\t): Promise<[VisitReturn, boolean]> {\n\t\t// Look up the package.json\n\t\tconst jsonPath = resolvePkgPath(\n\t\t\tpreviousOptions?.parentPkgPath ?? pkgGraph.pkgDir,\n\t\t\tcurrentNode.value.name,\n\t\t\t{\n\t\t\t\toptionalDepsFromParent: previousOptions?.optionalDependencies,\n\t\t\t\tisPatch: currentNode.value.isPatch,\n\t\t\t\tisRoot: currentNode.value.isRoot,\n\t\t\t},\n\t\t);\n\t\t// If we didn't throw any resolution errors, then we can assume this was optional - we shouldn't resolve down that path\n\t\tif (!jsonPath) {\n\t\t\treturn [{}, true];\n\t\t}\n\t\tlet pkgInfos: PkgInfo[] | undefined =\n\t\t\tpackagePathsMap[currentNode.value.name];\n\t\tif (pkgInfos) {\n\t\t\tif (pkgInfos.some((info) => info.packageJsonPath === jsonPath)) {\n\t\t\t\treturn [{}, false];\n\t\t\t}\n\t\t} else {\n\t\t\tpkgInfos = [] as PkgInfo[];\n\t\t\tpackagePathsMap[currentNode.value.name] = pkgInfos;\n\t\t}\n\n\t\tconst contents = await fileReadBatcher.read(jsonPath);\n\t\tconst json = JSON.parse(contents.toString());\n\t\tpkgInfos.push({\n\t\t\tpackageJsonPath: jsonPath,\n\t\t\tisModule: json.type === \"module\",\n\t\t});\n\t\treturn [\n\t\t\t{\n\t\t\t\toptionalDependencies: json.optionalDependencies,\n\t\t\t\tparentPkgPath: jsonPath,\n\t\t\t},\n\t\t\tfalse,\n\t\t];\n\t}\n\n\t// Iterate the packages and resolve all non-optional packages and existing optionals\n\tawait pkgGraph.topDownVisitAsync(resolvePackageJsons);\n\n\treturn Array.from(\n\t\tObject.keys(packagePathsMap).reduce((mods, p) => {\n\t\t\tconst infos = packagePathsMap[p];\n\t\t\tinfos.forEach((info) => {\n\t\t\t\tif (info.isModule) {\n\t\t\t\t\tmods.add(p);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn mods;\n\t\t}, new Set<string>()),\n\t);\n}\n"],"names":["readFile","resolvePackagePath","join","fsOpenFiles","resolvePkgPath","pkgDir","pkgName","options","optionalDepsFromParent","isPatch","isRoot","path","Error","FileReadBatcher","read","file","semaphore","batch","length","max","push","then","undefined","Promise","all","constructor","getESMPackages","pkgGraph","packagePathsMap","openInfo","available","fileReadBatcher","resolvePackageJsons","currentNode","previousOptions","jsonPath","parentPkgPath","value","name","optionalDependencies","pkgInfos","some","info","packageJsonPath","contents","json","JSON","parse","toString","isModule","type","topDownVisitAsync","Array","from","Object","keys","reduce","mods","p","infos","forEach","add","Set"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/operations/getESMPackages.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport resolvePackagePath from \"resolve-package-path\";\nimport {\n\tPackageGraph,\n\tPackageInfo,\n\tNode,\n\tPackageInfoKey,\n} from \"../packageGraphs\";\nimport { join } from \"path\";\nimport { fsOpenFiles } from \"systeminformation\";\n\nfunction resolvePkgPath(\n\tpkgDir: string,\n\tpkgName: string,\n\toptions: {\n\t\toptionalDepsFromParent?: {\n\t\t\t[dep: string]: string;\n\t\t};\n\t\t// If this was a patch, we probably can't find a package.json (or at least, I didn't solve this)\n\t\tisPatch: boolean;\n\t\tisRoot: boolean;\n\t},\n) {\n\tconst { optionalDepsFromParent, isPatch, isRoot } = options;\n\tconst path = resolvePackagePath(pkgName, pkgDir);\n\tif (!path && !optionalDepsFromParent?.[pkgName] && !isPatch) {\n\t\tif (isRoot) {\n\t\t\t// Accounts for an unresolvable root project since we're in it\n\t\t\treturn join(pkgDir, \"package.json\");\n\t\t}\n\t\tthrow new Error(\n\t\t\t`Non-optional dependency could not be found: ${pkgName} when looking from ${pkgDir}`,\n\t\t);\n\t}\n\treturn path;\n}\n// options: {\n// /**\n// * Depending on the integrity of your packages, you may get failures due to some packages saying\n// */\n// ignorePackages: string[]\n// }\ninterface VisitReturn {\n\t/**\n\t * The resolved path of the package.json that's requesting this. This is specifically for multi-version resolutions\n\t */\n\tparentPkgPath?: string;\n\toptionalDependencies?: {\n\t\t[dep: string]: string;\n\t};\n}\n\ninterface PkgInfo {\n\tpackageJsonPath: string;\n\tisModule: boolean;\n\toptionalDependencies?: {\n\t\t[dep: string]: string;\n\t};\n}\n\nclass FileReadBatcher {\n\tprivate batch: Promise<void>[] = [];\n\tprivate semaphore: Promise<void> | undefined;\n\treadonly max: number;\n\tconstructor(max: number) {\n\t\tthis.max = max;\n\t}\n\n\tasync read(file: string): Promise<Buffer> {\n\t\tdo {\n\t\t\tif (this.semaphore) {\n\t\t\t\tawait this.semaphore;\n\t\t\t}\n\t\t} while (this.batch.length > this.max);\n\n\t\tconst read = readFile(file);\n\t\tthis.batch.push(\n\t\t\tread.then(() => {\n\t\t\t\treturn undefined;\n\t\t\t}),\n\t\t);\n\t\tif (this.batch.length === this.max) {\n\t\t\tthis.semaphore = (async () => {\n\t\t\t\tawait Promise.all(this.batch);\n\t\t\t\tthis.semaphore = undefined;\n\t\t\t\tthis.batch.length = 0;\n\t\t\t})();\n\t\t}\n\n\t\treturn await read;\n\t}\n}\n\n/**\n * Returns the esm packages from a PackageGraph - Assumes we can read package.json (may not work with yarn plug'n'play)\n * @param pkgGraph\n * @returns\n */\nexport async function getESMPackages(pkgGraph: PackageGraph) {\n\tconst packagePathsMap: {\n\t\t// Since packages can be multiply referenced via nested modules, we can have multiple of these\n\t\t[pkgName: string]: PkgInfo[];\n\t} = {};\n\t// Types are wrong\n\tconst openInfo = (await fsOpenFiles()) as unknown as {\n\t\tavailable: number;\n\t} | null;\n\tlet available: number;\n\tif (!openInfo || openInfo.available == null) {\n\t\tavailable = 400;\n\t} else {\n\t\tavailable = openInfo.available > 400 ? 400 : openInfo.available;\n\t}\n\tif (available === 0) {\n\t\tthrow new Error(\n\t\t\t\"There are 0 available file handles to open so getESMPackages cannot read package.json's\",\n\t\t);\n\t}\n\tconst fileReadBatcher = new FileReadBatcher(available);\n\n\t// We need to resolve the packageJsons and are fine with optional dependencies missing since we can't tell if we need them\n\tasync function resolvePackageJsons(\n\t\tcurrentNode: Node<PackageInfo, PackageInfoKey>,\n\t\tpreviousOptions?: VisitReturn,\n\t): Promise<[VisitReturn, boolean]> {\n\t\t// Look up the package.json\n\t\tconst jsonPath = resolvePkgPath(\n\t\t\tpreviousOptions?.parentPkgPath ?? pkgGraph.pkgDir,\n\t\t\tcurrentNode.value.name,\n\t\t\t{\n\t\t\t\toptionalDepsFromParent: previousOptions?.optionalDependencies,\n\t\t\t\tisPatch: currentNode.value.isPatch,\n\t\t\t\tisRoot: currentNode.value.isRoot,\n\t\t\t},\n\t\t);\n\t\t// If we didn't throw any resolution errors, then we can assume this was optional - we shouldn't resolve down that path\n\t\tif (!jsonPath) {\n\t\t\treturn [{}, true];\n\t\t}\n\t\tlet pkgInfos: PkgInfo[] | undefined =\n\t\t\tpackagePathsMap[currentNode.value.name];\n\t\tif (pkgInfos) {\n\t\t\t// Cache layer to speed up processing when we've already see a package\n\t\t\tconst pkgInfo = pkgInfos.find(\n\t\t\t\t(info) => info.packageJsonPath === jsonPath,\n\t\t\t);\n\t\t\tif (pkgInfo) {\n\t\t\t\treturn [\n\t\t\t\t\t{\n\t\t\t\t\t\toptionalDependencies: pkgInfo.optionalDependencies,\n\t\t\t\t\t\tparentPkgPath: pkgInfo.packageJsonPath,\n\t\t\t\t\t},\n\t\t\t\t\tfalse,\n\t\t\t\t];\n\t\t\t}\n\t\t\tif (pkgInfos.some((info) => info.packageJsonPath === jsonPath)) {\n\t\t\t\treturn [{}, false];\n\t\t\t}\n\t\t} else {\n\t\t\tpkgInfos = [] as PkgInfo[];\n\t\t\tpackagePathsMap[currentNode.value.name] = pkgInfos;\n\t\t}\n\n\t\tconst contents = await fileReadBatcher.read(jsonPath);\n\t\tconst json = JSON.parse(contents.toString());\n\t\tpkgInfos.push({\n\t\t\tpackageJsonPath: jsonPath,\n\t\t\tisModule: json.type === \"module\",\n\t\t\toptionalDependencies: json.optionalDependencies,\n\t\t});\n\t\treturn [\n\t\t\t{\n\t\t\t\toptionalDependencies: json.optionalDependencies,\n\t\t\t\tparentPkgPath: jsonPath,\n\t\t\t},\n\t\t\tfalse,\n\t\t];\n\t}\n\n\t// Iterate the packages and resolve all non-optional packages and existing optionals\n\tawait pkgGraph.topDownVisitAsync(resolvePackageJsons);\n\n\treturn Array.from(\n\t\tObject.keys(packagePathsMap).reduce((mods, p) => {\n\t\t\tconst infos = packagePathsMap[p];\n\t\t\tinfos.forEach((info) => {\n\t\t\t\tif (info.isModule) {\n\t\t\t\t\tmods.add(p);\n\t\t\t\t}\n\t\t\t});\n\t\t\treturn mods;\n\t\t}, new Set<string>()),\n\t);\n}\n"],"names":["readFile","resolvePackagePath","join","fsOpenFiles","resolvePkgPath","pkgDir","pkgName","options","optionalDepsFromParent","isPatch","isRoot","path","Error","FileReadBatcher","read","file","semaphore","batch","length","max","push","then","undefined","Promise","all","constructor","getESMPackages","pkgGraph","packagePathsMap","openInfo","available","fileReadBatcher","resolvePackageJsons","currentNode","previousOptions","jsonPath","parentPkgPath","value","name","optionalDependencies","pkgInfos","pkgInfo","find","info","packageJsonPath","some","contents","json","JSON","parse","toString","isModule","type","topDownVisitAsync","Array","from","Object","keys","reduce","mods","p","infos","forEach","add","Set"],"mappings":"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"}
@@ -121,7 +121,7 @@ function _object_spread(target) {
121
121
  * @param visit
122
122
  * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters
123
123
  * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node
124
- * it is coming from
124
+ * it is coming from - note guestbook is deprecated due to needing to late check optional dependencies
125
125
  */ topDownVisitAsync(visit, firstArrivalOnly) {
126
126
  var _this = this;
127
127
  return _async_to_generator(function*() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/packageGraphs/Graph.ts"],"sourcesContent":["// TODO: it would be nice to split this into a package for reuse\n\n/**\n * Describes a node in a graph that has a value of a specific type\n * and then points to values of others nodes\n */\nexport interface Node<T, NodeKey> {\n\tself: NodeKey;\n\tfrom: NodeKey[];\n\tto: NodeKey[];\n\tvalue: T;\n}\n\n/**\n * A node that we only know where it goes to at the moment\n */\nexport interface DownstreamNode<T, NodeKey> {\n\tself: NodeKey;\n\tvalue: T;\n\tto: NodeKey[];\n}\n\n/**\n * If using a compound node key, then we require a node key serializer to get a base string out of it\n */\ntype NodeKeySerializer<T> = T extends string ? undefined : (t: T) => string;\n\n/**\n * Mnimal \"graph\" class that takes in a bunch of nodes and then allows you to visit them in a particular order.\n *\n * The value of the node <T> is used as the unique node key for referencing other nodes.\n */\nexport class Graph<\n\tT,\n\tNodeKey,\n\tNKSerializer extends NodeKeySerializer<NodeKey> = NodeKeySerializer<NodeKey>,\n> {\n\t// This map is partially filled so we allow undefined values internally\n\treadonly map = new Map<string, Node<T | undefined, NodeKey>>();\n\tprivate readonly noFrom = new Set<string>();\n\treadonly keySerializer: NKSerializer;\n\n\t/**\n\t *\n\t * @param keySerializer - if the graph has a compound key, then you must supply a function that converts a compound key to a string\n\t */\n\tconstructor(keySerializer: NKSerializer) {\n\t\tthis.keySerializer = keySerializer;\n\t}\n\n\tprivate getNodeKeyStr(nodeKey: NodeKey): string {\n\t\treturn this.keySerializer\n\t\t\t? this.keySerializer(nodeKey)\n\t\t\t: (nodeKey as string);\n\t}\n\n\taddDownstreamNode(node: DownstreamNode<T, NodeKey>) {\n\t\tconst nodeKeyStr = this.getNodeKeyStr(node.self);\n\n\t\t// If a previous node prestubbed in the next node, we add it here\n\t\tif (this.map.has(nodeKeyStr)) {\n\t\t\tconst preStubbedNode = this.map.get(nodeKeyStr)!;\n\t\t\tif (preStubbedNode.value !== undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Already added a downstream node of same key: ${nodeKeyStr} - Can't add ${JSON.stringify(node)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tpreStubbedNode.to.push(...node.to);\n\t\t\tpreStubbedNode.value = node.value;\n\t\t} else {\n\t\t\tthis.map.set(nodeKeyStr, {\n\t\t\t\tfrom: [],\n\t\t\t\t...node,\n\t\t\t});\n\t\t\tthis.noFrom.add(nodeKeyStr);\n\t\t}\n\n\t\t// Add to or pre-stub some nodes\n\t\tnode.to.forEach((n) => {\n\t\t\tconst nkStr = this.getNodeKeyStr(n);\n\t\t\tif (this.map.has(nkStr)) {\n\t\t\t\tconst existingNode = this.map.get(nkStr)!;\n\t\t\t\texistingNode.from.push(node.self);\n\t\t\t\tif (existingNode.from.length === 1) {\n\t\t\t\t\t// We were wrong about this package\n\t\t\t\t\tthis.noFrom.delete(nkStr);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.map.set(nkStr, {\n\t\t\t\t\tself: n,\n\t\t\t\t\tfrom: [node.self],\n\t\t\t\t\tto: [],\n\t\t\t\t\tvalue: undefined,\n\t\t\t\t} as Node<T | undefined, NodeKey>);\n\t\t\t}\n\t\t});\n\t}\n\n\tvalidate() {\n\t\tconst errors = [];\n\t\tfor (let [k, node] of this.map.entries()) {\n\t\t\tif (!node.value) {\n\t\t\t\terrors.push(\n\t\t\t\t\t`Unregistered node: ${k}! Node was pointed to by: ${JSON.stringify(node.from)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(errors.join(\"\\n\"));\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param visit\n\t * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters\n\t * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node\n\t * it is coming from\n\t */\n\tasync topDownVisitAsync<R>(\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tfirstArrivalOnly?: boolean,\n\t) {\n\t\tconst guestBook = firstArrivalOnly ? new Set<string>() : undefined;\n\t\tfor (const noFrom of this.noFrom) {\n\t\t\tconst node = this.map.get(noFrom)!;\n\t\t\tawait this.visitDownNodeAsync(node as Node<T, NodeKey>, visit, guestBook);\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param nodeKey - the key that we used to retrieve this node\n\t * @param node - the node itself\n\t * @param visit - the visit function\n\t * @param guestBook - This is used to track if we have already visited the node - note this means we don't expect the visit function to change results\n\t * regardless of the node that we come from\n\t * @param prevResult - the result of the last node that got here\n\t * @returns\n\t */\n\tasync visitDownNodeAsync<R>(\n\t\tnode: Node<T, NodeKey>,\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tguestBook?: Set<string>,\n\t\tprevResult?: R,\n\t) {\n\t\tif (guestBook?.has(this.getNodeKeyStr(node.self))) {\n\t\t\t// We already visited this node\n\t\t\treturn;\n\t\t}\n\t\tconst [result, stop] = await visit(node, prevResult);\n\t\tif (stop) {\n\t\t\t// We let the visitor control travel\n\t\t\treturn;\n\t\t}\n\t\tawait Promise.all(\n\t\t\tnode.to.map((n) => {\n\t\t\t\treturn this.visitDownNodeAsync(\n\t\t\t\t\tthis.map.get(this.getNodeKeyStr(n))! as Node<T, NodeKey>,\n\t\t\t\t\tvisit,\n\t\t\t\t\tguestBook,\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n}\n\ntype StopVisiting = boolean;\n\n/**\n * This function will be called for each visit while traversing along the \"to\" nodes. You can return\n * a result from the visit function that will be provided to any of the \"to\" visitors as the previous result.\n *\n * Additionally, if you return a boolean value in the second tuple, it can stop any further downstream visits from this\n * particular visitor function. (Keep in mind that a visitor can only stop further travel from itself, so if there are\n * multiple visits from multiple nodes each visitor will need to stop further travel. If you do use a guestbook, in a\n * visiting function, that would stop travel fromm the visitor function that first calls stop.)\n */\ntype VisitFunction<Node, R> = (\n\tcurrentNode: Node,\n\tpreviousResult?: R,\n) => Promise<[R, StopVisiting]>;\n"],"names":["Graph","getNodeKeyStr","nodeKey","keySerializer","addDownstreamNode","node","nodeKeyStr","self","map","has","preStubbedNode","get","value","undefined","Error","JSON","stringify","to","push","set","from","noFrom","add","forEach","n","nkStr","existingNode","length","delete","validate","errors","k","entries","join","topDownVisitAsync","visit","firstArrivalOnly","guestBook","Set","visitDownNodeAsync","prevResult","result","stop","Promise","all","constructor","Map"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/packageGraphs/Graph.ts"],"sourcesContent":["// TODO: it would be nice to split this into a package for reuse\n\n/**\n * Describes a node in a graph that has a value of a specific type\n * and then points to values of others nodes\n */\nexport interface Node<T, NodeKey> {\n\tself: NodeKey;\n\tfrom: NodeKey[];\n\tto: NodeKey[];\n\tvalue: T;\n}\n\n/**\n * A node that we only know where it goes to at the moment\n */\nexport interface DownstreamNode<T, NodeKey> {\n\tself: NodeKey;\n\tvalue: T;\n\tto: NodeKey[];\n}\n\n/**\n * If using a compound node key, then we require a node key serializer to get a base string out of it\n */\ntype NodeKeySerializer<T> = T extends string ? undefined : (t: T) => string;\n\n/**\n * Mnimal \"graph\" class that takes in a bunch of nodes and then allows you to visit them in a particular order.\n *\n * The value of the node <T> is used as the unique node key for referencing other nodes.\n */\nexport class Graph<\n\tT,\n\tNodeKey,\n\tNKSerializer extends NodeKeySerializer<NodeKey> = NodeKeySerializer<NodeKey>,\n> {\n\t// This map is partially filled so we allow undefined values internally\n\treadonly map = new Map<string, Node<T | undefined, NodeKey>>();\n\tprivate readonly noFrom = new Set<string>();\n\treadonly keySerializer: NKSerializer;\n\n\t/**\n\t *\n\t * @param keySerializer - if the graph has a compound key, then you must supply a function that converts a compound key to a string\n\t */\n\tconstructor(keySerializer: NKSerializer) {\n\t\tthis.keySerializer = keySerializer;\n\t}\n\n\tprivate getNodeKeyStr(nodeKey: NodeKey): string {\n\t\treturn this.keySerializer\n\t\t\t? this.keySerializer(nodeKey)\n\t\t\t: (nodeKey as string);\n\t}\n\n\taddDownstreamNode(node: DownstreamNode<T, NodeKey>) {\n\t\tconst nodeKeyStr = this.getNodeKeyStr(node.self);\n\n\t\t// If a previous node prestubbed in the next node, we add it here\n\t\tif (this.map.has(nodeKeyStr)) {\n\t\t\tconst preStubbedNode = this.map.get(nodeKeyStr)!;\n\t\t\tif (preStubbedNode.value !== undefined) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Already added a downstream node of same key: ${nodeKeyStr} - Can't add ${JSON.stringify(node)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tpreStubbedNode.to.push(...node.to);\n\t\t\tpreStubbedNode.value = node.value;\n\t\t} else {\n\t\t\tthis.map.set(nodeKeyStr, {\n\t\t\t\tfrom: [],\n\t\t\t\t...node,\n\t\t\t});\n\t\t\tthis.noFrom.add(nodeKeyStr);\n\t\t}\n\n\t\t// Add to or pre-stub some nodes\n\t\tnode.to.forEach((n) => {\n\t\t\tconst nkStr = this.getNodeKeyStr(n);\n\t\t\tif (this.map.has(nkStr)) {\n\t\t\t\tconst existingNode = this.map.get(nkStr)!;\n\t\t\t\texistingNode.from.push(node.self);\n\t\t\t\tif (existingNode.from.length === 1) {\n\t\t\t\t\t// We were wrong about this package\n\t\t\t\t\tthis.noFrom.delete(nkStr);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tthis.map.set(nkStr, {\n\t\t\t\t\tself: n,\n\t\t\t\t\tfrom: [node.self],\n\t\t\t\t\tto: [],\n\t\t\t\t\tvalue: undefined,\n\t\t\t\t} as Node<T | undefined, NodeKey>);\n\t\t\t}\n\t\t});\n\t}\n\n\tvalidate() {\n\t\tconst errors = [];\n\t\tfor (let [k, node] of this.map.entries()) {\n\t\t\tif (!node.value) {\n\t\t\t\terrors.push(\n\t\t\t\t\t`Unregistered node: ${k}! Node was pointed to by: ${JSON.stringify(node.from)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (errors.length > 0) {\n\t\t\tthrow new Error(errors.join(\"\\n\"));\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param visit\n\t * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters\n\t * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node\n\t * it is coming from - note guestbook is deprecated due to needing to late check optional dependencies\n\t */\n\tasync topDownVisitAsync<R>(\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tfirstArrivalOnly?: boolean,\n\t) {\n\t\tconst guestBook = firstArrivalOnly ? new Set<string>() : undefined;\n\t\tfor (const noFrom of this.noFrom) {\n\t\t\tconst node = this.map.get(noFrom)!;\n\t\t\tawait this.visitDownNodeAsync(node as Node<T, NodeKey>, visit, guestBook);\n\t\t}\n\t}\n\n\t/**\n\t *\n\t * @param nodeKey - the key that we used to retrieve this node\n\t * @param node - the node itself\n\t * @param visit - the visit function\n\t * @param guestBook - This is used to track if we have already visited the node - note this means we don't expect the visit function to change results\n\t * regardless of the node that we come from\n\t * @param prevResult - the result of the last node that got here\n\t * @returns\n\t */\n\tasync visitDownNodeAsync<R>(\n\t\tnode: Node<T, NodeKey>,\n\t\tvisit: VisitFunction<Node<T, NodeKey>, R>,\n\t\tguestBook?: Set<string>,\n\t\tprevResult?: R,\n\t) {\n\t\tif (guestBook?.has(this.getNodeKeyStr(node.self))) {\n\t\t\t// We already visited this node\n\t\t\treturn;\n\t\t}\n\t\tconst [result, stop] = await visit(node, prevResult);\n\t\tif (stop) {\n\t\t\t// We let the visitor control travel\n\t\t\treturn;\n\t\t}\n\t\tawait Promise.all(\n\t\t\tnode.to.map((n) => {\n\t\t\t\treturn this.visitDownNodeAsync(\n\t\t\t\t\tthis.map.get(this.getNodeKeyStr(n))! as Node<T, NodeKey>,\n\t\t\t\t\tvisit,\n\t\t\t\t\tguestBook,\n\t\t\t\t\tresult,\n\t\t\t\t);\n\t\t\t}),\n\t\t);\n\t}\n}\n\ntype StopVisiting = boolean;\n\n/**\n * This function will be called for each visit while traversing along the \"to\" nodes. You can return\n * a result from the visit function that will be provided to any of the \"to\" visitors as the previous result.\n *\n * Additionally, if you return a boolean value in the second tuple, it can stop any further downstream visits from this\n * particular visitor function. (Keep in mind that a visitor can only stop further travel from itself, so if there are\n * multiple visits from multiple nodes each visitor will need to stop further travel. If you do use a guestbook, in a\n * visiting function, that would stop travel fromm the visitor function that first calls stop.)\n */\ntype VisitFunction<Node, R> = (\n\tcurrentNode: Node,\n\tpreviousResult?: R,\n) => Promise<[R, StopVisiting]>;\n"],"names":["Graph","getNodeKeyStr","nodeKey","keySerializer","addDownstreamNode","node","nodeKeyStr","self","map","has","preStubbedNode","get","value","undefined","Error","JSON","stringify","to","push","set","from","noFrom","add","forEach","n","nkStr","existingNode","length","delete","validate","errors","k","entries","join","topDownVisitAsync","visit","firstArrivalOnly","guestBook","Set","visitDownNodeAsync","prevResult","result","stop","Promise","all","constructor","Map"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"getESMPackages.d.ts","sourceRoot":"","sources":["../../../src/operations/getESMPackages.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,YAAY,EAIZ,MAAM,kBAAkB,CAAC;AAmF1B;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,YAAY,qBAiF1D"}
1
+ {"version":3,"file":"getESMPackages.d.ts","sourceRoot":"","sources":["../../../src/operations/getESMPackages.ts"],"names":[],"mappings":"AAEA,OAAO,EACN,YAAY,EAIZ,MAAM,kBAAkB,CAAC;AAsF1B;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,YAAY,qBA+F1D"}
@@ -42,7 +42,7 @@ export declare class Graph<T, NodeKey, NKSerializer extends NodeKeySerializer<No
42
42
  * @param visit
43
43
  * @param firstArrivalOnly - if set to true, we are saying that we do not care about from where we get to the node, just the first arrival matters
44
44
  * This will depend on your visit function, since the visit function can pass parent -> child info that may change based on the node
45
- * it is coming from
45
+ * it is coming from - note guestbook is deprecated due to needing to late check optional dependencies
46
46
  */
47
47
  topDownVisitAsync<R>(visit: VisitFunction<Node<T, NodeKey>, R>, firstArrivalOnly?: boolean): Promise<void>;
48
48
  /**
package/package.json CHANGED
@@ -5,6 +5,10 @@
5
5
  "bin": {
6
6
  "get-esm-packages": "dist/esm/bin/get-esm-packages.mjs"
7
7
  },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/HanseltimeIndustries/esm-interop-tools.git"
11
+ },
8
12
  "exports": {
9
13
  ".": {
10
14
  "require": "./dist/cjs/index.js",
@@ -44,7 +48,7 @@
44
48
  "husky": "^9.1.7",
45
49
  "jest": "^29.7.0",
46
50
  "jest-chain-transform": "^0.0.8",
47
- "semantic-release": "^24.2.0",
51
+ "semantic-release": "^25.0.3",
48
52
  "ts-jest": "^29.2.5",
49
53
  "ts-node": "^10.9.2",
50
54
  "tswc": "^1.4.0",
@@ -61,5 +65,5 @@
61
65
  "access": "public"
62
66
  },
63
67
  "packageManager": "yarn@4.5.3",
64
- "version": "1.0.3"
68
+ "version": "1.0.4"
65
69
  }