Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions monosize.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ const config = {
'react-dom': 'ReactDOM',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵🏾‍♀️ visual changes to review in the Visual Change Report

vr-tests-react-components/Menu 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu.Nested Submenus Small Viewport Stacked.nested menu.chromium.png 759 Changed
vr-tests-react-components/Menu Converged - submenuIndicator slotted content 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Menu Converged - submenuIndicator slotted content.default - RTL.submenus open.chromium.png 404 Changed
vr-tests-react-components/Positioning 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/Positioning.Positioning end.chromium.png 12 Changed
vr-tests-react-components/Positioning.Positioning end.updated 2 times.chromium.png 616 Changed
vr-tests-react-components/ProgressBar converged 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - Dark Mode.default.chromium.png 34 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness - High Contrast.default.chromium.png 99 Changed
vr-tests-react-components/ProgressBar converged.Indeterminate + thickness.default.chromium.png 166 Changed
vr-tests-web-components/Avatar 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/Avatar. - Dark Mode.normal.chromium.png 10380 Changed
vr-tests-web-components/MenuList 3 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests-web-components/MenuList. - RTL.1st selected.chromium_2.png 39384 Changed
vr-tests-web-components/MenuList. - RTL.normal.chromium_1.png 39083 Changed
vr-tests-web-components/MenuList. - RTL.2nd selected.chromium_3.png 38816 Changed
vr-tests/Callout 2 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/Callout.Top left edge.default.chromium.png 2212 Changed
vr-tests/Callout.No callout width specified.default.chromium.png 2143 Changed
vr-tests/react-charting-AreaChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/react-charting-AreaChart.Custom Accessibility.default.chromium.png 11 Changed
vr-tests/react-charting-LineChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/react-charting-LineChart.Multiple.default.chromium.png 192 Changed
vr-tests/react-charting-VerticalBarChart 1 screenshots
Image Name Diff(in Pixels) Image Type
vr-tests/react-charting-VerticalBarChart.Basic - Secondary Y Axis.default.chromium.png 3 Changed

'react/compiler-runtime': 'ReactCompilerRuntime',
};
// ESM-first packages emit bare subpath imports (e.g. `use-sync-external-store/shim`) that lack
// a file extension. Once measured packages are `type: module`, webpack treats their `lib/` as
// ESM and enforces fully-specified imports; disable that so legacy CJS deps still resolve.
config.module = config.module ?? {};
config.module.rules = config.module.rules ?? [];
config.module.rules.push({ test: /\.[cm]?js$/, resolve: { fullySpecified: false } });
return config;
}),
reportResolvers: {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"devDependencies": {
"@actions/core": "1.9.1",
"@actions/github": "5.0.3",
"@arethetypeswrong/cli": "0.18.3",
"@babel/core": "7.29.0",
"@babel/generator": "7.29.1",
"@babel/parser": "7.29.3",
Expand Down
42 changes: 23 additions & 19 deletions scripts/monorepo/src/getDependencies.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,62 +10,66 @@ describe(`#getDependencies`, () => {
it(`should return package/s dependency tree array for all,devDeps and production dependencies`, async () => {
const deps = await getDependencies(packageName);

expect(deps.dependencies).toMatchInlineSnapshot(`
// graph traversal order is not deterministic across machines; sort by name for a stable snapshot
/** @type {(a: { name: string }, b: { name: string }) => number} */
const byName = (a, b) => a.name.localeCompare(b.name);

expect([...deps.dependencies].sort(byName)).toMatchInlineSnapshot(`
Array [
Object {
"dependencyType": "dependencies",
"isTopLevel": true,
"name": "react-shared-contexts",
"isTopLevel": false,
"name": "keyboard-keys",
},
Object {
"dependencyType": "dependencies",
"isTopLevel": true,
"name": "react-theme",
"name": "react-jsx-runtime",
},
Object {
"dependencyType": "dependencies",
"isTopLevel": true,
"name": "react-utilities",
"name": "react-shared-contexts",
},
Object {
"dependencyType": "dependencies",
"isTopLevel": true,
"name": "react-jsx-runtime",
"name": "react-theme",
},
Object {
"dependencyType": "dependencies",
"isTopLevel": false,
"name": "tokens",
"isTopLevel": true,
"name": "react-utilities",
},
Object {
"dependencyType": "dependencies",
"isTopLevel": false,
"name": "keyboard-keys",
"name": "tokens",
},
]
`);

expect(deps.devDependencies).toMatchInlineSnapshot(`
expect([...deps.devDependencies].sort(byName)).toMatchInlineSnapshot(`
Array [
Object {
"dependencyType": "devDependencies",
"isTopLevel": true,
"name": "react-conformance",
"isTopLevel": false,
"name": "eslint-plugin",
},
Object {
"dependencyType": "devDependencies",
"isTopLevel": true,
"name": "react-conformance-griffel",
"isTopLevel": false,
"name": "eslint-plugin-react-components",
},
Object {
"dependencyType": "devDependencies",
"isTopLevel": false,
"name": "eslint-plugin",
"isTopLevel": true,
"name": "react-conformance",
},
Object {
"dependencyType": "devDependencies",
"isTopLevel": false,
"name": "eslint-plugin-react-components",
"isTopLevel": true,
"name": "react-conformance-griffel",
},
Object {
"dependencyType": "devDependencies",
Expand All @@ -82,7 +86,7 @@ describe(`#getDependencies`, () => {

expect(packageInfo.absoluteRootPath).toEqual(expect.stringContaining('packages/react-components/react-text'));
expect(packageInfo?.dependencies).toEqual(expect.any(Object));
expect(packageInfo?.main).toEqual('lib-commonjs/index.js');
expect(packageInfo?.main).toEqual('lib-commonjs/index.cjs');
expect(packageInfo?.module).toEqual('lib/index.js');

const depResultWithoutProjectScope = await getDependencies('react-text');
Expand Down
31 changes: 31 additions & 0 deletions tools/workspace-plugin/src/plugins/workspace-plugin.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,37 @@ describe(`workspace-plugin`, () => {
expect(getTargetsNames(results)).toEqual(['clean', 'format', 'type-check']);
});

it('should add the test target when a jest.config.cjs (type:module) exists', async () => {
await tempFs.createFiles({
'proj/project.json': serializeJson({}),
'proj/package.json': serializeJson({ type: 'module' }),
'proj/jest.config.cjs': 'module.exports = {}',
});
const results = await createNodesFunction(['proj/project.json'], options, context);

expect(getTargetsNames(results)).toContain('test');
});

it('should add an optional attw target only when package.json declares exports', async () => {
await tempFs.createFiles({
'with-exports/project.json': serializeJson({ projectType: 'library', tags: ['vNext'] }),
'with-exports/package.json': serializeJson({ exports: { '.': './lib/index.js' } }),
'no-exports/project.json': serializeJson({ projectType: 'library', tags: ['vNext'] }),
'no-exports/package.json': serializeJson({}),
});

const withExports = await createNodesFunction(['with-exports/project.json'], options, context);
const noExports = await createNodesFunction(['no-exports/project.json'], options, context);

expect(getTargetsNames(withExports, 'with-exports')).toContain('attw');
expect(getTargets(withExports, 'with-exports')?.attw).toMatchObject({
executor: 'nx:run-commands',
dependsOn: ['build'],
options: { cwd: 'with-exports', command: expect.stringContaining('attw --pack --profile node16') },
});
expect(getTargetsNames(noExports, 'no-exports')).not.toContain('attw');
});

it('should add lint,test task only if configuration exists', async () => {
await tempFs.createFiles({
'proj/project.json': serializeJson({}),
Expand Down
47 changes: 42 additions & 5 deletions tools/workspace-plugin/src/plugins/workspace-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,11 @@ function buildWorkspaceProjectConfiguration(
targets[options.verifyPackaging.targetName] = verifyPackagingTarget;
}

const attwTarget = buildAttwTarget(projectRoot, config);
if (attwTarget) {
targets.attw = attwTarget;
}

let metadata: WorkspaceTargets['metadata'];

if (isReactProject) {
Expand Down Expand Up @@ -405,7 +410,11 @@ function buildTestTarget(
context: CreateNodesContextV2,
config: TaskBuilderConfig,
): TargetConfiguration<JestConfig.InitialOptions & Pick<RunCommandsOptions, 'cwd'>> | null {
if (!existsSync(join(projectRoot, 'jest.config.js')) && !existsSync(join(projectRoot, 'jest.config.ts'))) {
if (
!existsSync(join(projectRoot, 'jest.config.js')) &&
!existsSync(join(projectRoot, 'jest.config.cjs')) &&
!existsSync(join(projectRoot, 'jest.config.ts'))
) {
return null;
}

Expand All @@ -430,6 +439,28 @@ function buildTestTarget(
};
}

function buildAttwTarget(projectRoot: string, config: TaskBuilderConfig): TargetConfiguration | null {
// optional, published-library-only types/exports validation. Not part of `build` or CI gates.
if (!config.packageJSON.exports) {
return null;
}

return {
executor: 'nx:run-commands',
cache: true,
dependsOn: ['build'],
options: {
cwd: projectRoot,
command: `${config.pmc.exec} attw --pack --profile node16`,
},
inputs: ['default', { externalDependencies: ['@arethetypeswrong/cli'] }],
metadata: {
description: 'Validate package types & export map with @arethetypeswrong/cli (optional)',
technologies: ['typescript'],
},
};
}

function buildLintTarget(
projectRoot: string,
options: Required<WorkspacePluginOptions>,
Expand Down Expand Up @@ -864,16 +895,22 @@ function buildReactIntegrationTesterProjectConfiguration(
hasTypeCheck: storybookAdjacent || libraryWithStoriesAdj,
hasE2E: existsSync(join(projectRootPath, 'cypress.config.ts')) && !storybookAdjacent,
hasTest:
(existsSync(join(projectRootPath, 'jest.config.js')) || existsSync(join(projectRootPath, 'jest.config.ts'))) &&
(existsSync(join(projectRootPath, 'jest.config.js')) ||
existsSync(join(projectRootPath, 'jest.config.cjs')) ||
existsSync(join(projectRootPath, 'jest.config.ts'))) &&
!storybookAdjacent,
};

const ritConfigPathLocal = join(projectRootPath, 'rit.config.js');
// web packages ship as `type: module`, so their CommonJS rit config uses `.cjs`; fall back to `.js`
const ritConfigPathLocal = [
resolve(projectRootPath, 'rit.config.cjs'),
resolve(projectRootPath, 'rit.config.js'),
].find(candidate => existsSync(candidate));

if (existsSync(ritConfigPathLocal)) {
if (ritConfigPathLocal) {
try {
type RITConfig = { react: Record<string, { runConfig?: Record<string, { configPath: string }> }> };
const loaded = require(resolve(projectRootPath, 'rit.config.js'));
const loaded = require(ritConfigPathLocal);
const rit: RITConfig = loaded?.default ?? loaded;

if (rit && typeof rit === 'object' && rit.react && rit.react[reactVersion]) {
Expand Down
Loading
Loading