Skip to content

Commit 29fa245

Browse files
authored
Adds extensionless url support (#5931)
**What's the problem this PR addresses?** The v2 never supported referencing packages exposed as extensionless tgz tarballs, despite other clients being fine with them. Us being stricter here doesn't provide any value, and just hurts compatibility. Fixes #5929 **How did you fix it?** Adds support for extensionless urls, which are now interpreted as regular tarballs. **Checklist** <!--- Don't worry if you miss something, chores are automatically tested. --> <!--- This checklist exists to help you remember doing the chores when you submit a PR. --> <!--- Put an `x` in all the boxes that apply. --> - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). <!-- See https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released for more details. --> <!-- Check with `yarn version check` and fix with `yarn version check -i` --> - [x] I have set the packages that need to be released for my changes to be effective. <!-- The "Testing chores" workflow validates that your PR follows our guidelines. --> <!-- If it doesn't pass, click on it to see details as to what your PR might be missing. --> - [x] I will check that all automated PR checks pass before the PR gets reviewed.
1 parent 38d2007 commit 29fa245

File tree

6 files changed

+62
-26
lines changed

6 files changed

+62
-26
lines changed

.yarn/versions/70b508e3.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
releases:
2+
"@yarnpkg/cli": patch
3+
"@yarnpkg/plugin-http": patch
4+
5+
declined:
6+
- "@yarnpkg/plugin-compat"
7+
- "@yarnpkg/plugin-constraints"
8+
- "@yarnpkg/plugin-dlx"
9+
- "@yarnpkg/plugin-essentials"
10+
- "@yarnpkg/plugin-init"
11+
- "@yarnpkg/plugin-interactive-tools"
12+
- "@yarnpkg/plugin-nm"
13+
- "@yarnpkg/plugin-npm-cli"
14+
- "@yarnpkg/plugin-pack"
15+
- "@yarnpkg/plugin-patch"
16+
- "@yarnpkg/plugin-pnp"
17+
- "@yarnpkg/plugin-pnpm"
18+
- "@yarnpkg/plugin-stage"
19+
- "@yarnpkg/plugin-typescript"
20+
- "@yarnpkg/plugin-version"
21+
- "@yarnpkg/plugin-workspace-tools"
22+
- "@yarnpkg/builder"
23+
- "@yarnpkg/core"
24+
- "@yarnpkg/doctor"

packages/plugin-http/sources/TarballHttpFetcher.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,11 @@ import {Fetcher, FetchOptions, MinimalFetchOptions} from '@yarnpkg/core';
22
import {Locator} from '@yarnpkg/core';
33
import {httpUtils, structUtils, tgzUtils} from '@yarnpkg/core';
44

5-
import {TARBALL_REGEXP, PROTOCOL_REGEXP} from './constants';
5+
import * as urlUtils from './urlUtils';
66

77
export class TarballHttpFetcher implements Fetcher {
88
supports(locator: Locator, opts: MinimalFetchOptions) {
9-
if (!TARBALL_REGEXP.test(locator.reference))
10-
return false;
11-
12-
if (PROTOCOL_REGEXP.test(locator.reference))
13-
return true;
14-
15-
return false;
9+
return urlUtils.isTgzUrl(locator.reference);
1610
}
1711

1812
getLocalPath(locator: Locator, opts: FetchOptions) {

packages/plugin-http/sources/TarballHttpResolver.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,15 @@ import {Descriptor, Locator, Manifest} from '@yarnpkg
33
import {LinkType} from '@yarnpkg/core';
44
import {miscUtils, structUtils} from '@yarnpkg/core';
55

6-
import {PROTOCOL_REGEXP, TARBALL_REGEXP} from './constants';
6+
import * as urlUtils from './urlUtils';
77

88
export class TarballHttpResolver implements Resolver {
99
supportsDescriptor(descriptor: Descriptor, opts: MinimalResolveOptions) {
10-
if (!TARBALL_REGEXP.test(descriptor.range))
11-
return false;
12-
13-
if (PROTOCOL_REGEXP.test(descriptor.range))
14-
return true;
15-
16-
return false;
10+
return urlUtils.isTgzUrl(descriptor.range);
1711
}
1812

1913
supportsLocator(locator: Locator, opts: MinimalResolveOptions) {
20-
if (!TARBALL_REGEXP.test(locator.reference))
21-
return false;
22-
23-
if (PROTOCOL_REGEXP.test(locator.reference))
24-
return true;
25-
26-
return false;
14+
return urlUtils.isTgzUrl(locator.reference);
2715
}
2816

2917
shouldPersistResolution(locator: Locator, opts: MinimalResolveOptions) {

packages/plugin-http/sources/constants.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export function isTgzUrl(url: string) {
2+
let parsed: URL;
3+
try {
4+
parsed = new URL(url);
5+
} catch {
6+
return false;
7+
}
8+
9+
if (parsed.protocol !== `http:` && parsed.protocol !== `https:`)
10+
return false;
11+
12+
if (!parsed.pathname.match(/(\.tar\.gz|\.tgz|\/[^.]+)$/))
13+
return false;
14+
15+
return true;
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import * as urlUtils from '../sources/urlUtils';
2+
3+
const EXPECTATIONS: Array<[string, boolean]> = [
4+
[`https://example.org/package.tar.gz`, true],
5+
[`https://example.org/package.tgz`, true],
6+
[`https://example.org/package`, true],
7+
[`https://example.org/package.git`, false],
8+
[`https://example.org/package.tgz.git`, false],
9+
[`ftp://example.org/package.tgz`, false],
10+
[`1.2.3`, false],
11+
];
12+
13+
for (const [url, expected] of EXPECTATIONS) {
14+
test(`isTgzUrl(${JSON.stringify(url)}) === ${JSON.stringify(expected)}`, () => {
15+
expect(urlUtils.isTgzUrl(url)).toEqual(expected);
16+
});
17+
}

0 commit comments

Comments
 (0)