@hanseltime/esm-interop-tools 1.0.2 → 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.
@@ -29,6 +29,26 @@ function _path() {
29
29
  };
30
30
  return data;
31
31
  }
32
+ function _systeminformation() {
33
+ const data = require("systeminformation");
34
+ _systeminformation = function() {
35
+ return data;
36
+ };
37
+ return data;
38
+ }
39
+ function _define_property(obj, key, value) {
40
+ if (key in obj) {
41
+ Object.defineProperty(obj, key, {
42
+ value: value,
43
+ enumerable: true,
44
+ configurable: true,
45
+ writable: true
46
+ });
47
+ } else {
48
+ obj[key] = value;
49
+ }
50
+ return obj;
51
+ }
32
52
  function _interop_require_default(obj) {
33
53
  return obj && obj.__esModule ? obj : {
34
54
  default: obj
@@ -46,8 +66,47 @@ function resolvePkgPath(pkgDir, pkgName, options) {
46
66
  }
47
67
  return path;
48
68
  }
69
+ let FileReadBatcher = class FileReadBatcher {
70
+ async read(file) {
71
+ do {
72
+ if (this.semaphore) {
73
+ await this.semaphore;
74
+ }
75
+ }while (this.batch.length > this.max)
76
+ const read = (0, _promises().readFile)(file);
77
+ this.batch.push(read.then(()=>{
78
+ return undefined;
79
+ }));
80
+ if (this.batch.length === this.max) {
81
+ this.semaphore = (async ()=>{
82
+ await Promise.all(this.batch);
83
+ this.semaphore = undefined;
84
+ this.batch.length = 0;
85
+ })();
86
+ }
87
+ return await read;
88
+ }
89
+ constructor(max){
90
+ _define_property(this, "batch", []);
91
+ _define_property(this, "semaphore", void 0);
92
+ _define_property(this, "max", void 0);
93
+ this.max = max;
94
+ }
95
+ };
49
96
  async function getESMPackages(pkgGraph) {
50
97
  const packagePathsMap = {};
98
+ // Types are wrong
99
+ const openInfo = await (0, _systeminformation().fsOpenFiles)();
100
+ let available;
101
+ if (!openInfo || openInfo.available == null) {
102
+ available = 400;
103
+ } else {
104
+ available = openInfo.available > 400 ? 400 : openInfo.available;
105
+ }
106
+ if (available === 0) {
107
+ throw new Error("There are 0 available file handles to open so getESMPackages cannot read package.json's");
108
+ }
109
+ const fileReadBatcher = new FileReadBatcher(available);
51
110
  // We need to resolve the packageJsons and are fine with optional dependencies missing since we can't tell if we need them
52
111
  async function resolvePackageJsons(currentNode, previousOptions) {
53
112
  // Look up the package.json
@@ -65,6 +124,17 @@ async function getESMPackages(pkgGraph) {
65
124
  }
66
125
  let pkgInfos = packagePathsMap[currentNode.value.name];
67
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
+ }
68
138
  if (pkgInfos.some((info)=>info.packageJsonPath === jsonPath)) {
69
139
  return [
70
140
  {},
@@ -75,11 +145,12 @@ async function getESMPackages(pkgGraph) {
75
145
  pkgInfos = [];
76
146
  packagePathsMap[currentNode.value.name] = pkgInfos;
77
147
  }
78
- const contents = await (0, _promises().readFile)(jsonPath);
148
+ const contents = await fileReadBatcher.read(jsonPath);
79
149
  const json = JSON.parse(contents.toString());
80
150
  pkgInfos.push({
81
151
  packageJsonPath: jsonPath,
82
- isModule: json.type === "module"
152
+ isModule: json.type === "module",
153
+ optionalDependencies: json.optionalDependencies
83
154
  });
84
155
  return [
85
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\";\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\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// 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 readFile(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","pkgGraph","packagePathsMap","resolvePackageJsons","currentNode","previousOptions","jsonPath","parentPkgPath","value","name","optionalDependencies","pkgInfos","some","info","packageJsonPath","contents","readFile","json","JSON","parse","toString","push","isModule","type","topDownVisitAsync","Array","from","Object","keys","reduce","mods","p","infos","forEach","add","Set"],"mappings":";;;;+BA6DsBA;;;eAAAA;;;;yBA7DG;;;;;;;gEACM;;;;;;;yBAOV;;;;;;;;;;;AAErB,SAASC,eACRC,MAAc,EACdC,OAAe,EACfC,OAOC;IAED,MAAM,EAAEC,sBAAsB,EAAEC,OAAO,EAAEC,MAAM,EAAE,GAAGH;IACpD,MAAMI,OAAOC,IAAAA,6BAAkB,EAACN,SAASD;IACzC,IAAI,CAACM,QAAQ,CAACH,wBAAwB,CAACF,QAAQ,IAAI,CAACG,SAAS;QAC5D,IAAIC,QAAQ;YACX,8DAA8D;YAC9D,OAAOG,IAAAA,YAAI,EAACR,QAAQ;QACrB;QACA,MAAM,IAAIS,MACT,CAAC,4CAA4C,EAAER,QAAQ,mBAAmB,EAAED,QAAQ;IAEtF;IACA,OAAOM;AACR;AA2BO,eAAeR,eAAeY,QAAsB;IAC1D,MAAMC,kBAGF,CAAC;IACL,0HAA0H;IAC1H,eAAeC,oBACdC,WAA8C,EAC9CC,eAA6B;QAE7B,2BAA2B;QAC3B,MAAMC,WAAWhB,eAChBe,iBAAiBE,iBAAiBN,SAASV,MAAM,EACjDa,YAAYI,KAAK,CAACC,IAAI,EACtB;YACCf,wBAAwBW,iBAAiBK;YACzCf,SAASS,YAAYI,KAAK,CAACb,OAAO;YAClCC,QAAQQ,YAAYI,KAAK,CAACZ,MAAM;QACjC;QAED,uHAAuH;QACvH,IAAI,CAACU,UAAU;YACd,OAAO;gBAAC,CAAC;gBAAG;aAAK;QAClB;QACA,IAAIK,WACHT,eAAe,CAACE,YAAYI,KAAK,CAACC,IAAI,CAAC;QACxC,IAAIE,UAAU;YACb,IAAIA,SAASC,IAAI,CAAC,CAACC,OAASA,KAAKC,eAAe,KAAKR,WAAW;gBAC/D,OAAO;oBAAC,CAAC;oBAAG;iBAAM;YACnB;QACD,OAAO;YACNK,WAAW,EAAE;YACbT,eAAe,CAACE,YAAYI,KAAK,CAACC,IAAI,CAAC,GAAGE;QAC3C;QAEA,MAAMI,WAAW,MAAMC,IAAAA,oBAAQ,EAACV;QAChC,MAAMW,OAAOC,KAAKC,KAAK,CAACJ,SAASK,QAAQ;QACzCT,SAASU,IAAI,CAAC;YACbP,iBAAiBR;YACjBgB,UAAUL,KAAKM,IAAI,KAAK;QACzB;QACA,OAAO;YACN;gBACCb,sBAAsBO,KAAKP,oBAAoB;gBAC/CH,eAAeD;YAChB;YACA;SACA;IACF;IAEA,oFAAoF;IACpF,MAAML,SAASuB,iBAAiB,CAACrB;IAEjC,OAAOsB,MAAMC,IAAI,CAChBC,OAAOC,IAAI,CAAC1B,iBAAiB2B,MAAM,CAAC,CAACC,MAAMC;QAC1C,MAAMC,QAAQ9B,eAAe,CAAC6B,EAAE;QAChCC,MAAMC,OAAO,CAAC,CAACpB;YACd,IAAIA,KAAKS,QAAQ,EAAE;gBAClBQ,KAAKI,GAAG,CAACH;YACV;QACD;QACA,OAAOD;IACR,GAAG,IAAIK;AAET"}
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":"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"}
@@ -27,9 +27,23 @@ function _async_to_generator(fn) {
27
27
  });
28
28
  };
29
29
  }
30
+ function _define_property(obj, key, value) {
31
+ if (key in obj) {
32
+ Object.defineProperty(obj, key, {
33
+ value: value,
34
+ enumerable: true,
35
+ configurable: true,
36
+ writable: true
37
+ });
38
+ } else {
39
+ obj[key] = value;
40
+ }
41
+ return obj;
42
+ }
30
43
  import { readFile } from "node:fs/promises";
31
44
  import resolvePackagePath from "resolve-package-path";
32
45
  import { join } from "path";
46
+ import { fsOpenFiles } from "systeminformation";
33
47
  function resolvePkgPath(pkgDir, pkgName, options) {
34
48
  const { optionalDepsFromParent, isPatch, isRoot } = options;
35
49
  const path = resolvePackagePath(pkgName, pkgDir);
@@ -42,6 +56,36 @@ function resolvePkgPath(pkgDir, pkgName, options) {
42
56
  }
43
57
  return path;
44
58
  }
59
+ let FileReadBatcher = class FileReadBatcher {
60
+ read(file) {
61
+ var _this = this;
62
+ return _async_to_generator(function*() {
63
+ do {
64
+ if (_this.semaphore) {
65
+ yield _this.semaphore;
66
+ }
67
+ }while (_this.batch.length > _this.max)
68
+ const read = readFile(file);
69
+ _this.batch.push(read.then(()=>{
70
+ return undefined;
71
+ }));
72
+ if (_this.batch.length === _this.max) {
73
+ _this.semaphore = _async_to_generator(function*() {
74
+ yield Promise.all(_this.batch);
75
+ _this.semaphore = undefined;
76
+ _this.batch.length = 0;
77
+ })();
78
+ }
79
+ return yield read;
80
+ })();
81
+ }
82
+ constructor(max){
83
+ _define_property(this, "batch", []);
84
+ _define_property(this, "semaphore", void 0);
85
+ _define_property(this, "max", void 0);
86
+ this.max = max;
87
+ }
88
+ };
45
89
  /**
46
90
  * Returns the esm packages from a PackageGraph - Assumes we can read package.json (may not work with yarn plug'n'play)
47
91
  * @param pkgGraph
@@ -52,6 +96,18 @@ function resolvePkgPath(pkgDir, pkgName, options) {
52
96
  function _getESMPackages() {
53
97
  _getESMPackages = _async_to_generator(function*(pkgGraph) {
54
98
  const packagePathsMap = {};
99
+ // Types are wrong
100
+ const openInfo = yield fsOpenFiles();
101
+ let available;
102
+ if (!openInfo || openInfo.available == null) {
103
+ available = 400;
104
+ } else {
105
+ available = openInfo.available > 400 ? 400 : openInfo.available;
106
+ }
107
+ if (available === 0) {
108
+ throw new Error("There are 0 available file handles to open so getESMPackages cannot read package.json's");
109
+ }
110
+ const fileReadBatcher = new FileReadBatcher(available);
55
111
  function resolvePackageJsons(currentNode, previousOptions) {
56
112
  return _resolvePackageJsons.apply(this, arguments);
57
113
  }
@@ -74,6 +130,17 @@ function _getESMPackages() {
74
130
  }
75
131
  let pkgInfos = packagePathsMap[currentNode.value.name];
76
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
+ }
77
144
  if (pkgInfos.some((info)=>info.packageJsonPath === jsonPath)) {
78
145
  return [
79
146
  {},
@@ -84,11 +151,12 @@ function _getESMPackages() {
84
151
  pkgInfos = [];
85
152
  packagePathsMap[currentNode.value.name] = pkgInfos;
86
153
  }
87
- const contents = yield readFile(jsonPath);
154
+ const contents = yield fileReadBatcher.read(jsonPath);
88
155
  const json = JSON.parse(contents.toString());
89
156
  pkgInfos.push({
90
157
  packageJsonPath: jsonPath,
91
- isModule: json.type === "module"
158
+ isModule: json.type === "module",
159
+ optionalDependencies: json.optionalDependencies
92
160
  });
93
161
  return [
94
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\";\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\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// 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 readFile(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","resolvePkgPath","pkgDir","pkgName","options","optionalDepsFromParent","isPatch","isRoot","path","Error","getESMPackages","pkgGraph","packagePathsMap","resolvePackageJsons","currentNode","previousOptions","jsonPath","parentPkgPath","value","name","optionalDependencies","pkgInfos","some","info","packageJsonPath","contents","json","JSON","parse","toString","push","isModule","type","topDownVisitAsync","Array","from","Object","keys","reduce","mods","p","infos","forEach","add","Set"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAASA,QAAQ,QAAQ,mBAAc;AACvC,OAAOC,wBAAwB,uBAAuB;AAOtD,SAASC,IAAI,QAAQ,OAAO;AAE5B,SAASC,eACRC,MAAc,EACdC,OAAe,EACfC,OAOC;IAED,MAAM,EAAEC,sBAAsB,EAAEC,OAAO,EAAEC,MAAM,EAAE,GAAGH;IACpD,MAAMI,OAAOT,mBAAmBI,SAASD;IACzC,IAAI,CAACM,QAAQ,EAACH,mCAAAA,6CAAAA,sBAAwB,CAACF,QAAQ,KAAI,CAACG,SAAS;QAC5D,IAAIC,QAAQ;YACX,8DAA8D;YAC9D,OAAOP,KAAKE,QAAQ;QACrB;QACA,MAAM,IAAIO,MACT,CAAC,4CAA4C,EAAEN,QAAQ,mBAAmB,EAAED,QAAQ;IAEtF;IACA,OAAOM;AACR;AAsBA;;;;CAIC,GACD,gBAAsBE,eAAeC,QAAsB;WAArCD;;SAAAA;IAAAA,kBAAf,oBAAA,UAA8BC,QAAsB;QAC1D,MAAMC,kBAGF,CAAC;iBAEUC,oBACdC,WAA8C,EAC9CC,eAA6B;mBAFfF;;iBAAAA;YAAAA,uBADf,0HAA0H;YAC1H,oBAAA,UACCC,WAA8C,EAC9CC,eAA6B;oBAI5BA;gBAFD,2BAA2B;gBAC3B,MAAMC,WAAWf,eAChBc,CAAAA,iCAAAA,4BAAAA,sCAAAA,gBAAiBE,aAAa,cAA9BF,4CAAAA,iCAAkCJ,SAAST,MAAM,EACjDY,YAAYI,KAAK,CAACC,IAAI,EACtB;oBACCd,sBAAsB,EAAEU,4BAAAA,sCAAAA,gBAAiBK,oBAAoB;oBAC7Dd,SAASQ,YAAYI,KAAK,CAACZ,OAAO;oBAClCC,QAAQO,YAAYI,KAAK,CAACX,MAAM;gBACjC;gBAED,uHAAuH;gBACvH,IAAI,CAACS,UAAU;oBACd,OAAO;wBAAC,CAAC;wBAAG;qBAAK;gBAClB;gBACA,IAAIK,WACHT,eAAe,CAACE,YAAYI,KAAK,CAACC,IAAI,CAAC;gBACxC,IAAIE,UAAU;oBACb,IAAIA,SAASC,IAAI,CAAC,CAACC,OAASA,KAAKC,eAAe,KAAKR,WAAW;wBAC/D,OAAO;4BAAC,CAAC;4BAAG;yBAAM;oBACnB;gBACD,OAAO;oBACNK,WAAW,EAAE;oBACbT,eAAe,CAACE,YAAYI,KAAK,CAACC,IAAI,CAAC,GAAGE;gBAC3C;gBAEA,MAAMI,WAAW,MAAM3B,SAASkB;gBAChC,MAAMU,OAAOC,KAAKC,KAAK,CAACH,SAASI,QAAQ;gBACzCR,SAASS,IAAI,CAAC;oBACbN,iBAAiBR;oBACjBe,UAAUL,KAAKM,IAAI,KAAK;gBACzB;gBACA,OAAO;oBACN;wBACCZ,sBAAsBM,KAAKN,oBAAoB;wBAC/CH,eAAeD;oBAChB;oBACA;iBACA;YACF;mBA1CeH;;QA4Cf,oFAAoF;QACpF,MAAMF,SAASsB,iBAAiB,CAACpB;QAEjC,OAAOqB,MAAMC,IAAI,CAChBC,OAAOC,IAAI,CAACzB,iBAAiB0B,MAAM,CAAC,CAACC,MAAMC;YAC1C,MAAMC,QAAQ7B,eAAe,CAAC4B,EAAE;YAChCC,MAAMC,OAAO,CAAC,CAACnB;gBACd,IAAIA,KAAKQ,QAAQ,EAAE;oBAClBQ,KAAKI,GAAG,CAACH;gBACV;YACD;YACA,OAAOD;QACR,GAAG,IAAIK;IAET;WAhEsBlC"}
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;AAiD1B;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,YAAY,qBAgE1D"}
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",
@@ -30,7 +34,7 @@
30
34
  "devDependencies": {
31
35
  "@biomejs/biome": "1.9.4",
32
36
  "@commitlint/config-angular": "^19.6.0",
33
- "@hanseltime/pkgtest": "^1.0.0",
37
+ "@hanseltime/pkgtest": "^1.3.0",
34
38
  "@hanseltime/swc-plugin-node-globals-inject": "^1.0.0",
35
39
  "@rspack/cli": "^1.1.6",
36
40
  "@rspack/core": "^1.1.6",
@@ -39,12 +43,12 @@
39
43
  "@swc/cli": "^0.6.0",
40
44
  "@swc/core": "^1.10.18",
41
45
  "@types/jest": "^29.5.14",
42
- "@types/node": "^18",
46
+ "@types/node": "^20",
43
47
  "commitlint": "^19.6.1",
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",
@@ -54,11 +58,12 @@
54
58
  "dependencies": {
55
59
  "@semantic-release/exec": "^7.0.3",
56
60
  "commander": "^12.1.0",
57
- "resolve-package-path": "^4.0.3"
61
+ "resolve-package-path": "^4.0.3",
62
+ "systeminformation": "^5.25.11"
58
63
  },
59
64
  "publishConfig": {
60
65
  "access": "public"
61
66
  },
62
67
  "packageManager": "yarn@4.5.3",
63
- "version": "1.0.2"
68
+ "version": "1.0.4"
64
69
  }