@packall/core 0.1.0 → 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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/archive-6sqTn1C4.js +274 -0
- package/dist/archive-6sqTn1C4.js.map +1 -0
- package/dist/archive.d.ts +47 -15
- package/dist/archive.d.ts.map +1 -1
- package/dist/bundle.d.ts +6 -3
- package/dist/bundle.d.ts.map +1 -1
- package/dist/dependency-range.d.ts.map +1 -1
- package/dist/download.d.ts +2 -1
- package/dist/download.d.ts.map +1 -1
- package/dist/enums/artifact-kind.d.ts.map +1 -1
- package/dist/enums/edge-kind.d.ts.map +1 -1
- package/dist/enums/input-file-kind.d.ts.map +1 -1
- package/dist/enums/layout.d.ts.map +1 -1
- package/dist/enums/lockfile-format.d.ts.map +1 -1
- package/dist/enums/phase.d.ts.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +169 -344
- package/dist/index.js.map +1 -1
- package/dist/input-file.d.ts.map +1 -1
- package/dist/integrity.d.ts +37 -5
- package/dist/integrity.d.ts.map +1 -1
- package/dist/layout.d.ts +41 -7
- package/dist/layout.d.ts.map +1 -1
- package/dist/locked-resolve.d.ts.map +1 -1
- package/dist/lockfile/bun.d.ts.map +1 -1
- package/dist/lockfile/detect.d.ts.map +1 -1
- package/dist/lockfile/json.d.ts.map +1 -1
- package/dist/lockfile/names.d.ts.map +1 -1
- package/dist/lockfile/npm.d.ts.map +1 -1
- package/dist/lockfile/parse.d.ts.map +1 -1
- package/dist/lockfile/pnpm.d.ts.map +1 -1
- package/dist/lockfile/tree-builder.d.ts.map +1 -1
- package/dist/lockfile/types.d.ts.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/node/archiver.d.ts +5 -0
- package/dist/node/archiver.d.ts.map +1 -0
- package/dist/node/index.d.ts +13 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +55 -0
- package/dist/node/index.js.map +1 -0
- package/dist/options.d.ts +3 -3
- package/dist/options.d.ts.map +1 -1
- package/dist/platform.d.ts +5 -10
- package/dist/platform.d.ts.map +1 -1
- package/dist/progress.d.ts.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/resolve.d.ts.map +1 -1
- package/dist/schemas/lenient.d.ts.map +1 -1
- package/dist/schemas/package-json.d.ts.map +1 -1
- package/dist/spec.d.ts.map +1 -1
- package/dist/types/value-of.d.ts.map +1 -1
- package/dist/utils/is-record.d.ts.map +1 -1
- package/package.json +11 -10
- package/src/archive.ts +95 -92
- package/src/bundle.ts +736 -616
- package/src/dependency-range.ts +121 -115
- package/src/download.ts +155 -133
- package/src/enums/artifact-kind.ts +5 -5
- package/src/enums/edge-kind.ts +13 -13
- package/src/enums/input-file-kind.ts +9 -9
- package/src/enums/layout.ts +20 -20
- package/src/enums/lockfile-format.ts +6 -6
- package/src/enums/phase.ts +8 -8
- package/src/errors.ts +200 -198
- package/src/index.ts +126 -113
- package/src/input-file.ts +246 -234
- package/src/integrity.ts +165 -121
- package/src/layout.ts +63 -29
- package/src/locked-resolve.ts +471 -461
- package/src/lockfile/bun.ts +214 -207
- package/src/lockfile/detect.ts +80 -80
- package/src/lockfile/json.ts +91 -92
- package/src/lockfile/names.ts +9 -9
- package/src/lockfile/npm.ts +328 -308
- package/src/lockfile/parse.ts +32 -32
- package/src/lockfile/pnpm.ts +230 -225
- package/src/lockfile/tree-builder.ts +116 -116
- package/src/lockfile/types.ts +52 -52
- package/src/manifest.ts +129 -133
- package/src/node/archiver.ts +85 -0
- package/src/node/index.ts +13 -0
- package/src/options.ts +84 -84
- package/src/platform.ts +97 -101
- package/src/progress.ts +105 -106
- package/src/registry.ts +116 -115
- package/src/resolve.ts +560 -537
- package/src/schemas/lenient.ts +67 -60
- package/src/schemas/package-json.ts +11 -10
- package/src/spec.ts +123 -119
- package/src/types/value-of.ts +1 -1
- package/src/utils/is-record.ts +1 -1
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
* Packages, edges and skip warnings accumulate here while a parser walks a
|
|
5
5
|
* file, which is what lets each parser stay focused on its own encoding.
|
|
6
6
|
*/
|
|
7
|
-
import semver from "semver"
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
7
|
+
import semver from "semver";
|
|
8
|
+
|
|
9
|
+
import { parseDependencyTarget } from "../dependency-range.js";
|
|
10
|
+
import { LockedRootKind } from "../enums/edge-kind.js";
|
|
11
|
+
import type { LockfileFormat } from "../enums/lockfile-format.js";
|
|
12
|
+
import { LockfileError } from "../errors.js";
|
|
13
|
+
import { packageKey } from "../resolve.js";
|
|
14
|
+
import type { LockedEdge, LockedPackage, LockedRoot, LockedTree } from "./types.js";
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Which manifest block each root kind is declared in.
|
|
@@ -20,101 +21,101 @@ import type { LockedEdge, LockedPackage, LockedRoot, LockedTree } from "./types.
|
|
|
20
21
|
* rather than iterating this.
|
|
21
22
|
*/
|
|
22
23
|
export const fieldByRootKind = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
} as const satisfies Record<LockedRootKind, string
|
|
24
|
+
[LockedRootKind.Prod]: "dependencies",
|
|
25
|
+
[LockedRootKind.Optional]: "optionalDependencies",
|
|
26
|
+
[LockedRootKind.Dev]: "devDependencies",
|
|
27
|
+
[LockedRootKind.Peer]: "peerDependencies",
|
|
28
|
+
} as const satisfies Record<LockedRootKind, string>;
|
|
28
29
|
|
|
29
30
|
export class TreeBuilder {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
readonly packages = new Map<string, LockedPackage>();
|
|
32
|
+
readonly roots: Array<LockedRoot> = [];
|
|
33
|
+
readonly warnings: Array<string> = [];
|
|
34
|
+
readonly incomplete: Array<string> = [];
|
|
35
|
+
/** Names dropped on purpose, so an edge into one is explained, not alarming. */
|
|
36
|
+
private readonly skipped = new Set<string>();
|
|
37
|
+
private readonly seenWarnings = new Set<string>();
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
39
|
+
add(pkg: LockedPackage): void {
|
|
40
|
+
const key = packageKey(pkg.name, pkg.version);
|
|
41
|
+
const existing = this.packages.get(key);
|
|
42
|
+
if (existing === undefined) {
|
|
43
|
+
this.packages.set(key, pkg);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// The same package at the same version can appear at several paths in a
|
|
47
|
+
// nested layout. They are the same bytes; merge the edge sets so a copy
|
|
48
|
+
// recorded with fewer dependencies does not lose any.
|
|
49
|
+
this.packages.set(key, {
|
|
50
|
+
...existing,
|
|
51
|
+
dependencies: mergeEdges(existing.dependencies, pkg.dependencies),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
addRoot(root: LockedRoot): void {
|
|
56
|
+
if (this.roots.some((existing) => existing.name === root.name)) return;
|
|
57
|
+
this.roots.push(root);
|
|
58
|
+
}
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
warn(message: string): void {
|
|
61
|
+
if (this.seenWarnings.has(message)) return;
|
|
62
|
+
this.seenWarnings.add(message);
|
|
63
|
+
this.warnings.push(message);
|
|
64
|
+
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
/** Notes an entry that is real but cannot come from a registry. */
|
|
67
|
+
skip(name: string, spec: string, reason: string): void {
|
|
68
|
+
this.skipped.add(name);
|
|
69
|
+
this.warn(`skipped ${name}@${spec} (${reason}) — not fetchable from a registry`);
|
|
70
|
+
}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Records a required edge that resolved to nothing.
|
|
74
|
+
*
|
|
75
|
+
* An edge into something skipped on purpose is expected — you cannot bundle a
|
|
76
|
+
* `workspace:` sibling from a registry — so it stays a warning. Anything else
|
|
77
|
+
* means the file does not pin what it claims to.
|
|
78
|
+
*/
|
|
79
|
+
dangling(from: string, name: string): void {
|
|
80
|
+
if (this.skipped.has(name)) {
|
|
81
|
+
this.warn(`${from} requires ${name}, which is not fetchable from a registry`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
this.incomplete.push(`${name} (required by ${from})`);
|
|
85
|
+
}
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
87
|
+
finish(input: {
|
|
88
|
+
readonly format: LockfileFormat;
|
|
89
|
+
readonly lockfileVersion: string;
|
|
90
|
+
readonly path: string;
|
|
91
|
+
readonly importer?: string | undefined;
|
|
92
|
+
}): LockedTree {
|
|
93
|
+
if (this.packages.size === 0) {
|
|
94
|
+
throw new LockfileError(input.path, "lockfile pins no packages that can be bundled");
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
format: input.format,
|
|
98
|
+
lockfileVersion: input.lockfileVersion,
|
|
99
|
+
path: input.path,
|
|
100
|
+
importer: input.importer,
|
|
101
|
+
packages: this.packages,
|
|
102
|
+
roots: this.roots,
|
|
103
|
+
warnings: this.warnings,
|
|
104
|
+
incomplete: this.incomplete,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
const mergeEdges = (
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
a: ReadonlyArray<LockedEdge>,
|
|
111
|
+
b: ReadonlyArray<LockedEdge>,
|
|
111
112
|
): ReadonlyArray<LockedEdge> => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
113
|
+
const merged = new Map<string, LockedEdge>();
|
|
114
|
+
for (const edge of [...a, ...b]) {
|
|
115
|
+
merged.set(`${edge.name}@${edge.version}|${edge.kind}`, edge);
|
|
116
|
+
}
|
|
117
|
+
return [...merged.values()];
|
|
118
|
+
};
|
|
118
119
|
|
|
119
120
|
/**
|
|
120
121
|
* Reads the right-hand side of a locked entry as an exact version.
|
|
@@ -125,18 +126,18 @@ const mergeEdges = (
|
|
|
125
126
|
* stays identical between the two paths.
|
|
126
127
|
*/
|
|
127
128
|
export const asExactVersion = (
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
name: string,
|
|
130
|
+
raw: string,
|
|
130
131
|
):
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
132
|
+
| { readonly _tag: "Version"; readonly version: string }
|
|
133
|
+
| { readonly _tag: "Unsupported"; readonly reason: string } => {
|
|
134
|
+
const exact = semver.valid(raw, { loose: true });
|
|
135
|
+
if (exact !== null) return { _tag: "Version", version: exact };
|
|
135
136
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
}
|
|
137
|
+
const target = parseDependencyTarget(name, raw);
|
|
138
|
+
if (target._tag === "Unsupported") return { _tag: "Unsupported", reason: target.reason };
|
|
139
|
+
return { _tag: "Unsupported", reason: "not an exact version" };
|
|
140
|
+
};
|
|
140
141
|
|
|
141
142
|
/**
|
|
142
143
|
* Raised when a lockfile found by walking up turns out not to cover the
|
|
@@ -146,21 +147,20 @@ export const asExactVersion = (
|
|
|
146
147
|
* readable, it simply belongs to a different project, and bundling it would
|
|
147
148
|
* produce someone else's dependency set.
|
|
148
149
|
*/
|
|
149
|
-
export const notCovered = (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
150
|
+
export const notCovered = (path: string, importer: string, known: ReadonlyArray<string>): never => {
|
|
151
|
+
const listed = known
|
|
152
|
+
.slice(0, 8)
|
|
153
|
+
.map((entry) => ` ${entry}`)
|
|
154
|
+
.join("\n");
|
|
155
|
+
throw new LockfileError(
|
|
156
|
+
path,
|
|
157
|
+
`it does not cover ${importer}.\n` +
|
|
158
|
+
(known.length === 0
|
|
159
|
+
? " It records no workspace members."
|
|
160
|
+
: ` Workspace members it does record:\n${listed}` +
|
|
161
|
+
(known.length > 8 ? `\n … and ${known.length - 8} more` : "")),
|
|
162
|
+
);
|
|
163
|
+
};
|
|
164
164
|
|
|
165
165
|
/** `""` is how npm and bun spell the project at the lockfile's own level. */
|
|
166
|
-
export const importerKey = (importer: string): string => (importer === "." ? "" : importer)
|
|
166
|
+
export const importerKey = (importer: string): string => (importer === "." ? "" : importer);
|
package/src/lockfile/types.ts
CHANGED
|
@@ -5,70 +5,70 @@
|
|
|
5
5
|
* different ways; once flattened into this graph, nothing downstream has to
|
|
6
6
|
* know which manager wrote the file.
|
|
7
7
|
*/
|
|
8
|
-
import type { EdgeKind, LockedRootKind } from "../enums/edge-kind.js"
|
|
9
|
-
import type { LockfileFormat } from "../enums/lockfile-format.js"
|
|
8
|
+
import type { EdgeKind, LockedRootKind } from "../enums/edge-kind.js";
|
|
9
|
+
import type { LockfileFormat } from "../enums/lockfile-format.js";
|
|
10
10
|
|
|
11
11
|
/** One edge out of a locked package, already pinned to an exact version. */
|
|
12
12
|
export type LockedEdge = {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly version: string;
|
|
15
|
+
readonly kind: EdgeKind;
|
|
16
|
+
};
|
|
17
17
|
|
|
18
18
|
/** One package pinned by a lockfile. */
|
|
19
19
|
export type LockedPackage = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
20
|
+
readonly name: string;
|
|
21
|
+
readonly version: string;
|
|
22
|
+
readonly dependencies: ReadonlyArray<LockedEdge>;
|
|
23
|
+
};
|
|
24
24
|
|
|
25
25
|
/** A direct dependency of the locked project. */
|
|
26
26
|
export type LockedRoot = {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
27
|
+
readonly name: string;
|
|
28
|
+
readonly version: string;
|
|
29
|
+
readonly kind: LockedRootKind;
|
|
30
|
+
/** The range the manifest asked for, kept for reporting. */
|
|
31
|
+
readonly specifier?: string | undefined;
|
|
32
|
+
};
|
|
33
33
|
|
|
34
34
|
/** Options for reading a lockfile. */
|
|
35
35
|
export type LockfileParseOptions = {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
36
|
+
/**
|
|
37
|
+
* Which workspace member's dependencies become the roots, as a path relative
|
|
38
|
+
* to the lockfile in POSIX form — `"packages/core"`, or `"."` for the project
|
|
39
|
+
* at the lockfile's own level.
|
|
40
|
+
*
|
|
41
|
+
* Left undefined, every workspace member in the file contributes, which is
|
|
42
|
+
* what pointing `--file` straight at a lockfile should mean. It matters when
|
|
43
|
+
* a package.json found a lockfile by walking *up*: the file then pins the
|
|
44
|
+
* whole repository, and only one member of it was asked for.
|
|
45
|
+
*/
|
|
46
|
+
readonly importer?: string | undefined;
|
|
47
|
+
};
|
|
48
48
|
|
|
49
49
|
/** A whole lockfile, flattened. */
|
|
50
50
|
export type LockedTree = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
51
|
+
readonly format: LockfileFormat;
|
|
52
|
+
/** As the file declares it: `3`, `'9.0'`, `1`. */
|
|
53
|
+
readonly lockfileVersion: string;
|
|
54
|
+
/** Where it was read from, for error messages. */
|
|
55
|
+
readonly path: string;
|
|
56
|
+
/** The workspace member the roots came from, when one was selected. */
|
|
57
|
+
readonly importer?: string | undefined;
|
|
58
|
+
/** Every pinned package, keyed by `name@version`. */
|
|
59
|
+
readonly packages: ReadonlyMap<string, LockedPackage>;
|
|
60
|
+
/** The project's direct dependencies. */
|
|
61
|
+
readonly roots: ReadonlyArray<LockedRoot>;
|
|
62
|
+
/** Entries that were recognised but cannot be fetched from a registry. */
|
|
63
|
+
readonly warnings: ReadonlyArray<string>;
|
|
64
|
+
/**
|
|
65
|
+
* Required edges pointing at nothing the file pins.
|
|
66
|
+
*
|
|
67
|
+
* Distinct from `warnings`: a `workspace:` dependency that cannot be bundled
|
|
68
|
+
* is expected and gets a warning, while an ordinary registry dependency with
|
|
69
|
+
* no entry means the lockfile is genuinely partial and the bundle it produces
|
|
70
|
+
* would be missing a package. The caller decides what to do about it, but the
|
|
71
|
+
* two must not be confused.
|
|
72
|
+
*/
|
|
73
|
+
readonly incomplete: ReadonlyArray<string>;
|
|
74
|
+
};
|