Skip to content

Commit 4e4bfbf

Browse files
dependabot[bot]layershifterclaude
authored
chore(deps-dev): bump prettier 2 → 3 (#875)
* chore(deps-dev): bump prettier 2 → 3 prettier 3.x is async-only (prettier.format returns a Promise). With @griffel/* packages now on vitest, the runtime can handle async matchers natively, so: - Bump root prettier from 2.8.2 to 3.8.3 (and drop @types/prettier; prettier 3 ships its own types) - Add @griffel/core's new async \`toMatchFormattedInlineSnapshot\` matcher in packages/core/src/common/snapshotMatchers.ts. Accepts a renderer, a [classMap, rulesByBucket] tuple from resolveStyleRules, an array from resolveResetStyleRules, or a raw CSS string; awaits prettier 3 formatting before delegating to vitest's toMatchInlineSnapshot - Delete packages/core/src/common/snapshotSerializers.ts (the prettier- sync-based snapshot serializers) - Convert 8 core test files (makeStyles/makeResetStyles/makeStaticStyles/ resolveStyleRules{,.scope}/resolveResetStyleRules{,.scope}/ createDOMRenderer) to use the new async matcher - Replace the sync \`cssSerializer\`/HTML serializer pattern in 5 other test files with explicit async \`formatCss\`/\`formatHtml\` helpers - Add \`await\` to direct prettier.format() calls in 3 webpack-related test files One snapshot (resolveStyleRules \`boxShadow with multiple values\`) reflects prettier 3's new line-wrapping for multi-value box-shadow — formatting only, no logic change. babel-plugin-tester callers (babel-preset/transformPlugin.test.ts and webpack-extraction-plugin/babelPluginStripGriffelRuntime.test.ts) are unchanged — babel-plugin-tester v12 already handles prettier 3 internally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Change files --------- Co-authored-by: Oleksandr Fediashov <olfedias@microsoft.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 45e166b commit 4e4bfbf

23 files changed

Lines changed: 700 additions & 752 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "none",
3+
"comment": "chore: bump prettier from 2.8.2 to 3.8.3",
4+
"packageName": "@griffel/core",
5+
"email": "olfedias@microsoft.com",
6+
"dependentChangeType": "none"
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "none",
3+
"comment": "chore: bump prettier from 2.8.2 to 3.8.3",
4+
"packageName": "@griffel/webpack-plugin",
5+
"email": "olfedias@microsoft.com",
6+
"dependentChangeType": "none"
7+
}

e2e/utils/src/compareSnapshots.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ type CompareSnapshotsOptions = {
88
resultFile: string;
99
};
1010

11-
function formatCSS(css: string): string {
12-
return prettier.format(css, { parser: 'css' }).trim();
11+
async function formatCSS(css: string): Promise<string> {
12+
return (await prettier.format(css, { parser: 'css' })).trim();
1313
}
1414

1515
export async function compareSnapshots(options: CompareSnapshotsOptions): Promise<void> {
@@ -18,9 +18,9 @@ export async function compareSnapshots(options: CompareSnapshotsOptions): Promis
1818
const resultContentRaw = await fs.promises.readFile(resultFile, 'utf8');
1919
// Remove meta info added by Rspack
2020
const resultContentCleaned = resultContentRaw.replace(/head{--webpack-rspack-(\d+)-(\w+)-(\d+):&_(\d+);}/, '');
21-
const resultContent = formatCSS(resultContentCleaned);
21+
const resultContent = await formatCSS(resultContentCleaned);
2222

23-
const snapshotContent = formatCSS(await fs.promises.readFile(snapshotFile, 'utf8'));
23+
const snapshotContent = await formatCSS(await fs.promises.readFile(snapshotFile, 'utf8'));
2424

2525
const diff = snapshotDiff(snapshotContent, resultContent, {
2626
colors: true,

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,6 @@
9494
"@types/js-beautify": "^1.14.3",
9595
"@types/mini-css-extract-plugin": "2.5.1",
9696
"@types/node": "25.6.0",
97-
"@types/prettier": "2.7.3",
9897
"@types/react": "19.2.14",
9998
"@types/react-dom": "19.2.3",
10099
"@types/stylis": "4.2.7",
@@ -131,7 +130,7 @@
131130
"nano-staged": "~1.0.2",
132131
"nx": "22.7.1",
133132
"playwright": "^1.59.1",
134-
"prettier": "2.8.2",
133+
"prettier": "3.8.3",
135134
"prism-react-renderer": "2.4.1",
136135
"raw-loader": "4.0.2",
137136
"react": "19.2.5",
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { expect, chai, Snapshots } from 'vitest';
2+
import * as prettier from 'prettier';
3+
4+
import { DATA_BUCKET_ATTR } from '../constants.js';
5+
import type { resolveStyleRules } from '../runtime/resolveStyleRules.js';
6+
import { normalizeCSSBucketEntry } from '../runtime/utils/normalizeCSSBucketEntry.js';
7+
import type { CSSRulesByBucket, GriffelRenderer } from '../types.js';
8+
import type { resolveResetStyleRules } from '../runtime/resolveResetStyleRules.js';
9+
10+
const { toMatchInlineSnapshot } = Snapshots;
11+
12+
// eslint-disable-next-line eqeqeq
13+
const isObject = (value: unknown) => value != null && !Array.isArray(value) && typeof value === 'object';
14+
15+
type StyleRulesTuple = ReturnType<typeof resolveStyleRules>;
16+
type ResetStyleRulesTuple = ReturnType<typeof resolveResetStyleRules>;
17+
18+
const isRenderer = (value: unknown): value is GriffelRenderer =>
19+
isObject(value) && isObject((value as GriffelRenderer).stylesheets);
20+
const isStyleRulesTuple = (value: unknown): value is StyleRulesTuple =>
21+
Array.isArray(value) && value.length === 2 && !Array.isArray(value[0]);
22+
23+
function rendererToCSS(renderer: GriffelRenderer): string {
24+
const stylesheetKeys = Object.keys(renderer.stylesheets) as (keyof (typeof renderer)['stylesheets'])[];
25+
26+
const rules = stylesheetKeys.reduce((acc, styleEl) => {
27+
const stylesheet = renderer.stylesheets[styleEl];
28+
29+
if (stylesheet) {
30+
const cssRules = stylesheet.cssRules() ?? ([] as string[]);
31+
const attributes = Object.entries(stylesheet.elementAttributes).filter(([key]) => key !== DATA_BUCKET_ATTR);
32+
33+
if (cssRules.length === 0) {
34+
return acc;
35+
}
36+
37+
return [
38+
...acc,
39+
`/** bucket "${styleEl.slice(0, 1)}"${
40+
attributes.length > 0 ? ' ' + JSON.stringify(Object.fromEntries(attributes)) : ''
41+
} **/`,
42+
...cssRules,
43+
];
44+
}
45+
46+
return acc;
47+
}, [] as string[]);
48+
49+
return rules.join('\n');
50+
}
51+
52+
function styleRulesToCSS(value: StyleRulesTuple): string {
53+
const cssRulesByBucket = value[1];
54+
const keys = Object.keys(cssRulesByBucket) as (keyof typeof cssRulesByBucket)[];
55+
56+
return keys
57+
.flatMap(styleBucketName => cssRulesByBucket[styleBucketName]!.map(entry => normalizeCSSBucketEntry(entry)[0]))
58+
.join('\n');
59+
}
60+
61+
function resetStyleRulesToCSS(value: ResetStyleRulesTuple): string {
62+
const cssRulesByBucket: CSSRulesByBucket = Array.isArray(value[2]) ? { r: value[2] } : value[2];
63+
64+
return Object.entries(cssRulesByBucket)
65+
.filter(([, rules]) => rules.length > 0)
66+
.flatMap(([key, rules]) => [`/** bucket "${key}" */`, (rules as string[]).join('\n')])
67+
.join('\n');
68+
}
69+
70+
function toRawCSS(value: unknown): string {
71+
if (typeof value === 'string') {
72+
return value;
73+
}
74+
if (isRenderer(value)) {
75+
return rendererToCSS(value);
76+
}
77+
if (isStyleRulesTuple(value)) {
78+
return styleRulesToCSS(value);
79+
}
80+
if (Array.isArray(value)) {
81+
return resetStyleRulesToCSS(value as ResetStyleRulesTuple);
82+
}
83+
throw new Error(`toMatchFormattedInlineSnapshot: unsupported value type "${typeof value}"`);
84+
}
85+
86+
expect.extend({
87+
async toMatchFormattedInlineSnapshot(received: unknown, inlineSnapshot?: string) {
88+
// Capture the call site synchronously so vitest reports the right location on failure.
89+
// Must set the flag on this.assertion (the Chai assertion object) because toMatchInlineSnapshot
90+
// reads the error via chai.util.flag(assertion, 'error') where assertion = this.assertion.
91+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
92+
chai.util.flag((this as any).assertion, 'error', new Error());
93+
94+
const rawCSS = toRawCSS(received);
95+
const formatted = (await prettier.format(rawCSS, { parser: 'css' })).trim();
96+
97+
return toMatchInlineSnapshot.call(this, formatted, inlineSnapshot);
98+
},
99+
});
100+
101+
interface CustomMatchers<R = unknown> {
102+
toMatchFormattedInlineSnapshot(inlineSnapshot?: string): R;
103+
}
104+
105+
declare module 'vitest' {
106+
/* eslint-disable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
107+
interface Assertion<T = any> extends CustomMatchers<T> {}
108+
interface AsymmetricMatchersContaining extends CustomMatchers {}
109+
/* eslint-enable @typescript-eslint/no-empty-object-type, @typescript-eslint/no-empty-interface, @typescript-eslint/no-explicit-any */
110+
}

packages/core/src/common/snapshotSerializers.ts

Lines changed: 0 additions & 94 deletions
This file was deleted.

packages/core/src/makeResetStyles.test.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2-
import { griffelRendererSerializer } from './common/snapshotSerializers.js';
2+
import './common/snapshotMatchers.js';
33
import { createDOMRenderer } from './renderer/createDOMRenderer.js';
44
import { makeResetStyles } from './makeResetStyles.js';
55
import type { GriffelRenderer } from './types.js';
66

7-
expect.addSnapshotSerializer(griffelRendererSerializer);
8-
97
describe('makeResetStyles', () => {
108
let renderer: GriffelRenderer;
119

@@ -18,50 +16,50 @@ describe('makeResetStyles', () => {
1816
document.head.innerHTML = '';
1917
});
2018

21-
it('returns a single classname for a single style', () => {
19+
it('returns a single classname for a single style', async () => {
2220
const computeClassName = makeResetStyles({
2321
color: 'red',
2422
flexDirection: 'row',
2523
});
2624

2725
expect(computeClassName({ dir: 'ltr', renderer })).toEqual('r7lmmpp');
28-
expect(renderer).toMatchInlineSnapshot(`
29-
/** bucket "r" {"data-priority":"0"} **/
26+
await expect(renderer).toMatchFormattedInlineSnapshot(`
27+
"/** bucket "r" {"data-priority":"0"} **/
3028
.r7lmmpp {
3129
color: red;
3230
flex-direction: row;
33-
}
31+
}"
3432
`);
3533
});
3634

37-
it('handles RTL', () => {
35+
it('handles RTL', async () => {
3836
const computeClassName = makeResetStyles({
3937
padding: '40px 20px 10px 5px',
4038
});
4139

4240
expect(computeClassName({ dir: 'ltr', renderer })).toEqual('rgb6zd6');
4341
expect(computeClassName({ dir: 'rtl', renderer })).toEqual('rjhindo');
4442

45-
expect(renderer).toMatchInlineSnapshot(`
46-
/** bucket "r" {"data-priority":"0"} **/
43+
await expect(renderer).toMatchFormattedInlineSnapshot(`
44+
"/** bucket "r" {"data-priority":"0"} **/
4745
.rgb6zd6 {
4846
padding: 40px 20px 10px 5px;
4947
}
5048
.rjhindo {
5149
padding: 40px 5px 10px 20px;
52-
}
50+
}"
5351
`);
5452
});
5553

56-
it('handles at rules', () => {
54+
it('handles at rules', async () => {
5755
const computeClassName = makeResetStyles({
5856
color: 'red',
5957
'@media (min-width: 100px)': { color: 'blue' },
6058
});
6159

6260
expect(computeClassName({ dir: 'ltr', renderer })).toEqual('rbwcbv2');
63-
expect(renderer).toMatchInlineSnapshot(`
64-
/** bucket "r" {"data-priority":"0"} **/
61+
await expect(renderer).toMatchFormattedInlineSnapshot(`
62+
"/** bucket "r" {"data-priority":"0"} **/
6563
.rbwcbv2 {
6664
color: red;
6765
}
@@ -70,7 +68,7 @@ describe('makeResetStyles', () => {
7068
.rbwcbv2 {
7169
color: blue;
7270
}
73-
}
71+
}"
7472
`);
7573
});
7674

0 commit comments

Comments
 (0)