@gjsify/cli 0.35.0 → 0.37.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.
Files changed (124) hide show
  1. package/dist/cli.gjs.mjs +136 -126
  2. package/lib/actions/build.d.ts +19 -0
  3. package/lib/actions/build.js +2 -2
  4. package/lib/bundler-pick.js +72 -98
  5. package/lib/cli-fail.d.ts +4 -7
  6. package/lib/cli-fail.js +29 -55
  7. package/lib/commands/affected.js +161 -286
  8. package/lib/commands/install.d.ts +63 -66
  9. package/lib/commands/install.js +372 -536
  10. package/lib/commands/run.d.ts +1 -0
  11. package/lib/commands/run.js +37 -0
  12. package/lib/templates/install.mjs.tmpl +38 -68
  13. package/lib/types/cli-build-options.d.ts +33 -67
  14. package/lib/types/command.d.ts +9 -12
  15. package/lib/types/config-data.d.ts +125 -221
  16. package/lib/utils/auth-npmrc.d.ts +5 -10
  17. package/lib/utils/auth-npmrc.js +11 -21
  18. package/lib/utils/check-system-deps.d.ts +16 -0
  19. package/lib/utils/check-system-deps.js +49 -0
  20. package/lib/utils/clear-targets.d.ts +8 -11
  21. package/lib/utils/clear-targets.js +22 -29
  22. package/lib/utils/copy-targets.d.ts +13 -19
  23. package/lib/utils/copy-targets.js +31 -44
  24. package/lib/utils/dep-aggregation.d.ts +7 -15
  25. package/lib/utils/dep-aggregation.js +9 -22
  26. package/lib/utils/detect-native-packages.d.ts +83 -116
  27. package/lib/utils/detect-native-packages.js +111 -149
  28. package/lib/utils/dir-link.d.ts +29 -48
  29. package/lib/utils/dir-link.js +33 -56
  30. package/lib/utils/discover-showcases.d.ts +6 -7
  31. package/lib/utils/discover-showcases.js +11 -15
  32. package/lib/utils/dlx-cache.d.ts +29 -38
  33. package/lib/utils/dlx-cache.js +53 -63
  34. package/lib/utils/force-exit.d.ts +0 -3
  35. package/lib/utils/force-exit.js +13 -24
  36. package/lib/utils/gi-search-path.d.ts +16 -24
  37. package/lib/utils/gi-search-path.js +54 -82
  38. package/lib/utils/gjs-bundle-guard.d.ts +5 -13
  39. package/lib/utils/gjs-bundle-guard.js +35 -57
  40. package/lib/utils/gjs-source-escape.d.ts +2 -2
  41. package/lib/utils/gjs-source-escape.js +21 -39
  42. package/lib/utils/gjsify-shim.d.ts +26 -8
  43. package/lib/utils/gjsify-shim.js +128 -80
  44. package/lib/utils/html-entry.d.ts +8 -12
  45. package/lib/utils/html-entry.js +19 -28
  46. package/lib/utils/install-backend-native.d.ts +123 -161
  47. package/lib/utils/install-backend-native.js +536 -737
  48. package/lib/utils/install-backend.d.ts +42 -57
  49. package/lib/utils/install-backend.js +16 -21
  50. package/lib/utils/install-cache-fs.d.ts +10 -15
  51. package/lib/utils/install-cache-fs.js +18 -26
  52. package/lib/utils/install-lock.d.ts +5 -6
  53. package/lib/utils/install-lock.js +46 -65
  54. package/lib/utils/install-packument-cache.d.ts +27 -33
  55. package/lib/utils/install-packument-cache.js +44 -57
  56. package/lib/utils/install-progress.d.ts +2 -9
  57. package/lib/utils/install-progress.js +14 -39
  58. package/lib/utils/install-tarball-cache.d.ts +14 -20
  59. package/lib/utils/install-tarball-cache.js +41 -59
  60. package/lib/utils/library-output.d.ts +9 -22
  61. package/lib/utils/library-output.js +19 -37
  62. package/lib/utils/load-npmrc.d.ts +5 -6
  63. package/lib/utils/load-npmrc.js +18 -27
  64. package/lib/utils/node-bundle-guard.d.ts +4 -8
  65. package/lib/utils/node-bundle-guard.js +21 -35
  66. package/lib/utils/node-script.d.ts +12 -0
  67. package/lib/utils/node-script.js +95 -0
  68. package/lib/utils/node-version.d.ts +5 -14
  69. package/lib/utils/node-version.js +15 -24
  70. package/lib/utils/normalize-bundler-options.d.ts +7 -11
  71. package/lib/utils/normalize-bundler-options.js +24 -42
  72. package/lib/utils/npm-oidc.d.ts +23 -37
  73. package/lib/utils/npm-oidc.js +28 -53
  74. package/lib/utils/npm-otp-cache.d.ts +4 -4
  75. package/lib/utils/npm-otp-cache.js +20 -25
  76. package/lib/utils/npm-otp.d.ts +20 -30
  77. package/lib/utils/npm-otp.js +32 -51
  78. package/lib/utils/onboard-probe.d.ts +7 -13
  79. package/lib/utils/onboard-probe.js +16 -27
  80. package/lib/utils/parse-spec.d.ts +3 -3
  81. package/lib/utils/parse-spec.js +4 -5
  82. package/lib/utils/pkg-json-edit.d.ts +7 -12
  83. package/lib/utils/pkg-json-edit.js +13 -26
  84. package/lib/utils/pkg-json.d.ts +11 -18
  85. package/lib/utils/pkg-json.js +19 -28
  86. package/lib/utils/prefixed-output.d.ts +3 -4
  87. package/lib/utils/prefixed-output.js +13 -19
  88. package/lib/utils/prompt.d.ts +3 -4
  89. package/lib/utils/prompt.js +14 -18
  90. package/lib/utils/publish-diagnose.d.ts +11 -16
  91. package/lib/utils/publish-diagnose.js +15 -28
  92. package/lib/utils/publish-headers.d.ts +7 -11
  93. package/lib/utils/publish-headers.js +36 -65
  94. package/lib/utils/publishable-packages.d.ts +4 -6
  95. package/lib/utils/publishable-packages.js +14 -18
  96. package/lib/utils/resolve-gjs-entry.d.ts +5 -8
  97. package/lib/utils/resolve-gjs-entry.js +10 -27
  98. package/lib/utils/resolve-npm-package.d.ts +6 -11
  99. package/lib/utils/resolve-npm-package.js +29 -63
  100. package/lib/utils/resolve-plugin-by-name.d.ts +11 -19
  101. package/lib/utils/resolve-plugin-by-name.js +9 -14
  102. package/lib/utils/run-gjs.d.ts +19 -17
  103. package/lib/utils/run-gjs.js +37 -51
  104. package/lib/utils/run-lifecycle-script.d.ts +5 -9
  105. package/lib/utils/run-lifecycle-script.js +23 -42
  106. package/lib/utils/run-node.d.ts +23 -33
  107. package/lib/utils/run-node.js +56 -60
  108. package/lib/utils/runtimes.d.ts +25 -35
  109. package/lib/utils/runtimes.js +34 -46
  110. package/lib/utils/spawn.d.ts +32 -48
  111. package/lib/utils/spawn.js +51 -84
  112. package/lib/utils/stdin.d.ts +2 -2
  113. package/lib/utils/stdin.js +10 -25
  114. package/lib/utils/suggest.d.ts +6 -7
  115. package/lib/utils/suggest.js +8 -10
  116. package/lib/utils/system-gi.d.ts +18 -27
  117. package/lib/utils/system-gi.js +60 -114
  118. package/lib/utils/trust-registry.d.ts +4 -8
  119. package/lib/utils/trust-registry.js +7 -15
  120. package/lib/utils/win32-command.d.ts +8 -14
  121. package/lib/utils/win32-command.js +29 -43
  122. package/lib/utils/workspace-root.js +7 -12
  123. package/package.json +18 -17
  124. package/showcases.json +6 -0
@@ -6,64 +6,57 @@ interface ParsedSpec {
6
6
  range: string;
7
7
  }
8
8
  /**
9
- * One placed package in the resolved tree. Exported as a TYPE only: it is the
10
- * graph shape {@link computeOptionalFlags} and {@link applyPlatformFilter} take,
11
- * so a spec can inject a tree by hand instead of driving a whole install to reach
12
- * them. Nothing outside this module constructs one for real.
9
+ * One placed package in the resolved tree. Exported as a TYPE only, so a spec can
10
+ * hand {@link computeOptionalFlags} and {@link applyPlatformFilter} a graph
11
+ * directly instead of driving a whole install; nothing outside this module
12
+ * constructs one for real.
13
13
  */
14
14
  export interface ResolvedNode {
15
- /** Package name (e.g. `@gjsify/cli`, `lodash`). */
16
15
  name: string;
17
16
  version: string;
18
17
  tarballUrl: string;
19
18
  integrity?: string;
20
- /** Where this node lives relative to the install prefix. Always
21
- * starts with `node_modules/`; nested entries look like
22
- * `node_modules/<parent>/node_modules/<dep>`. */
19
+ /** Relative to the install prefix. Always starts with `node_modules/`; nested
20
+ * entries look like `node_modules/<parent>/node_modules/<dep>`. */
23
21
  installPath: string;
24
- /** `dependencies` field from the packument (range strings keyed by name). */
22
+ /** Ranges keyed by name, as published. */
25
23
  dependencies: Record<string, string>;
26
- /** `optionalDependencies` field from the packument. */
27
24
  optionalDependencies: Record<string, string>;
28
25
  bin?: string | Record<string, string>;
29
26
  /**
30
- * The version's `os`/`cpu`/`libc` declaration, as published. Recorded on the
31
- * node (and in the lockfile) so the compatibility VERDICT can be recomputed
32
- * for whichever host runs the install — see the header note on portability.
27
+ * The version's `os`/`cpu`/`libc` declaration, as published. Recorded here
28
+ * (and in the lockfile) so the VERDICT can be recomputed for whichever host
29
+ * runs the install — header note on portability.
33
30
  *
34
- * Read from the FULL packument, which is the only document that carries
35
- * `libc`. That is not an optimisation detail leaking into a comment: the
36
- * abbreviated document can never PROVE the absence of a `libc` restriction,
37
- * so a declaration built from it would be silently incomplete for exactly
38
- * the packages the field exists for (this repo publishes nine of them —
39
- * `@gjsify/{rolldown,lightningcss,oxfmt}-native`, `webgl`, `napi`,
40
- * `sab-native`, `terminal-native`, `http2-native`, `http-soup-bridge` all
41
- * declare `libc: ["glibc"]` and NO `os`/`cpu`).
31
+ * Read from the FULL packument, the only document carrying `libc`: the
32
+ * abbreviated one can never PROVE a `libc` restriction is absent, so a
33
+ * declaration built from it is silently incomplete for exactly the packages
34
+ * the field exists for (nine of this repo's own — `@gjsify/{rolldown,
35
+ * lightningcss,oxfmt}-native`, `webgl`, `napi`, `sab-native`,
36
+ * `terminal-native`, `http2-native`, `http-soup-bridge` — declare
37
+ * `libc: ["glibc"]` and NO `os`/`cpu`).
42
38
  */
43
39
  platform?: PlatformDeclaration;
44
40
  /**
45
41
  * Is this node reachable ONLY through optionalDependency edges? Decides what
46
- * an incompatible platform means: skip silently (optional) vs. fail the
47
- * install (required). npm calls the same set `optionalSet`.
42
+ * an incompatible platform means: skip silently vs. fail the install. npm
43
+ * calls the same set `optionalSet`.
48
44
  *
49
45
  * DERIVED, not an input — {@link computeOptionalFlags} recomputes it as a
50
- * fixpoint over the placed graph before anything reads it, on the fresh-
51
- * resolve AND the lockfile path. The value the BFS assigns at placement time
52
- * is a forward guess used only to decide whether a resolve FAILURE under this
53
- * node is tolerated; it is edge-order-dependent and must never be the final
54
- * answer (header note, invariant 2).
46
+ * fixpoint on both the fresh-resolve and the lockfile path before anything
47
+ * reads it. What the BFS assigns at placement time is a forward guess, used
48
+ * only to decide whether a resolve FAILURE under this node is tolerated.
55
49
  *
56
- * OPTIONAL FIELD, and absent must read as `false` (= required): nodes are
57
- * also built structurally by callers that only care about name/installPath,
58
- * and the safe default for an unknown edge kind is the loud one — a required
59
- * incompatible dependency fails the install instead of being silently
60
- * dropped from the tree.
50
+ * Absent must read as `false` (= required): callers also build nodes
51
+ * structurally caring only about name/installPath, and the safe default for
52
+ * an unknown edge kind is the loud one — a required incompatible dependency
53
+ * fails the install instead of vanishing from the tree.
61
54
  */
62
55
  optional?: boolean;
63
56
  /**
64
- * Set by {@link applyPlatformFilter}: this node cannot run on the install
65
- * target, so it is not downloaded or extracted. Never persisted — it is a
66
- * per-host verdict, not a property of the resolution.
57
+ * Set by {@link applyPlatformFilter}: not runnable on the install target, so
58
+ * not downloaded or extracted. Never persisted — a per-host verdict, not a
59
+ * property of the resolution.
67
60
  */
68
61
  inert?: boolean;
69
62
  }
@@ -74,21 +67,19 @@ export interface InstalledTopLevel {
74
67
  /**
75
68
  * {@link InstallOptions} plus what only the NATIVE backend can use.
76
69
  *
77
- * `optionalSpecs` exists because a spec is a flat `"<name>@<range>"` string by
78
- * the time it reaches here — `projectSpecsFromPackageJson` flattens
79
- * `dependencies`, `devDependencies` and `optionalDependencies` into one list —
80
- * yet the KIND decides what an incompatible `os`/`cpu`/`libc` means: an optional
81
- * dependency is skipped, a required one fails the install. The shape that makes
82
- * this concrete is `optionalDependencies: { fsevents }` in a project's own
83
- * manifest: on Linux npm leaves fsevents out and installs fine, so treating
84
- * every top-level spec as required would turn that into a hard EBADPLATFORM for
85
- * a package nothing on the host would ever load.
70
+ * `optionalSpecs` exists because a spec is a flat `"<name>@<range>"` string by the
71
+ * time it reaches here (`projectSpecsFromPackageJson` flattens `dependencies`,
72
+ * `devDependencies` and `optionalDependencies` into one list), yet the KIND
73
+ * decides what an incompatible `os`/`cpu`/`libc` means — skipped vs. fatal. The
74
+ * live shape is `optionalDependencies: { fsevents }` in a project manifest: npm
75
+ * leaves fsevents out on Linux and installs fine, so treating every top-level
76
+ * spec as required turns that into a hard EBADPLATFORM for a package nothing on
77
+ * the host would load.
86
78
  *
87
- * It rides the SAME options object `install-backend.ts` forwards wholesale to
88
- * this function. If that forwarding is ever changed to destructure, this field
89
- * must be forwarded with it — otherwise top-level optional deps quietly become
90
- * required again (and the `install-platform-filter` e2e goes red, which is where
91
- * that assumption is pinned).
79
+ * It rides the SAME options object `install-backend.ts` forwards wholesale here.
80
+ * If that forwarding is ever changed to destructure, this field must be forwarded
81
+ * with it, or top-level optional deps quietly become required again — the
82
+ * `install-platform-filter` e2e is where that assumption is pinned.
92
83
  */
93
84
  export interface NativeInstallOptions extends InstallOptions {
94
85
  /**
@@ -100,115 +91,90 @@ export interface NativeInstallOptions extends InstallOptions {
100
91
  }
101
92
  export declare function installPackagesNative(opts: NativeInstallOptions): Promise<InstalledTopLevel[]>;
102
93
  /**
103
- * Split a resolved tree into what THIS target can install, marking the rest
104
- * inert. Mirrors arborist's post-resolve platform pass
105
- * (`refs/npm-cli/workspaces/arborist/lib/arborist/build-ideal-tree.js`, the
106
- * `checkPlatform` loop around line 210) rather than filtering during the walk,
107
- * for two reasons: the verdict must be identical whether the tree came from a
108
- * fresh resolve or from `gjsify-lock.json`, and a node's optionality is only
109
- * final once every edge that could reach it has been visited.
94
+ * Split a resolved tree into what THIS target can install, marking the rest inert.
95
+ * A post-pass rather than a filter during the walk (as in arborist's
96
+ * `refs/npm-cli/workspaces/arborist/lib/arborist/build-ideal-tree.js`) for two
97
+ * reasons: the verdict must be identical whether the tree came from a fresh
98
+ * resolve or from `gjsify-lock.json`, and a node's optionality is only final once
99
+ * every edge that could reach it has been visited.
110
100
  *
111
101
  * The two outcomes are npm's, including the asymmetry around `force`:
112
- * - REQUIRED + incompatible → EBADPLATFORM. A required dependency the host
113
- * cannot run is a broken install, not a smaller one; failing loudly with
114
- * `pkgid`/`current`/`required` is the only honest answer. `--force`
115
- * suppresses it (the user is asserting something about their own machine).
116
- * - OPTIONAL + incompatible → inert: not downloaded, not extracted, still in
117
- * the lockfile. `--force` does NOT lift this — npm says so in as many words
118
- * ("We ignore the --force and --engine-strict flags") and it is right:
119
- * forcing an optional binary that cannot load buys a download and nothing
120
- * else.
102
+ * - REQUIRED + incompatible → EBADPLATFORM. A required dep the host cannot run
103
+ * is a broken install, not a smaller one, so it fails loudly with
104
+ * `pkgid`/`current`/`required`. `--force` suppresses it (the user is asserting
105
+ * something about their own machine).
106
+ * - OPTIONAL + incompatible → inert: not downloaded, not extracted, still in the
107
+ * lockfile. `--force` does NOT lift this — npm says so in as many words ("We
108
+ * ignore the --force and --engine-strict flags"), and forcing an optional
109
+ * binary that cannot load buys a download and nothing else.
121
110
  *
122
- * The skip line goes through the debug logger with npm's `current`/`required`
123
- * payload, so `--verbose` recovers exactly WHY a package is absent. Silence
124
- * here is what made the original defect invisible in the other direction: 3.67
125
- * GB arrived with no line saying it should not have.
111
+ * The skip line carries npm's `current`/`required` payload so `--verbose` recovers
112
+ * WHY a package is absent. Silence here is what made the original defect invisible
113
+ * in the other direction: 3.67 GB arrived with no line saying it should not have.
126
114
  */
127
115
  export declare function applyPlatformFilter(nodes: ResolvedNode[], target: PlatformTarget, force: boolean, log: Logger): ResolvedNode[];
128
116
  /**
129
117
  * Warn about a native package that installed WITHOUT a usable binary.
130
118
  *
131
- * gjsify install is node-free (it runs under GJS) and does NOT run a package's
132
- * `install`/`postinstall` lifecycle script — running e.g. `node-gyp rebuild` would
133
- * need Node + a C++ toolchain, breaking that property (see the header's "out of
134
- * scope"). Such a package works only if it SHIPS a prebuild for the platform (the
135
- * sanctioned path — `prebuilds/<platform>-<arch>/…`) or is later built by hand. When
136
- * neither is present the package silently loads no binary (the `@gjsify/node-gi
137
- * 0.21.0` case: installed, but `node_gi.node` absent → the consumer hit a runtime
138
- * failure with no hint). Surface it at install time with an actionable line. Pure
139
- * detection — no script is run, so node-free-ness is preserved.
119
+ * This install is node-free and does NOT run `install`/`postinstall` scripts —
120
+ * `node-gyp rebuild` would need Node plus a C++ toolchain. Such a package works
121
+ * only if it SHIPS a prebuild (`prebuilds/<platform>-<arch>/…`) or is built by
122
+ * hand; with neither it silently loads no binary, as `@gjsify/node-gi 0.21.0` did
123
+ * (installed, `node_gi.node` absent, consumer hit a runtime failure with no hint).
124
+ * Pure detection — no script is run, so node-free-ness is preserved.
140
125
  */
141
126
  export declare function warnMissingNativeBuilds(nodes: ResolvedNode[], prefix: string, log: Logger): void;
142
127
  /**
143
- * A node's REQUIRED dependency edges: its `dependencies`, minus every name its
144
- * `optionalDependencies` also lists. The one place that decides what kind an edge
145
- * is — both the resolve walk and the optionality fixpoint read it, so the two
146
- * cannot drift.
128
+ * A node's REQUIRED dependency edges: its `dependencies` minus every name its
129
+ * `optionalDependencies` also lists. The ONE place that decides an edge's kind —
130
+ * both the resolve walk and the optionality fixpoint read it, so they cannot drift.
147
131
  *
148
- * THE SUBTRACTION IS npm's RULE, not a policy of ours: "entries in
149
- * optionalDependencies will override entries of the same name in dependencies, so
150
- * it's usually best to only put in one place" (npm's package.json docs). Measured
151
- * on `@parcel/rust@2.16.4`, which lists all eight per-platform napi packages in
152
- * both blocks: `npm install` exits 0, installs `@parcel/rust-linux-x64-gnu` only,
153
- * and writes `"optional": true` for all eight in its `package-lock.json`.
132
+ * The subtraction is npm's rule, not ours: "entries in optionalDependencies will
133
+ * override entries of the same name in dependencies" (npm's package.json docs).
154
134
  *
155
- * WHY IT IS NOT MERELY A DEDUP: the kind decides what an incompatible
156
- * `os`/`cpu`/`libc` MEANS (`applyPlatformFilter` — fatal vs. inert) and whether a
157
- * failed resolve is tolerated. Reading `dependencies` alone therefore does not
158
- * just visit a name twice, it promotes a foreign-platform binary to a required
159
- * dependency and fails installs npm completes.
135
+ * NOT MERELY A DEDUP: the kind decides what an incompatible `os`/`cpu`/`libc` MEANS
136
+ * (fatal vs. inert in `applyPlatformFilter`) and whether a failed resolve is
137
+ * tolerated. Reading `dependencies` alone does not just visit a name twice, it
138
+ * promotes a foreign-platform binary to a required dependency and fails installs npm
139
+ * completes — the header note's invariant 3.
160
140
  *
161
- * The inverse direction is deliberately NOT symmetric: a name in
162
- * `optionalDependencies` alone is optional (no `dependencies` entry to override),
163
- * which is what {@link resolveDeps}'s second queue loop covers.
141
+ * Deliberately NOT symmetric: a name in `optionalDependencies` alone is optional (no
142
+ * `dependencies` entry to override), covered by {@link resolveDeps}'s second queue loop.
164
143
  */
165
144
  export declare function requiredDepEntries(node: Pick<ResolvedNode, 'dependencies' | 'optionalDependencies'>): [string, string][];
166
145
  /**
167
- * Recompute every node's `optional` flag as a FIXPOINT over the placed graph.
168
- * The only writer of the final flag; whatever the nodes arrive carrying is an
169
- * input nothing checked (a BFS forward guess on the resolve path, a value read
170
- * back out of a file on the lockfile path) and is overwritten unconditionally.
146
+ * Recompute every node's `optional` flag as a FIXPOINT over the placed graph. The
147
+ * only writer of the final flag; whatever the nodes arrive carrying is an input
148
+ * nothing checked (a BFS forward guess on the resolve path, a value read out of a
149
+ * file on the lockfile path) and is overwritten unconditionally.
171
150
  *
172
- * DEFINITION: a node is REQUIRED iff it is reachable from `requiredNames`
173
- * through REQUIRED edges alone ({@link requiredDepEntries} — `dependencies` minus
174
- * the names `optionalDependencies` overrides); every other node is optional.
175
- * Optionality is therefore INHERITED — a plain dependency OF an optional package
176
- * is still optional — which is what npm's `optionalSet` computes.
151
+ * DEFINITION: a node is REQUIRED iff reachable from `requiredNames` through
152
+ * REQUIRED edges alone ({@link requiredDepEntries}); every other node is optional.
153
+ * Optionality is therefore INHERITED — a plain dependency OF an optional package is
154
+ * still optional, which is what npm's `optionalSet` computes.
177
155
  *
178
156
  * WHY A FIXPOINT AND NOT A ONE-SHOT PROMOTION AT THE REUSE SITE (the reviewed
179
- * defect): the walk queues a node's own dep edges at the moment it is placed,
180
- * carrying the optionality it had THEN. Promoting the node later leaves its
181
- * children behind, so the answer depends on which edge BFS happened to traverse
182
- * first — a genuinely required transitive dep reached first through an optional
183
- * edge stayed flagged optional, was persisted that way, and was then silently
184
- * skipped by the platform filter on every machine instead of raising
185
- * EBADPLATFORM. A monotone worklist over the FINISHED graph cannot have that
186
- * property: "required" only ever spreads, so the result is independent of visit
187
- * order. npm reaches for the same shape and says so —
188
- * refs/npm-cli/workspaces/arborist/lib/calc-dep-flags.js: "If a node is changed,
189
- * we add to the queue and continue until no more changes."
157
+ * defect): the walk queues a node's dep edges when it is placed, carrying the
158
+ * optionality it had THEN, so promoting the node later leaves its children behind and
159
+ * the answer depends on which edge BFS traversed first. A required transitive dep
160
+ * reached first through an optional edge stayed flagged optional, was persisted that
161
+ * way, and was then silently skipped by the platform filter on every machine instead
162
+ * of raising EBADPLATFORM. A monotone worklist over the FINISHED graph cannot have
163
+ * that property: "required" only ever spreads, so the result is order-independent.
164
+ * Same shape as refs/npm-cli/workspaces/arborist/lib/calc-dep-flags.js.
190
165
  *
191
- * PATH-INDEPENDENCE IS THE OTHER REQUIREMENT, and it is why the lockfile carries
192
- * an `optionalDependencies` map per entry (v4). The walk USED to read
193
- * `dependencies` only, for exactly that reason — a lockfile entry recorded nothing
194
- * else, so consulting `node.optionalDependencies` would have made the two paths
195
- * compute different flags for the same tree. The premise was fixable and the
196
- * consequence was not: a publisher listing the same name in BOTH blocks means
197
- * "optional" to npm, came out REQUIRED here, and the shape is not rare — it is
198
- * `@parcel/rust@2.16.4` (all eight per-platform napi packages in both blocks), so
199
- * every Linux install of any tree containing parcel failed with EBADPLATFORM on
200
- * `@parcel/rust-darwin-x64` while `npm install` thinned the same tree and exited
201
- * 0. "Erring toward REQUIRED errs toward the loud failure" is true and was the
202
- * wrong trade: the loud failure was not a real one, and no `--force` lifts it
203
- * (nor should it). So the declaration is persisted and both paths subtract it.
204
- * Reading a pre-v4 lockfile leaves the map empty, which reproduces the old
205
- * behaviour for that file alone — see READABLE_LOCKFILE_VERSIONS.
166
+ * PATH-INDEPENDENCE is the other requirement, and why the lockfile carries an
167
+ * `optionalDependencies` map per entry (v4). This walk USED to read `dependencies`
168
+ * only, because a lockfile entry recorded nothing else and consulting
169
+ * `node.optionalDependencies` would have made the two paths compute different flags
170
+ * for one tree. That premise was fixable and its consequence — a both-blocks name
171
+ * coming out REQUIRED — was not (header note, invariant 3). A pre-v4 lockfile leaves
172
+ * the map empty and reproduces the old behaviour for that file alone
173
+ * (READABLE_LOCKFILE_VERSIONS).
206
174
  *
207
- * Runs before `writeLockfile` so the persisted flag is the final one, and before
208
- * `applyPlatformFilter` so the fatal-vs-inert decision reads it rather than the
209
- * guess. Exported so the unit spec can drive it with INJECTED graphs: the whole
210
- * fatal-vs-inert question is decided by these two functions in composition, and
211
- * that is worth pinning without a registry.
175
+ * Exported so the unit spec can drive it with INJECTED graphs — the whole
176
+ * fatal-vs-inert question is decided by this and `applyPlatformFilter` in
177
+ * composition, worth pinning without a registry.
212
178
  */
213
179
  export declare function computeOptionalFlags(nodes: ResolvedNode[], requiredNames: Set<string>, log: Logger): void;
214
180
  export declare function parseSpec(raw: string): ParsedSpec;
@@ -216,20 +182,18 @@ export declare function pickVersion(packument: Packument, range: string, preferr
216
182
  /**
217
183
  * Materialise ONE `node_modules/.bin/<name>` entry for `targetAbs`.
218
184
  *
219
- * Exported (and platform-injectable) so the Windows branch is unit-tested from
220
- * a Linux host — the file layout and shim contents are asserted there; only the
221
- * `symlinkSync`/`CreateSymbolicLink` syscall behaviour itself is OS-bound.
185
+ * Exported and platform-injectable so the Windows branch is unit-tested from a Linux
186
+ * host; only the `symlinkSync`/`CreateSymbolicLink` syscall itself is OS-bound.
222
187
  *
223
- * POSIX: a relative symlink, with a copy as the fallback (some filesystems and
224
- * container overlays reject symlinks).
188
+ * POSIX: a relative symlink, falling back to a copy (some filesystems and container
189
+ * overlays reject symlinks).
225
190
  *
226
- * Windows: `.bin/<name>` is not on `PATHEXT` and Windows has no shebang
227
- * handling, so a symlink OR a copy of a `#!/usr/bin/env node` script is
228
- * unrunnable — and a *file* symlink additionally needs elevation or Developer
229
- * Mode, so the previous code reliably fell into its copy fallback and produced
230
- * a dead entry. npm solves this with three sibling files (`<name>` for
231
- * git-bash/MSYS/WSL, `<name>.cmd` for cmd.exe, `<name>.ps1` for pwsh); we write
232
- * the same set from the same templates. See `./bin-shim.ts`.
191
+ * Windows: `.bin/<name>` is not on `PATHEXT` and Windows has no shebang handling, so a
192
+ * symlink OR a copy of a `#!/usr/bin/env node` script is unrunnable — and a *file*
193
+ * symlink additionally needs elevation or Developer Mode, so the previous code reliably
194
+ * fell into its copy fallback and produced a dead entry. npm's answer is three sibling
195
+ * files (`<name>` for git-bash/MSYS/WSL, `<name>.cmd` for cmd.exe, `<name>.ps1` for
196
+ * pwsh); the same set is written from the same templates (`./bin-shim.ts`).
233
197
  */
234
198
  export declare function writeBinEntry(opts: {
235
199
  binDir: string;
@@ -237,25 +201,23 @@ export declare function writeBinEntry(opts: {
237
201
  targetAbs: string;
238
202
  platform?: string;
239
203
  /**
240
- * Set when this entry is the package's GJS-runnable artifact (declared via
241
- * `gjsify.bin`). Then the entry is a GENERATED launcher rather than a link
242
- * to a file with a shebang — see {@link buildShLauncher} for why, and
243
- * {@link pickBinMap} for why `gjsify.bin` has to win here at all.
204
+ * Set when this entry is the package's GJS-runnable artifact (`gjsify.bin`), making
205
+ * it a GENERATED launcher rather than a link to a file with a shebang — see
206
+ * {@link buildShLauncher} for why, {@link pickBinMap} for why `gjsify.bin` wins.
244
207
  *
245
- * The preamble is what exports `GI_TYPELIB_PATH` / the loader path before
246
- * `gjs` starts. It cannot be done from inside the bundle: GI resolves the
247
- * typelib while the runtime boots, before the first line runs.
208
+ * The preamble exports `GI_TYPELIB_PATH` / the loader path before `gjs` starts. It
209
+ * cannot be done from inside the bundle: GI resolves the typelib while the runtime
210
+ * boots, before the first line runs.
248
211
  */
249
212
  gjs?: {
250
213
  envPreamble: string;
251
214
  prebuildDirs: readonly string[];
252
215
  };
253
216
  /**
254
- * The package's npm `bin` target, when it declares one ALONGSIDE
255
- * `gjsify.bin`. The launcher then picks a runtime per invocation instead of
256
- * hard-coding `gjs` — see {@link pickBinMap}. Absent for a package that
257
- * declares only one of the two, which is every package but `@gjsify/cli`
258
- * today.
217
+ * The package's npm `bin` target when it declares one ALONGSIDE `gjsify.bin`; the
218
+ * launcher then picks a runtime per invocation instead of hard-coding `gjs` (see
219
+ * {@link pickBinMap}). Absent for a package declaring only one of the two, which is
220
+ * every package but `@gjsify/cli` today.
259
221
  */
260
222
  nodeFallbackAbs?: string;
261
223
  }): void;