Skip to content

Commit 18c9a22

Browse files
committed
chore: script to generate dependencies
1 parent 9cacc86 commit 18c9a22

1 file changed

Lines changed: 268 additions & 0 deletions

File tree

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
#!/usr/bin/env node
2+
3+
const { execSync } = require("child_process");
4+
const fs = require("fs");
5+
const path = require("path");
6+
7+
/**
8+
* Generate dependencies.json and dependencies.txt from package.json using pnpm to get actual installed versions
9+
*
10+
* Usage: node generate-dependencies.js [path-to-package.json]
11+
*/
12+
13+
function getPackageJsonPath() {
14+
const arg = process.argv[2];
15+
if (arg) {
16+
return path.resolve(arg);
17+
}
18+
// Default to package.json in current directory
19+
return path.resolve(process.cwd(), "package.json");
20+
}
21+
22+
function readPackageJson(packageJsonPath) {
23+
if (!fs.existsSync(packageJsonPath)) {
24+
console.error(`Error: package.json not found at ${packageJsonPath}`);
25+
process.exit(1);
26+
}
27+
28+
try {
29+
const content = fs.readFileSync(packageJsonPath, "utf8");
30+
return JSON.parse(content);
31+
} catch (error) {
32+
console.error(`Error reading or parsing package.json: ${error.message}`);
33+
process.exit(1);
34+
}
35+
}
36+
37+
function getInstalledVersion(packageName, packageDir) {
38+
try {
39+
// Use pnpm list to get the actual installed version
40+
// --depth 0 to only show direct dependencies
41+
// --json for parseable output
42+
const output = execSync(`pnpm list "${packageName}" --depth 0 --json`, {
43+
cwd: packageDir,
44+
encoding: "utf8",
45+
stdio: ["pipe", "pipe", "pipe"]
46+
});
47+
48+
const result = JSON.parse(output);
49+
50+
// pnpm list returns an array of project results
51+
if (Array.isArray(result) && result.length > 0) {
52+
const dependencies = result[0].dependencies || {};
53+
if (dependencies[packageName]) {
54+
const version = dependencies[packageName].version;
55+
// Remove any leading 'v' if present
56+
return version.replace(/^v/, "");
57+
}
58+
}
59+
60+
return null;
61+
} catch (error) {
62+
// If pnpm list fails, try reading from node_modules
63+
try {
64+
const nodeModulesPath = path.join(packageDir, "node_modules", packageName, "package.json");
65+
if (fs.existsSync(nodeModulesPath)) {
66+
const pkgContent = JSON.parse(fs.readFileSync(nodeModulesPath, "utf8"));
67+
return pkgContent.version;
68+
}
69+
} catch (innerError) {
70+
// Ignore
71+
}
72+
73+
console.warn(`Warning: Could not determine installed version for ${packageName}`);
74+
return null;
75+
}
76+
}
77+
78+
function getPackageMetadata(packageName, version) {
79+
try {
80+
// Use pnpm view to get package metadata from npm registry
81+
const output = execSync(`pnpm view "${packageName}@${version}" --json`, {
82+
encoding: "utf8",
83+
stdio: ["pipe", "pipe", "pipe"]
84+
});
85+
86+
const metadata = JSON.parse(output);
87+
88+
return {
89+
name: metadata.name || packageName,
90+
version: metadata.version || version,
91+
license: metadata.license || "UNKNOWN",
92+
private: metadata.private || false,
93+
description: metadata.description || "",
94+
repository: formatRepository(metadata.repository),
95+
author: metadata.author || "",
96+
homepage: metadata.homepage || ""
97+
};
98+
} catch (error) {
99+
console.warn(`Warning: Could not fetch metadata for ${packageName}@${version}`);
100+
return {
101+
name: packageName,
102+
version: version,
103+
license: "UNKNOWN",
104+
private: false,
105+
description: "",
106+
repository: "",
107+
author: "",
108+
homepage: ""
109+
};
110+
}
111+
}
112+
113+
function formatRepository(repo) {
114+
if (!repo) return "undefined";
115+
if (typeof repo === "string") return repo;
116+
if (repo.url) return repo.url;
117+
return "undefined";
118+
}
119+
120+
function getLicenseText(packageName, version, packageDir) {
121+
// Try to find LICENSE file in node_modules
122+
const possiblePaths = [
123+
path.join(packageDir, "node_modules", packageName, "LICENSE"),
124+
path.join(packageDir, "node_modules", packageName, "LICENSE.md"),
125+
path.join(packageDir, "node_modules", packageName, "LICENSE.txt"),
126+
path.join(packageDir, "node_modules", packageName, "license"),
127+
path.join(packageDir, "node_modules", packageName, "license.md"),
128+
path.join(packageDir, "node_modules", packageName, "license.txt")
129+
];
130+
131+
for (const licensePath of possiblePaths) {
132+
if (fs.existsSync(licensePath)) {
133+
try {
134+
return fs.readFileSync(licensePath, "utf8").trim();
135+
} catch (error) {
136+
// Continue to next path
137+
}
138+
}
139+
}
140+
141+
// If not found in node_modules, try pnpm's virtual store
142+
const pnpmStorePath = path.join(
143+
packageDir,
144+
"..",
145+
"..",
146+
"node_modules",
147+
".pnpm",
148+
`${packageName}@${version}`,
149+
"node_modules",
150+
packageName
151+
);
152+
153+
for (const filename of ["LICENSE", "LICENSE.md", "LICENSE.txt", "license", "license.md", "license.txt"]) {
154+
const licensePath = path.join(pnpmStorePath, filename);
155+
if (fs.existsSync(licensePath)) {
156+
try {
157+
return fs.readFileSync(licensePath, "utf8").trim();
158+
} catch (error) {
159+
// Continue
160+
}
161+
}
162+
}
163+
164+
return null;
165+
}
166+
167+
function generateDependenciesJson(packageJsonPath) {
168+
const packageJson = readPackageJson(packageJsonPath);
169+
const packageDir = path.dirname(packageJsonPath);
170+
171+
const dependencies = packageJson.dependencies || {};
172+
const dependencyNames = Object.keys(dependencies);
173+
174+
if (dependencyNames.length === 0) {
175+
console.log("No dependencies found in package.json");
176+
return { jsonData: [], detailedData: [] };
177+
}
178+
179+
console.log(`Found ${dependencyNames.length} dependencies, resolving versions...`);
180+
181+
const jsonData = [];
182+
const detailedData = [];
183+
184+
for (const depName of dependencyNames) {
185+
const version = getInstalledVersion(depName, packageDir);
186+
187+
if (version) {
188+
// Add to JSON format
189+
jsonData.push({
190+
[depName]: {
191+
version: version,
192+
url: null
193+
}
194+
});
195+
196+
// Fetch metadata for TXT format
197+
const metadata = getPackageMetadata(depName, version);
198+
const licenseText = getLicenseText(depName, version, packageDir);
199+
200+
detailedData.push({
201+
...metadata,
202+
licenseText
203+
});
204+
205+
console.log(` ✓ ${depName}@${version}`);
206+
} else {
207+
console.warn(` ✗ ${depName} - version not found`);
208+
}
209+
}
210+
211+
return { jsonData, detailedData };
212+
}
213+
214+
function generateDependenciesTxt(detailedData) {
215+
const sections = [];
216+
217+
for (const dep of detailedData) {
218+
const lines = [];
219+
220+
lines.push(`Name: ${dep.name}`);
221+
lines.push(`Version: ${dep.version}`);
222+
lines.push(`License: ${dep.license}`);
223+
lines.push(`Private: ${dep.private}`);
224+
lines.push(`Description: ${dep.description}`);
225+
lines.push(`Repository: ${dep.repository}`);
226+
227+
if (dep.author) {
228+
lines.push(`Author: ${dep.author}`);
229+
}
230+
231+
if (dep.homepage) {
232+
lines.push(`Homepage: ${dep.homepage}`);
233+
}
234+
235+
if (dep.licenseText) {
236+
lines.push("License Copyright:");
237+
lines.push("===");
238+
lines.push("");
239+
lines.push(dep.licenseText);
240+
}
241+
242+
sections.push(lines.join("\n"));
243+
}
244+
245+
return sections.join("\n\n---\n\n");
246+
}
247+
248+
function main() {
249+
const packageJsonPath = getPackageJsonPath();
250+
const jsonOutputPath = path.join(process.cwd(), "dependencies.json");
251+
const txtOutputPath = path.join(process.cwd(), "dependencies.txt");
252+
253+
console.log(`Reading package.json from: ${packageJsonPath}`);
254+
255+
const { jsonData, detailedData } = generateDependenciesJson(packageJsonPath);
256+
257+
// Write dependencies.json
258+
fs.writeFileSync(jsonOutputPath, JSON.stringify(jsonData));
259+
console.log(`\n✓ Generated dependencies.json at: ${jsonOutputPath}`);
260+
console.log(` Total dependencies: ${jsonData.length}`);
261+
262+
// Write dependencies.txt
263+
const txtContent = generateDependenciesTxt(detailedData);
264+
fs.writeFileSync(txtOutputPath, txtContent + "\n");
265+
console.log(`✓ Generated dependencies.txt at: ${txtOutputPath}`);
266+
}
267+
268+
main();

0 commit comments

Comments
 (0)