node-modules-tools 0.3.0 → 0.4.1

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.
@@ -0,0 +1,147 @@
1
+ import { relative, dirname } from 'pathe';
2
+ import { x } from 'tinyexec';
3
+ import { CLUSTER_DEP_PROD, CLUSTER_DEP_DEV, CLUSTER_DEP_OPTIONAL } from '../constants.mjs';
4
+
5
+ async function resolveRoot(options) {
6
+ let raw;
7
+ try {
8
+ raw = (await x("npm", ["root"], { throwOnError: true, nodeOptions: { cwd: options.cwd } })).stdout.trim();
9
+ } catch (err) {
10
+ console.error("Failed to resolve root directory");
11
+ console.error(err);
12
+ }
13
+ return raw ? dirname(raw) : options.cwd;
14
+ }
15
+ async function getNpmVersion(options) {
16
+ try {
17
+ const raw = await x("npm", ["--version"], { throwOnError: true, nodeOptions: { cwd: options.cwd } });
18
+ return raw.stdout.trim();
19
+ } catch (err) {
20
+ console.error("Failed to get npm version");
21
+ console.error(err);
22
+ return void 0;
23
+ }
24
+ }
25
+ async function queryDependencies(options, query, lockfileOnly = false) {
26
+ const args = ["query"];
27
+ if (lockfileOnly)
28
+ args.push("--package-lock-only");
29
+ args.push(query);
30
+ const process = x("npm", args, {
31
+ throwOnError: true,
32
+ nodeOptions: {
33
+ stdio: "pipe",
34
+ cwd: options.cwd
35
+ }
36
+ });
37
+ const json = await import('./json-parse-stream.mjs').then((r) => r.parseJsonStreamWithConcatArrays(process.process.stdout));
38
+ if (!Array.isArray(json))
39
+ throw new Error(`Failed to parse \`npm query\` output, expected an array but got: ${String(json)}`);
40
+ return json;
41
+ }
42
+ async function listPackageDependencies(options) {
43
+ const [
44
+ rootPackage,
45
+ workspaces,
46
+ devDependencies,
47
+ prodDependencies,
48
+ optionalDependencies,
49
+ packageManagerVersion,
50
+ root
51
+ ] = await Promise.all([
52
+ queryDependencies(options, ":root", true).then((res) => res[0]),
53
+ queryDependencies(options, ".workspace", true),
54
+ queryDependencies(options, ".dev"),
55
+ queryDependencies(options, ".prod"),
56
+ queryDependencies(options, ".optional"),
57
+ getNpmVersion(options),
58
+ resolveRoot(options)
59
+ ]);
60
+ if (!rootPackage)
61
+ throw new Error("Could not find root package.json");
62
+ const packages = /* @__PURE__ */ new Map();
63
+ const packageSpecByLocation = /* @__PURE__ */ new Map();
64
+ packageSpecByLocation.set(rootPackage.location, rootPackage._id);
65
+ packages.set(rootPackage._id, {
66
+ name: rootPackage.name,
67
+ version: rootPackage.version,
68
+ spec: rootPackage._id,
69
+ private: rootPackage.private,
70
+ filepath: rootPackage.path,
71
+ workspace: true,
72
+ dependencies: /* @__PURE__ */ new Set(),
73
+ clusters: /* @__PURE__ */ new Set()
74
+ });
75
+ workspaces.forEach((pkg, i) => {
76
+ let name = pkg.name;
77
+ if (!name) {
78
+ let path = relative(root, pkg.path);
79
+ if (path === ".")
80
+ path = "";
81
+ const suffix = path.toLowerCase().replace(/[^a-z0-9-]+/g, "_").slice(0, 20);
82
+ name = suffix ? `#workspace-${suffix}` : `#workspace-package-${i + 1}`;
83
+ }
84
+ const version = pkg.version || "0.0.0";
85
+ const node = {
86
+ spec: pkg._id,
87
+ name,
88
+ version,
89
+ filepath: pkg.path,
90
+ dependencies: /* @__PURE__ */ new Set(),
91
+ private: pkg.private,
92
+ workspace: true,
93
+ clusters: /* @__PURE__ */ new Set()
94
+ };
95
+ packageSpecByLocation.set(pkg.location, node.spec);
96
+ packages.set(node.spec, node);
97
+ });
98
+ function normalize(raw, clusters) {
99
+ if (packages.has(raw._id))
100
+ return;
101
+ packageSpecByLocation.set(raw.location, raw._id);
102
+ packages.set(raw._id, {
103
+ name: raw.name,
104
+ version: raw.version,
105
+ spec: raw._id,
106
+ private: raw.private,
107
+ filepath: raw.path,
108
+ workspace: false,
109
+ dependencies: /* @__PURE__ */ new Set(),
110
+ clusters: new Set(clusters)
111
+ });
112
+ }
113
+ prodDependencies.forEach((raw) => {
114
+ normalize(raw, [CLUSTER_DEP_PROD]);
115
+ });
116
+ devDependencies.forEach((raw) => {
117
+ normalize(raw, [CLUSTER_DEP_DEV]);
118
+ });
119
+ optionalDependencies.forEach((raw) => {
120
+ normalize(raw, [CLUSTER_DEP_OPTIONAL]);
121
+ });
122
+ Array.of(
123
+ ...devDependencies,
124
+ ...prodDependencies,
125
+ ...optionalDependencies,
126
+ ...workspaces,
127
+ rootPackage
128
+ ).forEach((raw) => {
129
+ const pkg = packages.get(raw._id);
130
+ if (!pkg)
131
+ return;
132
+ raw.to.forEach((to) => {
133
+ const resolved = packageSpecByLocation.get(to);
134
+ if (!resolved)
135
+ return;
136
+ pkg.dependencies.add(resolved);
137
+ });
138
+ });
139
+ return {
140
+ root,
141
+ packageManager: "npm",
142
+ packageManagerVersion,
143
+ packages
144
+ };
145
+ }
146
+
147
+ export { listPackageDependencies };
@@ -1,3 +1,3 @@
1
- export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, c as PackageModuleTypes } from './shared/node-modules-tools.BxS2oEP2.mjs';
1
+ export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, c as PackageModuleTypes } from './shared/node-modules-tools.CX5_YEVA.mjs';
2
2
  import 'pkg-types';
3
3
  import 'publint';
@@ -1,3 +1,3 @@
1
- export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, c as PackageModuleTypes } from './shared/node-modules-tools.BxS2oEP2.js';
1
+ export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, c as PackageModuleTypes } from './shared/node-modules-tools.CX5_YEVA.js';
2
2
  import 'pkg-types';
3
3
  import 'publint';
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { AgentName } from 'package-manager-detector';
2
- import { P as PackageNodeRaw, a as PackageNodeBase, b as PackageNode } from './shared/node-modules-tools.BxS2oEP2.mjs';
3
- export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, F as FileCategory, h as PackageInstallSizeInfo, g as PackageModuleType, f as PackageModuleTypeSimple, c as PackageModuleTypes } from './shared/node-modules-tools.BxS2oEP2.mjs';
2
+ import { P as PackageNodeRaw, a as PackageNodeBase, b as PackageNode } from './shared/node-modules-tools.CX5_YEVA.mjs';
3
+ export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, F as FileCategory, N as NpmMeta, h as NpmMetaLatest, i as PackageInstallSizeInfo, g as PackageModuleType, f as PackageModuleTypeSimple, c as PackageModuleTypes } from './shared/node-modules-tools.CX5_YEVA.mjs';
4
+ export { Message as PublintMessage } from 'publint';
4
5
  export { PackageNodeLike, constructPackageFilter, constructPackageFilters } from './utils.mjs';
5
6
  import 'pkg-types';
6
- import 'publint';
7
7
 
8
8
  interface BaseOptions {
9
9
  /**
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { AgentName } from 'package-manager-detector';
2
- import { P as PackageNodeRaw, a as PackageNodeBase, b as PackageNode } from './shared/node-modules-tools.BxS2oEP2.js';
3
- export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, F as FileCategory, h as PackageInstallSizeInfo, g as PackageModuleType, f as PackageModuleTypeSimple, c as PackageModuleTypes } from './shared/node-modules-tools.BxS2oEP2.js';
2
+ import { P as PackageNodeRaw, a as PackageNodeBase, b as PackageNode } from './shared/node-modules-tools.CX5_YEVA.js';
3
+ export { d as CLUSTER_DEP_DEV, e as CLUSTER_DEP_OPTIONAL, C as CLUSTER_DEP_PROD, F as FileCategory, N as NpmMeta, h as NpmMetaLatest, i as PackageInstallSizeInfo, g as PackageModuleType, f as PackageModuleTypeSimple, c as PackageModuleTypes } from './shared/node-modules-tools.CX5_YEVA.js';
4
+ export { Message as PublintMessage } from 'publint';
4
5
  export { PackageNodeLike, constructPackageFilter, constructPackageFilters } from './utils.js';
5
6
  import 'pkg-types';
6
- import 'publint';
7
7
 
8
8
  interface BaseOptions {
9
9
  /**
package/dist/index.mjs CHANGED
@@ -20,6 +20,8 @@ async function listPackageDependenciesRaw(manager, options) {
20
20
  let result;
21
21
  if (manager === "pnpm")
22
22
  result = await import('./chunks/index.mjs').then((r) => r.listPackageDependencies(options));
23
+ else if (manager === "npm")
24
+ result = await import('./chunks/index2.mjs').then((r) => r.listPackageDependencies(options));
23
25
  else
24
26
  throw new Error(`Package manager ${manager} is not yet supported`);
25
27
  return populateRawResult(result);
@@ -62,17 +62,39 @@ interface PackageNode extends PackageNodeBase {
62
62
  homepage?: string;
63
63
  engines?: Record<string, string>;
64
64
  installSize?: PackageInstallSizeInfo;
65
- publishTime?: string;
65
+ npmMeta?: NpmMeta;
66
+ npmMetaLatest?: NpmMetaLatest;
66
67
  /**
67
68
  * Result for publint, null for invalid, undefined for not checked yet, empty array for all good
68
69
  */
69
70
  publint?: Message[] | null;
70
71
  };
71
72
  }
73
+ interface NpmMeta {
74
+ publishedAt: number;
75
+ deprecated?: string;
76
+ }
77
+ /**
78
+ * Npm meta of the latest version of a certain package
79
+ * Unlike NpmMeta with is immutable, NpmMetaLatest is coupled with time,
80
+ * so the `vaildUntil` is used to determine if the meta would need to be updated.
81
+ */
82
+ interface NpmMetaLatest extends NpmMeta {
83
+ version: string;
84
+ /**
85
+ * Date when the meta was fetched
86
+ */
87
+ fetechedAt: number;
88
+ /**
89
+ * We calculate a smart "TTL" based on how open the package updates.
90
+ * If this timestemp is greater than the current time, the meta should be discarded.
91
+ */
92
+ vaildUntil: number;
93
+ }
72
94
 
73
95
  declare const PackageModuleTypes: readonly PackageModuleType[];
74
96
  declare const CLUSTER_DEP_PROD = "dep:prod";
75
97
  declare const CLUSTER_DEP_DEV = "dep:dev";
76
98
  declare const CLUSTER_DEP_OPTIONAL = "dep:optional";
77
99
 
78
- export { CLUSTER_DEP_PROD as C, type FileCategory as F, type PackageNodeRaw as P, type PackageNodeBase as a, type PackageNode as b, PackageModuleTypes as c, CLUSTER_DEP_DEV as d, CLUSTER_DEP_OPTIONAL as e, type PackageModuleTypeSimple as f, type PackageModuleType as g, type PackageInstallSizeInfo as h };
100
+ export { CLUSTER_DEP_PROD as C, type FileCategory as F, type NpmMeta as N, type PackageNodeRaw as P, type PackageNodeBase as a, type PackageNode as b, PackageModuleTypes as c, CLUSTER_DEP_DEV as d, CLUSTER_DEP_OPTIONAL as e, type PackageModuleTypeSimple as f, type PackageModuleType as g, type NpmMetaLatest as h, type PackageInstallSizeInfo as i };
@@ -62,17 +62,39 @@ interface PackageNode extends PackageNodeBase {
62
62
  homepage?: string;
63
63
  engines?: Record<string, string>;
64
64
  installSize?: PackageInstallSizeInfo;
65
- publishTime?: string;
65
+ npmMeta?: NpmMeta;
66
+ npmMetaLatest?: NpmMetaLatest;
66
67
  /**
67
68
  * Result for publint, null for invalid, undefined for not checked yet, empty array for all good
68
69
  */
69
70
  publint?: Message[] | null;
70
71
  };
71
72
  }
73
+ interface NpmMeta {
74
+ publishedAt: number;
75
+ deprecated?: string;
76
+ }
77
+ /**
78
+ * Npm meta of the latest version of a certain package
79
+ * Unlike NpmMeta with is immutable, NpmMetaLatest is coupled with time,
80
+ * so the `vaildUntil` is used to determine if the meta would need to be updated.
81
+ */
82
+ interface NpmMetaLatest extends NpmMeta {
83
+ version: string;
84
+ /**
85
+ * Date when the meta was fetched
86
+ */
87
+ fetechedAt: number;
88
+ /**
89
+ * We calculate a smart "TTL" based on how open the package updates.
90
+ * If this timestemp is greater than the current time, the meta should be discarded.
91
+ */
92
+ vaildUntil: number;
93
+ }
72
94
 
73
95
  declare const PackageModuleTypes: readonly PackageModuleType[];
74
96
  declare const CLUSTER_DEP_PROD = "dep:prod";
75
97
  declare const CLUSTER_DEP_DEV = "dep:dev";
76
98
  declare const CLUSTER_DEP_OPTIONAL = "dep:optional";
77
99
 
78
- export { CLUSTER_DEP_PROD as C, type FileCategory as F, type PackageNodeRaw as P, type PackageNodeBase as a, type PackageNode as b, PackageModuleTypes as c, CLUSTER_DEP_DEV as d, CLUSTER_DEP_OPTIONAL as e, type PackageModuleTypeSimple as f, type PackageModuleType as g, type PackageInstallSizeInfo as h };
100
+ export { CLUSTER_DEP_PROD as C, type FileCategory as F, type NpmMeta as N, type PackageNodeRaw as P, type PackageNodeBase as a, type PackageNode as b, PackageModuleTypes as c, CLUSTER_DEP_DEV as d, CLUSTER_DEP_OPTIONAL as e, type PackageModuleTypeSimple as f, type PackageModuleType as g, type NpmMetaLatest as h, type PackageInstallSizeInfo as i };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "node-modules-tools",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "0.4.1",
5
5
  "description": "Tools for inspecting node_modules",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com>",
7
7
  "license": "MIT",