diff --git a/.changeset/tester-react-native-export.md b/.changeset/tester-react-native-export.md new file mode 100644 index 0000000000..0649ab190f --- /dev/null +++ b/.changeset/tester-react-native-export.md @@ -0,0 +1,5 @@ +--- +'@fluentui-react-native/tester': patch +--- + +Point the `react-native` export condition at `./src/index.tsx`; it referenced `./src/index.ts`, which does not exist. diff --git a/apps/fluent-tester/package.json b/apps/fluent-tester/package.json index fc4bf900da..5e0905636b 100644 --- a/apps/fluent-tester/package.json +++ b/apps/fluent-tester/package.json @@ -16,7 +16,7 @@ "exports": { ".": { "types": "./lib/index.d.ts", - "react-native": "./src/index.ts", + "react-native": "./src/index.tsx", "import": "./lib/index.js", "default": "./src/index.tsx" } diff --git a/scripts/src/tasks/constrain.ts b/scripts/src/tasks/constrain.ts index 3dfc21250a..d852827c11 100644 --- a/scripts/src/tasks/constrain.ts +++ b/scripts/src/tasks/constrain.ts @@ -45,6 +45,7 @@ export function constrain(workspace: Yarn.Constraints.Workspace): void { } assertDeprecations(ctx); useCatalogs(ctx); + ensureReactNativeExports(ctx); } export function constrainRoot(workspace: Yarn.Constraints.Workspace): void { @@ -81,6 +82,36 @@ function useCatalogs(ctx: PackageContext): void { } } +/** + * Metro resolves the "react-native" export condition to TypeScript source. Ensure published packages point that condition + * at a file that exists, and that React Native libraries provide it for every export. + */ +function ensureReactNativeExports(ctx: PackageContext): void { + const { exports, peerDependencies, private: isPrivate } = ctx.manifest; + if (isPrivate || !exports || typeof exports !== 'object' || Array.isArray(exports)) { + return; + } + const requireCondition = Boolean(peerDependencies?.['react-native']); + for (const [subpath, conditions] of Object.entries(exports)) { + if (!conditions || typeof conditions !== 'object' || Array.isArray(conditions)) { + continue; + } + const target = (conditions as Record)['react-native']; + if (typeof target === 'string') { + if (!repoCtx.hasFile(ctx.root, target)) { + const swapped = target.endsWith('.tsx') ? target.slice(0, -1) : target.endsWith('.ts') ? `${target}x` : undefined; + if (swapped && repoCtx.hasFile(ctx.root, swapped)) { + ctx.enforce(['exports', subpath, 'react-native'], swapped); + } else { + ctx.error(`exports["${subpath}"]["react-native"] points to ${target}, which does not exist`); + } + } + } else if (requireCondition) { + ctx.error(`exports["${subpath}"] is missing a "react-native" condition pointing to its TypeScript source`); + } + } +} + function assertDeprecations(ctx: PackageContext): void { // placeholder to add deprecated packages or parts of package.json to remove them ctx.enforce('scripts.lint-package', undefined);