From a6a3149670275ef4d4132c2aeecf05a2611b5a1c Mon Sep 17 00:00:00 2001 From: Tommy Nguyen <4123478+tido64@users.noreply.github.com> Date: Wed, 28 Aug 2024 08:20:26 +0200 Subject: [PATCH] fix(tools-node): allow empty scope in package names (#3311) --- .changeset/beige-otters-dream.md | 6 ++++++ packages/test-app/jest.config.js | 1 + packages/test-app/metro.config.js | 1 + packages/test-app/src/Home.tsx | 2 +- packages/test-app/tsconfig.json | 4 ++-- packages/tools-node/src/package.ts | 10 +++++----- packages/tools-node/test/package.test.ts | 8 ++++---- 7 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 .changeset/beige-otters-dream.md diff --git a/.changeset/beige-otters-dream.md b/.changeset/beige-otters-dream.md new file mode 100644 index 000000000..df9309501 --- /dev/null +++ b/.changeset/beige-otters-dream.md @@ -0,0 +1,6 @@ +--- +"@rnx-kit/metro-plugin-typescript": patch +"@rnx-kit/tools-node": patch +--- + +Allow empty scope in package names diff --git a/packages/test-app/jest.config.js b/packages/test-app/jest.config.js index 74aecfdab..869691f4d 100644 --- a/packages/test-app/jest.config.js +++ b/packages/test-app/jest.config.js @@ -10,6 +10,7 @@ function isPnpmMode() { const config = { preset: "@rnx-kit/jest-preset/private", moduleNameMapper: { + "^@/(.*)$": "/src/internal/$1", "^internal(.*)$": "/src/internal$1", }, }; diff --git a/packages/test-app/metro.config.js b/packages/test-app/metro.config.js index 585167efc..a44c75da2 100644 --- a/packages/test-app/metro.config.js +++ b/packages/test-app/metro.config.js @@ -16,6 +16,7 @@ const blockList = exclusionList([ module.exports = makeMetroConfig({ resolver: { extraNodeModules: { + "@/hermes": path.resolve(__dirname, "src", "internal", "hermes.ts"), internal: path.resolve(__dirname, "src", "internal"), ...(useAuthMock ? { diff --git a/packages/test-app/src/Home.tsx b/packages/test-app/src/Home.tsx index ad6851702..6d0d97354 100644 --- a/packages/test-app/src/Home.tsx +++ b/packages/test-app/src/Home.tsx @@ -1,13 +1,13 @@ // Both `internal` imports are used to verify that `metro-resolver-symlinks` // resolves them correctly when `experimental_retryResolvingFromDisk` is // enabled. +import { getHermesVersion } from "@/hermes"; import { getReactNativeVersion, isBridgeless, isFabricInstance, isRemoteDebuggingAvailable, } from "internal"; -import { getHermesVersion } from "internal/hermes"; import type { PropsWithChildren } from "react"; import React, { useCallback, useState } from "react"; import type { NativeSyntheticEvent } from "react-native"; diff --git a/packages/test-app/tsconfig.json b/packages/test-app/tsconfig.json index 93280c8b9..be1621b3c 100644 --- a/packages/test-app/tsconfig.json +++ b/packages/test-app/tsconfig.json @@ -4,8 +4,8 @@ "checkJs": false, "noEmit": true, "paths": { - "internal": ["./src/internal"], - "internal/*": ["./src/internal/*"] + "@/*": ["./src/internal/*"], + "internal": ["./src/internal"] } }, "include": ["src"] diff --git a/packages/tools-node/src/package.ts b/packages/tools-node/src/package.ts index e69bd7869..f6c619e88 100644 --- a/packages/tools-node/src/package.ts +++ b/packages/tools-node/src/package.ts @@ -22,11 +22,11 @@ export function parsePackageRef(r: string): PackageRef { // If `/` is not found, the reference could be a path alias. const indexSeparator = r.indexOf("/"); if (indexSeparator >= 0) { - // The separator must start from position >= 2 to ensure that it is '@' - // and at least one other character. Further, the separator must have - // at least 1 character following it, before the end of the string. - if (indexSeparator < 2 || indexSeparator + 2 >= r.length) { - throw new Error(`Invalid package reference: "${r}"`); + // The separator must have at least 1 character following it, before the + // end of the string. Note that the scope may be an empty string. + // TypeScript does not place any restrictions on import re-mappings. + if (indexSeparator + 1 >= r.length) { + throw new Error(`Invalid package reference: ${r}`); } return { diff --git a/packages/tools-node/test/package.test.ts b/packages/tools-node/test/package.test.ts index 94ae63a99..a91430605 100644 --- a/packages/tools-node/test/package.test.ts +++ b/packages/tools-node/test/package.test.ts @@ -50,6 +50,10 @@ describe("Node > Package", () => { deepEqual(parsePackageRef("@alias"), { name: "@alias" }); }); + it("parsePackageRef(@/core) is allowed", () => { + deepEqual(parsePackageRef("@/core"), { scope: "@", name: "core" }); + }); + it("parsePackageRef(undefined) throws an Error", () => { // @ts-expect-error Argument of type 'undefined' is not assignable to parameter of type 'string' throws(() => parsePackageRef(undefined)); @@ -59,10 +63,6 @@ describe("Node > Package", () => { throws(() => parsePackageRef("@babel/")); }); - it("parsePackageRef(@/core) throws an Error", () => { - throws(() => parsePackageRef("@/core")); - }); - it("readPackage() loads package.json when given its containing directory", () => { const manifest = readPackage(fixtureDir); equal(manifest.name, "test-package");