Skip to content

Commit

Permalink
fix(postcss-syntax): return location of the makeStyles/makeResetStyle…
Browse files Browse the repository at this point in the history
…s call expression if slots can't be located (#631)

* location

* Change files
  • Loading branch information
YuanboXue-Amber authored Dec 31, 2024
1 parent 510b07d commit 8312835
Show file tree
Hide file tree
Showing 5 changed files with 238 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "patch",
"comment": "fix: return location of the makeStyles/makeResetStyles call expression when it is not called with object expression",
"packageName": "@griffel/postcss-syntax",
"email": "[email protected]",
"dependentChangeType": "patch"
}
22 changes: 20 additions & 2 deletions packages/postcss-syntax/src/location-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export type ResetCommentDirectivesByHookDeclarator = Record</** hook declarator
export type ResetLocationsByHookDeclarator = Record</** hook declarator */ string, t.SourceLocation>;

export interface LocationPluginState extends PluginPass {
callExpressionLocations?: Record</** hook declarator */ string, t.SourceLocation>;
locations?: LocationsByHookDeclarator;
commentDirectives?: CommentDirectivesByHookDeclarator;

Expand All @@ -22,11 +23,12 @@ export interface LocationPluginState extends PluginPass {
}

export interface LocationPluginMetadata {
locations: Record<string, Record<string, t.SourceLocation>>;
callExpressionLocations: Record</** hook declarator */ string, t.SourceLocation>;
locations: LocationsByHookDeclarator;
commentDirectives: CommentDirectivesByHookDeclarator;

resetCommentDirectives: ResetCommentDirectivesByHookDeclarator;
resetLocations: Record<string, t.SourceLocation>;
resetLocations: ResetLocationsByHookDeclarator;
}

// eslint-disable-next-line @typescript-eslint/no-empty-interface
Expand Down Expand Up @@ -57,6 +59,7 @@ const plugin = declare<LocationPluginOptions, PluginObj<LocationPluginState>>((a
name: '@griffel/slot-location-plugin',

pre() {
this.callExpressionLocations = {};
this.locations = {};
this.resetLocations = {};
this.commentDirectives = {};
Expand All @@ -67,6 +70,7 @@ const plugin = declare<LocationPluginOptions, PluginObj<LocationPluginState>>((a
Program: {
exit() {
Object.assign(this.file.metadata, {
callExpressionLocations: this.callExpressionLocations,
locations: this.locations,
resetLocations: this.resetLocations,
commentDirectives: this.commentDirectives,
Expand Down Expand Up @@ -94,6 +98,13 @@ const plugin = declare<LocationPluginOptions, PluginObj<LocationPluginState>>((a
// but since we only collect locations, the plugin is idempotent and we
// it's safe enough to avoid doing that check
if (functionKinds.includes(callee.node.name)) {
if (path.node.loc) {
state.callExpressionLocations ??= {};
state.callExpressionLocations[declaratorId] = {
...path.node.loc,
};
}

const locations = path.get('arguments')[0];
if (!locations.isObjectExpression()) {
return;
Expand Down Expand Up @@ -130,6 +141,13 @@ const plugin = declare<LocationPluginOptions, PluginObj<LocationPluginState>>((a
}

if (resetFunctionKinds.includes(callee.node.name)) {
if (path.node.loc) {
state.callExpressionLocations ??= {};
state.callExpressionLocations[declaratorId] = {
...path.node.loc,
};
}

state.resetLocations ??= {};
const resetStyles = path.get('arguments')[0];
if (!resetStyles.isObjectExpression()) {
Expand Down
57 changes: 57 additions & 0 deletions packages/postcss-syntax/src/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,38 @@ export const useStyles = makeStyles({
});
});

it('should map style locations to makeStyles call when it is not called with object expressions', () => {
const fixture = `
import { makeStyles } from "@griffel/react";
const styles = {
slot1: {
color: "red",
},
slot2: {
backgroundColor: "green",
},
};
export const useStyles = makeStyles(styles);
`;
const root = parse(fixture, { from: 'fixture.styles.ts' });

expect(root.toString()).toMatchInlineSnapshot(`
".fe3e8s9{color:red;}
.fcnqdeg{background-color:green;}"
`);

root.walk(node => {
const slot = node.raw(GRIFFEL_SLOT_RAW);
expect(['slot1', 'slot2']).toContain(slot);
expect(node.raw(GRIFFEL_SLOT_LOCATION_RAW)).toEqual({
start: { line: 13, column: 25, index: 173 },
end: { line: 13, column: 43, index: 191 },
});
});
});

it('should hold original source in document raw field', () => {
const fixture = `
import { makeStyles } from '@griffel/react';
Expand Down Expand Up @@ -334,6 +366,31 @@ export const useResetStyles2 = makeResetStyles({
});
});

it('should map style locations to makeResetStyles call when it is not called with object expressions', () => {
const fixture = `
import { makeResetStyles } from "@griffel/react";
const styles = {
color: "red",
backgroundColor: "green",
};
export const useResetStyles = makeResetStyles(styles);
`;
const root = parse(fixture, { from: 'fixture.styles.ts' });

expect(root.toString()).toMatchInlineSnapshot(`".rbe9p1m{color:red;background-color:green;}"`);

root.walk(node => {
const declarator = node.raw(GRIFFEL_DECLARATOR_RAW);
expect(declarator).toEqual('useResetStyles');
expect(node.raw(GRIFFEL_DECLARATOR_LOCATION_RAW)).toEqual({
start: { line: 9, column: 30, index: 147 },
end: { line: 9, column: 53, index: 170 },
});
});
});

it('should hold original source in document raw field', () => {
const fixture = `
import { makeResetStyles } from '@griffel/react';
Expand Down
15 changes: 11 additions & 4 deletions packages/postcss-syntax/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,15 @@ export const parse = (css: string | { toString(): string }, opts?: ParserOptions
},
});

const { cssEntries, cssResetEntries, resetLocations, locations, commentDirectives, resetCommentDirectives } =
metadata;
const {
cssEntries,
cssResetEntries,
callExpressionLocations,
resetLocations,
locations,
commentDirectives,
resetCommentDirectives,
} = metadata;

const cssRuleSlotNames: string[] = [];
const cssRules: string[] = [];
Expand Down Expand Up @@ -74,9 +81,9 @@ export const parse = (css: string | { toString(): string }, opts?: ParserOptions
node.raws[GRIFFEL_DECLARATOR_RAW] = declarator;
if (slot) {
node.raws[GRIFFEL_SLOT_RAW] = slot;
node.raws[GRIFFEL_SLOT_LOCATION_RAW] = locations[declarator][slot];
node.raws[GRIFFEL_SLOT_LOCATION_RAW] = locations[declarator]?.[slot] ?? callExpressionLocations[declarator];
} else {
node.raws[GRIFFEL_DECLARATOR_LOCATION_RAW] = resetLocations[declarator];
node.raws[GRIFFEL_DECLARATOR_LOCATION_RAW] = resetLocations[declarator] ?? callExpressionLocations[declarator];
}
});

Expand Down
143 changes: 143 additions & 0 deletions packages/postcss-syntax/src/transform-sync.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,147 @@ describe('transformSync', () => {
}
`);
});

it('should return location of makeStyles call expression', () => {
const sourceCode = `
import type { GriffelStyle } from "@griffel/react";
import { makeStyles } from "@griffel/react";
const mixin = (): GriffelStyle => ({
marginTop: "4px",
});
const styles = {
root: {
color: "red",
backgroundColor: "green",
...mixin(),
},
};
export const useStyles1 = makeStyles(styles);
export const useStyles2 = makeStyles(styles);
`;
const options: TransformOptions = {
filename: 'test.styles.ts',
pluginOptions: {
babelOptions: {
presets: ['@babel/preset-typescript'],
},
generateMetadata: true,
},
};

const result = transformSync(sourceCode, options);

expect(result.metadata.cssEntries).toMatchInlineSnapshot(`
Object {
"useStyles1": Object {
"root": Array [
".fe3e8s9{color:red;}",
".fcnqdeg{background-color:green;}",
".fvjh0tl{margin-top:4px;}",
],
},
"useStyles2": Object {
"root": Array [
".fe3e8s9{color:red;}",
".fcnqdeg{background-color:green;}",
".fvjh0tl{margin-top:4px;}",
],
},
}
`);
expect(result.metadata.callExpressionLocations).toEqual({
useStyles1: {
end: {
column: 50,
index: 383,
line: 17,
},
start: {
column: 32,
index: 365,
line: 17,
},
},
useStyles2: {
end: {
column: 50,
index: 435,
line: 18,
},
start: {
column: 32,
index: 417,
line: 18,
},
},
});
});

it('should return location of makeResetStyles call expression', () => {
const sourceCode = `
import type { GriffelStyle } from "@griffel/react";
import { makeResetStyles } from "@griffel/react";
const mixin = (): GriffelStyle => ({
marginTop: "4px",
});
const styles = {
color: "red",
backgroundColor: "green",
...mixin(),
};
export const useResetStyles1 = makeResetStyles(styles);
export const useResetStyles2 = makeResetStyles(styles);
`;
const options: TransformOptions = {
filename: 'test.styles.ts',
pluginOptions: {
babelOptions: {
presets: ['@babel/preset-typescript'],
},
generateMetadata: true,
},
};

const result = transformSync(sourceCode, options);

expect(result.metadata.cssResetEntries).toMatchInlineSnapshot(`
Object {
"useResetStyles1": Array [
".rv6h41g{color:red;background-color:green;margin-top:4px;}",
],
"useResetStyles2": Array [
".rv6h41g{color:red;background-color:green;margin-top:4px;}",
],
}
`);
expect(result.metadata.callExpressionLocations).toEqual({
useResetStyles1: {
end: {
column: 60,
index: 362,
line: 12,
},
start: {
column: 37,
index: 339,
line: 12,
},
},
useResetStyles2: {
end: {
column: 60,
index: 424,
line: 13,
},
start: {
column: 37,
index: 401,
line: 13,
},
},
});
});
});

0 comments on commit 8312835

Please sign in to comment.