@pnpm/resolving.local-resolver 1002.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015-2016 Rico Sta. Cruz and other contributors
4
+ Copyright (c) 2016-2026 Zoltan Kochan and other contributors
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # @pnpm/local-resolver
2
+
3
+ > Resolver for local packages
4
+
5
+ <!--@shields('npm')-->
6
+ [![npm version](https://img.shields.io/npm/v/@pnpm/local-resolver.svg)](https://www.npmjs.com/package/@pnpm/local-resolver)
7
+ <!--/@-->
8
+
9
+ ## Installation
10
+
11
+ ```
12
+ pnpm add @pnpm/local-resolver
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```js
18
+ 'use strict'
19
+ const resolveFromLocal = require('@pnpm/local-resolver').default
20
+
21
+ resolveFromLocal({bareSpecifier: './example-package'}, {prefix: process.cwd()})
22
+ .then(resolveResult => console.log(resolveResult))
23
+ //> { id: 'link:example-package',
24
+ // normalizedBareSpecifier: 'link:example-package',
25
+ // package:
26
+ // { name: 'foo',
27
+ // version: '1.0.0',
28
+ // readme: '# foo\n',
29
+ // readmeFilename: 'README.md',
30
+ // description: '',
31
+ // _id: 'foo@1.0.0' },
32
+ // resolution: { directory: 'example-package', type: 'directory' }
33
+ // resolvedVia: 'local-filesystem' }
34
+ ```
35
+
36
+ ## License
37
+
38
+ MIT
package/lib/index.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import type { DirectoryResolution, Resolution, ResolveResult, TarballResolution } from '@pnpm/resolving.resolver-base';
2
+ import type { DependencyManifest, PkgResolutionId } from '@pnpm/types';
3
+ import { type WantedLocalDependency } from './parseBareSpecifier.js';
4
+ export { type WantedLocalDependency };
5
+ export interface LocalResolveResult extends ResolveResult {
6
+ manifest?: DependencyManifest;
7
+ normalizedBareSpecifier?: string;
8
+ resolution: DirectoryResolution | TarballResolution;
9
+ resolvedVia: 'local-filesystem';
10
+ }
11
+ /**
12
+ * Resolves a package hosted on the local filesystem
13
+ */
14
+ export declare function resolveFromLocal(ctx: {
15
+ preserveAbsolutePaths?: boolean;
16
+ }, wantedDependency: WantedLocalDependency, opts: {
17
+ lockfileDir?: string;
18
+ projectDir: string;
19
+ currentPkg?: {
20
+ id: PkgResolutionId;
21
+ resolution: DirectoryResolution | TarballResolution | Resolution;
22
+ };
23
+ update?: false | 'compatible' | 'latest';
24
+ }): Promise<LocalResolveResult | null>;
package/lib/index.js ADDED
@@ -0,0 +1,85 @@
1
+ import { existsSync } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { getTarballIntegrity } from '@pnpm/crypto.hash';
4
+ import { PnpmError } from '@pnpm/error';
5
+ import { logger } from '@pnpm/logger';
6
+ import { readProjectManifestOnly } from '@pnpm/workspace.project-manifest-reader';
7
+ import { parseBareSpecifier } from './parseBareSpecifier.js';
8
+ export {};
9
+ /**
10
+ * Resolves a package hosted on the local filesystem
11
+ */
12
+ export async function resolveFromLocal(ctx, wantedDependency, opts) {
13
+ const preserveAbsolutePaths = ctx.preserveAbsolutePaths ?? false;
14
+ const spec = parseBareSpecifier(wantedDependency, opts.projectDir, opts.lockfileDir ?? opts.projectDir, { preserveAbsolutePaths });
15
+ if (spec == null)
16
+ return null;
17
+ if (spec.type === 'file') {
18
+ const integrity = await getTarballIntegrity(spec.fetchSpec);
19
+ return {
20
+ id: spec.id,
21
+ normalizedBareSpecifier: spec.normalizedBareSpecifier,
22
+ resolution: {
23
+ integrity,
24
+ tarball: spec.id,
25
+ },
26
+ resolvedVia: 'local-filesystem',
27
+ };
28
+ }
29
+ // Skip resolution if we have a current package and not updating
30
+ if (opts.currentPkg?.resolution && spec.type === 'directory' && !opts.update) {
31
+ return {
32
+ id: opts.currentPkg.id,
33
+ resolution: opts.currentPkg.resolution,
34
+ resolvedVia: 'local-filesystem',
35
+ };
36
+ }
37
+ let localDependencyManifest;
38
+ try {
39
+ localDependencyManifest = await readProjectManifestOnly(spec.fetchSpec);
40
+ }
41
+ catch (internalErr) { // eslint-disable-line
42
+ if (!existsSync(spec.fetchSpec)) {
43
+ if (spec.id.startsWith('file:')) {
44
+ throw new PnpmError('LINKED_PKG_DIR_NOT_FOUND', `Could not install from "${spec.fetchSpec}" as it does not exist.`);
45
+ }
46
+ logger.warn({
47
+ message: `Installing a dependency from a non-existent directory: ${spec.fetchSpec}`,
48
+ prefix: opts.projectDir,
49
+ });
50
+ localDependencyManifest = {
51
+ name: path.basename(spec.fetchSpec),
52
+ version: '0.0.0',
53
+ };
54
+ }
55
+ else {
56
+ switch (internalErr.code) {
57
+ case 'ENOTDIR': {
58
+ throw new PnpmError('NOT_PACKAGE_DIRECTORY', `Could not install from "${spec.fetchSpec}" as it is not a directory.`);
59
+ }
60
+ case 'ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND':
61
+ case 'ENOENT': {
62
+ localDependencyManifest = {
63
+ name: path.basename(spec.fetchSpec),
64
+ version: '0.0.0',
65
+ };
66
+ break;
67
+ }
68
+ default: {
69
+ throw internalErr;
70
+ }
71
+ }
72
+ }
73
+ }
74
+ return {
75
+ id: spec.id,
76
+ manifest: localDependencyManifest,
77
+ normalizedBareSpecifier: spec.normalizedBareSpecifier,
78
+ resolution: {
79
+ directory: spec.dependencyPath,
80
+ type: 'directory',
81
+ },
82
+ resolvedVia: 'local-filesystem',
83
+ };
84
+ }
85
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,15 @@
1
+ import type { PkgResolutionId } from '@pnpm/resolving.resolver-base';
2
+ export interface LocalPackageSpec {
3
+ dependencyPath: string;
4
+ fetchSpec: string;
5
+ id: PkgResolutionId;
6
+ type: 'directory' | 'file';
7
+ normalizedBareSpecifier: string;
8
+ }
9
+ export interface WantedLocalDependency {
10
+ bareSpecifier: string;
11
+ injected?: boolean;
12
+ }
13
+ export declare function parseBareSpecifier(wd: WantedLocalDependency, projectDir: string, lockfileDir: string, opts: {
14
+ preserveAbsolutePaths: boolean;
15
+ }): LocalPackageSpec | null;
@@ -0,0 +1,105 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import { PnpmError } from '@pnpm/error';
4
+ import normalize from 'normalize-path';
5
+ // @ts-expect-error
6
+ const isWindows = process.platform === 'win32' || global['FAKE_WINDOWS'];
7
+ const isFilespec = isWindows ? /^(?:[./\\]|~\/|[a-z]:)/i : /^(?:[./]|~\/|[a-z]:)/i;
8
+ const isFilename = /\.(?:tgz|tar.gz|tar)$/i;
9
+ const isAbsolutePath = /^\/|^[A-Z]:/i;
10
+ class PathIsUnsupportedProtocolError extends PnpmError {
11
+ bareSpecifier;
12
+ protocol;
13
+ constructor(bareSpecifier, protocol) {
14
+ super('PATH_IS_UNSUPPORTED_PROTOCOL', 'Local dependencies via `path:` protocol are not supported. ' +
15
+ 'Use the `link:` protocol for folder dependencies and `file:` for local tarballs');
16
+ this.bareSpecifier = bareSpecifier;
17
+ this.protocol = protocol;
18
+ }
19
+ }
20
+ export function parseBareSpecifier(wd, projectDir, lockfileDir, opts) {
21
+ if (wd.bareSpecifier.startsWith('link:') || wd.bareSpecifier.startsWith('workspace:')) {
22
+ return fromLocal(wd, projectDir, lockfileDir, 'directory', opts);
23
+ }
24
+ if (wd.bareSpecifier.endsWith('.tgz') ||
25
+ wd.bareSpecifier.endsWith('.tar.gz') ||
26
+ wd.bareSpecifier.endsWith('.tar') ||
27
+ wd.bareSpecifier.includes(path.sep) ||
28
+ wd.bareSpecifier.startsWith('file:') ||
29
+ isFilespec.test(wd.bareSpecifier)) {
30
+ const type = isFilename.test(wd.bareSpecifier) ? 'file' : 'directory';
31
+ return fromLocal(wd, projectDir, lockfileDir, type, opts);
32
+ }
33
+ if (wd.bareSpecifier.startsWith('path:')) {
34
+ throw new PathIsUnsupportedProtocolError(wd.bareSpecifier, 'path:');
35
+ }
36
+ return null;
37
+ }
38
+ function fromLocal({ bareSpecifier, injected }, projectDir, lockfileDir, type, opts) {
39
+ const spec = bareSpecifier.replace(/\\/g, '/')
40
+ .replace(/^(?:file|link|workspace):\/*([A-Z]:)/i, '$1') // drive name paths on windows
41
+ .replace(/^(?:file|link|workspace):(?:\/*([~./]))?/, '$1');
42
+ let protocol;
43
+ if (bareSpecifier.startsWith('file:')) {
44
+ protocol = 'file:';
45
+ }
46
+ else if (bareSpecifier.startsWith('link:')) {
47
+ protocol = 'link:';
48
+ }
49
+ else {
50
+ protocol = type === 'directory' && !injected ? 'link:' : 'file:';
51
+ }
52
+ let fetchSpec;
53
+ let normalizedBareSpecifier;
54
+ if (/^~\//.test(spec)) {
55
+ // this is needed for windows and for file:~/foo/bar
56
+ fetchSpec = resolvePath(os.homedir(), spec.slice(2));
57
+ normalizedBareSpecifier = `${protocol}${spec}`;
58
+ }
59
+ else {
60
+ fetchSpec = resolvePath(projectDir, spec);
61
+ if (isAbsolute(spec)) {
62
+ normalizedBareSpecifier = `${protocol}${spec}`;
63
+ }
64
+ else {
65
+ normalizedBareSpecifier = `${protocol}${path.relative(projectDir, fetchSpec)}`;
66
+ }
67
+ }
68
+ function normalizeRelativeOrAbsolute(relativeTo, fromPath) {
69
+ let specPath;
70
+ if (opts.preserveAbsolutePaths && isAbsolute(spec)) {
71
+ specPath = path.resolve(fromPath);
72
+ }
73
+ else {
74
+ specPath = path.relative(relativeTo, fromPath);
75
+ }
76
+ return normalize(specPath);
77
+ }
78
+ injected = protocol === 'file:';
79
+ const dependencyPath = injected
80
+ ? normalizeRelativeOrAbsolute(lockfileDir, fetchSpec)
81
+ : normalize(path.resolve(fetchSpec));
82
+ const id = (!injected && (type === 'directory' || projectDir === lockfileDir)
83
+ ? `${protocol}${normalizeRelativeOrAbsolute(projectDir, fetchSpec)}`
84
+ : `${protocol}${normalizeRelativeOrAbsolute(lockfileDir, fetchSpec)}`);
85
+ return {
86
+ dependencyPath,
87
+ fetchSpec,
88
+ id,
89
+ normalizedBareSpecifier,
90
+ type,
91
+ };
92
+ }
93
+ function resolvePath(where, spec) {
94
+ if (isAbsolutePath.test(spec))
95
+ return spec;
96
+ return path.resolve(where, spec);
97
+ }
98
+ function isAbsolute(dir) {
99
+ if (dir[0] === '/')
100
+ return true;
101
+ if (/^[A-Z]:/i.test(dir))
102
+ return true;
103
+ return false;
104
+ }
105
+ //# sourceMappingURL=parseBareSpecifier.js.map
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@pnpm/resolving.local-resolver",
3
+ "version": "1002.1.4",
4
+ "description": "Resolver for local packages",
5
+ "keywords": [
6
+ "pnpm",
7
+ "pnpm11",
8
+ "npm",
9
+ "resolver"
10
+ ],
11
+ "license": "MIT",
12
+ "funding": "https://opencollective.com/pnpm",
13
+ "repository": "https://github.com/pnpm/pnpm/tree/main/resolving/local-resolver",
14
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/resolving/local-resolver#readme",
15
+ "bugs": {
16
+ "url": "https://github.com/pnpm/pnpm/issues"
17
+ },
18
+ "type": "module",
19
+ "main": "lib/index.js",
20
+ "types": "lib/index.d.ts",
21
+ "exports": {
22
+ ".": "./lib/index.js"
23
+ },
24
+ "files": [
25
+ "lib",
26
+ "!*.map"
27
+ ],
28
+ "dependencies": {
29
+ "normalize-path": "^3.0.0",
30
+ "@pnpm/crypto.hash": "1000.2.1",
31
+ "@pnpm/error": "1000.0.5",
32
+ "@pnpm/types": "1000.9.0",
33
+ "@pnpm/resolving.resolver-base": "1005.1.0",
34
+ "@pnpm/workspace.project-manifest-reader": "1001.1.4"
35
+ },
36
+ "peerDependencies": {
37
+ "@pnpm/logger": ">=1001.0.0 <1002.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@jest/globals": "30.0.5",
41
+ "@types/normalize-path": "^3.0.2",
42
+ "@pnpm/resolving.local-resolver": "1002.1.4",
43
+ "@pnpm/logger": "1001.0.1"
44
+ },
45
+ "engines": {
46
+ "node": ">=22.13"
47
+ },
48
+ "jest": {
49
+ "preset": "@pnpm/jest-config"
50
+ },
51
+ "scripts": {
52
+ "lint": "eslint \"src/**/*.ts\" \"test/**/*.ts\"",
53
+ "_test": "cross-env NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules --disable-warning=ExperimentalWarning --disable-warning=DEP0169\" jest",
54
+ "test": "pnpm run compile && pnpm run _test",
55
+ "fix": "tslint -c tslint.json src/**/*.ts test/**/*.ts --fix",
56
+ "compile": "tsgo --build && pnpm run lint --fix"
57
+ }
58
+ }