@facetlayer/docs-tool 0.1.3 → 0.2.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/browseGlobalNpmInstall.d.ts +15 -0
- package/dist/browseGlobalNpmInstall.d.ts.map +1 -0
- package/dist/browseNpmLibrary.d.ts +4 -0
- package/dist/browseNpmLibrary.d.ts.map +1 -1
- package/dist/cli.js +101 -35
- package/dist/index.js +99 -33
- package/package.json +1 -1
- package/src/browseGlobalNpmInstall.ts +79 -0
- package/src/browseNpmLibrary.ts +22 -6
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface GlobalLibraryLocation {
|
|
2
|
+
libraryPath: string;
|
|
3
|
+
libraryName: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Get the global npm prefix directory.
|
|
7
|
+
* Returns null if it cannot be determined.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getGlobalNpmPrefix(): Promise<string | null>;
|
|
10
|
+
/**
|
|
11
|
+
* Find a library in the global npm installation directory.
|
|
12
|
+
* This is where `npm install -g` puts packages.
|
|
13
|
+
*/
|
|
14
|
+
export declare function findInGlobalNpmInstall(libraryName: string): Promise<GlobalLibraryLocation | null>;
|
|
15
|
+
//# sourceMappingURL=browseGlobalNpmInstall.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browseGlobalNpmInstall.d.ts","sourceRoot":"","sources":["../src/browseGlobalNpmInstall.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB;AAOD;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBjE;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAoCvG"}
|
|
@@ -11,6 +11,10 @@ export interface NpmLibraryDocs {
|
|
|
11
11
|
hasReadme: boolean;
|
|
12
12
|
hasDocsFolder: boolean;
|
|
13
13
|
}
|
|
14
|
+
/**
|
|
15
|
+
* Check if a package exists at the given path with a package.json
|
|
16
|
+
*/
|
|
17
|
+
export declare function packageExistsAt(packagePath: string): boolean;
|
|
14
18
|
/**
|
|
15
19
|
* Find a library by name in node_modules directories.
|
|
16
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browseNpmLibrary.d.ts","sourceRoot":"","sources":["../src/browseNpmLibrary.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"browseNpmLibrary.d.ts","sourceRoot":"","sources":["../src/browseNpmLibrary.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;IACnB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAE5D;AAsGD;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAiCvG;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CASjD;AA6GD;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CA0C3H;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,cAAc,CA+BvF;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAQ/H"}
|
package/dist/cli.js
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
import yargs from "yargs";
|
|
5
5
|
import { hideBin } from "yargs/helpers";
|
|
6
6
|
import { readFileSync as readFileSync3 } from "fs";
|
|
7
|
-
import { join as
|
|
7
|
+
import { join as join5, dirname as dirname2 } from "path";
|
|
8
8
|
import { fileURLToPath } from "url";
|
|
9
9
|
|
|
10
10
|
// src/index.ts
|
|
11
11
|
import { readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
12
|
-
import { join as
|
|
12
|
+
import { join as join4, basename, relative } from "path";
|
|
13
13
|
|
|
14
14
|
// src/browseLocalLibrary.ts
|
|
15
15
|
import { resolve, join } from "path";
|
|
@@ -34,24 +34,83 @@ function browseLocalLibrary(targetPath) {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
// src/browseNpmLibrary.ts
|
|
37
|
-
import { readFileSync, readdirSync, existsSync as
|
|
38
|
-
import { join as
|
|
37
|
+
import { readFileSync, readdirSync, existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
|
|
38
|
+
import { join as join3, dirname } from "path";
|
|
39
39
|
import { homedir } from "os";
|
|
40
|
+
import { runShellCommand as runShellCommand2 } from "@facetlayer/subprocess-wrapper";
|
|
41
|
+
|
|
42
|
+
// src/browseGlobalNpmInstall.ts
|
|
43
|
+
import { existsSync as existsSync2 } from "fs";
|
|
44
|
+
import { join as join2 } from "path";
|
|
40
45
|
import { runShellCommand } from "@facetlayer/subprocess-wrapper";
|
|
46
|
+
var cachedGlobalPrefix = void 0;
|
|
47
|
+
async function getGlobalNpmPrefix() {
|
|
48
|
+
var _a;
|
|
49
|
+
if (cachedGlobalPrefix !== void 0) {
|
|
50
|
+
return cachedGlobalPrefix;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
const result = await runShellCommand("npm", ["prefix", "-g"]);
|
|
54
|
+
if (result.failed() || !result.stdout) {
|
|
55
|
+
cachedGlobalPrefix = null;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
cachedGlobalPrefix = ((_a = result.stdout[0]) == null ? void 0 : _a.trim()) || null;
|
|
59
|
+
return cachedGlobalPrefix;
|
|
60
|
+
} catch {
|
|
61
|
+
cachedGlobalPrefix = null;
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function findInGlobalNpmInstall(libraryName) {
|
|
66
|
+
const globalPrefix = await getGlobalNpmPrefix();
|
|
67
|
+
if (!globalPrefix) {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
const globalNodeModules = join2(globalPrefix, "lib", "node_modules");
|
|
71
|
+
if (!existsSync2(globalNodeModules)) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
if (libraryName.startsWith("@")) {
|
|
75
|
+
const [scope, pkgName] = libraryName.split("/");
|
|
76
|
+
if (pkgName) {
|
|
77
|
+
const fullPath2 = join2(globalNodeModules, scope, pkgName);
|
|
78
|
+
if (packageExistsAt(fullPath2)) {
|
|
79
|
+
return {
|
|
80
|
+
libraryPath: fullPath2,
|
|
81
|
+
libraryName
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
const fullPath = join2(globalNodeModules, libraryName);
|
|
88
|
+
if (packageExistsAt(fullPath)) {
|
|
89
|
+
return {
|
|
90
|
+
libraryPath: fullPath,
|
|
91
|
+
libraryName
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/browseNpmLibrary.ts
|
|
98
|
+
function packageExistsAt(packagePath) {
|
|
99
|
+
return existsSync3(packagePath) && existsSync3(join3(packagePath, "package.json"));
|
|
100
|
+
}
|
|
41
101
|
function findExactMatch(nodeModulesPath, libraryName) {
|
|
42
102
|
if (libraryName.startsWith("@")) {
|
|
43
103
|
const [scope, pkgName] = libraryName.split("/");
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (existsSync2(fullPath2) && existsSync2(join2(fullPath2, "package.json"))) {
|
|
104
|
+
if (pkgName) {
|
|
105
|
+
const fullPath2 = join3(nodeModulesPath, scope, pkgName);
|
|
106
|
+
if (packageExistsAt(fullPath2)) {
|
|
48
107
|
return fullPath2;
|
|
49
108
|
}
|
|
50
109
|
}
|
|
51
110
|
return null;
|
|
52
111
|
}
|
|
53
|
-
const fullPath =
|
|
54
|
-
if (
|
|
112
|
+
const fullPath = join3(nodeModulesPath, libraryName);
|
|
113
|
+
if (packageExistsAt(fullPath)) {
|
|
55
114
|
return fullPath;
|
|
56
115
|
}
|
|
57
116
|
return null;
|
|
@@ -59,21 +118,21 @@ function findExactMatch(nodeModulesPath, libraryName) {
|
|
|
59
118
|
function findPartialMatches(nodeModulesPath, partialName) {
|
|
60
119
|
const matches = [];
|
|
61
120
|
const lowerPartial = partialName.toLowerCase();
|
|
62
|
-
if (!
|
|
121
|
+
if (!existsSync3(nodeModulesPath)) {
|
|
63
122
|
return matches;
|
|
64
123
|
}
|
|
65
124
|
const entries = readdirSync(nodeModulesPath, { withFileTypes: true });
|
|
66
125
|
for (const entry of entries) {
|
|
67
126
|
if (!entry.isDirectory()) continue;
|
|
68
127
|
if (entry.name.startsWith("@")) {
|
|
69
|
-
const scopePath =
|
|
128
|
+
const scopePath = join3(nodeModulesPath, entry.name);
|
|
70
129
|
const scopedEntries = readdirSync(scopePath, { withFileTypes: true });
|
|
71
130
|
for (const scopedEntry of scopedEntries) {
|
|
72
131
|
if (!scopedEntry.isDirectory()) continue;
|
|
73
132
|
const fullName = `${entry.name}/${scopedEntry.name}`;
|
|
74
133
|
if (fullName.toLowerCase().includes(lowerPartial)) {
|
|
75
|
-
const fullPath =
|
|
76
|
-
if (
|
|
134
|
+
const fullPath = join3(scopePath, scopedEntry.name);
|
|
135
|
+
if (existsSync3(join3(fullPath, "package.json"))) {
|
|
77
136
|
matches.push({
|
|
78
137
|
libraryPath: fullPath,
|
|
79
138
|
libraryName: fullName,
|
|
@@ -84,8 +143,8 @@ function findPartialMatches(nodeModulesPath, partialName) {
|
|
|
84
143
|
}
|
|
85
144
|
} else {
|
|
86
145
|
if (entry.name.toLowerCase().includes(lowerPartial)) {
|
|
87
|
-
const fullPath =
|
|
88
|
-
if (
|
|
146
|
+
const fullPath = join3(nodeModulesPath, entry.name);
|
|
147
|
+
if (existsSync3(join3(fullPath, "package.json"))) {
|
|
89
148
|
matches.push({
|
|
90
149
|
libraryPath: fullPath,
|
|
91
150
|
libraryName: entry.name,
|
|
@@ -101,8 +160,8 @@ function getNodeModulesPaths(startDir) {
|
|
|
101
160
|
const paths = [];
|
|
102
161
|
let currentDir = startDir;
|
|
103
162
|
while (true) {
|
|
104
|
-
const nodeModulesPath =
|
|
105
|
-
if (
|
|
163
|
+
const nodeModulesPath = join3(currentDir, "node_modules");
|
|
164
|
+
if (existsSync3(nodeModulesPath)) {
|
|
106
165
|
paths.push(nodeModulesPath);
|
|
107
166
|
}
|
|
108
167
|
const parentDir = dirname(currentDir);
|
|
@@ -143,16 +202,16 @@ function findLibraryInNodeModules(libraryName, startDir) {
|
|
|
143
202
|
return null;
|
|
144
203
|
}
|
|
145
204
|
function getInstallationDirectory() {
|
|
146
|
-
const stateDir =
|
|
147
|
-
const installDir =
|
|
148
|
-
if (!
|
|
205
|
+
const stateDir = join3(homedir(), ".cache", "docs-tool");
|
|
206
|
+
const installDir = join3(stateDir, "installed-packages");
|
|
207
|
+
if (!existsSync3(installDir)) {
|
|
149
208
|
mkdirSync(installDir, { recursive: true });
|
|
150
209
|
}
|
|
151
210
|
return installDir;
|
|
152
211
|
}
|
|
153
212
|
function ensureInstallDirInitialized(installDir) {
|
|
154
|
-
const packageJsonPath =
|
|
155
|
-
if (!
|
|
213
|
+
const packageJsonPath = join3(installDir, "package.json");
|
|
214
|
+
if (!existsSync3(packageJsonPath)) {
|
|
156
215
|
const packageJson2 = {
|
|
157
216
|
name: "docs-tool-installed-packages",
|
|
158
217
|
version: "1.0.0",
|
|
@@ -163,8 +222,8 @@ function ensureInstallDirInitialized(installDir) {
|
|
|
163
222
|
}
|
|
164
223
|
}
|
|
165
224
|
function findInInstallDir(installDir, libraryName) {
|
|
166
|
-
const nodeModulesPath =
|
|
167
|
-
if (!
|
|
225
|
+
const nodeModulesPath = join3(installDir, "node_modules");
|
|
226
|
+
if (!existsSync3(nodeModulesPath)) {
|
|
168
227
|
return null;
|
|
169
228
|
}
|
|
170
229
|
const exactPath = findExactMatch(nodeModulesPath, libraryName);
|
|
@@ -184,7 +243,7 @@ function findInInstallDir(installDir, libraryName) {
|
|
|
184
243
|
async function getLatestVersion(libraryName) {
|
|
185
244
|
var _a;
|
|
186
245
|
try {
|
|
187
|
-
const result = await
|
|
246
|
+
const result = await runShellCommand2("npm", ["view", libraryName, "version"]);
|
|
188
247
|
if (result.failed() || !result.stdout) {
|
|
189
248
|
return null;
|
|
190
249
|
}
|
|
@@ -195,7 +254,7 @@ async function getLatestVersion(libraryName) {
|
|
|
195
254
|
}
|
|
196
255
|
function getInstalledVersion(libraryPath) {
|
|
197
256
|
try {
|
|
198
|
-
const packageJsonPath =
|
|
257
|
+
const packageJsonPath = join3(libraryPath, "package.json");
|
|
199
258
|
const packageJson2 = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
200
259
|
return packageJson2.version || null;
|
|
201
260
|
} catch {
|
|
@@ -205,7 +264,7 @@ function getInstalledVersion(libraryPath) {
|
|
|
205
264
|
async function installLibrary(installDir, libraryName) {
|
|
206
265
|
ensureInstallDirInitialized(installDir);
|
|
207
266
|
console.log(`Installing ${libraryName}...`);
|
|
208
|
-
const result = await
|
|
267
|
+
const result = await runShellCommand2("npm", ["install", libraryName, "--ignore-scripts"], {
|
|
209
268
|
cwd: installDir
|
|
210
269
|
});
|
|
211
270
|
if (result.failed()) {
|
|
@@ -215,7 +274,7 @@ async function installLibrary(installDir, libraryName) {
|
|
|
215
274
|
}
|
|
216
275
|
async function updateLibrary(installDir, libraryName) {
|
|
217
276
|
console.log(`Updating ${libraryName} to latest version...`);
|
|
218
|
-
const result = await
|
|
277
|
+
const result = await runShellCommand2("npm", ["update", libraryName, "--ignore-scripts"], {
|
|
219
278
|
cwd: installDir
|
|
220
279
|
});
|
|
221
280
|
if (result.failed()) {
|
|
@@ -229,6 +288,13 @@ async function findLibrary(libraryName, options) {
|
|
|
229
288
|
if (localResult) {
|
|
230
289
|
return localResult;
|
|
231
290
|
}
|
|
291
|
+
const globalResult = await findInGlobalNpmInstall(libraryName);
|
|
292
|
+
if (globalResult) {
|
|
293
|
+
return {
|
|
294
|
+
...globalResult,
|
|
295
|
+
matchType: "exact"
|
|
296
|
+
};
|
|
297
|
+
}
|
|
232
298
|
if (options == null ? void 0 : options.skipInstall) {
|
|
233
299
|
return null;
|
|
234
300
|
}
|
|
@@ -250,10 +316,10 @@ async function findLibrary(libraryName, options) {
|
|
|
250
316
|
function getLibraryDocs(libraryPath, libraryName) {
|
|
251
317
|
const dirs = [];
|
|
252
318
|
const files = [];
|
|
253
|
-
const readmePath =
|
|
254
|
-
const docsPath =
|
|
255
|
-
const hasReadme =
|
|
256
|
-
const hasDocsFolder =
|
|
319
|
+
const readmePath = join3(libraryPath, "README.md");
|
|
320
|
+
const docsPath = join3(libraryPath, "docs");
|
|
321
|
+
const hasReadme = existsSync3(readmePath);
|
|
322
|
+
const hasDocsFolder = existsSync3(docsPath);
|
|
257
323
|
if (hasReadme) {
|
|
258
324
|
files.push(readmePath);
|
|
259
325
|
}
|
|
@@ -314,7 +380,7 @@ var DocFilesHelper = class {
|
|
|
314
380
|
const files = readdirSync2(dir);
|
|
315
381
|
for (const file of files) {
|
|
316
382
|
if (!file.endsWith(".md")) continue;
|
|
317
|
-
this.fileMap.set(file,
|
|
383
|
+
this.fileMap.set(file, join4(dir, file));
|
|
318
384
|
}
|
|
319
385
|
}
|
|
320
386
|
}
|
|
@@ -472,7 +538,7 @@ function parseTarget(target) {
|
|
|
472
538
|
var __filename = fileURLToPath(import.meta.url);
|
|
473
539
|
var __dirname = dirname2(__filename);
|
|
474
540
|
var packageJson = JSON.parse(
|
|
475
|
-
readFileSync3(
|
|
541
|
+
readFileSync3(join5(__dirname, "../package.json"), "utf-8")
|
|
476
542
|
);
|
|
477
543
|
async function main() {
|
|
478
544
|
await yargs(hideBin(process.argv)).command(
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import { readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
|
|
3
|
-
import { join as
|
|
3
|
+
import { join as join4, basename, relative } from "path";
|
|
4
4
|
|
|
5
5
|
// src/browseLocalLibrary.ts
|
|
6
6
|
import { resolve, join } from "path";
|
|
@@ -25,24 +25,83 @@ function browseLocalLibrary(targetPath) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// src/browseNpmLibrary.ts
|
|
28
|
-
import { readFileSync, readdirSync, existsSync as
|
|
29
|
-
import { join as
|
|
28
|
+
import { readFileSync, readdirSync, existsSync as existsSync3, mkdirSync, writeFileSync } from "fs";
|
|
29
|
+
import { join as join3, dirname } from "path";
|
|
30
30
|
import { homedir } from "os";
|
|
31
|
+
import { runShellCommand as runShellCommand2 } from "@facetlayer/subprocess-wrapper";
|
|
32
|
+
|
|
33
|
+
// src/browseGlobalNpmInstall.ts
|
|
34
|
+
import { existsSync as existsSync2 } from "fs";
|
|
35
|
+
import { join as join2 } from "path";
|
|
31
36
|
import { runShellCommand } from "@facetlayer/subprocess-wrapper";
|
|
37
|
+
var cachedGlobalPrefix = void 0;
|
|
38
|
+
async function getGlobalNpmPrefix() {
|
|
39
|
+
var _a;
|
|
40
|
+
if (cachedGlobalPrefix !== void 0) {
|
|
41
|
+
return cachedGlobalPrefix;
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
const result = await runShellCommand("npm", ["prefix", "-g"]);
|
|
45
|
+
if (result.failed() || !result.stdout) {
|
|
46
|
+
cachedGlobalPrefix = null;
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
cachedGlobalPrefix = ((_a = result.stdout[0]) == null ? void 0 : _a.trim()) || null;
|
|
50
|
+
return cachedGlobalPrefix;
|
|
51
|
+
} catch {
|
|
52
|
+
cachedGlobalPrefix = null;
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
async function findInGlobalNpmInstall(libraryName) {
|
|
57
|
+
const globalPrefix = await getGlobalNpmPrefix();
|
|
58
|
+
if (!globalPrefix) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const globalNodeModules = join2(globalPrefix, "lib", "node_modules");
|
|
62
|
+
if (!existsSync2(globalNodeModules)) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (libraryName.startsWith("@")) {
|
|
66
|
+
const [scope, pkgName] = libraryName.split("/");
|
|
67
|
+
if (pkgName) {
|
|
68
|
+
const fullPath2 = join2(globalNodeModules, scope, pkgName);
|
|
69
|
+
if (packageExistsAt(fullPath2)) {
|
|
70
|
+
return {
|
|
71
|
+
libraryPath: fullPath2,
|
|
72
|
+
libraryName
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
const fullPath = join2(globalNodeModules, libraryName);
|
|
79
|
+
if (packageExistsAt(fullPath)) {
|
|
80
|
+
return {
|
|
81
|
+
libraryPath: fullPath,
|
|
82
|
+
libraryName
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// src/browseNpmLibrary.ts
|
|
89
|
+
function packageExistsAt(packagePath) {
|
|
90
|
+
return existsSync3(packagePath) && existsSync3(join3(packagePath, "package.json"));
|
|
91
|
+
}
|
|
32
92
|
function findExactMatch(nodeModulesPath, libraryName) {
|
|
33
93
|
if (libraryName.startsWith("@")) {
|
|
34
94
|
const [scope, pkgName] = libraryName.split("/");
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (existsSync2(fullPath2) && existsSync2(join2(fullPath2, "package.json"))) {
|
|
95
|
+
if (pkgName) {
|
|
96
|
+
const fullPath2 = join3(nodeModulesPath, scope, pkgName);
|
|
97
|
+
if (packageExistsAt(fullPath2)) {
|
|
39
98
|
return fullPath2;
|
|
40
99
|
}
|
|
41
100
|
}
|
|
42
101
|
return null;
|
|
43
102
|
}
|
|
44
|
-
const fullPath =
|
|
45
|
-
if (
|
|
103
|
+
const fullPath = join3(nodeModulesPath, libraryName);
|
|
104
|
+
if (packageExistsAt(fullPath)) {
|
|
46
105
|
return fullPath;
|
|
47
106
|
}
|
|
48
107
|
return null;
|
|
@@ -50,21 +109,21 @@ function findExactMatch(nodeModulesPath, libraryName) {
|
|
|
50
109
|
function findPartialMatches(nodeModulesPath, partialName) {
|
|
51
110
|
const matches = [];
|
|
52
111
|
const lowerPartial = partialName.toLowerCase();
|
|
53
|
-
if (!
|
|
112
|
+
if (!existsSync3(nodeModulesPath)) {
|
|
54
113
|
return matches;
|
|
55
114
|
}
|
|
56
115
|
const entries = readdirSync(nodeModulesPath, { withFileTypes: true });
|
|
57
116
|
for (const entry of entries) {
|
|
58
117
|
if (!entry.isDirectory()) continue;
|
|
59
118
|
if (entry.name.startsWith("@")) {
|
|
60
|
-
const scopePath =
|
|
119
|
+
const scopePath = join3(nodeModulesPath, entry.name);
|
|
61
120
|
const scopedEntries = readdirSync(scopePath, { withFileTypes: true });
|
|
62
121
|
for (const scopedEntry of scopedEntries) {
|
|
63
122
|
if (!scopedEntry.isDirectory()) continue;
|
|
64
123
|
const fullName = `${entry.name}/${scopedEntry.name}`;
|
|
65
124
|
if (fullName.toLowerCase().includes(lowerPartial)) {
|
|
66
|
-
const fullPath =
|
|
67
|
-
if (
|
|
125
|
+
const fullPath = join3(scopePath, scopedEntry.name);
|
|
126
|
+
if (existsSync3(join3(fullPath, "package.json"))) {
|
|
68
127
|
matches.push({
|
|
69
128
|
libraryPath: fullPath,
|
|
70
129
|
libraryName: fullName,
|
|
@@ -75,8 +134,8 @@ function findPartialMatches(nodeModulesPath, partialName) {
|
|
|
75
134
|
}
|
|
76
135
|
} else {
|
|
77
136
|
if (entry.name.toLowerCase().includes(lowerPartial)) {
|
|
78
|
-
const fullPath =
|
|
79
|
-
if (
|
|
137
|
+
const fullPath = join3(nodeModulesPath, entry.name);
|
|
138
|
+
if (existsSync3(join3(fullPath, "package.json"))) {
|
|
80
139
|
matches.push({
|
|
81
140
|
libraryPath: fullPath,
|
|
82
141
|
libraryName: entry.name,
|
|
@@ -92,8 +151,8 @@ function getNodeModulesPaths(startDir) {
|
|
|
92
151
|
const paths = [];
|
|
93
152
|
let currentDir = startDir;
|
|
94
153
|
while (true) {
|
|
95
|
-
const nodeModulesPath =
|
|
96
|
-
if (
|
|
154
|
+
const nodeModulesPath = join3(currentDir, "node_modules");
|
|
155
|
+
if (existsSync3(nodeModulesPath)) {
|
|
97
156
|
paths.push(nodeModulesPath);
|
|
98
157
|
}
|
|
99
158
|
const parentDir = dirname(currentDir);
|
|
@@ -134,16 +193,16 @@ function findLibraryInNodeModules(libraryName, startDir) {
|
|
|
134
193
|
return null;
|
|
135
194
|
}
|
|
136
195
|
function getInstallationDirectory() {
|
|
137
|
-
const stateDir =
|
|
138
|
-
const installDir =
|
|
139
|
-
if (!
|
|
196
|
+
const stateDir = join3(homedir(), ".cache", "docs-tool");
|
|
197
|
+
const installDir = join3(stateDir, "installed-packages");
|
|
198
|
+
if (!existsSync3(installDir)) {
|
|
140
199
|
mkdirSync(installDir, { recursive: true });
|
|
141
200
|
}
|
|
142
201
|
return installDir;
|
|
143
202
|
}
|
|
144
203
|
function ensureInstallDirInitialized(installDir) {
|
|
145
|
-
const packageJsonPath =
|
|
146
|
-
if (!
|
|
204
|
+
const packageJsonPath = join3(installDir, "package.json");
|
|
205
|
+
if (!existsSync3(packageJsonPath)) {
|
|
147
206
|
const packageJson = {
|
|
148
207
|
name: "docs-tool-installed-packages",
|
|
149
208
|
version: "1.0.0",
|
|
@@ -154,8 +213,8 @@ function ensureInstallDirInitialized(installDir) {
|
|
|
154
213
|
}
|
|
155
214
|
}
|
|
156
215
|
function findInInstallDir(installDir, libraryName) {
|
|
157
|
-
const nodeModulesPath =
|
|
158
|
-
if (!
|
|
216
|
+
const nodeModulesPath = join3(installDir, "node_modules");
|
|
217
|
+
if (!existsSync3(nodeModulesPath)) {
|
|
159
218
|
return null;
|
|
160
219
|
}
|
|
161
220
|
const exactPath = findExactMatch(nodeModulesPath, libraryName);
|
|
@@ -175,7 +234,7 @@ function findInInstallDir(installDir, libraryName) {
|
|
|
175
234
|
async function getLatestVersion(libraryName) {
|
|
176
235
|
var _a;
|
|
177
236
|
try {
|
|
178
|
-
const result = await
|
|
237
|
+
const result = await runShellCommand2("npm", ["view", libraryName, "version"]);
|
|
179
238
|
if (result.failed() || !result.stdout) {
|
|
180
239
|
return null;
|
|
181
240
|
}
|
|
@@ -186,7 +245,7 @@ async function getLatestVersion(libraryName) {
|
|
|
186
245
|
}
|
|
187
246
|
function getInstalledVersion(libraryPath) {
|
|
188
247
|
try {
|
|
189
|
-
const packageJsonPath =
|
|
248
|
+
const packageJsonPath = join3(libraryPath, "package.json");
|
|
190
249
|
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
191
250
|
return packageJson.version || null;
|
|
192
251
|
} catch {
|
|
@@ -196,7 +255,7 @@ function getInstalledVersion(libraryPath) {
|
|
|
196
255
|
async function installLibrary(installDir, libraryName) {
|
|
197
256
|
ensureInstallDirInitialized(installDir);
|
|
198
257
|
console.log(`Installing ${libraryName}...`);
|
|
199
|
-
const result = await
|
|
258
|
+
const result = await runShellCommand2("npm", ["install", libraryName, "--ignore-scripts"], {
|
|
200
259
|
cwd: installDir
|
|
201
260
|
});
|
|
202
261
|
if (result.failed()) {
|
|
@@ -206,7 +265,7 @@ async function installLibrary(installDir, libraryName) {
|
|
|
206
265
|
}
|
|
207
266
|
async function updateLibrary(installDir, libraryName) {
|
|
208
267
|
console.log(`Updating ${libraryName} to latest version...`);
|
|
209
|
-
const result = await
|
|
268
|
+
const result = await runShellCommand2("npm", ["update", libraryName, "--ignore-scripts"], {
|
|
210
269
|
cwd: installDir
|
|
211
270
|
});
|
|
212
271
|
if (result.failed()) {
|
|
@@ -220,6 +279,13 @@ async function findLibrary(libraryName, options) {
|
|
|
220
279
|
if (localResult) {
|
|
221
280
|
return localResult;
|
|
222
281
|
}
|
|
282
|
+
const globalResult = await findInGlobalNpmInstall(libraryName);
|
|
283
|
+
if (globalResult) {
|
|
284
|
+
return {
|
|
285
|
+
...globalResult,
|
|
286
|
+
matchType: "exact"
|
|
287
|
+
};
|
|
288
|
+
}
|
|
223
289
|
if (options == null ? void 0 : options.skipInstall) {
|
|
224
290
|
return null;
|
|
225
291
|
}
|
|
@@ -241,10 +307,10 @@ async function findLibrary(libraryName, options) {
|
|
|
241
307
|
function getLibraryDocs(libraryPath, libraryName) {
|
|
242
308
|
const dirs = [];
|
|
243
309
|
const files = [];
|
|
244
|
-
const readmePath =
|
|
245
|
-
const docsPath =
|
|
246
|
-
const hasReadme =
|
|
247
|
-
const hasDocsFolder =
|
|
310
|
+
const readmePath = join3(libraryPath, "README.md");
|
|
311
|
+
const docsPath = join3(libraryPath, "docs");
|
|
312
|
+
const hasReadme = existsSync3(readmePath);
|
|
313
|
+
const hasDocsFolder = existsSync3(docsPath);
|
|
248
314
|
if (hasReadme) {
|
|
249
315
|
files.push(readmePath);
|
|
250
316
|
}
|
|
@@ -305,7 +371,7 @@ var DocFilesHelper = class {
|
|
|
305
371
|
const files = readdirSync2(dir);
|
|
306
372
|
for (const file of files) {
|
|
307
373
|
if (!file.endsWith(".md")) continue;
|
|
308
|
-
this.fileMap.set(file,
|
|
374
|
+
this.fileMap.set(file, join4(dir, file));
|
|
309
375
|
}
|
|
310
376
|
}
|
|
311
377
|
}
|
package/package.json
CHANGED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { runShellCommand } from '@facetlayer/subprocess-wrapper';
|
|
4
|
+
import { packageExistsAt } from './browseNpmLibrary.ts';
|
|
5
|
+
|
|
6
|
+
export interface GlobalLibraryLocation {
|
|
7
|
+
libraryPath: string;
|
|
8
|
+
libraryName: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Cached global npm prefix to avoid repeated shell calls
|
|
13
|
+
*/
|
|
14
|
+
let cachedGlobalPrefix: string | null | undefined = undefined;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get the global npm prefix directory.
|
|
18
|
+
* Returns null if it cannot be determined.
|
|
19
|
+
*/
|
|
20
|
+
export async function getGlobalNpmPrefix(): Promise<string | null> {
|
|
21
|
+
if (cachedGlobalPrefix !== undefined) {
|
|
22
|
+
return cachedGlobalPrefix;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const result = await runShellCommand('npm', ['prefix', '-g']);
|
|
27
|
+
if (result.failed() || !result.stdout) {
|
|
28
|
+
cachedGlobalPrefix = null;
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
cachedGlobalPrefix = result.stdout[0]?.trim() || null;
|
|
32
|
+
return cachedGlobalPrefix;
|
|
33
|
+
} catch {
|
|
34
|
+
cachedGlobalPrefix = null;
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Find a library in the global npm installation directory.
|
|
41
|
+
* This is where `npm install -g` puts packages.
|
|
42
|
+
*/
|
|
43
|
+
export async function findInGlobalNpmInstall(libraryName: string): Promise<GlobalLibraryLocation | null> {
|
|
44
|
+
const globalPrefix = await getGlobalNpmPrefix();
|
|
45
|
+
if (!globalPrefix) {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const globalNodeModules = join(globalPrefix, 'lib', 'node_modules');
|
|
50
|
+
if (!existsSync(globalNodeModules)) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Handle scoped packages like @scope/package
|
|
55
|
+
if (libraryName.startsWith('@')) {
|
|
56
|
+
const [scope, pkgName] = libraryName.split('/');
|
|
57
|
+
if (pkgName) {
|
|
58
|
+
const fullPath = join(globalNodeModules, scope, pkgName);
|
|
59
|
+
if (packageExistsAt(fullPath)) {
|
|
60
|
+
return {
|
|
61
|
+
libraryPath: fullPath,
|
|
62
|
+
libraryName: libraryName,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Regular package
|
|
70
|
+
const fullPath = join(globalNodeModules, libraryName);
|
|
71
|
+
if (packageExistsAt(fullPath)) {
|
|
72
|
+
return {
|
|
73
|
+
libraryPath: fullPath,
|
|
74
|
+
libraryName: libraryName,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
}
|
package/src/browseNpmLibrary.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { join, dirname } from 'path';
|
|
|
3
3
|
import { homedir } from 'os';
|
|
4
4
|
import { runShellCommand } from '@facetlayer/subprocess-wrapper';
|
|
5
5
|
import { DocFilesHelper } from './index.ts';
|
|
6
|
+
import { findInGlobalNpmInstall } from './browseGlobalNpmInstall.ts';
|
|
6
7
|
|
|
7
8
|
export interface LibraryLocation {
|
|
8
9
|
libraryPath: string;
|
|
@@ -18,6 +19,13 @@ export interface NpmLibraryDocs {
|
|
|
18
19
|
hasDocsFolder: boolean;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/**
|
|
23
|
+
* Check if a package exists at the given path with a package.json
|
|
24
|
+
*/
|
|
25
|
+
export function packageExistsAt(packagePath: string): boolean {
|
|
26
|
+
return existsSync(packagePath) && existsSync(join(packagePath, 'package.json'));
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
/**
|
|
22
30
|
* Check if a directory contains a package that matches the given name exactly
|
|
23
31
|
*/
|
|
@@ -25,10 +33,9 @@ function findExactMatch(nodeModulesPath: string, libraryName: string): string |
|
|
|
25
33
|
// Handle scoped packages like @scope/package
|
|
26
34
|
if (libraryName.startsWith('@')) {
|
|
27
35
|
const [scope, pkgName] = libraryName.split('/');
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
if (existsSync(fullPath) && existsSync(join(fullPath, 'package.json'))) {
|
|
36
|
+
if (pkgName) {
|
|
37
|
+
const fullPath = join(nodeModulesPath, scope, pkgName);
|
|
38
|
+
if (packageExistsAt(fullPath)) {
|
|
32
39
|
return fullPath;
|
|
33
40
|
}
|
|
34
41
|
}
|
|
@@ -37,7 +44,7 @@ function findExactMatch(nodeModulesPath: string, libraryName: string): string |
|
|
|
37
44
|
|
|
38
45
|
// Regular package
|
|
39
46
|
const fullPath = join(nodeModulesPath, libraryName);
|
|
40
|
-
if (
|
|
47
|
+
if (packageExistsAt(fullPath)) {
|
|
41
48
|
return fullPath;
|
|
42
49
|
}
|
|
43
50
|
return null;
|
|
@@ -288,11 +295,20 @@ export async function findLibrary(libraryName: string, options?: { skipInstall?:
|
|
|
288
295
|
return localResult;
|
|
289
296
|
}
|
|
290
297
|
|
|
298
|
+
// Second, check global npm installation (where `npm install -g` puts packages)
|
|
299
|
+
const globalResult = await findInGlobalNpmInstall(libraryName);
|
|
300
|
+
if (globalResult) {
|
|
301
|
+
return {
|
|
302
|
+
...globalResult,
|
|
303
|
+
matchType: 'exact',
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
|
|
291
307
|
if (options?.skipInstall) {
|
|
292
308
|
return null;
|
|
293
309
|
}
|
|
294
310
|
|
|
295
|
-
//
|
|
311
|
+
// Third, check our installation directory
|
|
296
312
|
const installDir = getInstallationDirectory();
|
|
297
313
|
let installedResult = findInInstallDir(installDir, libraryName);
|
|
298
314
|
|