@monorepolint/utils 0.6.0-alpha.2 → 0.6.0-alpha.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.
Files changed (56) hide show
  1. package/.turbo/turbo-clean.log +1 -1
  2. package/.turbo/turbo-compile-typescript.log +1 -1
  3. package/.turbo/turbo-lint.log +7 -7
  4. package/.turbo/turbo-test.log +11 -10
  5. package/.turbo/turbo-transpile-typescript.log +4 -4
  6. package/CHANGELOG.md +4 -0
  7. package/build/js/index.js +489 -443
  8. package/build/js/index.js.map +1 -1
  9. package/build/tsconfig.tsbuildinfo +1 -1
  10. package/build/types/CachingHost.d.ts.map +1 -1
  11. package/build/types/Host.d.ts.map +1 -1
  12. package/build/types/PackageJson.d.ts.map +1 -1
  13. package/build/types/SimpleHost.d.ts.map +1 -1
  14. package/build/types/Table.d.ts.map +1 -1
  15. package/build/types/findWorkspaceDir.d.ts.map +1 -1
  16. package/build/types/getPackageNameToDir.d.ts.map +1 -1
  17. package/build/types/getWorkspacePackageDirs.d.ts.map +1 -1
  18. package/build/types/index.d.ts +7 -7
  19. package/build/types/index.d.ts.map +1 -1
  20. package/build/types/matchesAnyGlob.d.ts.map +1 -1
  21. package/build/types/mutateJson.d.ts.map +1 -1
  22. package/build/types/nanosecondsToSanity.d.ts.map +1 -1
  23. package/coverage/AggregateTiming.ts.html +2 -2
  24. package/coverage/CachingHost.ts.html +252 -42
  25. package/coverage/Host.ts.html +15 -3
  26. package/coverage/PackageJson.ts.html +4 -4
  27. package/coverage/SimpleHost.ts.html +40 -7
  28. package/coverage/Table.ts.html +137 -29
  29. package/coverage/Timing.ts.html +1 -1
  30. package/coverage/clover.xml +527 -396
  31. package/coverage/coverage-final.json +13 -13
  32. package/coverage/findWorkspaceDir.ts.html +4 -4
  33. package/coverage/getPackageNameToDir.ts.html +18 -6
  34. package/coverage/getWorkspacePackageDirs.ts.html +168 -138
  35. package/coverage/index.html +40 -40
  36. package/coverage/index.ts.html +30 -30
  37. package/coverage/matchesAnyGlob.ts.html +37 -10
  38. package/coverage/mutateJson.ts.html +17 -5
  39. package/coverage/nanosecondsToSanity.ts.html +11 -5
  40. package/package.json +1 -2
  41. package/src/AggregateTiming.ts +1 -1
  42. package/src/CachingHost.ts +104 -34
  43. package/src/Host.ts +5 -1
  44. package/src/PackageJson.ts +3 -3
  45. package/src/SimpleHost.ts +14 -3
  46. package/src/Table.ts +58 -22
  47. package/src/__tests__/CachingHost.spec.ts +203 -166
  48. package/src/findWorkspaceDir.ts +3 -3
  49. package/src/getPackageNameToDir.ts +6 -2
  50. package/src/getWorkspacePackageDirs.ts +19 -9
  51. package/src/index.ts +7 -7
  52. package/src/matchesAnyGlob.ts +12 -3
  53. package/src/mutateJson.ts +5 -1
  54. package/src/nanosecondsToSanity.ts +3 -1
  55. package/vitest.config.mjs +6 -7
  56. package/vitest.config.mjs.timestamp-1736878329730-aa478e2241542.mjs +2 -2
package/build/js/index.js CHANGED
@@ -1,149 +1,289 @@
1
- // src/getWorkspacePackageDirs.ts
2
- import { existsSync } from "fs";
3
- import * as glob from "glob";
4
- import * as path from "node:path";
5
- import * as fs from "node:fs";
6
- import readYamlFile from "read-yaml-file";
7
- import { findPackages } from "find-packages";
8
- async function findPNPMWorkspacePackages(workspaceRoot) {
9
- workspaceRoot = fs.realpathSync(workspaceRoot);
10
- const workspaceManifest = await readYamlFile.default(
11
- path.join(workspaceRoot, "pnpm-workspace.yaml")
12
- );
13
- return findPackages(workspaceRoot, {
14
- ignore: ["**/node_modules/**", "**/bower_components/**"],
15
- includeRoot: true,
16
- patterns: workspaceManifest.packages
17
- });
1
+ // src/nanosecondsToSanity.ts
2
+ function nanosecondsToSanity(n, precision = 9) {
3
+ return n / BigInt(1e9) + "." + ("" + n % BigInt(1e9)).padStart(9, "0").substring(0, precision) + "s";
18
4
  }
19
- async function getWorkspacePackageDirs(host, workspaceDir, resolvePaths = false) {
20
- const packageJson = host.readJson(path.join(workspaceDir, "package.json"));
21
- const isPnpmWorkspace = host.exists(path.join(workspaceDir, "pnpm-workspace.yaml"));
22
- if (isPnpmWorkspace) {
23
- const workspacePackages = await findPNPMWorkspacePackages(workspaceDir);
24
- if (workspacePackages.length === 0) {
25
- throw new Error("Invalid workspaceDir: " + workspaceDir);
5
+
6
+ // src/Table.ts
7
+ var Table = class {
8
+ #rows = [];
9
+ #config;
10
+ #columnWidths = [];
11
+ #footer = [];
12
+ #footerRowConfig;
13
+ #totalWidth = 0;
14
+ constructor(config) {
15
+ this.#config = {
16
+ padding: 2,
17
+ ...config
18
+ };
19
+ this.#columnWidths.fill(0, 0, config.columns.length);
20
+ if (config.showFooter) {
21
+ this.#footerRowConfig = [];
22
+ for (const columnConfig of config.columns) {
23
+ if (columnConfig.footer === void 0) {
24
+ throw new Error("Must specify footer fields when showFooter is true");
25
+ } else if (typeof columnConfig.footer === "string") {
26
+ this.#footerRowConfig.push({
27
+ type: "string",
28
+ alignment: "left",
29
+ aggregate: "static",
30
+ value: columnConfig.footer
31
+ });
32
+ } else if ("value" in columnConfig.footer) {
33
+ this.#footerRowConfig.push({
34
+ type: "string",
35
+ alignment: "left",
36
+ ...columnConfig.footer
37
+ });
38
+ } else if ("aggregate" in columnConfig.footer) {
39
+ if (columnConfig.type !== "bigint") {
40
+ throw new Error("expecting bigint for aggregate");
41
+ }
42
+ this.#footerRowConfig.push({
43
+ type: columnConfig.type,
44
+ renderAs: columnConfig.renderAs,
45
+ precision: columnConfig.precision,
46
+ alignment: "right",
47
+ ...columnConfig.footer
48
+ });
49
+ }
50
+ }
26
51
  }
27
- return workspacePackages.map((project) => project.dir).filter((d) => d !== workspaceDir);
28
52
  }
29
- if (!packageJson.workspaces) {
30
- throw new Error("Unsupported! Monorepo is not backed by either pnpm nor yarn workspaces.");
53
+ addRow(...data) {
54
+ this.#rows.push(data);
31
55
  }
32
- const ret = [];
33
- const packageGlobs = Array.isArray(packageJson.workspaces) ? packageJson.workspaces : packageJson.workspaces.packages || [];
34
- for (const pattern of packageGlobs) {
35
- for (const packagePath of glob.sync(pattern, { cwd: workspaceDir })) {
36
- const packageJsonPath = path.join(workspaceDir, packagePath, "package.json");
37
- if (existsSync(packageJsonPath)) {
38
- if (resolvePaths === true) {
39
- ret.push(path.resolve(path.join(workspaceDir, packagePath)));
40
- } else {
41
- ret.push(packagePath);
56
+ #sumColumn(c) {
57
+ let total = BigInt(0);
58
+ for (const row of this.#rows) {
59
+ total += row[c];
60
+ }
61
+ return total;
62
+ }
63
+ #updateFooterRow() {
64
+ const footerRowConfig = this.#footerRowConfig;
65
+ if (footerRowConfig) {
66
+ for (let c = 0; c < footerRowConfig.length; c++) {
67
+ const footerColConfig = footerRowConfig[c];
68
+ switch (footerColConfig.aggregate) {
69
+ case "sum":
70
+ this.#footer[c] = this.#sumColumn(c);
71
+ break;
72
+ case "average":
73
+ this.#footer[c] = this.#sumColumn(c) / BigInt(this.#rows.length);
74
+ break;
75
+ case "static":
76
+ this.#footer[c] = footerColConfig.value;
77
+ break;
42
78
  }
43
79
  }
44
80
  }
45
81
  }
46
- return ret;
47
- }
48
-
49
- // src/mutateJson.ts
50
- function mutateJson(path4, host, mutator) {
51
- let file = host.readJson(path4);
52
- file = mutator(file);
53
- host.writeJson(path4, file);
54
- }
55
-
56
- // src/findWorkspaceDir.ts
57
- import * as path2 from "path";
58
- import * as fs2 from "fs";
59
- import { findUp } from "find-up";
60
- async function findPnpmWorkspaceDir(cwd) {
61
- const workspaceManifestLocation = await findUp("pnpm-workspace.yaml", {
62
- cwd: await fs2.promises.realpath(cwd)
63
- });
64
- return workspaceManifestLocation && path2.dirname(workspaceManifestLocation);
65
- }
66
- async function findWorkspaceDir(host, dir) {
67
- const maybePnpmWorkspaceDir = await findPnpmWorkspaceDir(dir);
68
- if (maybePnpmWorkspaceDir != null) {
69
- return maybePnpmWorkspaceDir;
82
+ #calculateColumnWidths() {
83
+ var _a;
84
+ this.#columnWidths.fill(0, 0, this.#config.columns.length);
85
+ for (let c = 0; c < this.#config.columns.length; c++) {
86
+ const colConfig = this.#config.columns[c];
87
+ this.#columnWidths[c] = Math.max(
88
+ (this.#config.columns[c].header ?? "").length,
89
+ ...this.#rows.map((a) => this.#getCellValueAsString(a[c], colConfig).length),
90
+ this.#footer && this.#footerRowConfig ? this.#getCellValueAsString(
91
+ ((_a = this.#footer) == null ? void 0 : _a[c]) ?? "",
92
+ this.#footerRowConfig[c]
93
+ ).length : 0
94
+ );
95
+ }
96
+ this.#totalWidth = 0;
97
+ for (const colWidth of this.#columnWidths) {
98
+ this.#totalWidth += colWidth;
99
+ }
100
+ this.#totalWidth += (this.#columnWidths.length - 1) * this.#config.padding;
70
101
  }
71
- const packagePath = path2.join(dir, "package.json");
72
- if (host.exists(packagePath)) {
73
- const packageJson = host.readJson(packagePath);
74
- if (packageJson.workspaces !== void 0) {
75
- return dir;
102
+ #printSeparator(fillString) {
103
+ const paddingString = "".padStart(this.#config.padding, " ");
104
+ let hr2 = "";
105
+ for (let c = 0; c < this.#columnWidths.length; c++) {
106
+ hr2 += "".padStart(this.#columnWidths[c], fillString) + paddingString;
107
+ }
108
+ hr2 = hr2.trimRight();
109
+ console.log(hr2);
110
+ }
111
+ #printHeaderRow() {
112
+ if (this.#config.showHeader) {
113
+ const colConfigs = this.#config.columns;
114
+ const paddingString = "".padStart(this.#config.padding, " ");
115
+ let hr = "";
116
+ for (let c = 0; c < colConfigs.length; c++) {
117
+ const heading = colConfigs[c].header ?? "";
118
+ hr += heading.padEnd(this.#columnWidths[c], " ") + paddingString;
119
+ }
120
+ hr = hr.trimRight();
121
+ console.log(hr);
122
+ this.#printSeparator("-");
76
123
  }
77
124
  }
78
- const nextDir = path2.normalize(path2.join(dir, ".."));
79
- if (nextDir === dir) {
80
- return void 0;
125
+ #printFooterRow() {
126
+ const footerRow = this.#footer;
127
+ if (footerRow) {
128
+ this.#printSeparator("=");
129
+ const paddingString = "".padStart(this.#config.padding, " ");
130
+ let hr = "";
131
+ for (let c = 0; c < footerRow.length; c++) {
132
+ hr += this.#getCellValueAligned(footerRow[c], this.#footerRowConfig[c], c) + paddingString;
133
+ }
134
+ hr = hr.trimRight();
135
+ console.log(hr);
136
+ }
81
137
  }
82
- return findWorkspaceDir(host, nextDir);
83
- }
84
-
85
- // src/getPackageNameToDir.ts
86
- import { join as pathJoin } from "path";
87
- async function getPackageNameToDir(host, workspaceDir, resolvePaths = false) {
88
- const ret = /* @__PURE__ */ new Map();
89
- const workspacePackages = await getWorkspacePackageDirs(host, workspaceDir, resolvePaths);
90
- for (const packageDir of workspacePackages) {
91
- const packagePath = pathJoin(packageDir, "package.json");
92
- const { name } = host.readJson(packagePath);
93
- if (name === void 0) {
94
- throw new Error(`Package needs a name: ${packagePath}`);
138
+ print() {
139
+ if (this.#config.sortColumn !== void 0) {
95
140
  }
96
- ret.set(name, packageDir);
141
+ this.#updateFooterRow();
142
+ this.#calculateColumnWidths();
143
+ console.log();
144
+ console.log(`${this.#config.title}`);
145
+ console.log("".padStart(this.#totalWidth, "="));
146
+ const paddingString = "".padStart(this.#config.padding, " ");
147
+ if (this.#config.showHeader) {
148
+ this.#printHeaderRow();
149
+ }
150
+ for (let r = 0; r < this.#rows.length; r++) {
151
+ let rowText = "";
152
+ for (let c = 0; c < this.#config.columns.length; c++) {
153
+ rowText += this.getEntryAsStringAligned(c, r) + paddingString;
154
+ }
155
+ rowText.trim();
156
+ console.log(rowText);
157
+ }
158
+ if (this.#config.showFooter) this.#printFooterRow();
159
+ console.log();
97
160
  }
98
- return ret;
99
- }
100
-
101
- // src/SimpleHost.ts
102
- import * as realFs from "fs";
103
- var SimpleHost = class {
104
- constructor(fs3 = realFs) {
105
- this.fs = fs3;
161
+ #getCellValueAsString(value, config) {
162
+ if (config.type === "bigint" && config.renderAs === "nanoseconds") {
163
+ return nanosecondsToSanity(value, config.precision ?? 9);
164
+ } else {
165
+ return "" + value;
166
+ }
106
167
  }
107
- mkdir(directoryPath, opts) {
108
- this.fs.mkdirSync(directoryPath, { recursive: (opts == null ? void 0 : opts.recursive) ?? false });
168
+ #getCellValueAligned(value, config, column) {
169
+ let result;
170
+ if (config.type === "bigint" && config.renderAs === "nanoseconds") {
171
+ result = nanosecondsToSanity(value, config.precision ?? 9);
172
+ } else {
173
+ result = "" + value;
174
+ }
175
+ if (config.alignment === "left") {
176
+ return result.padEnd(this.#columnWidths[column]);
177
+ } else {
178
+ return result.padStart(this.#columnWidths[column]);
179
+ }
109
180
  }
110
- rmdir(directoryPath) {
111
- this.fs.rmdirSync(directoryPath);
181
+ getEntryAsString(colNum, rowNum) {
182
+ const config = this.#config.columns[colNum];
183
+ if (config.type === "bigint" && config.renderAs === "nanoseconds") {
184
+ return nanosecondsToSanity(
185
+ this.#rows[rowNum][colNum],
186
+ config.precision ?? 9
187
+ );
188
+ } else {
189
+ return "" + this.#rows[rowNum][colNum];
190
+ }
112
191
  }
113
- exists(path4) {
114
- return this.fs.existsSync(path4);
192
+ getEntryAsStringAligned(colNum, rowNum) {
193
+ const config = this.#config.columns[colNum];
194
+ let result;
195
+ if (config.type === "bigint" && config.renderAs === "nanoseconds") {
196
+ result = nanosecondsToSanity(
197
+ this.#rows[rowNum][colNum],
198
+ config.precision ?? 9
199
+ );
200
+ } else {
201
+ result = "" + this.#rows[rowNum][colNum];
202
+ }
203
+ if (config.alignment === "left") {
204
+ return result.padEnd(this.#columnWidths[colNum]);
205
+ } else {
206
+ return result.padStart(this.#columnWidths[colNum]);
207
+ }
115
208
  }
116
- writeFile(path4, body, opts) {
117
- if (opts) {
118
- this.fs.writeFileSync(path4, body, { encoding: opts.encoding });
209
+ getColumnWidth(colNum, config) {
210
+ let maxWidth = Math.max(
211
+ (config.header ?? "").length,
212
+ this.#footer && this.#footerRowConfig ? this.#getCellValueAsString(
213
+ this.#footer[colNum],
214
+ this.#footerRowConfig[colNum]
215
+ ).length : 0
216
+ );
217
+ for (let r = 0; r < this.#rows.length; r++) {
218
+ maxWidth = Math.max(maxWidth, this.getEntryAsString(colNum, r).length);
219
+ }
220
+ return maxWidth;
221
+ }
222
+ };
223
+
224
+ // src/AggregateTiming.ts
225
+ var AggregateTiming = class {
226
+ constructor(title) {
227
+ this.title = title;
228
+ }
229
+ #data = /* @__PURE__ */ new Map();
230
+ #last;
231
+ start(name) {
232
+ const time = process.hrtime.bigint();
233
+ if (this.#last) {
234
+ this.#last.total += time;
235
+ }
236
+ let data = this.#data.get(name);
237
+ if (data === void 0) {
238
+ data = { count: 1, total: -time };
239
+ this.#data.set(name, data);
119
240
  } else {
120
- this.fs.writeFileSync(path4, body);
241
+ data.total -= time;
242
+ data.count++;
121
243
  }
244
+ this.#last = data;
122
245
  }
123
- readFile(path4, opts) {
124
- if (opts == null ? void 0 : opts.asJson) {
125
- return JSON.parse(this.fs.readFileSync(path4, "utf-8"));
246
+ stop() {
247
+ const time = process.hrtime.bigint();
248
+ if (this.#last) {
249
+ this.#last.total += time;
250
+ this.#last = void 0;
126
251
  }
127
- return this.fs.readFileSync(path4, opts == null ? void 0 : opts.encoding);
128
- }
129
- deleteFile(path4) {
130
- this.fs.unlinkSync(path4);
131
- }
132
- readJson(filename) {
133
- const contents = this.fs.readFileSync(filename, "utf-8");
134
- return JSON.parse(contents);
135
- }
136
- writeJson(path4, o) {
137
- return this.fs.writeFileSync(path4, JSON.stringify(o, void 0, 2) + "\n");
138
252
  }
139
- flush() {
140
- return Promise.resolve();
253
+ printResults() {
254
+ const table = new Table({
255
+ sortColumn: -1,
256
+ showFooter: true,
257
+ showHeader: true,
258
+ title: this.title,
259
+ columns: [
260
+ {
261
+ header: "Duration",
262
+ type: "bigint",
263
+ renderAs: "nanoseconds",
264
+ footer: { aggregate: "sum" }
265
+ },
266
+ { header: "Task", type: "string", alignment: "left", footer: "TOTAL" },
267
+ { header: "Count", type: "bigint", footer: { aggregate: "sum" } },
268
+ { header: "Avg", type: "bigint", footer: { aggregate: "average" } }
269
+ ]
270
+ });
271
+ for (const [name, value] of this.#data) {
272
+ table.addRow(
273
+ value.total,
274
+ name,
275
+ BigInt(value.count),
276
+ // fixme this can be a number later
277
+ value.total / BigInt(value.count)
278
+ );
279
+ }
280
+ table.print();
141
281
  }
142
282
  };
143
283
 
144
284
  // src/CachingHost.ts
145
- import * as realFs2 from "node:fs";
146
- import * as path3 from "node:path";
285
+ import * as realFs from "node:fs";
286
+ import * as path from "node:path";
147
287
  function assertNoTombstone(node) {
148
288
  if (node.tombstone) {
149
289
  throw new Error(`Unexpected tombstone ${JSON.stringify(node)}`);
@@ -170,7 +310,7 @@ function assertHasParent(node) {
170
310
  }
171
311
  }
172
312
  var CachingHost = class {
173
- constructor(fs3 = realFs2) {
313
+ constructor(fs3 = realFs) {
174
314
  this.fs = fs3;
175
315
  }
176
316
  // We need many trees because of windows, key is the `root`
@@ -183,19 +323,21 @@ var CachingHost = class {
183
323
  parent: node.parent,
184
324
  dir: node.dir
185
325
  };
186
- node.parent.dir.set(path3.basename(node.fullPath), newNode);
326
+ node.parent.dir.set(path.basename(node.fullPath), newNode);
187
327
  return newNode;
188
328
  }
189
329
  #unstubDirectory(node) {
190
330
  for (const child of this.fs.readdirSync(node.fullPath)) {
191
- this.#getNode(path3.join(node.fullPath, child));
331
+ this.#getNode(path.join(node.fullPath, child));
192
332
  }
193
333
  node.stub = false;
194
334
  }
195
335
  #stubify(filePath, parent) {
196
- const canonicalPath = path3.resolve(filePath);
197
- if (!parent && canonicalPath !== path3.parse(canonicalPath).root) {
198
- throw new Error(`parent can only be null if path is root. Instead got: ${canonicalPath}`);
336
+ const canonicalPath = path.resolve(filePath);
337
+ if (!parent && canonicalPath !== path.parse(canonicalPath).root) {
338
+ throw new Error(
339
+ `parent can only be null if path is root. Instead got: ${canonicalPath}`
340
+ );
199
341
  }
200
342
  const stat = this.fs.lstatSync(canonicalPath);
201
343
  let node;
@@ -225,15 +367,19 @@ var CachingHost = class {
225
367
  needsFlush: false
226
368
  };
227
369
  } else {
228
- throw new Error(`what is not a file nor symlink nor directory? nothing we care about: ${canonicalPath}`);
370
+ throw new Error(
371
+ `what is not a file nor symlink nor directory? nothing we care about: ${canonicalPath}`
372
+ );
229
373
  }
230
374
  if (!parent && node.type === "dir") {
231
375
  this.#trees.set(canonicalPath, node);
232
376
  return node;
233
377
  } else if (parent) {
234
- parent.dir.set(path3.basename(canonicalPath), node);
378
+ parent.dir.set(path.basename(canonicalPath), node);
235
379
  } else {
236
- throw new Error(`root can only be a dir, got ${JSON.stringify(node)} for path: ${canonicalPath}`);
380
+ throw new Error(
381
+ `root can only be a dir, got ${JSON.stringify(node)} for path: ${canonicalPath}`
382
+ );
237
383
  }
238
384
  return node;
239
385
  }
@@ -242,13 +388,13 @@ var CachingHost = class {
242
388
  * You should check the `fullPath` of the result.
243
389
  */
244
390
  #getNearestAncestorNode(filePath) {
245
- const canonicalPath = path3.resolve(filePath);
246
- const { root } = path3.parse(canonicalPath);
391
+ const canonicalPath = path.resolve(filePath);
392
+ const { root } = path.parse(canonicalPath);
247
393
  const parts = [];
248
394
  let maybePath = canonicalPath;
249
395
  while (maybePath !== root) {
250
- parts.unshift(path3.basename(maybePath));
251
- maybePath = path3.dirname(maybePath);
396
+ parts.unshift(path.basename(maybePath));
397
+ maybePath = path.dirname(maybePath);
252
398
  }
253
399
  let curPath = root;
254
400
  let curNode = this.#trees.get(root) ?? this.#stubify(curPath, void 0);
@@ -257,7 +403,9 @@ var CachingHost = class {
257
403
  assertNoTombstone(curNode);
258
404
  assertNotType(curNode, "file");
259
405
  if (curNode.type === "symlink") {
260
- const linkedNode = this.#getNodeResolvingSymlinks(path3.resolve(path3.dirname(curPath), curNode.symlink));
406
+ const linkedNode = this.#getNodeResolvingSymlinks(
407
+ path.resolve(path.dirname(curPath), curNode.symlink)
408
+ );
261
409
  assertExists(linkedNode);
262
410
  assertNoTombstone(linkedNode);
263
411
  assertType(linkedNode, "dir");
@@ -265,16 +413,18 @@ var CachingHost = class {
265
413
  }
266
414
  assertType(curNode, "dir");
267
415
  assertNoTombstone(curNode);
268
- curNode = curNode.dir.get(part) ?? this.#stubify(path3.join(curNode.fullPath, part), curNode);
269
- curPath = path3.join(curPath, part);
416
+ curNode = curNode.dir.get(part) ?? this.#stubify(path.join(curNode.fullPath, part), curNode);
417
+ curPath = path.join(curPath, part);
270
418
  }
271
419
  } catch (e) {
272
420
  }
273
421
  return { pathWithSymlinks: curPath, node: curNode };
274
422
  }
275
423
  #getNode(filePath) {
276
- const canonicalPath = path3.resolve(filePath);
277
- const { pathWithSymlinks, node } = this.#getNearestAncestorNode(canonicalPath);
424
+ const canonicalPath = path.resolve(filePath);
425
+ const { pathWithSymlinks, node } = this.#getNearestAncestorNode(
426
+ canonicalPath
427
+ );
278
428
  if (pathWithSymlinks === canonicalPath) {
279
429
  return node;
280
430
  }
@@ -287,16 +437,18 @@ var CachingHost = class {
287
437
  return this.#getNodeResolvingSymlinks(node.symlink, follows--);
288
438
  }
289
439
  mkdir(filePath, opts = { recursive: false }) {
290
- const canonicalPath = path3.resolve(filePath);
291
- const { node, pathWithSymlinks } = this.#getNearestAncestorNode(canonicalPath);
440
+ const canonicalPath = path.resolve(filePath);
441
+ const { node, pathWithSymlinks } = this.#getNearestAncestorNode(
442
+ canonicalPath
443
+ );
292
444
  if (filePath === pathWithSymlinks) {
293
445
  assertType(node, "dir");
294
446
  assertHasParent(node);
295
447
  if (!node.tombstone) return;
296
- } else if (path3.dirname(filePath) === pathWithSymlinks) {
448
+ } else if (path.dirname(filePath) === pathWithSymlinks) {
297
449
  assertType(node, "dir");
298
450
  assertNoTombstone(node);
299
- node.dir.set(path3.basename(filePath), {
451
+ node.dir.set(path.basename(filePath), {
300
452
  type: "dir",
301
453
  fullPath: filePath,
302
454
  parent: node,
@@ -305,15 +457,17 @@ var CachingHost = class {
305
457
  });
306
458
  return;
307
459
  }
308
- if (!opts.recursive && path3.dirname(canonicalPath) !== pathWithSymlinks) {
460
+ if (!opts.recursive && path.dirname(canonicalPath) !== pathWithSymlinks) {
309
461
  throw new Error("no such file or directory");
310
462
  }
311
463
  const rootPath = pathWithSymlinks;
312
464
  let maybePath = canonicalPath;
313
465
  const toMake = [];
314
466
  while (maybePath !== rootPath) {
315
- toMake.unshift(path3.resolve(node.fullPath, path3.relative(rootPath, maybePath)));
316
- maybePath = path3.dirname(maybePath);
467
+ toMake.unshift(
468
+ path.resolve(node.fullPath, path.relative(rootPath, maybePath))
469
+ );
470
+ maybePath = path.dirname(maybePath);
317
471
  }
318
472
  for (const dirToMake of toMake) {
319
473
  this.mkdir(dirToMake);
@@ -366,7 +520,7 @@ var CachingHost = class {
366
520
  }
367
521
  writeFile(filePath, body, opts) {
368
522
  const fileContentsAsBuffer = typeof body === "string" ? Buffer.from(body, opts == null ? void 0 : opts.encoding) : Buffer.from(body);
369
- const canonicalPath = path3.resolve(filePath);
523
+ const canonicalPath = path.resolve(filePath);
370
524
  const existingNode = this.#getNodeResolvingSymlinks(canonicalPath);
371
525
  if (existingNode) {
372
526
  if (existingNode.type === "dir") {
@@ -379,11 +533,13 @@ var CachingHost = class {
379
533
  });
380
534
  return;
381
535
  }
382
- const maybeDirNode = this.#getNodeResolvingSymlinks(path3.dirname(canonicalPath));
536
+ const maybeDirNode = this.#getNodeResolvingSymlinks(
537
+ path.dirname(canonicalPath)
538
+ );
383
539
  assertExists(maybeDirNode);
384
540
  assertType(maybeDirNode, "dir");
385
541
  assertNoTombstone(maybeDirNode);
386
- maybeDirNode.dir.set(path3.basename(canonicalPath), {
542
+ maybeDirNode.dir.set(path.basename(canonicalPath), {
387
543
  type: "file",
388
544
  fullPath: canonicalPath,
389
545
  parent: maybeDirNode,
@@ -392,7 +548,7 @@ var CachingHost = class {
392
548
  });
393
549
  }
394
550
  deleteFile(filePath) {
395
- const canonicalPath = path3.resolve(filePath);
551
+ const canonicalPath = path.resolve(filePath);
396
552
  const node = this.#getNode(canonicalPath);
397
553
  if (!node || node.type === "file" && node.tombstone === true) return;
398
554
  assertNotType(node, "dir");
@@ -427,265 +583,165 @@ var CachingHost = class {
427
583
  async #flushSymlinkNode(node) {
428
584
  if (!node.needsFlush) return;
429
585
  try {
430
- const linkValue = await this.fs.promises.readlink(node.fullPath);
431
- if (linkValue === node.symlink) {
432
- return;
433
- }
434
- } catch (e) {
435
- }
436
- return this.fs.promises.symlink(node.symlink, node.fullPath);
437
- }
438
- async #flushDirNode(node) {
439
- if (!node.tombstone && node.needsFlush) {
440
- try {
441
- await this.fs.promises.access(node.fullPath);
442
- } catch (e) {
443
- await this.fs.promises.mkdir(node.fullPath);
444
- }
445
- }
446
- const promises2 = [];
447
- for (const child of node.dir.values()) {
448
- if (node.tombstone && !child.tombstone) {
449
- throw new Error("Unexpected failure during sanity check. A non-deleted child is on a deleted dir");
450
- }
451
- if (child.type === "dir") {
452
- promises2.push(this.#flushDirNode(child));
453
- } else if (child.type === "file") {
454
- promises2.push(this.#flushFileNode(child));
455
- } else if (child.type === "symlink") {
456
- promises2.push(this.#flushSymlinkNode(child));
457
- } else {
458
- throw new Error("should never happen");
459
- }
460
- }
461
- await Promise.all(promises2);
462
- if (node.tombstone) {
463
- return this.fs.promises.rmdir(node.fullPath);
464
- }
465
- return;
466
- }
467
- flush() {
468
- const promises2 = [];
469
- for (const rootNode of this.#trees.values()) {
470
- promises2.push(this.#flushDirNode(rootNode));
471
- }
472
- return Promise.all(promises2);
473
- }
474
- };
475
-
476
- // src/matchesAnyGlob.ts
477
- import micromatch from "micromatch";
478
-
479
- // src/nanosecondsToSanity.ts
480
- function nanosecondsToSanity(n, precision = 9) {
481
- return n / BigInt(1e9) + "." + ("" + n % BigInt(1e9)).padStart(9, "0").substring(0, precision) + "s";
482
- }
483
-
484
- // src/Table.ts
485
- var Table = class {
486
- #rows = [];
487
- #config;
488
- #columnWidths = [];
489
- #footer = [];
490
- #footerRowConfig;
491
- #totalWidth = 0;
492
- constructor(config) {
493
- this.#config = {
494
- padding: 2,
495
- ...config
496
- };
497
- this.#columnWidths.fill(0, 0, config.columns.length);
498
- if (config.showFooter) {
499
- this.#footerRowConfig = [];
500
- for (const columnConfig of config.columns) {
501
- if (columnConfig.footer === void 0) {
502
- throw new Error("Must specify footer fields when showFooter is true");
503
- } else if (typeof columnConfig.footer === "string") {
504
- this.#footerRowConfig.push({
505
- type: "string",
506
- alignment: "left",
507
- aggregate: "static",
508
- value: columnConfig.footer
509
- });
510
- } else if ("value" in columnConfig.footer) {
511
- this.#footerRowConfig.push({
512
- type: "string",
513
- alignment: "left",
514
- ...columnConfig.footer
515
- });
516
- } else if ("aggregate" in columnConfig.footer) {
517
- if (columnConfig.type !== "bigint") throw new Error("expecting bigint for aggregate");
518
- this.#footerRowConfig.push({
519
- type: columnConfig.type,
520
- renderAs: columnConfig.renderAs,
521
- precision: columnConfig.precision,
522
- alignment: "right",
523
- ...columnConfig.footer
524
- });
525
- }
526
- }
527
- }
528
- }
529
- addRow(...data) {
530
- this.#rows.push(data);
531
- }
532
- #sumColumn(c) {
533
- let total = BigInt(0);
534
- for (const row of this.#rows) {
535
- total += row[c];
536
- }
537
- return total;
538
- }
539
- #updateFooterRow() {
540
- const footerRowConfig = this.#footerRowConfig;
541
- if (footerRowConfig) {
542
- for (let c = 0; c < footerRowConfig.length; c++) {
543
- const footerColConfig = footerRowConfig[c];
544
- switch (footerColConfig.aggregate) {
545
- case "sum":
546
- this.#footer[c] = this.#sumColumn(c);
547
- break;
548
- case "average":
549
- this.#footer[c] = this.#sumColumn(c) / BigInt(this.#rows.length);
550
- break;
551
- case "static":
552
- this.#footer[c] = footerColConfig.value;
553
- break;
554
- }
555
- }
556
- }
557
- }
558
- #calculateColumnWidths() {
559
- var _a;
560
- this.#columnWidths.fill(0, 0, this.#config.columns.length);
561
- for (let c = 0; c < this.#config.columns.length; c++) {
562
- const colConfig = this.#config.columns[c];
563
- this.#columnWidths[c] = Math.max(
564
- (this.#config.columns[c].header ?? "").length,
565
- ...this.#rows.map((a) => this.#getCellValueAsString(a[c], colConfig).length),
566
- this.#footer && this.#footerRowConfig ? this.#getCellValueAsString(((_a = this.#footer) == null ? void 0 : _a[c]) ?? "", this.#footerRowConfig[c]).length : 0
567
- );
568
- }
569
- this.#totalWidth = 0;
570
- for (const colWidth of this.#columnWidths) {
571
- this.#totalWidth += colWidth;
572
- }
573
- this.#totalWidth += (this.#columnWidths.length - 1) * this.#config.padding;
574
- }
575
- #printSeparator(fillString) {
576
- const paddingString = "".padStart(this.#config.padding, " ");
577
- let hr2 = "";
578
- for (let c = 0; c < this.#columnWidths.length; c++) {
579
- hr2 += "".padStart(this.#columnWidths[c], fillString) + paddingString;
580
- }
581
- hr2 = hr2.trimRight();
582
- console.log(hr2);
583
- }
584
- #printHeaderRow() {
585
- if (this.#config.showHeader) {
586
- const colConfigs = this.#config.columns;
587
- const paddingString = "".padStart(this.#config.padding, " ");
588
- let hr = "";
589
- for (let c = 0; c < colConfigs.length; c++) {
590
- const heading = colConfigs[c].header ?? "";
591
- hr += heading.padEnd(this.#columnWidths[c], " ") + paddingString;
592
- }
593
- hr = hr.trimRight();
594
- console.log(hr);
595
- this.#printSeparator("-");
596
- }
597
- }
598
- #printFooterRow() {
599
- const footerRow = this.#footer;
600
- if (footerRow) {
601
- this.#printSeparator("=");
602
- const paddingString = "".padStart(this.#config.padding, " ");
603
- let hr = "";
604
- for (let c = 0; c < footerRow.length; c++) {
605
- hr += this.#getCellValueAligned(footerRow[c], this.#footerRowConfig[c], c) + paddingString;
606
- }
607
- hr = hr.trimRight();
608
- console.log(hr);
609
- }
610
- }
611
- print() {
612
- if (this.#config.sortColumn !== void 0) {
613
- }
614
- this.#updateFooterRow();
615
- this.#calculateColumnWidths();
616
- console.log();
617
- console.log(`${this.#config.title}`);
618
- console.log("".padStart(this.#totalWidth, "="));
619
- const paddingString = "".padStart(this.#config.padding, " ");
620
- if (this.#config.showHeader) {
621
- this.#printHeaderRow();
622
- }
623
- for (let r = 0; r < this.#rows.length; r++) {
624
- let rowText = "";
625
- for (let c = 0; c < this.#config.columns.length; c++) {
626
- rowText += this.getEntryAsStringAligned(c, r) + paddingString;
586
+ const linkValue = await this.fs.promises.readlink(node.fullPath);
587
+ if (linkValue === node.symlink) {
588
+ return;
627
589
  }
628
- rowText.trim();
629
- console.log(rowText);
590
+ } catch (e) {
630
591
  }
631
- if (this.#config.showFooter) this.#printFooterRow();
632
- console.log();
592
+ return this.fs.promises.symlink(node.symlink, node.fullPath);
633
593
  }
634
- #getCellValueAsString(value, config) {
635
- if (config.type === "bigint" && config.renderAs === "nanoseconds") {
636
- return nanosecondsToSanity(value, config.precision ?? 9);
637
- } else {
638
- return "" + value;
594
+ async #flushDirNode(node) {
595
+ if (!node.tombstone && node.needsFlush) {
596
+ try {
597
+ await this.fs.promises.access(node.fullPath);
598
+ } catch (e) {
599
+ await this.fs.promises.mkdir(node.fullPath);
600
+ }
639
601
  }
640
- }
641
- #getCellValueAligned(value, config, column) {
642
- let result;
643
- if (config.type === "bigint" && config.renderAs === "nanoseconds") {
644
- result = nanosecondsToSanity(value, config.precision ?? 9);
645
- } else {
646
- result = "" + value;
602
+ const promises2 = [];
603
+ for (const child of node.dir.values()) {
604
+ if (node.tombstone && !child.tombstone) {
605
+ throw new Error(
606
+ "Unexpected failure during sanity check. A non-deleted child is on a deleted dir"
607
+ );
608
+ }
609
+ if (child.type === "dir") {
610
+ promises2.push(this.#flushDirNode(child));
611
+ } else if (child.type === "file") {
612
+ promises2.push(this.#flushFileNode(child));
613
+ } else if (child.type === "symlink") {
614
+ promises2.push(this.#flushSymlinkNode(child));
615
+ } else {
616
+ throw new Error("should never happen");
617
+ }
647
618
  }
648
- if (config.alignment === "left") {
649
- return result.padEnd(this.#columnWidths[column]);
650
- } else {
651
- return result.padStart(this.#columnWidths[column]);
619
+ await Promise.all(promises2);
620
+ if (node.tombstone) {
621
+ return this.fs.promises.rmdir(node.fullPath);
652
622
  }
623
+ return;
653
624
  }
654
- getEntryAsString(colNum, rowNum) {
655
- const config = this.#config.columns[colNum];
656
- if (config.type === "bigint" && config.renderAs === "nanoseconds") {
657
- return nanosecondsToSanity(this.#rows[rowNum][colNum], config.precision ?? 9);
658
- } else {
659
- return "" + this.#rows[rowNum][colNum];
625
+ flush() {
626
+ const promises2 = [];
627
+ for (const rootNode of this.#trees.values()) {
628
+ promises2.push(this.#flushDirNode(rootNode));
660
629
  }
630
+ return Promise.all(promises2);
661
631
  }
662
- getEntryAsStringAligned(colNum, rowNum) {
663
- const config = this.#config.columns[colNum];
664
- let result;
665
- if (config.type === "bigint" && config.renderAs === "nanoseconds") {
666
- result = nanosecondsToSanity(this.#rows[rowNum][colNum], config.precision ?? 9);
667
- } else {
668
- result = "" + this.#rows[rowNum][colNum];
632
+ };
633
+
634
+ // src/findWorkspaceDir.ts
635
+ import { findUp } from "find-up";
636
+ import * as fs from "fs";
637
+ import * as path2 from "path";
638
+ async function findPnpmWorkspaceDir(cwd) {
639
+ const workspaceManifestLocation = await findUp("pnpm-workspace.yaml", {
640
+ cwd: await fs.promises.realpath(cwd)
641
+ });
642
+ return workspaceManifestLocation && path2.dirname(workspaceManifestLocation);
643
+ }
644
+ async function findWorkspaceDir(host, dir) {
645
+ const maybePnpmWorkspaceDir = await findPnpmWorkspaceDir(dir);
646
+ if (maybePnpmWorkspaceDir != null) {
647
+ return maybePnpmWorkspaceDir;
648
+ }
649
+ const packagePath = path2.join(dir, "package.json");
650
+ if (host.exists(packagePath)) {
651
+ const packageJson = host.readJson(packagePath);
652
+ if (packageJson.workspaces !== void 0) {
653
+ return dir;
669
654
  }
670
- if (config.alignment === "left") {
671
- return result.padEnd(this.#columnWidths[colNum]);
672
- } else {
673
- return result.padStart(this.#columnWidths[colNum]);
655
+ }
656
+ const nextDir = path2.normalize(path2.join(dir, ".."));
657
+ if (nextDir === dir) {
658
+ return void 0;
659
+ }
660
+ return findWorkspaceDir(host, nextDir);
661
+ }
662
+
663
+ // src/getPackageNameToDir.ts
664
+ import { join as pathJoin } from "path";
665
+
666
+ // src/getWorkspacePackageDirs.ts
667
+ import { findPackages } from "find-packages";
668
+ import { existsSync } from "fs";
669
+ import * as glob from "glob";
670
+ import * as fs2 from "node:fs";
671
+ import * as path3 from "node:path";
672
+ import readYamlFile from "read-yaml-file";
673
+ async function findPNPMWorkspacePackages(workspaceRoot) {
674
+ workspaceRoot = fs2.realpathSync(workspaceRoot);
675
+ const workspaceManifest = await readYamlFile.default(
676
+ path3.join(workspaceRoot, "pnpm-workspace.yaml")
677
+ );
678
+ return findPackages(workspaceRoot, {
679
+ ignore: ["**/node_modules/**", "**/bower_components/**"],
680
+ includeRoot: true,
681
+ patterns: workspaceManifest.packages
682
+ });
683
+ }
684
+ async function getWorkspacePackageDirs(host, workspaceDir, resolvePaths = false) {
685
+ const packageJson = host.readJson(
686
+ path3.join(workspaceDir, "package.json")
687
+ );
688
+ const isPnpmWorkspace = host.exists(
689
+ path3.join(workspaceDir, "pnpm-workspace.yaml")
690
+ );
691
+ if (isPnpmWorkspace) {
692
+ const workspacePackages = await findPNPMWorkspacePackages(workspaceDir);
693
+ if (workspacePackages.length === 0) {
694
+ throw new Error("Invalid workspaceDir: " + workspaceDir);
674
695
  }
696
+ return workspacePackages.map((project) => project.dir).filter((d) => d !== workspaceDir);
675
697
  }
676
- getColumnWidth(colNum, config) {
677
- let maxWidth = Math.max(
678
- (config.header ?? "").length,
679
- this.#footer && this.#footerRowConfig ? this.#getCellValueAsString(this.#footer[colNum], this.#footerRowConfig[colNum]).length : 0
698
+ if (!packageJson.workspaces) {
699
+ throw new Error(
700
+ "Unsupported! Monorepo is not backed by either pnpm nor yarn workspaces."
680
701
  );
681
- for (let r = 0; r < this.#rows.length; r++) {
682
- maxWidth = Math.max(maxWidth, this.getEntryAsString(colNum, r).length);
702
+ }
703
+ const ret = [];
704
+ const packageGlobs = Array.isArray(packageJson.workspaces) ? packageJson.workspaces : packageJson.workspaces.packages || [];
705
+ for (const pattern of packageGlobs) {
706
+ for (const packagePath of glob.sync(pattern, { cwd: workspaceDir })) {
707
+ const packageJsonPath = path3.join(
708
+ workspaceDir,
709
+ packagePath,
710
+ "package.json"
711
+ );
712
+ if (existsSync(packageJsonPath)) {
713
+ if (resolvePaths === true) {
714
+ ret.push(path3.resolve(path3.join(workspaceDir, packagePath)));
715
+ } else {
716
+ ret.push(packagePath);
717
+ }
718
+ }
683
719
  }
684
- return maxWidth;
685
720
  }
686
- };
721
+ return ret;
722
+ }
723
+
724
+ // src/getPackageNameToDir.ts
725
+ async function getPackageNameToDir(host, workspaceDir, resolvePaths = false) {
726
+ const ret = /* @__PURE__ */ new Map();
727
+ const workspacePackages = await getWorkspacePackageDirs(
728
+ host,
729
+ workspaceDir,
730
+ resolvePaths
731
+ );
732
+ for (const packageDir of workspacePackages) {
733
+ const packagePath = pathJoin(packageDir, "package.json");
734
+ const { name } = host.readJson(packagePath);
735
+ if (name === void 0) {
736
+ throw new Error(`Package needs a name: ${packagePath}`);
737
+ }
738
+ ret.set(name, packageDir);
739
+ }
740
+ return ret;
741
+ }
687
742
 
688
743
  // src/matchesAnyGlob.ts
744
+ import micromatch from "micromatch";
689
745
  var cache = /* @__PURE__ */ new Map();
690
746
  var singleMatcherCache = /* @__PURE__ */ new Map();
691
747
  var compiledGlobCache = /* @__PURE__ */ new Map();
@@ -755,63 +811,53 @@ matchesAnyGlob.printStats = () => {
755
811
  table.print();
756
812
  };
757
813
 
758
- // src/AggregateTiming.ts
759
- var AggregateTiming = class {
760
- constructor(title) {
761
- this.title = title;
814
+ // src/mutateJson.ts
815
+ function mutateJson(path4, host, mutator) {
816
+ let file = host.readJson(path4);
817
+ file = mutator(file);
818
+ host.writeJson(path4, file);
819
+ }
820
+
821
+ // src/SimpleHost.ts
822
+ import * as realFs2 from "fs";
823
+ var SimpleHost = class {
824
+ constructor(fs3 = realFs2) {
825
+ this.fs = fs3;
762
826
  }
763
- #data = /* @__PURE__ */ new Map();
764
- #last;
765
- start(name) {
766
- const time = process.hrtime.bigint();
767
- if (this.#last) {
768
- this.#last.total += time;
769
- }
770
- let data = this.#data.get(name);
771
- if (data === void 0) {
772
- data = { count: 1, total: -time };
773
- this.#data.set(name, data);
827
+ mkdir(directoryPath, opts) {
828
+ this.fs.mkdirSync(directoryPath, { recursive: (opts == null ? void 0 : opts.recursive) ?? false });
829
+ }
830
+ rmdir(directoryPath) {
831
+ this.fs.rmdirSync(directoryPath);
832
+ }
833
+ exists(path4) {
834
+ return this.fs.existsSync(path4);
835
+ }
836
+ writeFile(path4, body, opts) {
837
+ if (opts) {
838
+ this.fs.writeFileSync(path4, body, { encoding: opts.encoding });
774
839
  } else {
775
- data.total -= time;
776
- data.count++;
840
+ this.fs.writeFileSync(path4, body);
777
841
  }
778
- this.#last = data;
779
842
  }
780
- stop() {
781
- const time = process.hrtime.bigint();
782
- if (this.#last) {
783
- this.#last.total += time;
784
- this.#last = void 0;
843
+ readFile(path4, opts) {
844
+ if (opts == null ? void 0 : opts.asJson) {
845
+ return JSON.parse(this.fs.readFileSync(path4, "utf-8"));
785
846
  }
847
+ return this.fs.readFileSync(path4, opts == null ? void 0 : opts.encoding);
786
848
  }
787
- printResults() {
788
- const table = new Table({
789
- sortColumn: -1,
790
- showFooter: true,
791
- showHeader: true,
792
- title: this.title,
793
- columns: [
794
- {
795
- header: "Duration",
796
- type: "bigint",
797
- renderAs: "nanoseconds",
798
- footer: { aggregate: "sum" }
799
- },
800
- { header: "Task", type: "string", alignment: "left", footer: "TOTAL" },
801
- { header: "Count", type: "bigint", footer: { aggregate: "sum" } },
802
- { header: "Avg", type: "bigint", footer: { aggregate: "average" } }
803
- ]
804
- });
805
- for (const [name, value] of this.#data) {
806
- table.addRow(
807
- value.total,
808
- name,
809
- BigInt(value.count),
810
- // fixme this can be a number later
811
- value.total / BigInt(value.count)
812
- );
813
- }
814
- table.print();
849
+ deleteFile(path4) {
850
+ this.fs.unlinkSync(path4);
851
+ }
852
+ readJson(filename) {
853
+ const contents = this.fs.readFileSync(filename, "utf-8");
854
+ return JSON.parse(contents);
855
+ }
856
+ writeJson(path4, o) {
857
+ return this.fs.writeFileSync(path4, JSON.stringify(o, void 0, 2) + "\n");
858
+ }
859
+ flush() {
860
+ return Promise.resolve();
815
861
  }
816
862
  };
817
863
 
@@ -871,13 +917,13 @@ export {
871
917
  nanosecondsToSanity
872
918
  };
873
919
  /*!
874
- * Copyright 2019 Palantir Technologies, Inc.
920
+ * Copyright 2022 Palantir Technologies, Inc.
875
921
  *
876
922
  * Licensed under the MIT license. See LICENSE file in the project root for details.
877
923
  *
878
924
  */
879
925
  /*!
880
- * Copyright 2022 Palantir Technologies, Inc.
926
+ * Copyright 2019 Palantir Technologies, Inc.
881
927
  *
882
928
  * Licensed under the MIT license. See LICENSE file in the project root for details.
883
929
  *