nx 23.1.0 → 23.1.2
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/bin/nx.js +2 -1
- package/dist/release/changelog-renderer/index.js +4 -5
- package/dist/release/index.d.ts +1 -1
- package/dist/src/ai/configure-ai-agents-disclaimer.d.ts +5 -0
- package/dist/src/ai/configure-ai-agents-disclaimer.js +31 -0
- package/dist/src/analytics/analytics.d.ts +6 -0
- package/dist/src/analytics/analytics.js +16 -8
- package/dist/src/analytics/index.d.ts +1 -1
- package/dist/src/analytics/index.js +2 -1
- package/dist/src/command-line/add/add.js +13 -1
- package/dist/src/command-line/affected/affected.js +1 -0
- package/dist/src/command-line/configure-ai-agents/configure-ai-agents.js +2 -2
- package/dist/src/command-line/graph/graph.d.ts +1 -0
- package/dist/src/command-line/graph/graph.js +15 -6
- package/dist/src/command-line/import/import.js +2 -3
- package/dist/src/command-line/init/ai-agent-prompts.d.ts +1 -1
- package/dist/src/command-line/init/ai-agent-prompts.js +7 -6
- package/dist/src/command-line/init/command-object.js +10 -2
- package/dist/src/command-line/init/configure-plugins.js +3 -2
- package/dist/src/command-line/init/implementation/add-nx-to-monorepo.js +4 -2
- package/dist/src/command-line/init/implementation/add-nx-to-nest.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-npm-repo.js +4 -3
- package/dist/src/command-line/init/implementation/add-nx-to-turborepo.js +4 -3
- package/dist/src/command-line/init/implementation/angular/index.js +4 -2
- package/dist/src/command-line/init/implementation/angular/integrated-workspace.js +2 -5
- package/dist/src/command-line/init/implementation/angular/legacy-angular-versions.js +3 -0
- package/dist/src/command-line/init/implementation/dot-nx/add-nx-scripts.js +4 -1
- package/dist/src/command-line/init/implementation/utils.d.ts +3 -3
- package/dist/src/command-line/init/implementation/utils.js +22 -3
- package/dist/src/command-line/init/init-v2.js +4 -5
- package/dist/src/command-line/migrate/execute-migration.d.ts +72 -0
- package/dist/src/command-line/migrate/execute-migration.js +389 -0
- package/dist/src/command-line/migrate/migrate-ui-api.js +17 -12
- package/dist/src/command-line/migrate/migrate.d.ts +5 -45
- package/dist/src/command-line/migrate/migrate.js +122 -402
- package/dist/src/command-line/nx-cloud/connect/connect-to-nx-cloud.js +1 -1
- package/dist/src/command-line/nx-cloud/connect/view-logs.js +2 -0
- package/dist/src/command-line/release/changelog.js +5 -0
- package/dist/src/command-line/release/index.d.ts +1 -1
- package/dist/src/command-line/release/utils/git.js +7 -3
- package/dist/src/command-line/release/utils/release-graph.d.ts +19 -2
- package/dist/src/command-line/release/utils/release-graph.js +71 -19
- package/dist/src/command-line/release/utils/remote-release-clients/github.js +7 -1
- package/dist/src/command-line/release/utils/remote-release-clients/gitlab.js +1 -1
- package/dist/src/command-line/release/utils/shared.d.ts +2 -2
- package/dist/src/command-line/release/version/release-group-processor.d.ts +24 -0
- package/dist/src/command-line/release/version/release-group-processor.js +80 -6
- package/dist/src/command-line/release/version/version-actions.d.ts +27 -2
- package/dist/src/command-line/release/version/version-actions.js +9 -1
- package/dist/src/command-line/release/version.js +9 -5
- package/dist/src/command-line/reset/reset.js +6 -1
- package/dist/src/command-line/run/run-one.js +1 -0
- package/dist/src/command-line/run-many/run-many.js +1 -0
- package/dist/src/command-line/show/show-target/info.js +11 -2
- package/dist/src/command-line/show/show-target/inputs.js +50 -153
- package/dist/src/command-line/show/show-target/outputs.js +48 -173
- package/dist/src/command-line/show/show-target/utils.d.ts +28 -0
- package/dist/src/command-line/show/show-target/utils.js +83 -3
- package/dist/src/command-line/watch/watch.js +13 -0
- package/dist/src/command-line/yargs-utils/shared-options.d.ts +1 -1
- package/dist/src/commands-runner/create-command-graph.js +5 -0
- package/dist/src/config/nx-json.d.ts +5 -3
- package/dist/src/core/graph/main.js +1 -1
- package/dist/src/core/graph/styles.js +1 -1
- package/dist/src/daemon/client/client.d.ts +52 -3
- package/dist/src/daemon/client/client.js +177 -55
- package/dist/src/daemon/client/daemon-environment.d.ts +17 -0
- package/dist/src/daemon/client/daemon-environment.js +110 -2
- package/dist/src/daemon/client/daemon-socket-messenger.js +4 -0
- package/dist/src/daemon/message-types/daemon-message.d.ts +32 -0
- package/dist/src/daemon/message-types/daemon-message.js +25 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.d.ts +5 -0
- package/dist/src/daemon/server/file-watching/file-watcher-sockets.js +16 -0
- package/dist/src/daemon/server/handle-tasks-execution-hooks.d.ts +1 -1
- package/dist/src/daemon/server/latest-nx.js +5 -2
- package/dist/src/daemon/server/server.js +31 -4
- package/dist/src/daemon/server/shutdown-utils.d.ts +5 -0
- package/dist/src/daemon/server/shutdown-utils.js +11 -4
- package/dist/src/daemon/socket-utils.d.ts +1 -0
- package/dist/src/daemon/socket-utils.js +24 -3
- package/dist/src/daemon/tmp-dir.d.ts +43 -3
- package/dist/src/daemon/tmp-dir.js +437 -15
- package/dist/src/devkit-internals.d.ts +96 -3
- package/dist/src/devkit-internals.js +200 -4
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.d.ts +5 -0
- package/dist/src/generators/internal-utils/format-changed-files-with-prettier-if-available.js +9 -2
- package/dist/src/generators/tree.d.ts +4 -2
- package/dist/src/generators/utils/nx-json.js +13 -3
- package/dist/src/hasher/check-task-files.d.ts +86 -0
- package/dist/src/hasher/check-task-files.js +378 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.d.ts +12 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.js +250 -0
- package/dist/src/migrations/update-23-2-0/set-cache-on-executor-target-defaults.md +50 -0
- package/dist/src/native/index.d.ts +31 -2
- package/dist/src/native/index.js +71 -28
- package/dist/src/native/native-bindings.js +3 -0
- package/dist/src/native/native-file-cache-location.d.ts +17 -1
- package/dist/src/native/native-file-cache-location.js +86 -12
- package/dist/src/native/nx.wasm32-wasi.debug.wasm +0 -0
- package/dist/src/native/nx.wasm32-wasi.wasm +0 -0
- package/dist/src/nx-cloud/utilities/get-cloud-options.js +5 -2
- package/dist/src/nx-cloud/utilities/onboarding.js +5 -2
- package/dist/src/plugins/js/lock-file/bun-parser.js +43 -10
- package/dist/src/plugins/js/lock-file/npm-parser.js +71 -27
- package/dist/src/plugins/js/lock-file/pnpm-parser.js +110 -17
- package/dist/src/plugins/js/lock-file/project-graph-pruning.js +15 -9
- package/dist/src/plugins/js/lock-file/utils/pnpm-normalizer.js +3 -0
- package/dist/src/plugins/js/lock-file/yarn-parser.js +32 -5
- package/dist/src/plugins/js/project-graph/affected/npm-packages.js +51 -20
- package/dist/src/plugins/js/project-graph/build-dependencies/target-project-locator.js +14 -4
- package/dist/src/plugins/js/utils/register.d.ts +18 -0
- package/dist/src/plugins/js/utils/register.js +81 -0
- package/dist/src/plugins/js/utils/typescript.d.ts +9 -0
- package/dist/src/plugins/js/utils/typescript.js +15 -0
- package/dist/src/project-graph/affected/affected-project-graph-models.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.d.ts +1 -1
- package/dist/src/project-graph/affected/affected-project-graph.js +2 -2
- package/dist/src/project-graph/affected/locators/project-glob-changes.js +5 -2
- package/dist/src/project-graph/build-project-graph.js +7 -1
- package/dist/src/project-graph/error-types.d.ts +12 -1
- package/dist/src/project-graph/error-types.js +68 -3
- package/dist/src/project-graph/file-utils.js +6 -1
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.d.ts +1 -0
- package/dist/src/project-graph/plugins/isolation/isolated-plugin.js +22 -1
- package/dist/src/project-graph/plugins/isolation/messaging.d.ts +16 -3
- package/dist/src/project-graph/plugins/isolation/messaging.js +3 -0
- package/dist/src/project-graph/plugins/isolation/plugin-worker.js +58 -8
- package/dist/src/project-graph/plugins/loaded-nx-plugin.js +1 -0
- package/dist/src/project-graph/plugins/transpiler.js +4 -0
- package/dist/src/project-graph/project-graph.js +23 -0
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.d.ts +10 -12
- package/dist/src/project-graph/utils/project-configuration/name-substitution-manager.js +93 -63
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.d.ts +5 -8
- package/dist/src/project-graph/utils/project-configuration/project-nodes-manager.js +16 -15
- package/dist/src/project-graph/utils/project-configuration/source-maps.d.ts +12 -5
- package/dist/src/project-graph/utils/project-configuration/source-maps.js +21 -7
- package/dist/src/project-graph/utils/project-configuration/target-defaults.d.ts +1 -1
- package/dist/src/project-graph/utils/project-configuration/target-defaults.js +26 -27
- package/dist/src/project-graph/utils/project-configuration/target-merging.js +50 -8
- package/dist/src/project-graph/utils/project-configuration/target-normalization.js +149 -6
- package/dist/src/project-graph/utils/project-configuration/utils.d.ts +15 -0
- package/dist/src/project-graph/utils/project-configuration/utils.js +42 -6
- package/dist/src/project-graph/utils/project-configuration-utils.d.ts +15 -12
- package/dist/src/project-graph/utils/project-configuration-utils.js +79 -101
- package/dist/src/tasks-runner/life-cycles/performance-analysis.d.ts +11 -4
- package/dist/src/tasks-runner/life-cycles/performance-analysis.js +15 -6
- package/dist/src/tasks-runner/life-cycles/performance-life-cycle.js +5 -4
- package/dist/src/tasks-runner/life-cycles/performance-report.d.ts +18 -8
- package/dist/src/tasks-runner/life-cycles/performance-report.js +66 -29
- package/dist/src/tasks-runner/run-command.js +4 -2
- package/dist/src/tasks-runner/task-env.d.ts +9 -0
- package/dist/src/tasks-runner/task-env.js +31 -4
- package/dist/src/tasks-runner/task-orchestrator.d.ts +4 -1
- package/dist/src/tasks-runner/task-orchestrator.js +23 -10
- package/dist/src/tasks-runner/utils.js +2 -6
- package/dist/src/utils/acknowledge-build-scripts.d.ts +13 -0
- package/dist/src/utils/acknowledge-build-scripts.js +102 -0
- package/dist/src/utils/analytics-prompt.d.ts +0 -6
- package/dist/src/utils/analytics-prompt.js +0 -51
- package/dist/src/utils/assert-workspace-validity.js +7 -2
- package/dist/src/utils/catalog/manager-utils.d.ts +1 -2
- package/dist/src/utils/catalog/manager-utils.js +22 -5
- package/dist/src/utils/catalog/pnpm-manager.d.ts +1 -0
- package/dist/src/utils/catalog/pnpm-manager.js +3 -15
- package/dist/src/utils/catalog/yarn-manager.d.ts +1 -0
- package/dist/src/utils/catalog/yarn-manager.js +3 -15
- package/dist/src/utils/command-line-utils.js +30 -20
- package/dist/src/utils/fileutils.d.ts +5 -0
- package/dist/src/utils/fileutils.js +7 -2
- package/dist/src/utils/git-revision.d.ts +12 -0
- package/dist/src/utils/git-revision.js +25 -0
- package/dist/src/utils/git-utils.d.ts +16 -3
- package/dist/src/utils/git-utils.js +146 -52
- package/dist/src/utils/git-worktrees.d.ts +30 -0
- package/dist/src/utils/git-worktrees.js +212 -0
- package/dist/src/utils/ignore.d.ts +128 -1
- package/dist/src/utils/ignore.js +182 -12
- package/dist/src/utils/long-running-target.d.ts +10 -0
- package/dist/src/utils/long-running-target.js +19 -0
- package/dist/src/utils/min-release-age/behavior/bun.js +7 -11
- package/dist/src/utils/min-release-age/behavior/npm.js +5 -2
- package/dist/src/utils/min-release-age/behavior/pnpm.js +9 -7
- package/dist/src/utils/min-release-age/packument.js +1 -1
- package/dist/src/utils/nx-tmp-dir.d.ts +18 -0
- package/dist/src/utils/nx-tmp-dir.js +40 -0
- package/dist/src/utils/owned-private-dir.d.ts +132 -0
- package/dist/src/utils/owned-private-dir.js +323 -0
- package/dist/src/utils/package-json.js +11 -7
- package/dist/src/utils/package-manager-config/bunfig.d.ts +14 -0
- package/dist/src/utils/package-manager-config/bunfig.js +49 -0
- package/dist/src/utils/package-manager-config/npmrc.d.ts +23 -0
- package/dist/src/utils/package-manager-config/npmrc.js +124 -0
- package/dist/src/utils/package-manager-config/pnpm-config.d.ts +17 -0
- package/dist/src/utils/package-manager-config/pnpm-config.js +60 -0
- package/dist/src/utils/package-manager.d.ts +23 -2
- package/dist/src/utils/package-manager.js +264 -43
- package/dist/src/utils/provenance.js +18 -16
- package/dist/src/utils/registry-config/bun.d.ts +2 -0
- package/dist/src/utils/registry-config/bun.js +257 -0
- package/dist/src/utils/registry-config/index.d.ts +13 -0
- package/dist/src/utils/registry-config/index.js +102 -0
- package/dist/src/utils/registry-config/pnpm.d.ts +2 -0
- package/dist/src/utils/registry-config/pnpm.js +1551 -0
- package/dist/src/utils/registry-config/utils.d.ts +195 -0
- package/dist/src/utils/registry-config/utils.js +496 -0
- package/dist/src/utils/registry-config/yarn-berry.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-berry.js +612 -0
- package/dist/src/utils/registry-config/yarn-classic.d.ts +2 -0
- package/dist/src/utils/registry-config/yarn-classic.js +1001 -0
- package/dist/src/utils/safe-spawn.d.ts +24 -0
- package/dist/src/utils/safe-spawn.js +104 -0
- package/dist/src/utils/shell-quoting.d.ts +15 -0
- package/dist/src/utils/shell-quoting.js +35 -0
- package/dist/src/utils/wait-for-socket-connection.d.ts +11 -0
- package/dist/src/utils/wait-for-socket-connection.js +14 -8
- package/dist/src/utils/workspace-id.d.ts +20 -0
- package/dist/src/utils/workspace-id.js +54 -0
- package/migrations.json +13 -1
- package/package.json +22 -17
- package/dist/src/migrations/update-17-3-0/nx-release-path.d.ts +0 -3
- package/dist/src/migrations/update-17-3-0/nx-release-path.js +0 -47
- package/dist/src/utils/min-release-age/npmrc.d.ts +0 -15
- package/dist/src/utils/min-release-age/npmrc.js +0 -45
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
declare const safeSharedRootBrand: unique symbol;
|
|
2
|
+
declare const sharedRootEstablishedBrand: unique symbol;
|
|
3
|
+
declare const ownedRealDirBrand: unique symbol;
|
|
4
|
+
declare const ownedPrivateDirBrand: unique symbol;
|
|
5
|
+
/** Verified safe to keep an owner-only directory under. Not created. */
|
|
6
|
+
export type SafeSharedRoot = string & {
|
|
7
|
+
readonly [safeSharedRootBrand]: true;
|
|
8
|
+
};
|
|
9
|
+
/** Created if absent, then verified safe as above. */
|
|
10
|
+
export type EstablishedSharedRoot = string & {
|
|
11
|
+
readonly [sharedRootEstablishedBrand]: true;
|
|
12
|
+
};
|
|
13
|
+
/** An existing real directory owned by us. Mode is *not* checked. */
|
|
14
|
+
export type OwnedRealDir = string & {
|
|
15
|
+
readonly [ownedRealDirBrand]: true;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* POSIX: created if absent, owned by us, and carrying no group or other bits —
|
|
19
|
+
* re-locked first if it was looser. The mode is checked on whichever branch
|
|
20
|
+
* produced it, so the brand does not depend on who created the directory.
|
|
21
|
+
*
|
|
22
|
+
* Windows: only *is a real directory*. `getuid` is unavailable there, so
|
|
23
|
+
* neither ownership nor mode is checked; `%TMP%` is already per-account.
|
|
24
|
+
*/
|
|
25
|
+
export type OwnedPrivateDir = string & {
|
|
26
|
+
readonly [ownedPrivateDirBrand]: true;
|
|
27
|
+
};
|
|
28
|
+
/** Why a guard refused a directory. Data, not a sentence: `remedyFor` decides on it. */
|
|
29
|
+
export type DirRefusal = {
|
|
30
|
+
kind: 'not-created';
|
|
31
|
+
dir: string;
|
|
32
|
+
code?: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: 'not-inspectable';
|
|
35
|
+
dir: string;
|
|
36
|
+
code?: string;
|
|
37
|
+
} | {
|
|
38
|
+
kind: 'not-a-directory';
|
|
39
|
+
dir: string;
|
|
40
|
+
symlink?: true;
|
|
41
|
+
} | {
|
|
42
|
+
kind: 'foreign-owner';
|
|
43
|
+
dir: string;
|
|
44
|
+
uid: number;
|
|
45
|
+
} | {
|
|
46
|
+
kind: 'foreign-shared-container';
|
|
47
|
+
dir: string;
|
|
48
|
+
uid: number;
|
|
49
|
+
} | {
|
|
50
|
+
kind: 'not-tightenable';
|
|
51
|
+
dir: string;
|
|
52
|
+
mode: number;
|
|
53
|
+
} | {
|
|
54
|
+
kind: 'peer-writable-not-sticky';
|
|
55
|
+
dir: string;
|
|
56
|
+
mode: number;
|
|
57
|
+
};
|
|
58
|
+
/** A guard's verdict. */
|
|
59
|
+
export type GuardResult<T> = {
|
|
60
|
+
status: 'ok';
|
|
61
|
+
path: T;
|
|
62
|
+
} | {
|
|
63
|
+
status: 'refused';
|
|
64
|
+
refusal: DirRefusal;
|
|
65
|
+
};
|
|
66
|
+
/** The user-facing sentence for a refusal. The only place wording is decided. */
|
|
67
|
+
export declare function describeRefusal(r: DirRefusal): string;
|
|
68
|
+
/** What the user can do about a refusal, or `undefined` when there is nothing. */
|
|
69
|
+
export declare function remedyFor(r: DirRefusal): string | undefined;
|
|
70
|
+
/** One refusal as an `Error`, so several can travel in an `AggregateError`. */
|
|
71
|
+
export declare class DirectoryRefusedError extends Error {
|
|
72
|
+
readonly refusal: DirRefusal;
|
|
73
|
+
constructor(refusal: DirRefusal);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Whether a shared container is safe to keep an owner-only directory under.
|
|
77
|
+
*
|
|
78
|
+
* On POSIX, a container writable by other users must be sticky, and it must be
|
|
79
|
+
* owned by either root or the current user. Windows short-circuits after the
|
|
80
|
+
* directory test — the OS temp root is already scoped to one account, so there
|
|
81
|
+
* is no shared level whose ownership could matter.
|
|
82
|
+
*
|
|
83
|
+
* Sticky directories still let the directory's own owner rename entries, so a
|
|
84
|
+
* container owned by another unprivileged user could replace a previously
|
|
85
|
+
* verified private directory beneath it.
|
|
86
|
+
*/
|
|
87
|
+
export declare function isSafeSharedRoot(dir: string): GuardResult<SafeSharedRoot>;
|
|
88
|
+
/**
|
|
89
|
+
* Whether other users on this machine can write into `dir`. Gates whether a
|
|
90
|
+
* refusal message may cite other users, so it must not over-report: `false` on
|
|
91
|
+
* Windows, where libuv synthesizes `st_mode` from the READONLY attribute and
|
|
92
|
+
* reports an ordinary per-account directory as `0666`, and `false` on a path
|
|
93
|
+
* that cannot be inspected.
|
|
94
|
+
*
|
|
95
|
+
* `statSync`, not `lstatSync`: the question is about the directory that will be
|
|
96
|
+
* used, not the link pointing at it. Link modes mislead in both directions —
|
|
97
|
+
* Linux creates symlinks `0777`, macOS applies the umask. Nothing here decides
|
|
98
|
+
* whether a path is accepted, so following the link costs nothing the guards
|
|
99
|
+
* do not already re-check.
|
|
100
|
+
*/
|
|
101
|
+
export declare function isPeerWritable(dir: string): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Create a shared container as sticky + world-writable if it does not exist,
|
|
104
|
+
* and report whether the resulting path is safe for the current user.
|
|
105
|
+
*
|
|
106
|
+
* **A container that already exists is never modified — only judged.** Do not
|
|
107
|
+
* chmod before deciding trust: `CAP_FOWNER` (root's default in Docker and most
|
|
108
|
+
* CI images) can chmod a directory it does not own, so a peer-owned root would
|
|
109
|
+
* be widened to `1777` and then refused, and an operator who deliberately
|
|
110
|
+
* tightened this root would have it re-widened on every `nx` process.
|
|
111
|
+
*/
|
|
112
|
+
export declare function ensureSafeSharedRoot(dir: string): GuardResult<EstablishedSharedRoot>;
|
|
113
|
+
/**
|
|
114
|
+
* Whether `dir` is an existing real directory owned by us. Unlike
|
|
115
|
+
* `ensureOwnedPrivateDir` it creates nothing and repairs nothing — for callers
|
|
116
|
+
* that only want to know whether a path is safe to act on, such as deleting.
|
|
117
|
+
*/
|
|
118
|
+
export declare function isOwnedRealDirectory(dir: string): OwnedRealDir | null;
|
|
119
|
+
/** The path segment separating one user's Nx runtime state from another's. */
|
|
120
|
+
export declare function getUserSegment(): string;
|
|
121
|
+
/**
|
|
122
|
+
* Ensure `dir` exists, is a real directory owned by us, and carries no group or
|
|
123
|
+
* other bits at all — read and search alone reach a socket inside it, so 0755 is
|
|
124
|
+
* re-locked rather than accepted. A `refused` status carries which check said
|
|
125
|
+
* no — usually `foreign-owner` for a directory another user planted, but also
|
|
126
|
+
* `not-created`/`not-inspectable` for a filesystem error, `not-a-directory`, or
|
|
127
|
+
* `not-tightenable` when the re-lock did not land.
|
|
128
|
+
*
|
|
129
|
+
* Node builtins only: reached from the native binding loader.
|
|
130
|
+
*/
|
|
131
|
+
export declare function ensureOwnedPrivateDir(dir: string): GuardResult<OwnedPrivateDir>;
|
|
132
|
+
export {};
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DirectoryRefusedError = void 0;
|
|
4
|
+
exports.describeRefusal = describeRefusal;
|
|
5
|
+
exports.remedyFor = remedyFor;
|
|
6
|
+
exports.isSafeSharedRoot = isSafeSharedRoot;
|
|
7
|
+
exports.isPeerWritable = isPeerWritable;
|
|
8
|
+
exports.ensureSafeSharedRoot = ensureSafeSharedRoot;
|
|
9
|
+
exports.isOwnedRealDirectory = isOwnedRealDirectory;
|
|
10
|
+
exports.getUserSegment = getUserSegment;
|
|
11
|
+
exports.ensureOwnedPrivateDir = ensureOwnedPrivateDir;
|
|
12
|
+
const node_fs_1 = require("node:fs");
|
|
13
|
+
const node_os_1 = require("node:os");
|
|
14
|
+
// A string discriminant, not a boolean `ok`: this repo compiles with
|
|
15
|
+
// `strict: false`, where TypeScript does not narrow a union on a boolean literal.
|
|
16
|
+
const allow = (path) => ({ status: 'ok', path });
|
|
17
|
+
const deny = (refusal) => ({
|
|
18
|
+
status: 'refused',
|
|
19
|
+
refusal,
|
|
20
|
+
});
|
|
21
|
+
const notADirectory = (dir, stats) => stats.isSymbolicLink()
|
|
22
|
+
? { kind: 'not-a-directory', dir, symlink: true }
|
|
23
|
+
: { kind: 'not-a-directory', dir };
|
|
24
|
+
// Four octal digits, so a sticky container reads `1777` and a plain directory
|
|
25
|
+
// `0755` — the notation `chmod` and `ls` use. Prefixing a literal `0` instead
|
|
26
|
+
// renders sticky modes as `01777`, which is not a form anyone writes.
|
|
27
|
+
const asMode = (mode) => (mode & 0o7777).toString(8).padStart(4, '0');
|
|
28
|
+
/** The user-facing sentence for a refusal. The only place wording is decided. */
|
|
29
|
+
function describeRefusal(r) {
|
|
30
|
+
switch (r.kind) {
|
|
31
|
+
case 'not-created':
|
|
32
|
+
return `${r.dir} could not be created${r.code ? ` (${r.code})` : ''}`;
|
|
33
|
+
case 'not-inspectable':
|
|
34
|
+
return `${r.dir} could not be inspected${r.code ? ` (${r.code})` : ''}`;
|
|
35
|
+
case 'not-a-directory':
|
|
36
|
+
return r.symlink
|
|
37
|
+
? `${r.dir} is a symlink, not a real directory — something replaced the path Nx expected to create`
|
|
38
|
+
: `${r.dir} exists and is not a directory`;
|
|
39
|
+
case 'foreign-owner':
|
|
40
|
+
return `${r.dir} is owned by uid ${r.uid}, not by you`;
|
|
41
|
+
case 'foreign-shared-container':
|
|
42
|
+
return `${r.dir} belongs to another user (uid ${r.uid}) rather than to you or to root`;
|
|
43
|
+
case 'not-tightenable':
|
|
44
|
+
return `${r.dir} is reachable by other users (mode ${asMode(r.mode)}) and could not be tightened to 0700`;
|
|
45
|
+
case 'peer-writable-not-sticky':
|
|
46
|
+
return `${r.dir} is writable by other users but not sticky (mode ${asMode(r.mode)}), so a peer could replace directories inside it`;
|
|
47
|
+
default: {
|
|
48
|
+
// This repo sets `strict: false` and leaves `noImplicitReturns` unset, so
|
|
49
|
+
// a new DirRefusal member would otherwise compile here and render as
|
|
50
|
+
// `undefined` inside the aggregate message. Assignability to `never` still
|
|
51
|
+
// holds under these settings, so this is a real compile-time guard.
|
|
52
|
+
const unhandled = r;
|
|
53
|
+
throw new Error(`Unhandled directory refusal: ${unhandled.kind}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Single-quoted for a shell, so a path with a space or quote survives a paste. */
|
|
58
|
+
const shellQuote = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
59
|
+
/** What the user can do about a refusal, or `undefined` when there is nothing. */
|
|
60
|
+
function remedyFor(r) {
|
|
61
|
+
switch (r.kind) {
|
|
62
|
+
case 'not-a-directory':
|
|
63
|
+
return r.symlink
|
|
64
|
+
? `${r.dir} is a symlink where Nx expects a directory. If you did not create it, treat it as hostile: remove the link itself (not what it points at) and run the command again.`
|
|
65
|
+
: undefined;
|
|
66
|
+
case 'foreign-owner':
|
|
67
|
+
return `${r.dir} belongs to another user on this machine, so Nx cannot keep its own directory there. Set NX_SOCKET_DIR to a short directory your user owns, or move it aside — which you can do yourself if you own the directory it sits in, and otherwise needs an administrator.`;
|
|
68
|
+
case 'not-tightenable':
|
|
69
|
+
// Both producers reach here having already established that the directory
|
|
70
|
+
// is ours, so `chmod` is the user's to run. Names no cause: one producer
|
|
71
|
+
// is a mount that discards the mode, the other is any `chmod` failure.
|
|
72
|
+
return `${r.dir} is reachable by other users (mode ${asMode(r.mode)}) and Nx could not restrict it. Run \`chmod 0700 ${shellQuote(r.dir)}\` and try again; if the mode does not stick, set NX_SOCKET_DIR to a short directory on a filesystem that keeps POSIX permissions.`;
|
|
73
|
+
case 'foreign-shared-container':
|
|
74
|
+
// Unreachable today: `isSafeSharedRoot` denies with this kind only when
|
|
75
|
+
// `stats.uid !== 0`, so a root-owned container never reaches here.
|
|
76
|
+
if (r.uid === 0) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const q = shellQuote(r.dir);
|
|
80
|
+
return `${r.dir} belongs to another user on this machine, so Nx cannot keep a private directory beneath it. Ask an administrator to hand it to root with \`sudo chown root ${q} && sudo chmod 1777 ${q}\`; every user can then keep their own directory under it.`;
|
|
81
|
+
case 'not-created':
|
|
82
|
+
case 'not-inspectable':
|
|
83
|
+
case 'peer-writable-not-sticky':
|
|
84
|
+
return undefined;
|
|
85
|
+
default: {
|
|
86
|
+
// Matches `describeRefusal`'s arm, so a new kind cannot ship with a
|
|
87
|
+
// sentence and no advice — which is how `not-tightenable` went unadvised.
|
|
88
|
+
const unhandled = r;
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** One refusal as an `Error`, so several can travel in an `AggregateError`. */
|
|
94
|
+
class DirectoryRefusedError extends Error {
|
|
95
|
+
constructor(refusal) {
|
|
96
|
+
super(describeRefusal(refusal));
|
|
97
|
+
this.refusal = refusal;
|
|
98
|
+
this.name = 'DirectoryRefusedError';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
exports.DirectoryRefusedError = DirectoryRefusedError;
|
|
102
|
+
/**
|
|
103
|
+
* chmod a path only if it is a real directory, never following a symlink at its
|
|
104
|
+
* final component — `chmodSync` follows them, retargeting the mode change. The
|
|
105
|
+
* directory check is on the descriptor, not the errno: a deny-list fails *open*
|
|
106
|
+
* on codes it does not know. `O_NONBLOCK` stops a planted FIFO blocking `openSync`.
|
|
107
|
+
*/
|
|
108
|
+
function chmodRealDirectory(path, mode) {
|
|
109
|
+
let fd;
|
|
110
|
+
try {
|
|
111
|
+
fd = (0, node_fs_1.openSync)(path, node_fs_1.constants.O_RDONLY | node_fs_1.constants.O_NOFOLLOW | node_fs_1.constants.O_NONBLOCK);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
if (!(0, node_fs_1.fstatSync)(fd).isDirectory()) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
(0, node_fs_1.fchmodSync)(fd, mode);
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
(0, node_fs_1.closeSync)(fd);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Sticky. Restricts rename and unlink in a writable directory to the owner of
|
|
132
|
+
* each entry — plus the directory's own owner, which is why the ownership check
|
|
133
|
+
* below is not redundant with this one.
|
|
134
|
+
*/
|
|
135
|
+
const S_ISVTX = 0o1000;
|
|
136
|
+
/**
|
|
137
|
+
* Whether a shared container is safe to keep an owner-only directory under.
|
|
138
|
+
*
|
|
139
|
+
* On POSIX, a container writable by other users must be sticky, and it must be
|
|
140
|
+
* owned by either root or the current user. Windows short-circuits after the
|
|
141
|
+
* directory test — the OS temp root is already scoped to one account, so there
|
|
142
|
+
* is no shared level whose ownership could matter.
|
|
143
|
+
*
|
|
144
|
+
* Sticky directories still let the directory's own owner rename entries, so a
|
|
145
|
+
* container owned by another unprivileged user could replace a previously
|
|
146
|
+
* verified private directory beneath it.
|
|
147
|
+
*/
|
|
148
|
+
function isSafeSharedRoot(dir) {
|
|
149
|
+
try {
|
|
150
|
+
const stats = (0, node_fs_1.lstatSync)(dir);
|
|
151
|
+
if (!stats.isDirectory()) {
|
|
152
|
+
return deny(notADirectory(dir, stats));
|
|
153
|
+
}
|
|
154
|
+
if (process.platform === 'win32') {
|
|
155
|
+
// The OS temp root is already scoped to the current Windows user.
|
|
156
|
+
return allow(dir);
|
|
157
|
+
}
|
|
158
|
+
if (typeof process.getuid === 'function' &&
|
|
159
|
+
stats.uid !== process.getuid() &&
|
|
160
|
+
stats.uid !== 0) {
|
|
161
|
+
return deny({ kind: 'foreign-shared-container', dir, uid: stats.uid });
|
|
162
|
+
}
|
|
163
|
+
return !(stats.mode & 0o022) || !!(stats.mode & S_ISVTX)
|
|
164
|
+
? allow(dir)
|
|
165
|
+
: deny({ kind: 'peer-writable-not-sticky', dir, mode: stats.mode });
|
|
166
|
+
}
|
|
167
|
+
catch (e) {
|
|
168
|
+
return deny({ kind: 'not-inspectable', dir, code: e?.code });
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Whether other users on this machine can write into `dir`. Gates whether a
|
|
173
|
+
* refusal message may cite other users, so it must not over-report: `false` on
|
|
174
|
+
* Windows, where libuv synthesizes `st_mode` from the READONLY attribute and
|
|
175
|
+
* reports an ordinary per-account directory as `0666`, and `false` on a path
|
|
176
|
+
* that cannot be inspected.
|
|
177
|
+
*
|
|
178
|
+
* `statSync`, not `lstatSync`: the question is about the directory that will be
|
|
179
|
+
* used, not the link pointing at it. Link modes mislead in both directions —
|
|
180
|
+
* Linux creates symlinks `0777`, macOS applies the umask. Nothing here decides
|
|
181
|
+
* whether a path is accepted, so following the link costs nothing the guards
|
|
182
|
+
* do not already re-check.
|
|
183
|
+
*/
|
|
184
|
+
function isPeerWritable(dir) {
|
|
185
|
+
if (process.platform === 'win32') {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
return !!((0, node_fs_1.statSync)(dir).mode & 0o022);
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Create a shared container as sticky + world-writable if it does not exist,
|
|
197
|
+
* and report whether the resulting path is safe for the current user.
|
|
198
|
+
*
|
|
199
|
+
* **A container that already exists is never modified — only judged.** Do not
|
|
200
|
+
* chmod before deciding trust: `CAP_FOWNER` (root's default in Docker and most
|
|
201
|
+
* CI images) can chmod a directory it does not own, so a peer-owned root would
|
|
202
|
+
* be widened to `1777` and then refused, and an operator who deliberately
|
|
203
|
+
* tightened this root would have it re-widened on every `nx` process.
|
|
204
|
+
*/
|
|
205
|
+
function ensureSafeSharedRoot(dir) {
|
|
206
|
+
if (process.platform === 'win32') {
|
|
207
|
+
try {
|
|
208
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
209
|
+
return allow(dir);
|
|
210
|
+
}
|
|
211
|
+
catch (e) {
|
|
212
|
+
return deny({ kind: 'not-created', dir, code: e?.code });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
(0, node_fs_1.mkdirSync)(dir, { mode: 0o1777 });
|
|
217
|
+
// Ours, created a statement ago. Load-bearing on macOS: XNU strips S_ISVTX
|
|
218
|
+
// at mkdir, so the sticky bit exists solely because of this call.
|
|
219
|
+
chmodRealDirectory(dir, 0o1777);
|
|
220
|
+
}
|
|
221
|
+
catch (e) {
|
|
222
|
+
if (e?.code !== 'EEXIST') {
|
|
223
|
+
return deny({ kind: 'not-created', dir, code: e?.code });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// One verdict for both branches: the chmod above can fail and leave a
|
|
227
|
+
// peer-writable non-sticky container, which trusting the creation would brand
|
|
228
|
+
// safe.
|
|
229
|
+
const verdict = isSafeSharedRoot(dir);
|
|
230
|
+
return verdict.status === 'ok'
|
|
231
|
+
? allow(dir)
|
|
232
|
+
: deny(verdict.refusal);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Whether `dir` is an existing real directory owned by us. Unlike
|
|
236
|
+
* `ensureOwnedPrivateDir` it creates nothing and repairs nothing — for callers
|
|
237
|
+
* that only want to know whether a path is safe to act on, such as deleting.
|
|
238
|
+
*/
|
|
239
|
+
function isOwnedRealDirectory(dir) {
|
|
240
|
+
try {
|
|
241
|
+
const stats = (0, node_fs_1.lstatSync)(dir);
|
|
242
|
+
if (!stats.isDirectory()) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return typeof process.getuid !== 'function' ||
|
|
246
|
+
stats.uid === process.getuid()
|
|
247
|
+
? dir
|
|
248
|
+
: null;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/** The path segment separating one user's Nx runtime state from another's. */
|
|
255
|
+
function getUserSegment() {
|
|
256
|
+
try {
|
|
257
|
+
if (typeof process.getuid === 'function') {
|
|
258
|
+
return String(process.getuid());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch { }
|
|
262
|
+
try {
|
|
263
|
+
const { username } = (0, node_os_1.userInfo)();
|
|
264
|
+
if (username) {
|
|
265
|
+
return username;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
catch { }
|
|
269
|
+
return 'unknown';
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Ensure `dir` exists, is a real directory owned by us, and carries no group or
|
|
273
|
+
* other bits at all — read and search alone reach a socket inside it, so 0755 is
|
|
274
|
+
* re-locked rather than accepted. A `refused` status carries which check said
|
|
275
|
+
* no — usually `foreign-owner` for a directory another user planted, but also
|
|
276
|
+
* `not-created`/`not-inspectable` for a filesystem error, `not-a-directory`, or
|
|
277
|
+
* `not-tightenable` when the re-lock did not land.
|
|
278
|
+
*
|
|
279
|
+
* Node builtins only: reached from the native binding loader.
|
|
280
|
+
*/
|
|
281
|
+
function ensureOwnedPrivateDir(dir) {
|
|
282
|
+
try {
|
|
283
|
+
(0, node_fs_1.mkdirSync)(dir, { mode: 0o700 });
|
|
284
|
+
}
|
|
285
|
+
catch (e) {
|
|
286
|
+
if (e?.code !== 'EEXIST') {
|
|
287
|
+
return deny({ kind: 'not-created', dir, code: e?.code });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// One verdict for both branches, as in `ensureSafeSharedRoot`: mounts that
|
|
291
|
+
// ignore the mode argument can land a directory Nx asked for at 0700 on 0777,
|
|
292
|
+
// so the creation path is judged like any other.
|
|
293
|
+
try {
|
|
294
|
+
const stats = (0, node_fs_1.lstatSync)(dir);
|
|
295
|
+
// Before the Windows short-circuit: "is a real directory" holds on every
|
|
296
|
+
// platform.
|
|
297
|
+
if (!stats.isDirectory()) {
|
|
298
|
+
return deny(notADirectory(dir, stats));
|
|
299
|
+
}
|
|
300
|
+
if (typeof process.getuid !== 'function') {
|
|
301
|
+
// Windows: the roots there are per-user OS temp dirs, not a shared /tmp.
|
|
302
|
+
return allow(dir);
|
|
303
|
+
}
|
|
304
|
+
if (stats.uid !== process.getuid()) {
|
|
305
|
+
return deny({ kind: 'foreign-owner', dir, uid: stats.uid });
|
|
306
|
+
}
|
|
307
|
+
if (stats.mode & 0o077) {
|
|
308
|
+
if (!chmodRealDirectory(dir, 0o700)) {
|
|
309
|
+
return deny({ kind: 'not-tightenable', dir, mode: stats.mode });
|
|
310
|
+
}
|
|
311
|
+
// Read the mode back rather than trusting the chmod's return: mounts that
|
|
312
|
+
// ignore modes report success and change nothing.
|
|
313
|
+
const after = (0, node_fs_1.lstatSync)(dir);
|
|
314
|
+
if (after.mode & 0o077) {
|
|
315
|
+
return deny({ kind: 'not-tightenable', dir, mode: after.mode });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return allow(dir);
|
|
319
|
+
}
|
|
320
|
+
catch (e) {
|
|
321
|
+
return deny({ kind: 'not-inspectable', dir, code: e?.code });
|
|
322
|
+
}
|
|
323
|
+
}
|
|
@@ -225,19 +225,23 @@ function preparePackageInstallation(pkg, requiredVersion, packageManager) {
|
|
|
225
225
|
// it into the temp dir, so the `-w` here resolves to the temp dir.
|
|
226
226
|
const pmCommands = (0, package_manager_1.getPackageManagerCommand)(packageManager);
|
|
227
227
|
const preInstallCommand = pmCommands.preInstall;
|
|
228
|
-
//
|
|
228
|
+
// Keep peer dependencies out of the temp install. `ensurePackage` puts the
|
|
229
229
|
// workspace's `node_modules` on `NODE_PATH`, so a loaded package resolves its
|
|
230
230
|
// peers from the workspace instead of pulling its own (possibly incompatible)
|
|
231
231
|
// copies into the temp dir.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
232
|
+
//
|
|
233
|
+
// npm needs `--legacy-peer-deps` rather than `--omit=peer`: npm marks a package
|
|
234
|
+
// as a peer if anything in the tree peer-depends on it, so `--omit=peer` also
|
|
235
|
+
// prunes packages that are real dependencies. Bun's `--omit=peer` does not.
|
|
236
|
+
const skipPeerDependenciesFlags = {
|
|
237
|
+
npm: '--legacy-peer-deps',
|
|
238
|
+
bun: '--omit=peer',
|
|
239
|
+
pnpm: '--config.auto-install-peers=false',
|
|
240
|
+
};
|
|
237
241
|
const installCommand = [
|
|
238
242
|
pmCommands.addDev,
|
|
239
243
|
`${pkg}@${requiredVersion}`,
|
|
240
|
-
|
|
244
|
+
skipPeerDependenciesFlags[packageManager],
|
|
241
245
|
pmCommands.ignoreScriptsFlag,
|
|
242
246
|
]
|
|
243
247
|
.filter(Boolean)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The directory holding bun's global config files (.bunfig.toml and, for bun's
|
|
3
|
+
* npmrc support, .npmrc): $XDG_CONFIG_HOME when set, else the home dir (bun's
|
|
4
|
+
* getHomeConfigPath). Null when neither is set, where bun reads no global
|
|
5
|
+
* config.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getBunGlobalConfigBase(env: NodeJS.ProcessEnv): string | null;
|
|
8
|
+
/**
|
|
9
|
+
* Parses a bunfig.toml: null when absent, 'unreadable' when it cannot be read
|
|
10
|
+
* (bun skips it and resolves on, so most callers collapse the two), 'invalid'
|
|
11
|
+
* when bun's own TOML parser would reject it (bun hard-errors there, so no
|
|
12
|
+
* resolution is left for a caller to reproduce).
|
|
13
|
+
*/
|
|
14
|
+
export declare function readBunfigRaw(path: string): Record<string, unknown> | 'unreadable' | 'invalid' | null;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBunGlobalConfigBase = getBunGlobalConfigBase;
|
|
4
|
+
exports.readBunfigRaw = readBunfigRaw;
|
|
5
|
+
const fs_1 = require("fs");
|
|
6
|
+
/**
|
|
7
|
+
* The directory holding bun's global config files (.bunfig.toml and, for bun's
|
|
8
|
+
* npmrc support, .npmrc): $XDG_CONFIG_HOME when set, else the home dir (bun's
|
|
9
|
+
* getHomeConfigPath). Null when neither is set, where bun reads no global
|
|
10
|
+
* config.
|
|
11
|
+
*/
|
|
12
|
+
function getBunGlobalConfigBase(env) {
|
|
13
|
+
// bun's getenvZ treats a set-but-empty var as present, so an exported empty
|
|
14
|
+
// XDG_CONFIG_HOME still short-circuits HOME (bun: `XDG_CONFIG_HOME orelse HOME`).
|
|
15
|
+
if (env.XDG_CONFIG_HOME !== undefined) {
|
|
16
|
+
return env.XDG_CONFIG_HOME;
|
|
17
|
+
}
|
|
18
|
+
// Mirrors bun's platform-specific HOME accessor (env_var.zig).
|
|
19
|
+
const home = process.platform === 'win32' ? env.USERPROFILE : env.HOME;
|
|
20
|
+
return home ?? null;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parses a bunfig.toml: null when absent, 'unreadable' when it cannot be read
|
|
24
|
+
* (bun skips it and resolves on, so most callers collapse the two), 'invalid'
|
|
25
|
+
* when bun's own TOML parser would reject it (bun hard-errors there, so no
|
|
26
|
+
* resolution is left for a caller to reproduce).
|
|
27
|
+
*/
|
|
28
|
+
function readBunfigRaw(path) {
|
|
29
|
+
// Outside the try because a parser that will not load is a broken
|
|
30
|
+
// installation, not a corrupt bunfig.
|
|
31
|
+
const { parse } = require('smol-toml');
|
|
32
|
+
let raw;
|
|
33
|
+
try {
|
|
34
|
+
raw = (0, fs_1.readFileSync)(path, 'utf-8');
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
// ENOTDIR (a path through a non-directory) is another shape of absent, the
|
|
38
|
+
// same way the .npmrc reader classifies it.
|
|
39
|
+
return error?.code === 'ENOENT' || error?.code === 'ENOTDIR'
|
|
40
|
+
? null
|
|
41
|
+
: 'unreadable';
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return parse(raw);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return 'invalid';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface NpmrcEntry {
|
|
2
|
+
key: string;
|
|
3
|
+
value: string;
|
|
4
|
+
/** True when the source used ini's `key[]` array-append syntax. */
|
|
5
|
+
array?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parses an .npmrc file into its `key = value` entries the way npm/yarn/pnpm do
|
|
9
|
+
* (via the `ini` package). Returns null when the file is missing, and
|
|
10
|
+
* 'unreadable' when it exists but cannot be read (permissions, a directory):
|
|
11
|
+
* package managers diverge on that state, so each caller decides whether to
|
|
12
|
+
* skip, warn, or abort rather than having it collapsed into "absent" here.
|
|
13
|
+
*/
|
|
14
|
+
export declare function readNpmrcEntries(path: string): NpmrcEntry[] | 'unreadable' | null;
|
|
15
|
+
export declare function parseNpmrcContent(raw: string): NpmrcEntry[];
|
|
16
|
+
/**
|
|
17
|
+
* Reads an .npmrc-format file into a map with ini's semantics for repeated
|
|
18
|
+
* keys: scalars last-write-wins, `key[]` values joined. Null and 'unreadable'
|
|
19
|
+
* pass through from {@link readNpmrcEntries}.
|
|
20
|
+
*/
|
|
21
|
+
export declare function readNpmrcMap(path: string): Map<string, string> | 'unreadable' | null;
|
|
22
|
+
/** Those entries under ini's semantics for repeated keys. */
|
|
23
|
+
export declare function npmrcEntriesToMap(entries: NpmrcEntry[]): Map<string, string>;
|