-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathversion-info.ts
More file actions
109 lines (93 loc) · 3.46 KB
/
version-info.ts
File metadata and controls
109 lines (93 loc) · 3.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
import packageJson from "@/../package.json" with { type: "json" };
import { existsSync, readdirSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";
import type { EnsApiVersionInfo } from "@ensnode/ensnode-sdk";
/**
* Get ENS API version
*/
function getEnsApiVersion(): string {
return packageJson.version;
}
/**
* Get NPM package version.
*
* Note:
* Since we use PNPM's `catalog:` references, reading directly from
* the `package.json` file would give us `catalog:` values, and not resolved
* version values. We need the latter, so we implement our own version
* resolution method.
*/
function getPackageVersion(packageName: string): string {
try {
// Start from current file's directory
const currentFile = fileURLToPath(import.meta.url);
let searchDir = dirname(currentFile);
while (true) {
const workspaceFile = join(searchDir, "pnpm-workspace.yaml");
const isWorkspaceRoot = existsSync(workspaceFile);
// Check for node_modules in current directory
const nodeModulesPath = join(searchDir, "node_modules", packageName, "package.json");
if (existsSync(nodeModulesPath)) {
const packageJson = JSON.parse(readFileSync(nodeModulesPath, "utf8"));
return packageJson.version;
}
// Check PNPM's .pnpm virtual store
const pnpmDir = join(searchDir, "node_modules", ".pnpm");
if (existsSync(pnpmDir)) {
const version = getPackageVersionFromPnpmStore(pnpmDir, packageName);
if (version) return version;
}
// If we're at workspace root and still haven't found it, stop searching
if (isWorkspaceRoot) {
throw new Error(
`Package ${packageName} not found in any node_modules up to workspace root`,
);
}
// Move up one directory
const parentDir = dirname(searchDir);
// Prevent infinite loop if we reach filesystem root
if (parentDir === searchDir) {
throw new Error(`Package ${packageName} not found and no workspace root detected`);
}
searchDir = parentDir;
}
} catch {
return "unknown";
}
}
/**
* Get package version from PNPM virtual store.
*
* PNPM stores packages in its virtual store that
* can be located at, for example, `./node_modules/.pnpm` path.
*
* This function is used in a fallback method by {@link getPackageVersion} to
* get package version by package name in case it was not found
* directly in `./node_modules` directory.
*/
function getPackageVersionFromPnpmStore(pnpmDir: string, packageName: string): string | null {
try {
const entries = readdirSync(pnpmDir);
// Convert package name to PNPM's format: @scope/name -> @scope+name
const normalizedName = packageName.replace("/", "+");
// Find entries that match the package name
// They will be in format: packagename@version or @scope+packagename@version
for (const entry of entries) {
if (entry.startsWith(`${normalizedName}@`)) {
const pkgPath = join(pnpmDir, entry, "node_modules", packageName, "package.json");
if (existsSync(pkgPath)) {
const packageJson = JSON.parse(readFileSync(pkgPath, "utf8"));
return packageJson.version;
}
}
}
} catch (_error) {
// Ignore errors in this helper
}
return null;
}
export const ensApiVersionInfo = {
ensApi: getEnsApiVersion(),
ensNormalize: getPackageVersion("@adraffy/ens-normalize"),
} as const satisfies EnsApiVersionInfo;