Skip to content

Commit 6ff935b

Browse files
authored
fix: allow subpath imports that start with #/ (#468)
1 parent 79e2961 commit 6ff935b

File tree

5 files changed

+141
-5
lines changed

5 files changed

+141
-5
lines changed

lib/util/entrypoints.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -520,9 +520,8 @@ function assertImportsFieldRequest(request) {
520520
if (request.length === 1) {
521521
throw new Error("Request should have at least 2 characters");
522522
}
523-
if (request.charCodeAt(1) === slashCode) {
524-
throw new Error('Request should not start with "#/"');
525-
}
523+
// Note: #/ patterns are now allowed per Node.js PR #60864
524+
// https://github.com/nodejs/node/pull/60864
526525
if (request.charCodeAt(request.length - 1) === slashCode) {
527526
throw new Error("Only requesting file allowed");
528527
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "imports-slash-pattern",
3+
"imports": {
4+
"#/*": "./src/*"
5+
}
6+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = "deep";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
module.exports = "utils";

test/importsField.test.js

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,9 @@ describe("process imports field", () => {
891891
},
892892
{
893893
name: "incorrect request #4",
894-
expect: new Error('Request should not start with "#/"'),
894+
// Note: #/ patterns are now allowed per Node.js PR #60864
895+
// but #/ alone still fails because it ends with "/" (requesting directory)
896+
expect: new Error("Only requesting file allowed"),
895897
suite: [
896898
{
897899
"#a/": {
@@ -919,6 +921,86 @@ describe("process imports field", () => {
919921
},
920922
// #endregion
921923

924+
// #region #/ slash pattern (node.js PR #60864)
925+
// These tests cover the new Node.js behavior that allows #/ patterns
926+
// See: https://github.com/nodejs/node/pull/60864
927+
{
928+
name: "#/ slash pattern #1",
929+
// #/* pattern should map #/utils.js to ./src/utils.js
930+
expect: ["./src/utils.js"],
931+
suite: [
932+
{
933+
"#/*": "./src/*",
934+
},
935+
"#/utils.js",
936+
[],
937+
],
938+
},
939+
{
940+
name: "#/ slash pattern #2",
941+
// #/* pattern should map #/nested/deep.js to ./src/nested/deep.js
942+
expect: ["./src/nested/deep.js"],
943+
suite: [
944+
{
945+
"#/*": "./src/*",
946+
},
947+
"#/nested/deep.js",
948+
[],
949+
],
950+
},
951+
{
952+
name: "#/ slash pattern #3",
953+
// #/main direct mapping (starts with #/ but is not a wildcard)
954+
expect: ["./main.js"],
955+
suite: [
956+
{
957+
"#/main": "./main.js",
958+
},
959+
"#/main",
960+
[],
961+
],
962+
},
963+
{
964+
name: "#/ slash pattern #4",
965+
// Conditional mapping with #/* pattern
966+
expect: ["./browser/utils.js"],
967+
suite: [
968+
{
969+
"#/*": {
970+
browser: "./browser/*",
971+
default: "./src/*",
972+
},
973+
},
974+
"#/utils.js",
975+
["browser"],
976+
],
977+
},
978+
{
979+
name: "#/ slash pattern #5",
980+
// #/lib/ subpath folder mapping (legacy syntax with #/ prefix)
981+
expect: ["./lib/utils.js"],
982+
suite: [
983+
{
984+
"#/lib/": "./lib/",
985+
},
986+
"#/lib/utils.js",
987+
[],
988+
],
989+
},
990+
{
991+
name: "#/ slash pattern #6",
992+
// Symmetric exports/imports pattern as shown in Node.js PR
993+
expect: ["./src/index.js"],
994+
suite: [
995+
{
996+
"#/*": "./src/*",
997+
},
998+
"#/index.js",
999+
[],
1000+
],
1001+
},
1002+
// #endregion
1003+
9221004
// #region Directory imports targets may backtrack above the package base
9231005
{
9241006
name: "backtracking package base #1",
@@ -1334,10 +1416,12 @@ describe("importsFieldPlugin", () => {
13341416
});
13351417

13361418
it("should work and throw an error on invalid imports #1", (done) => {
1419+
// Note: #/ patterns are now allowed per Node.js PR #60864
1420+
// #/dep will now try to resolve but fail because there's no mapping
13371421
resolver.resolve({}, fixture, "#/dep", {}, (err, result) => {
13381422
if (!err) return done(new Error(`expect error, got ${result}`));
13391423
expect(err).toBeInstanceOf(Error);
1340-
expect(err.message).toMatch(/Request should not start with "#\/"/);
1424+
expect(err.message).toMatch(/is not imported from package/);
13411425
done();
13421426
});
13431427
});
@@ -1531,4 +1615,49 @@ describe("importsFieldPlugin", () => {
15311615
done();
15321616
});
15331617
});
1618+
1619+
// Tests for #/ slash pattern support (node.js PR #60864)
1620+
// These tests cover the new Node.js behavior that allows #/ patterns
1621+
// See: https://github.com/nodejs/node/pull/60864
1622+
describe("#/ slash pattern (node.js PR #60864)", () => {
1623+
const slashPatternFixture = path.resolve(
1624+
__dirname,
1625+
"fixtures",
1626+
"imports-slash-pattern",
1627+
);
1628+
1629+
it("should resolve #/utils.js using #/* pattern", (done) => {
1630+
resolver.resolve(
1631+
{},
1632+
slashPatternFixture,
1633+
"#/utils.js",
1634+
{},
1635+
(err, result) => {
1636+
if (err) return done(err);
1637+
if (!result) return done(new Error("No result"));
1638+
expect(result).toEqual(
1639+
path.resolve(slashPatternFixture, "src/utils.js"),
1640+
);
1641+
done();
1642+
},
1643+
);
1644+
});
1645+
1646+
it("should resolve #/nested/deep.js using #/* pattern", (done) => {
1647+
resolver.resolve(
1648+
{},
1649+
slashPatternFixture,
1650+
"#/nested/deep.js",
1651+
{},
1652+
(err, result) => {
1653+
if (err) return done(err);
1654+
if (!result) return done(new Error("No result"));
1655+
expect(result).toEqual(
1656+
path.resolve(slashPatternFixture, "src/nested/deep.js"),
1657+
);
1658+
done();
1659+
},
1660+
);
1661+
});
1662+
});
15341663
});

0 commit comments

Comments
 (0)