lllink 1.14.4 → 1.15.0
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.
- package/dist/index.mjs +124 -59
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
import { cp, mkdir, readFile, readdir, rename, rm, stat, symlink } from "node:fs/promises";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join, relative, resolve } from "node:path";
|
|
5
|
-
typeof Bun
|
|
5
|
+
if (typeof Bun === "undefined") {
|
|
6
|
+
console.error(`Must run in Bun due to using ~ resolutions`);
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
6
9
|
const IGNORE_DIR = "node_modules";
|
|
7
10
|
async function findLocalPackages(rootDir) {
|
|
8
11
|
const results = {};
|
|
@@ -25,10 +28,13 @@ async function findLocalPackages(rootDir) {
|
|
|
25
28
|
if (entryStat.isDirectory()) {
|
|
26
29
|
const pkgJsonPath = join(fullPath, "package.json");
|
|
27
30
|
try {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
pkgData
|
|
31
|
+
const pkgJsonStat = await stat(pkgJsonPath);
|
|
32
|
+
if (pkgJsonStat.isFile()) {
|
|
33
|
+
const raw = await readFile(pkgJsonPath, "utf-8");
|
|
34
|
+
const pkgData = JSON.parse(raw);
|
|
35
|
+
if (pkgData.name && !pkgData.name.startsWith("@types/")) {
|
|
36
|
+
results[pkgData.name] = fullPath;
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
} catch {
|
|
34
40
|
await recurse(fullPath);
|
|
@@ -36,25 +42,33 @@ async function findLocalPackages(rootDir) {
|
|
|
36
42
|
}
|
|
37
43
|
}));
|
|
38
44
|
}
|
|
39
|
-
|
|
45
|
+
await recurse(rootDir);
|
|
46
|
+
return results;
|
|
40
47
|
}
|
|
41
48
|
async function linkPackages(externalPackages) {
|
|
42
49
|
const backupDir = join(process.cwd(), "node_modules", ".cache", "lllink", "moved");
|
|
43
50
|
await mkdir(backupDir, {
|
|
44
|
-
recursive:
|
|
51
|
+
recursive: true
|
|
45
52
|
});
|
|
46
53
|
for (const pkgName of Object.keys(externalPackages)) {
|
|
47
54
|
const localPath = join(process.cwd(), "node_modules", ...pkgName.split("/"));
|
|
48
55
|
try {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
const existingStat = await stat(localPath);
|
|
57
|
+
if (existingStat) {
|
|
58
|
+
await cp(localPath, join(backupDir, pkgName.replace("/", "__")), {
|
|
59
|
+
recursive: true,
|
|
60
|
+
dereference: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
53
63
|
const externalPath = externalPackages[pkgName];
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
64
|
+
if (externalPath) {
|
|
65
|
+
console.info(`symlink ${relative(process.cwd(), localPath)} to ${externalPath.replace(homedir(), "~")}`);
|
|
66
|
+
await rm(localPath, {
|
|
67
|
+
recursive: true,
|
|
68
|
+
force: true
|
|
69
|
+
}).catch(() => {});
|
|
70
|
+
await symlink(externalPath, localPath);
|
|
71
|
+
}
|
|
58
72
|
} catch {}
|
|
59
73
|
}
|
|
60
74
|
}
|
|
@@ -68,36 +82,50 @@ async function undoLinks() {
|
|
|
68
82
|
return;
|
|
69
83
|
}
|
|
70
84
|
for (const item of movedItems) {
|
|
71
|
-
const originalName = item.replace("__", "/")
|
|
72
|
-
|
|
85
|
+
const originalName = item.replace("__", "/");
|
|
86
|
+
const nmPath = join(process.cwd(), "node_modules", ...originalName.split("/"));
|
|
73
87
|
await rm(nmPath, {
|
|
74
|
-
recursive:
|
|
75
|
-
force:
|
|
76
|
-
}).catch(() => {})
|
|
88
|
+
recursive: true,
|
|
89
|
+
force: true
|
|
90
|
+
}).catch(() => {});
|
|
91
|
+
await rename(join(backupDir, item), nmPath).catch(() => {});
|
|
92
|
+
console.info(`Restored: ${originalName}`);
|
|
77
93
|
}
|
|
78
94
|
}
|
|
79
95
|
async function checkAllPackageVersionsAligned(workspaceDirs, packagesToCheck) {
|
|
80
|
-
const allPackageVersions = []
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for (const pkgName of Object.keys(packagesToCheck))
|
|
96
|
+
const allPackageVersions = [];
|
|
97
|
+
const allDirs = [process.cwd(), ...workspaceDirs];
|
|
98
|
+
const allDepsToCheck = /* @__PURE__ */new Set();
|
|
99
|
+
for (const pkgName of Object.keys(packagesToCheck)) {
|
|
100
|
+
allDepsToCheck.add(pkgName);
|
|
101
|
+
}
|
|
84
102
|
for (const [pkgName, pkgPath] of Object.entries(packagesToCheck)) {
|
|
85
103
|
const deps = await getPackageDependencies(pkgPath);
|
|
86
|
-
for (const dep of deps)
|
|
104
|
+
for (const dep of deps) {
|
|
105
|
+
allDepsToCheck.add(dep);
|
|
106
|
+
}
|
|
87
107
|
}
|
|
88
108
|
for (const workspaceDir of allDirs) {
|
|
89
|
-
const resolved = resolve(workspaceDir)
|
|
90
|
-
|
|
91
|
-
|
|
109
|
+
const resolved = resolve(workspaceDir);
|
|
110
|
+
const workspaceName = workspaceDir === process.cwd() ? "current" : workspaceDir.split("/").pop() || workspaceDir;
|
|
111
|
+
const packages = await collectSpecificNodeModulePackages(resolved, workspaceName, allDepsToCheck);
|
|
92
112
|
allPackageVersions.push(...packages);
|
|
93
113
|
}
|
|
94
114
|
const packageGroups = {};
|
|
95
|
-
for (const pkg of allPackageVersions)
|
|
115
|
+
for (const pkg of allPackageVersions) {
|
|
116
|
+
if (!packageGroups[pkg.name]) {
|
|
117
|
+
packageGroups[pkg.name] = [];
|
|
118
|
+
}
|
|
119
|
+
packageGroups[pkg.name].push(pkg);
|
|
120
|
+
}
|
|
96
121
|
const mismatches = [];
|
|
97
122
|
for (const [pkgName, versions] of Object.entries(packageGroups)) {
|
|
98
123
|
const versionsByWorkspace = {};
|
|
99
|
-
for (const version of versions)
|
|
100
|
-
|
|
124
|
+
for (const version of versions) {
|
|
125
|
+
versionsByWorkspace[version.workspace] = version.version;
|
|
126
|
+
}
|
|
127
|
+
const uniqueVersions = new Set(Object.values(versionsByWorkspace));
|
|
128
|
+
if (uniqueVersions.size > 1) {
|
|
101
129
|
const uniqueVersionsArray = Object.entries(versionsByWorkspace).map(([workspace, version]) => ({
|
|
102
130
|
name: pkgName,
|
|
103
131
|
version,
|
|
@@ -110,7 +138,10 @@ async function checkAllPackageVersionsAligned(workspaceDirs, packagesToCheck) {
|
|
|
110
138
|
});
|
|
111
139
|
}
|
|
112
140
|
}
|
|
113
|
-
if (mismatches.length === 0)
|
|
141
|
+
if (mismatches.length === 0) {
|
|
142
|
+
console.info("\u2713 All package versions are aligned across workspaces!");
|
|
143
|
+
return true;
|
|
144
|
+
}
|
|
114
145
|
console.info(`
|
|
115
146
|
\u274C Found ${mismatches.length} packages with mismatched versions, this may cause issues linking:
|
|
116
147
|
`);
|
|
@@ -119,25 +150,35 @@ async function checkAllPackageVersionsAligned(workspaceDirs, packagesToCheck) {
|
|
|
119
150
|
versions
|
|
120
151
|
} of mismatches) {
|
|
121
152
|
console.info(`Package: ${name}`);
|
|
122
|
-
for (const version of versions)
|
|
153
|
+
for (const version of versions) {
|
|
154
|
+
console.info(` ${version.workspace}: ${version.version}`);
|
|
155
|
+
}
|
|
123
156
|
console.info("");
|
|
124
157
|
}
|
|
125
|
-
return
|
|
158
|
+
return false;
|
|
126
159
|
}
|
|
127
160
|
async function getPackageDependencies(packagePath) {
|
|
128
161
|
const dependencies = /* @__PURE__ */new Set();
|
|
129
162
|
try {
|
|
130
|
-
const pkgJsonPath = join(packagePath, "package.json")
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
for (const depType of depTypes)
|
|
163
|
+
const pkgJsonPath = join(packagePath, "package.json");
|
|
164
|
+
const raw = await readFile(pkgJsonPath, "utf-8");
|
|
165
|
+
const pkgData = JSON.parse(raw);
|
|
166
|
+
const depTypes = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
167
|
+
for (const depType of depTypes) {
|
|
168
|
+
if (pkgData[depType]) {
|
|
169
|
+
for (const depName of Object.keys(pkgData[depType])) {
|
|
170
|
+
if (!depName.startsWith("@types/")) {
|
|
171
|
+
dependencies.add(depName);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
135
176
|
} catch {}
|
|
136
177
|
return Array.from(dependencies);
|
|
137
178
|
}
|
|
138
179
|
async function collectSpecificNodeModulePackages(workspaceDir, workspaceName, packagesToFind) {
|
|
139
|
-
const packages = []
|
|
140
|
-
|
|
180
|
+
const packages = [];
|
|
181
|
+
const nodeModulesPath = join(workspaceDir, "node_modules");
|
|
141
182
|
async function recurseNodeModules(dir, depth = 0) {
|
|
142
183
|
if (depth > 10) return;
|
|
143
184
|
let entries;
|
|
@@ -155,23 +196,31 @@ async function collectSpecificNodeModulePackages(workspaceDir, workspaceName, pa
|
|
|
155
196
|
continue;
|
|
156
197
|
}
|
|
157
198
|
if (entryStat.isDirectory()) {
|
|
158
|
-
if (entry.startsWith("@"))
|
|
199
|
+
if (entry.startsWith("@")) {
|
|
200
|
+
await recurseNodeModules(fullPath, depth + 1);
|
|
201
|
+
} else if (entry !== ".bin" && entry !== ".cache") {
|
|
159
202
|
const pkgJsonPath = join(fullPath, "package.json");
|
|
160
203
|
try {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
204
|
+
const pkgJsonStat = await stat(pkgJsonPath);
|
|
205
|
+
if (pkgJsonStat.isFile()) {
|
|
206
|
+
const raw = await readFile(pkgJsonPath, "utf-8");
|
|
207
|
+
const pkgData = JSON.parse(raw);
|
|
208
|
+
if (pkgData.name && pkgData.version && packagesToFind.has(pkgData.name) && !pkgData.name.startsWith("@types/")) {
|
|
209
|
+
packages.push({
|
|
210
|
+
name: pkgData.name,
|
|
211
|
+
version: pkgData.version,
|
|
212
|
+
workspace: workspaceName,
|
|
213
|
+
path: fullPath
|
|
214
|
+
});
|
|
215
|
+
}
|
|
170
216
|
}
|
|
171
217
|
} catch {
|
|
172
218
|
const nestedNodeModules = join(fullPath, "node_modules");
|
|
173
219
|
try {
|
|
174
|
-
|
|
220
|
+
const nestedStat = await stat(nestedNodeModules);
|
|
221
|
+
if (nestedStat.isDirectory()) {
|
|
222
|
+
await recurseNodeModules(nestedNodeModules, depth + 1);
|
|
223
|
+
}
|
|
175
224
|
} catch {}
|
|
176
225
|
}
|
|
177
226
|
}
|
|
@@ -185,20 +234,36 @@ async function collectSpecificNodeModulePackages(workspaceDir, workspaceName, pa
|
|
|
185
234
|
}
|
|
186
235
|
async function main() {
|
|
187
236
|
const args = process.argv.slice(2);
|
|
188
|
-
args.includes("--unlink")
|
|
237
|
+
if (args.includes("--unlink")) {
|
|
238
|
+
await undoLinks();
|
|
239
|
+
process.exit(0);
|
|
240
|
+
}
|
|
189
241
|
const workspaceDirs = args.filter(arg => !arg.startsWith("--"));
|
|
190
|
-
args.length === 0
|
|
242
|
+
if (args.length === 0) {
|
|
243
|
+
console.info("No workspace directories provided.");
|
|
244
|
+
process.exit(0);
|
|
245
|
+
}
|
|
191
246
|
const allLocalPackages = {};
|
|
192
247
|
for (const workspaceDir of workspaceDirs) {
|
|
193
|
-
const resolved = resolve(workspaceDir)
|
|
194
|
-
|
|
248
|
+
const resolved = resolve(workspaceDir);
|
|
249
|
+
const found = await findLocalPackages(resolved);
|
|
195
250
|
Object.assign(allLocalPackages, found);
|
|
196
251
|
}
|
|
197
|
-
if (!(await checkAllPackageVersionsAligned(workspaceDirs, allLocalPackages)))
|
|
198
|
-
|
|
252
|
+
if (!(await checkAllPackageVersionsAligned(workspaceDirs, allLocalPackages))) {
|
|
253
|
+
if (args.includes("--check")) {
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
if (args.includes("--check")) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
await linkPackages(allLocalPackages);
|
|
262
|
+
console.info(`
|
|
199
263
|
\u2713 linked ${Object.keys(allLocalPackages).length} packages`);
|
|
200
264
|
}
|
|
201
265
|
main().catch(err => {
|
|
202
|
-
console.error("Error:", err)
|
|
266
|
+
console.error("Error:", err);
|
|
267
|
+
process.exit(1);
|
|
203
268
|
});
|
|
204
269
|
//# sourceMappingURL=index.mjs.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lllink",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.15.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"module": "dist",
|
|
6
6
|
"exports": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@biomejs/biome": "2.3.3",
|
|
26
|
-
"@tamagui/build": "2.0.0-rc.
|
|
26
|
+
"@tamagui/build": "2.0.0-rc.36-1775258360494"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|