Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(postcss-syntax): return location of the makeStyles/makeResetStyles call expression if slots can't be located #631

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
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,
},
},
});
});
});
Loading