@packall/core 0.0.1 → 0.1.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/{Archive.d.ts → archive.d.ts} +5 -5
- package/dist/archive.d.ts.map +1 -0
- package/dist/{Bundle.d.ts → bundle.d.ts} +51 -36
- package/dist/bundle.d.ts.map +1 -0
- package/dist/{DependencyRange.d.ts → dependency-range.d.ts} +2 -2
- package/dist/dependency-range.d.ts.map +1 -0
- package/dist/{Download.d.ts → download.d.ts} +7 -7
- package/dist/download.d.ts.map +1 -0
- package/dist/enums/artifact-kind.d.ts +8 -0
- package/dist/enums/artifact-kind.d.ts.map +1 -0
- package/dist/enums/edge-kind.d.ts +29 -0
- package/dist/enums/edge-kind.d.ts.map +1 -0
- package/dist/enums/input-file-kind.d.ts +12 -0
- package/dist/enums/input-file-kind.d.ts.map +1 -0
- package/dist/enums/layout.d.ts +23 -0
- package/dist/enums/layout.d.ts.map +1 -0
- package/dist/enums/lockfile-format.d.ts +9 -0
- package/dist/enums/lockfile-format.d.ts.map +1 -0
- package/dist/enums/phase.d.ts +11 -0
- package/dist/enums/phase.d.ts.map +1 -0
- package/dist/{Errors.d.ts → errors.d.ts} +49 -7
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.d.ts +44 -28
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2416 -1180
- package/dist/index.js.map +1 -1
- package/dist/input-file.d.ts +77 -0
- package/dist/input-file.d.ts.map +1 -0
- package/dist/{Integrity.d.ts → integrity.d.ts} +3 -3
- package/dist/integrity.d.ts.map +1 -0
- package/dist/{Layout.d.ts → layout.d.ts} +1 -1
- package/dist/{Layout.d.ts.map → layout.d.ts.map} +1 -1
- package/dist/locked-resolve.d.ts +47 -0
- package/dist/locked-resolve.d.ts.map +1 -0
- package/dist/lockfile/bun.d.ts +3 -0
- package/dist/lockfile/bun.d.ts.map +1 -0
- package/dist/lockfile/detect.d.ts +31 -0
- package/dist/lockfile/detect.d.ts.map +1 -0
- package/dist/lockfile/json.d.ts +23 -0
- package/dist/lockfile/json.d.ts.map +1 -0
- package/dist/lockfile/names.d.ts +16 -0
- package/dist/lockfile/names.d.ts.map +1 -0
- package/dist/lockfile/npm.d.ts +3 -0
- package/dist/lockfile/npm.d.ts.map +1 -0
- package/dist/lockfile/parse.d.ts +23 -0
- package/dist/lockfile/parse.d.ts.map +1 -0
- package/dist/lockfile/pnpm.d.ts +20 -0
- package/dist/lockfile/pnpm.d.ts.map +1 -0
- package/dist/lockfile/tree-builder.d.ts +70 -0
- package/dist/lockfile/tree-builder.d.ts.map +1 -0
- package/dist/lockfile/types.d.ts +70 -0
- package/dist/lockfile/types.d.ts.map +1 -0
- package/dist/{Manifest.d.ts → manifest.d.ts} +7 -15
- package/dist/manifest.d.ts.map +1 -0
- package/dist/{Options.d.ts → options.d.ts} +9 -27
- package/dist/options.d.ts.map +1 -0
- package/dist/{Platform.d.ts → platform.d.ts} +9 -9
- package/dist/platform.d.ts.map +1 -0
- package/dist/{Progress.d.ts → progress.d.ts} +10 -9
- package/dist/progress.d.ts.map +1 -0
- package/dist/{Registry.d.ts → registry.d.ts} +42 -44
- package/dist/registry.d.ts.map +1 -0
- package/dist/{Resolve.d.ts → resolve.d.ts} +25 -26
- package/dist/resolve.d.ts.map +1 -0
- package/dist/schemas/lenient.d.ts +38 -0
- package/dist/schemas/lenient.d.ts.map +1 -0
- package/dist/schemas/package-json.d.ts +44 -0
- package/dist/schemas/package-json.d.ts.map +1 -0
- package/dist/{Spec.d.ts → spec.d.ts} +4 -4
- package/dist/spec.d.ts.map +1 -0
- package/dist/types/value-of.d.ts +9 -0
- package/dist/types/value-of.d.ts.map +1 -0
- package/dist/utils/is-record.d.ts +8 -0
- package/dist/utils/is-record.d.ts.map +1 -0
- package/package.json +3 -2
- package/src/{Archive.ts → archive.ts} +92 -92
- package/src/{Bundle.ts → bundle.ts} +616 -570
- package/src/{DependencyRange.ts → dependency-range.ts} +115 -115
- package/src/{Download.ts → download.ts} +133 -132
- package/src/enums/artifact-kind.ts +9 -0
- package/src/enums/edge-kind.ts +32 -0
- package/src/enums/input-file-kind.ts +13 -0
- package/src/enums/layout.ts +25 -0
- package/src/enums/lockfile-format.ts +10 -0
- package/src/enums/phase.ts +12 -0
- package/src/{Errors.ts → errors.ts} +87 -5
- package/src/index.ts +133 -35
- package/src/{InputFile.ts → input-file.ts} +127 -44
- package/src/{Integrity.ts → integrity.ts} +121 -122
- package/src/locked-resolve.ts +461 -0
- package/src/lockfile/bun.ts +207 -0
- package/src/lockfile/detect.ts +80 -0
- package/src/lockfile/json.ts +132 -0
- package/src/lockfile/names.ts +20 -0
- package/src/lockfile/npm.ts +308 -0
- package/src/lockfile/parse.ts +56 -0
- package/src/lockfile/pnpm.ts +225 -0
- package/src/lockfile/tree-builder.ts +166 -0
- package/src/lockfile/types.ts +74 -0
- package/src/{Manifest.ts → manifest.ts} +133 -133
- package/src/{Options.ts → options.ts} +7 -27
- package/src/{Platform.ts → platform.ts} +23 -23
- package/src/{Progress.ts → progress.ts} +106 -106
- package/src/{Registry.ts → registry.ts} +115 -121
- package/src/{Resolve.ts → resolve.ts} +537 -528
- package/src/schemas/lenient.ts +123 -0
- package/src/schemas/package-json.ts +27 -0
- package/src/{Spec.ts → spec.ts} +11 -19
- package/src/types/value-of.ts +8 -0
- package/src/utils/is-record.ts +8 -0
- package/dist/Archive.d.ts.map +0 -1
- package/dist/Bundle.d.ts.map +0 -1
- package/dist/DependencyRange.d.ts.map +0 -1
- package/dist/Download.d.ts.map +0 -1
- package/dist/Errors.d.ts.map +0 -1
- package/dist/InputFile.d.ts +0 -46
- package/dist/InputFile.d.ts.map +0 -1
- package/dist/Integrity.d.ts.map +0 -1
- package/dist/Manifest.d.ts.map +0 -1
- package/dist/Options.d.ts.map +0 -1
- package/dist/Platform.d.ts.map +0 -1
- package/dist/Progress.d.ts.map +0 -1
- package/dist/Registry.d.ts.map +0 -1
- package/dist/Resolve.d.ts.map +0 -1
- package/dist/Spec.d.ts.map +0 -1
- /package/src/{Layout.ts → layout.ts} +0 -0
|
@@ -1,133 +1,133 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The manifest written into every bundle.
|
|
3
|
-
*
|
|
4
|
-
* This is the audit trail. Before anything is imported into a corporate
|
|
5
|
-
* registry somebody is usually required to answer "what exactly is in here and
|
|
6
|
-
* where did it come from" — this file answers that without unpacking a single
|
|
7
|
-
* tarball.
|
|
8
|
-
*/
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import { formatSpec } from "./
|
|
14
|
-
|
|
15
|
-
/** Schema version, bumped when the shape changes incompatibly. */
|
|
16
|
-
export const MANIFEST_VERSION = 1
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
readonly name: string
|
|
20
|
-
readonly version: string
|
|
21
|
-
/** Path of this tarball inside the bundle. */
|
|
22
|
-
readonly path: string
|
|
23
|
-
/** The URL it was downloaded from. */
|
|
24
|
-
readonly tarball: string
|
|
25
|
-
/** SRI integrity string as advertised by the source registry, when present. */
|
|
26
|
-
readonly integrity?: string | undefined
|
|
27
|
-
/** Legacy sha1, present on older published versions. */
|
|
28
|
-
readonly shasum?: string | undefined
|
|
29
|
-
/** Actual size on disk, in bytes. */
|
|
30
|
-
readonly bytes?: number | undefined
|
|
31
|
-
/** Human-readable justifications: `root:react@18.2.0`, `prod:scheduler@0.23.0`. */
|
|
32
|
-
readonly reasons: ReadonlyArray<string>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export
|
|
36
|
-
readonly manifestVersion: number
|
|
37
|
-
readonly tool: { readonly name: string; readonly version: string }
|
|
38
|
-
readonly createdAt: string
|
|
39
|
-
readonly registry: { readonly kind: string; readonly url: string }
|
|
40
|
-
/** What the user asked for, verbatim. */
|
|
41
|
-
readonly requested: ReadonlyArray<string>
|
|
42
|
-
/** What each request expanded to. */
|
|
43
|
-
readonly roots: ReadonlyArray<{
|
|
44
|
-
readonly spec: string
|
|
45
|
-
readonly versions: ReadonlyArray<string>
|
|
46
|
-
readonly packageCount: number
|
|
47
|
-
}>
|
|
48
|
-
readonly options: {
|
|
49
|
-
readonly layout: string
|
|
50
|
-
readonly optionalDependencies: boolean
|
|
51
|
-
readonly peerDependencies: boolean
|
|
52
|
-
readonly platforms: string
|
|
53
|
-
readonly allVersions: boolean
|
|
54
|
-
readonly includePrerelease: boolean
|
|
55
|
-
readonly integrityVerified: boolean
|
|
56
|
-
}
|
|
57
|
-
readonly packages: ReadonlyArray<ManifestEntry>
|
|
58
|
-
readonly warnings: ReadonlyArray<string>
|
|
59
|
-
readonly totals: {
|
|
60
|
-
readonly packages: number
|
|
61
|
-
readonly bytes: number
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/** Renders a package's reasons into short, greppable strings. */
|
|
66
|
-
export const formatReasons = (pkg: ResolvedPackage): ReadonlyArray<string> =>
|
|
67
|
-
pkg.reasons.map((reason) =>
|
|
68
|
-
reason._tag === "Root" ? `root:${reason.spec}` : `${reason.kind}:${reason.from}`
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
/** Builds the manifest for a completed (or dry) run. */
|
|
72
|
-
export const buildManifest = (input: {
|
|
73
|
-
readonly resolution: Resolution
|
|
74
|
-
/** Only the packages actually included in *this* archive. */
|
|
75
|
-
readonly included: ReadonlyArray<ResolvedPackage>
|
|
76
|
-
readonly options: BundleOptions
|
|
77
|
-
readonly registry: { readonly kind: string; readonly url: string }
|
|
78
|
-
readonly toolVersion: string
|
|
79
|
-
readonly sizes: ReadonlyMap<string, number>
|
|
80
|
-
readonly createdAt?: Date | undefined
|
|
81
|
-
}): BundleManifest => {
|
|
82
|
-
const includedNames = new Set(input.included.map((
|
|
83
|
-
|
|
84
|
-
const packages: ReadonlyArray<ManifestEntry> = input.included.map((pkg) => {
|
|
85
|
-
const key = `${pkg.name}@${pkg.version}`
|
|
86
|
-
return {
|
|
87
|
-
name: pkg.name,
|
|
88
|
-
version: pkg.version,
|
|
89
|
-
path: packagePath(pkg.name, pkg.version),
|
|
90
|
-
tarball: pkg.manifest.dist.tarball,
|
|
91
|
-
integrity: pkg.manifest.dist.integrity,
|
|
92
|
-
shasum: pkg.manifest.dist.shasum,
|
|
93
|
-
bytes: input.sizes.get(key),
|
|
94
|
-
reasons: formatReasons(pkg)
|
|
95
|
-
}
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
const totalBytes = packages.reduce((sum, entry) => sum + (entry.bytes ?? 0), 0)
|
|
99
|
-
|
|
100
|
-
return {
|
|
101
|
-
manifestVersion: MANIFEST_VERSION,
|
|
102
|
-
tool: { name: "packall", version: input.toolVersion },
|
|
103
|
-
createdAt: (input.createdAt ?? new Date()).toISOString(),
|
|
104
|
-
registry: input.registry,
|
|
105
|
-
requested: input.resolution.roots.map((root) => formatSpec(root.spec)),
|
|
106
|
-
roots: input.resolution.roots.map((root) => ({
|
|
107
|
-
spec: formatSpec(root.spec),
|
|
108
|
-
versions: root.versions,
|
|
109
|
-
packageCount: root.closure.filter((key) => includedNames.has(key)).length
|
|
110
|
-
})),
|
|
111
|
-
options: {
|
|
112
|
-
layout: input.options.layout,
|
|
113
|
-
optionalDependencies: input.options.scope.optional,
|
|
114
|
-
peerDependencies: input.options.scope.peer,
|
|
115
|
-
platforms: formatPlatformFilter(input.options.scope.platforms),
|
|
116
|
-
allVersions: input.options.allVersions,
|
|
117
|
-
includePrerelease: input.options.includePrerelease,
|
|
118
|
-
integrityVerified: input.options.verifyIntegrity
|
|
119
|
-
},
|
|
120
|
-
packages,
|
|
121
|
-
warnings: input.resolution.warnings.map((warning) =>
|
|
122
|
-
warning.from === undefined ? warning.message : `${warning.from}: ${warning.message}`
|
|
123
|
-
),
|
|
124
|
-
totals: {
|
|
125
|
-
packages: packages.length,
|
|
126
|
-
bytes: totalBytes
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** Serialises a manifest with stable key order and a trailing newline. */
|
|
132
|
-
export const serializeManifest = (manifest: BundleManifest): string =>
|
|
133
|
-
`${JSON.stringify(manifest, null, 2)}\n`
|
|
1
|
+
/**
|
|
2
|
+
* The manifest written into every bundle.
|
|
3
|
+
*
|
|
4
|
+
* This is the audit trail. Before anything is imported into a corporate
|
|
5
|
+
* registry somebody is usually required to answer "what exactly is in here and
|
|
6
|
+
* where did it come from" — this file answers that without unpacking a single
|
|
7
|
+
* tarball.
|
|
8
|
+
*/
|
|
9
|
+
import { packagePath } from "./layout.js"
|
|
10
|
+
import type { BundleOptions } from "./options.js"
|
|
11
|
+
import { formatPlatformFilter } from "./platform.js"
|
|
12
|
+
import type { Resolution, ResolvedPackage } from "./resolve.js"
|
|
13
|
+
import { formatSpec } from "./spec.js"
|
|
14
|
+
|
|
15
|
+
/** Schema version, bumped when the shape changes incompatibly. */
|
|
16
|
+
export const MANIFEST_VERSION = 1
|
|
17
|
+
|
|
18
|
+
export type ManifestEntry = {
|
|
19
|
+
readonly name: string
|
|
20
|
+
readonly version: string
|
|
21
|
+
/** Path of this tarball inside the bundle. */
|
|
22
|
+
readonly path: string
|
|
23
|
+
/** The URL it was downloaded from. */
|
|
24
|
+
readonly tarball: string
|
|
25
|
+
/** SRI integrity string as advertised by the source registry, when present. */
|
|
26
|
+
readonly integrity?: string | undefined
|
|
27
|
+
/** Legacy sha1, present on older published versions. */
|
|
28
|
+
readonly shasum?: string | undefined
|
|
29
|
+
/** Actual size on disk, in bytes. */
|
|
30
|
+
readonly bytes?: number | undefined
|
|
31
|
+
/** Human-readable justifications: `root:react@18.2.0`, `prod:scheduler@0.23.0`. */
|
|
32
|
+
readonly reasons: ReadonlyArray<string>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export type BundleManifest = {
|
|
36
|
+
readonly manifestVersion: number
|
|
37
|
+
readonly tool: { readonly name: string; readonly version: string }
|
|
38
|
+
readonly createdAt: string
|
|
39
|
+
readonly registry: { readonly kind: string; readonly url: string }
|
|
40
|
+
/** What the user asked for, verbatim. */
|
|
41
|
+
readonly requested: ReadonlyArray<string>
|
|
42
|
+
/** What each request expanded to. */
|
|
43
|
+
readonly roots: ReadonlyArray<{
|
|
44
|
+
readonly spec: string
|
|
45
|
+
readonly versions: ReadonlyArray<string>
|
|
46
|
+
readonly packageCount: number
|
|
47
|
+
}>
|
|
48
|
+
readonly options: {
|
|
49
|
+
readonly layout: string
|
|
50
|
+
readonly optionalDependencies: boolean
|
|
51
|
+
readonly peerDependencies: boolean
|
|
52
|
+
readonly platforms: string
|
|
53
|
+
readonly allVersions: boolean
|
|
54
|
+
readonly includePrerelease: boolean
|
|
55
|
+
readonly integrityVerified: boolean
|
|
56
|
+
}
|
|
57
|
+
readonly packages: ReadonlyArray<ManifestEntry>
|
|
58
|
+
readonly warnings: ReadonlyArray<string>
|
|
59
|
+
readonly totals: {
|
|
60
|
+
readonly packages: number
|
|
61
|
+
readonly bytes: number
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Renders a package's reasons into short, greppable strings. */
|
|
66
|
+
export const formatReasons = (pkg: ResolvedPackage): ReadonlyArray<string> =>
|
|
67
|
+
pkg.reasons.map((reason) =>
|
|
68
|
+
reason._tag === "Root" ? `root:${reason.spec}` : `${reason.kind}:${reason.from}`
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
/** Builds the manifest for a completed (or dry) run. */
|
|
72
|
+
export const buildManifest = (input: {
|
|
73
|
+
readonly resolution: Resolution
|
|
74
|
+
/** Only the packages actually included in *this* archive. */
|
|
75
|
+
readonly included: ReadonlyArray<ResolvedPackage>
|
|
76
|
+
readonly options: BundleOptions
|
|
77
|
+
readonly registry: { readonly kind: string; readonly url: string }
|
|
78
|
+
readonly toolVersion: string
|
|
79
|
+
readonly sizes: ReadonlyMap<string, number>
|
|
80
|
+
readonly createdAt?: Date | undefined
|
|
81
|
+
}): BundleManifest => {
|
|
82
|
+
const includedNames = new Set(input.included.map((pkg) => `${pkg.name}@${pkg.version}`))
|
|
83
|
+
|
|
84
|
+
const packages: ReadonlyArray<ManifestEntry> = input.included.map((pkg) => {
|
|
85
|
+
const key = `${pkg.name}@${pkg.version}`
|
|
86
|
+
return {
|
|
87
|
+
name: pkg.name,
|
|
88
|
+
version: pkg.version,
|
|
89
|
+
path: packagePath(pkg.name, pkg.version),
|
|
90
|
+
tarball: pkg.manifest.dist.tarball,
|
|
91
|
+
integrity: pkg.manifest.dist.integrity,
|
|
92
|
+
shasum: pkg.manifest.dist.shasum,
|
|
93
|
+
bytes: input.sizes.get(key),
|
|
94
|
+
reasons: formatReasons(pkg)
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
const totalBytes = packages.reduce((sum, entry) => sum + (entry.bytes ?? 0), 0)
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
manifestVersion: MANIFEST_VERSION,
|
|
102
|
+
tool: { name: "packall", version: input.toolVersion },
|
|
103
|
+
createdAt: (input.createdAt ?? new Date()).toISOString(),
|
|
104
|
+
registry: input.registry,
|
|
105
|
+
requested: input.resolution.roots.map((root) => formatSpec(root.spec)),
|
|
106
|
+
roots: input.resolution.roots.map((root) => ({
|
|
107
|
+
spec: formatSpec(root.spec),
|
|
108
|
+
versions: root.versions,
|
|
109
|
+
packageCount: root.closure.filter((key) => includedNames.has(key)).length
|
|
110
|
+
})),
|
|
111
|
+
options: {
|
|
112
|
+
layout: input.options.layout,
|
|
113
|
+
optionalDependencies: input.options.scope.optional,
|
|
114
|
+
peerDependencies: input.options.scope.peer,
|
|
115
|
+
platforms: formatPlatformFilter(input.options.scope.platforms),
|
|
116
|
+
allVersions: input.options.allVersions,
|
|
117
|
+
includePrerelease: input.options.includePrerelease,
|
|
118
|
+
integrityVerified: input.options.verifyIntegrity
|
|
119
|
+
},
|
|
120
|
+
packages,
|
|
121
|
+
warnings: input.resolution.warnings.map((warning) =>
|
|
122
|
+
warning.from === undefined ? warning.message : `${warning.from}: ${warning.message}`
|
|
123
|
+
),
|
|
124
|
+
totals: {
|
|
125
|
+
packages: packages.length,
|
|
126
|
+
bytes: totalBytes
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Serialises a manifest with stable key order and a trailing newline. */
|
|
132
|
+
export const serializeManifest = (manifest: BundleManifest): string =>
|
|
133
|
+
`${JSON.stringify(manifest, null, 2)}\n`
|
|
@@ -5,32 +5,12 @@
|
|
|
5
5
|
* actually installs offline on a machine that is not the one you built it on.
|
|
6
6
|
* Every switch that makes the bundle smaller is opt-in.
|
|
7
7
|
*/
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
/** How the resulting tarball(s) are shaped. */
|
|
12
|
-
export type Layout =
|
|
13
|
-
/**
|
|
14
|
-
* One tarball per requested spec, each carrying its own complete dependency
|
|
15
|
-
* closure. Shared dependencies repeat across tarballs, so the total is
|
|
16
|
-
* larger — but each one imports, rolls back and hands off independently.
|
|
17
|
-
*/
|
|
18
|
-
| "per-spec"
|
|
19
|
-
/**
|
|
20
|
-
* One tarball for everything, with the union of all closures deduplicated.
|
|
21
|
-
* Smallest output and a single import step; all-or-nothing to roll back.
|
|
22
|
-
*/
|
|
23
|
-
| "single"
|
|
24
|
-
/**
|
|
25
|
-
* No archive at all — just the npm-layout directory tree, ready for
|
|
26
|
-
* `jf rt upload` or rsync.
|
|
27
|
-
*/
|
|
28
|
-
| "dir"
|
|
29
|
-
|
|
30
|
-
export const layouts: ReadonlyArray<Layout> = ["per-spec", "single", "dir"]
|
|
8
|
+
import { Layout } from "./enums/layout.js"
|
|
9
|
+
import type { PlatformFilter } from "./platform.js"
|
|
10
|
+
import { allPlatforms } from "./platform.js"
|
|
31
11
|
|
|
32
12
|
/** Which dependency edges the resolver follows. */
|
|
33
|
-
export
|
|
13
|
+
export type DependencyScope = {
|
|
34
14
|
/**
|
|
35
15
|
* Follow `optionalDependencies`. On by default — this is where per-platform
|
|
36
16
|
* native binaries live, and omitting them is the most common reason an
|
|
@@ -53,7 +33,7 @@ export const defaultScope: DependencyScope = {
|
|
|
53
33
|
}
|
|
54
34
|
|
|
55
35
|
/** Options governing version selection and the dependency walk. */
|
|
56
|
-
export
|
|
36
|
+
export type ResolveOptions = {
|
|
57
37
|
readonly scope: DependencyScope
|
|
58
38
|
/**
|
|
59
39
|
* When a root spec is a range, take *every* published version that satisfies
|
|
@@ -79,7 +59,7 @@ export const defaultResolveOptions: ResolveOptions = {
|
|
|
79
59
|
}
|
|
80
60
|
|
|
81
61
|
/** Options for a full bundle run. */
|
|
82
|
-
export
|
|
62
|
+
export type BundleOptions = ResolveOptions & {
|
|
83
63
|
readonly layout: Layout
|
|
84
64
|
/** Directory the finished artifacts are written to. */
|
|
85
65
|
readonly outDir: string
|
|
@@ -116,7 +96,7 @@ export interface BundleOptions extends ResolveOptions {
|
|
|
116
96
|
|
|
117
97
|
export const defaultBundleOptions: Omit<BundleOptions, "outDir"> = {
|
|
118
98
|
...defaultResolveOptions,
|
|
119
|
-
layout:
|
|
99
|
+
layout: Layout.PerSpec,
|
|
120
100
|
dryRun: false,
|
|
121
101
|
verifyIntegrity: true,
|
|
122
102
|
force: false
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
/** A target to keep, e.g. `linux-x64`, `linux-x64-musl`, or just `linux`. */
|
|
18
|
-
export
|
|
18
|
+
export type PlatformTarget = {
|
|
19
19
|
readonly os: string
|
|
20
20
|
/** Undefined means "every architecture for this OS". */
|
|
21
21
|
readonly cpu?: string | undefined
|
|
@@ -33,6 +33,13 @@ export type PlatformFilter =
|
|
|
33
33
|
| { readonly _tag: "All" }
|
|
34
34
|
| { readonly _tag: "Targets"; readonly targets: ReadonlyArray<PlatformTarget> }
|
|
35
35
|
|
|
36
|
+
/** Constraints declared by a package, as they appear in its manifest. */
|
|
37
|
+
export type PlatformConstraints = {
|
|
38
|
+
readonly os?: ReadonlyArray<string> | undefined
|
|
39
|
+
readonly cpu?: ReadonlyArray<string> | undefined
|
|
40
|
+
readonly libc?: ReadonlyArray<string> | undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
36
43
|
export const allPlatforms: PlatformFilter = { _tag: "All" }
|
|
37
44
|
|
|
38
45
|
export const platformTargets = (targets: ReadonlyArray<PlatformTarget>): PlatformFilter => ({
|
|
@@ -54,7 +61,7 @@ export const currentPlatform = (): PlatformTarget => ({
|
|
|
54
61
|
* and installs nothing. `--platform windows` silently matching no binding at
|
|
55
62
|
* all would be precisely that, so it is corrected rather than accepted.
|
|
56
63
|
*/
|
|
57
|
-
const
|
|
64
|
+
const osByAlias: Readonly<Record<string, string | undefined>> = {
|
|
58
65
|
win: "win32",
|
|
59
66
|
windows: "win32",
|
|
60
67
|
mac: "darwin",
|
|
@@ -76,7 +83,7 @@ const KNOWN_OS: ReadonlySet<string> = new Set([
|
|
|
76
83
|
"win32"
|
|
77
84
|
])
|
|
78
85
|
|
|
79
|
-
const LIBC = new Set(["musl", "glibc"])
|
|
86
|
+
const LIBC: ReadonlySet<string> = new Set(["musl", "glibc"])
|
|
80
87
|
|
|
81
88
|
/**
|
|
82
89
|
* Parses `linux`, `linux-x64`, `darwin-arm64`, `win32-x64`, `linux-x64-musl`,
|
|
@@ -91,24 +98,22 @@ const LIBC = new Set(["musl", "glibc"])
|
|
|
91
98
|
* once alongside the list of accepted forms.
|
|
92
99
|
*/
|
|
93
100
|
export const parsePlatformTarget = (input: string): PlatformTarget | null => {
|
|
94
|
-
const parts = input.trim().toLowerCase().split("-").filter((
|
|
95
|
-
|
|
101
|
+
const parts = input.trim().toLowerCase().split("-").filter((part) => part.length > 0)
|
|
102
|
+
const [rawOs, second, third] = parts
|
|
103
|
+
if (rawOs === undefined || parts.length > 3) return null
|
|
96
104
|
|
|
97
|
-
const
|
|
98
|
-
const os = OS_ALIASES[rawOs] ?? rawOs
|
|
105
|
+
const os = osByAlias[rawOs] ?? rawOs
|
|
99
106
|
if (!KNOWN_OS.has(os)) return null
|
|
100
107
|
|
|
101
|
-
if (
|
|
108
|
+
if (second === undefined) return { os }
|
|
102
109
|
|
|
103
110
|
// `linux-musl` is an OS plus a libc, not an OS plus an architecture.
|
|
104
|
-
if (
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (parts.length === 2) return { os, cpu }
|
|
111
|
+
if (third === undefined) {
|
|
112
|
+
return LIBC.has(second) ? { os, libc: second } : { os, cpu: second }
|
|
113
|
+
}
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return { os, cpu, libc }
|
|
115
|
+
if (!LIBC.has(third)) return null
|
|
116
|
+
return { os, cpu: second, libc: third }
|
|
112
117
|
}
|
|
113
118
|
|
|
114
119
|
/**
|
|
@@ -140,13 +145,6 @@ const listAllows = (list: ReadonlyArray<string> | undefined, value: string): boo
|
|
|
140
145
|
return hasPositive ? positiveMatched : true
|
|
141
146
|
}
|
|
142
147
|
|
|
143
|
-
/** Constraints declared by a package, as they appear in its manifest. */
|
|
144
|
-
export interface PlatformConstraints {
|
|
145
|
-
readonly os?: ReadonlyArray<string> | undefined
|
|
146
|
-
readonly cpu?: ReadonlyArray<string> | undefined
|
|
147
|
-
readonly libc?: ReadonlyArray<string> | undefined
|
|
148
|
-
}
|
|
149
|
-
|
|
150
148
|
/** Would this package install on this specific target? */
|
|
151
149
|
export const matchesTarget = (
|
|
152
150
|
constraints: PlatformConstraints,
|
|
@@ -177,6 +175,8 @@ export const isIncluded = (
|
|
|
177
175
|
export const formatPlatformFilter = (filter: PlatformFilter): string => {
|
|
178
176
|
if (filter._tag === "All") return "all"
|
|
179
177
|
return filter.targets
|
|
180
|
-
.map((
|
|
178
|
+
.map((target) =>
|
|
179
|
+
[target.os, target.cpu, target.libc].filter((part) => part !== undefined).join("-")
|
|
180
|
+
)
|
|
181
181
|
.join(",")
|
|
182
182
|
}
|
|
@@ -1,106 +1,106 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Progress reporting.
|
|
3
|
-
*
|
|
4
|
-
* The engine emits structured events; it never writes to a terminal. That
|
|
5
|
-
* separation is what lets the CLI draw a live TTY view, CI print plain lines,
|
|
6
|
-
* and the test suite assert on an array of events without any of them
|
|
7
|
-
* interfering with each other.
|
|
8
|
-
*/
|
|
9
|
-
import * as Context from "effect/Context"
|
|
10
|
-
import * as Effect from "effect/Effect"
|
|
11
|
-
import * as Layer from "effect/Layer"
|
|
12
|
-
import * as Ref from "effect/Ref"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
/** A
|
|
18
|
-
|
|
19
|
-
/** A phase
|
|
20
|
-
| { readonly _tag: "
|
|
21
|
-
/**
|
|
22
|
-
| {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
readonly
|
|
26
|
-
|
|
27
|
-
readonly
|
|
28
|
-
/**
|
|
29
|
-
readonly
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
/** A tarball download
|
|
34
|
-
| {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
readonly
|
|
38
|
-
readonly
|
|
39
|
-
readonly
|
|
40
|
-
readonly
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
readonly
|
|
47
|
-
readonly
|
|
48
|
-
readonly
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
/** An archive
|
|
53
|
-
| { readonly _tag: "
|
|
54
|
-
/**
|
|
55
|
-
| { readonly _tag: "
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/** Service tag for progress reporting. */
|
|
65
|
-
export class Progress extends Context.Service<Progress,
|
|
66
|
-
"@packall/core/Progress"
|
|
67
|
-
) {}
|
|
68
|
-
|
|
69
|
-
/** Emits an event to whichever reporter is installed. */
|
|
70
|
-
export const emit = (event: ProgressEvent): Effect.Effect<void, never, Progress> =>
|
|
71
|
-
Effect.gen(function*() {
|
|
72
|
-
const progress = yield* Progress
|
|
73
|
-
yield* progress.emit(event)
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Discards every event.
|
|
78
|
-
*
|
|
79
|
-
* The default for library consumers and for tests that do not care about
|
|
80
|
-
* progress — silence should never require ceremony.
|
|
81
|
-
*/
|
|
82
|
-
export const layerSilent: Layer.Layer<Progress> = Layer.succeed(Progress)({
|
|
83
|
-
emit: () => Effect.void
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
/** Sends every event to a callback. Used by the CLI renderer. */
|
|
87
|
-
export const layerCallback = (
|
|
88
|
-
onEvent: (event: ProgressEvent) => void
|
|
89
|
-
): Layer.Layer<Progress> =>
|
|
90
|
-
Layer.succeed(Progress)({
|
|
91
|
-
emit: (event) => Effect.sync(() => onEvent(event))
|
|
92
|
-
})
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Accumulates every event into a `Ref`, for assertions.
|
|
96
|
-
*
|
|
97
|
-
* Returned as `
|
|
98
|
-
* transcript afterwards.
|
|
99
|
-
*/
|
|
100
|
-
export const makeCollector = Effect.gen(function*() {
|
|
101
|
-
const ref = yield* Ref.make<ReadonlyArray<ProgressEvent>>([])
|
|
102
|
-
const layer = Layer.succeed(Progress)({
|
|
103
|
-
emit: (event: ProgressEvent) => Ref.update(ref, (events) => [...events, event])
|
|
104
|
-
})
|
|
105
|
-
return { layer, events: Ref.get(ref) } as const
|
|
106
|
-
})
|
|
1
|
+
/**
|
|
2
|
+
* Progress reporting.
|
|
3
|
+
*
|
|
4
|
+
* The engine emits structured events; it never writes to a terminal. That
|
|
5
|
+
* separation is what lets the CLI draw a live TTY view, CI print plain lines,
|
|
6
|
+
* and the test suite assert on an array of events without any of them
|
|
7
|
+
* interfering with each other.
|
|
8
|
+
*/
|
|
9
|
+
import * as Context from "effect/Context"
|
|
10
|
+
import * as Effect from "effect/Effect"
|
|
11
|
+
import * as Layer from "effect/Layer"
|
|
12
|
+
import * as Ref from "effect/Ref"
|
|
13
|
+
import type { Phase } from "./enums/phase.js"
|
|
14
|
+
|
|
15
|
+
/** A structured progress event. */
|
|
16
|
+
export type ProgressEvent =
|
|
17
|
+
/** A phase began. `total` is set only when it is known up front. */
|
|
18
|
+
| { readonly _tag: "PhaseStarted"; readonly phase: Phase; readonly total?: number | undefined }
|
|
19
|
+
/** A phase finished. */
|
|
20
|
+
| { readonly _tag: "PhaseCompleted"; readonly phase: Phase }
|
|
21
|
+
/** The resolver discovered a package that has to be included. */
|
|
22
|
+
| {
|
|
23
|
+
readonly _tag: "PackageResolved"
|
|
24
|
+
readonly name: string
|
|
25
|
+
readonly version: string
|
|
26
|
+
/** Running count of resolved packages, for a live counter. */
|
|
27
|
+
readonly resolvedCount: number
|
|
28
|
+
/** Packages still queued for resolution. */
|
|
29
|
+
readonly pendingCount: number
|
|
30
|
+
}
|
|
31
|
+
/** A tarball download started. */
|
|
32
|
+
| { readonly _tag: "DownloadStarted"; readonly name: string; readonly version: string }
|
|
33
|
+
/** A tarball download finished. */
|
|
34
|
+
| {
|
|
35
|
+
readonly _tag: "DownloadCompleted"
|
|
36
|
+
readonly name: string
|
|
37
|
+
readonly version: string
|
|
38
|
+
readonly bytes: number
|
|
39
|
+
readonly completedCount: number
|
|
40
|
+
readonly totalCount: number
|
|
41
|
+
}
|
|
42
|
+
/** A download failed and will be retried. */
|
|
43
|
+
| {
|
|
44
|
+
readonly _tag: "DownloadRetrying"
|
|
45
|
+
readonly name: string
|
|
46
|
+
readonly version: string
|
|
47
|
+
readonly attempt: number
|
|
48
|
+
readonly reason: string
|
|
49
|
+
}
|
|
50
|
+
/** An archive is being written. */
|
|
51
|
+
| { readonly _tag: "ArchiveStarted"; readonly path: string; readonly entryCount: number }
|
|
52
|
+
/** An archive finished. */
|
|
53
|
+
| { readonly _tag: "ArchiveCompleted"; readonly path: string; readonly bytes: number }
|
|
54
|
+
/** Something noteworthy but non-fatal, e.g. a deprecated package. */
|
|
55
|
+
| { readonly _tag: "Warning"; readonly message: string }
|
|
56
|
+
|
|
57
|
+
export declare namespace Progress {
|
|
58
|
+
/** The reporting sink. */
|
|
59
|
+
export type Service = {
|
|
60
|
+
readonly emit: (event: ProgressEvent) => Effect.Effect<void>
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Service tag for progress reporting. */
|
|
65
|
+
export class Progress extends Context.Service<Progress, Progress.Service>()(
|
|
66
|
+
"@packall/core/Progress"
|
|
67
|
+
) {}
|
|
68
|
+
|
|
69
|
+
/** Emits an event to whichever reporter is installed. */
|
|
70
|
+
export const emit = (event: ProgressEvent): Effect.Effect<void, never, Progress> =>
|
|
71
|
+
Effect.gen(function*() {
|
|
72
|
+
const progress = yield* Progress
|
|
73
|
+
yield* progress.emit(event)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Discards every event.
|
|
78
|
+
*
|
|
79
|
+
* The default for library consumers and for tests that do not care about
|
|
80
|
+
* progress — silence should never require ceremony.
|
|
81
|
+
*/
|
|
82
|
+
export const layerSilent: Layer.Layer<Progress> = Layer.succeed(Progress)({
|
|
83
|
+
emit: () => Effect.void
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
/** Sends every event to a callback. Used by the CLI renderer. */
|
|
87
|
+
export const layerCallback = (
|
|
88
|
+
onEvent: (event: ProgressEvent) => void
|
|
89
|
+
): Layer.Layer<Progress> =>
|
|
90
|
+
Layer.succeed(Progress)({
|
|
91
|
+
emit: (event) => Effect.sync(() => onEvent(event))
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Accumulates every event into a `Ref`, for assertions.
|
|
96
|
+
*
|
|
97
|
+
* Returned as `{ layer, events }` so a test can provide the layer and then read
|
|
98
|
+
* the transcript afterwards.
|
|
99
|
+
*/
|
|
100
|
+
export const makeCollector = Effect.gen(function*() {
|
|
101
|
+
const ref = yield* Ref.make<ReadonlyArray<ProgressEvent>>([])
|
|
102
|
+
const layer = Layer.succeed(Progress)({
|
|
103
|
+
emit: (event: ProgressEvent) => Ref.update(ref, (events) => [...events, event])
|
|
104
|
+
})
|
|
105
|
+
return { layer, events: Ref.get(ref) } as const
|
|
106
|
+
})
|