From f41999357aa9bb48b6b692bc627eef7b54725d58 Mon Sep 17 00:00:00 2001 From: Alexandre Stahmer <47224540+astahmer@users.noreply.github.com> Date: Wed, 21 Feb 2024 03:01:53 +0100 Subject: [PATCH] fix: allow multiple aliases from /css entrypoint (#2232) --- .changeset/shiny-eagles-love.md | 16 +++++ packages/core/__tests__/file-matcher.test.ts | 23 ++++-- packages/core/src/file-matcher.ts | 63 ++++++++++------ packages/parser/__tests__/output.test.ts | 76 ++++++++++++-------- packages/parser/src/parser.ts | 2 +- 5 files changed, 119 insertions(+), 61 deletions(-) create mode 100644 .changeset/shiny-eagles-love.md diff --git a/.changeset/shiny-eagles-love.md b/.changeset/shiny-eagles-love.md new file mode 100644 index 000000000..23f3c8bb0 --- /dev/null +++ b/.changeset/shiny-eagles-love.md @@ -0,0 +1,16 @@ +--- +'@pandacss/parser': patch +'@pandacss/core': patch +--- + +- Prevent extracting style props of `styled` when not explicitly imported + +- Allow using multiple aliases for the same identifier for the `/css` entrypoints just like `/patterns` and `/recipes` + +```ts +import { css } from '../styled-system/css' +import { css as css2 } from '../styled-system/css' + +css({ display: 'flex' }) +css2({ flexDirection: 'column' }) // this wasn't working before, now it does +``` diff --git a/packages/core/__tests__/file-matcher.test.ts b/packages/core/__tests__/file-matcher.test.ts index 05b9da179..fda56189d 100644 --- a/packages/core/__tests__/file-matcher.test.ts +++ b/packages/core/__tests__/file-matcher.test.ts @@ -6,16 +6,24 @@ describe('file matcher', () => { const ctx = createContext() const file = ctx.imports.file([ + { mod: 'styled-system/css', name: 'css', alias: 'css' }, // import { css as xcss } from 'styled-system/css' { mod: 'styled-system/css', name: 'css', alias: 'xcss' }, // import { cva } from 'styled-system/css' { mod: 'styled-system/css', name: 'cva', alias: 'cva' }, ]) - expect(file.cvaAlias).toMatchInlineSnapshot('"cva"') - - expect(file.cssAlias).toMatchInlineSnapshot('"xcss"') - expect(file.getAlias('css')).toMatchInlineSnapshot('"xcss"') + expect(file.getAliases('cva')).toMatchInlineSnapshot(` + [ + "cva", + ] + `) + expect(file.getAliases('css')).toMatchInlineSnapshot(` + [ + "css", + "xcss", + ] + `) expect(file.getName('xcss')).toMatchInlineSnapshot('"css"') }) @@ -51,13 +59,14 @@ describe('file matcher', () => { const ctx = createContext() const file = ctx.imports.file([ + { mod: 'styled-system/jsx', name: 'styled', alias: 'styled' }, { mod: 'styled-system/jsx', name: 'Stack', alias: 'Stack' }, { mod: 'styled-system/jsx', name: 'VStack', alias: '__VStack' }, ]) - expect(file.isJsxFactory('styled')).toMatchInlineSnapshot('true') - expect(file.isJsxFactory('styled.div')).toMatchInlineSnapshot('true') - expect(file.isJsxFactory('Comp')).toMatchInlineSnapshot('false') + expect(file.isJsxFactory('styled')).toMatchInlineSnapshot(`true`) + expect(file.isJsxFactory('styled.div')).toMatchInlineSnapshot(`true`) + expect(file.isJsxFactory('Comp')).toMatchInlineSnapshot(`undefined`) }) test('is valid pattern', () => { diff --git a/packages/core/src/file-matcher.ts b/packages/core/src/file-matcher.ts index aba303234..20b9d8272 100644 --- a/packages/core/src/file-matcher.ts +++ b/packages/core/src/file-matcher.ts @@ -24,6 +24,11 @@ export class FileMatcher { imports: ImportResult[] private importMap: ImportMapOutput + private cssAliases = new Set() + private cvaAliases = new Set() + private svaAliases = new Set() + private jsxFactoryAliases = new Set() + private recipeAliases = new Set() private patternAliases = new Set() @@ -31,11 +36,6 @@ export class FileMatcher { private functions = new Map>() private components = new Map>() - cvaAlias = 'cva' - cssAlias = 'css' - svaAlias = 'sva' - jsxFactoryAlias = 'styled' - constructor( private context: Pick, opts: FileMatcherOptions, @@ -47,7 +47,6 @@ export class FileMatcher { this.assignAliases() this.assignProperties() - this.assignImportAliases() } private assignAliases() { @@ -59,26 +58,37 @@ export class FileMatcher { if (this.isValidPattern(result.alias)) { this.patternAliases.add(result.alias) } + + if (result.name === 'css') { + this.cssAliases.add(result.alias) + } + + if (result.name === 'cva') { + this.cvaAliases.add(result.alias) + } + + if (result.name === 'sva') { + this.svaAliases.add(result.alias) + } + + if (result.name === this.context.jsx.factoryName) { + this.jsxFactoryAliases.add(result.alias) + } }) } private assignProperties() { this.context.jsx.nodes.forEach((node) => { - const alias = this.getAlias(node.jsxName) - node.props?.forEach((prop) => this.propertiesMap.set(prop, true)) - this.functions.set(node.baseName, this.propertiesMap) - this.functions.set(alias, this.propertiesMap) - this.components.set(alias, this.propertiesMap) + const aliases = this.getAliases(node.jsxName) + aliases.forEach((alias) => { + node.props?.forEach((prop) => this.propertiesMap.set(prop, true)) + this.functions.set(node.baseName, this.propertiesMap) + this.functions.set(alias, this.propertiesMap) + this.components.set(alias, this.propertiesMap) + }) }) } - private assignImportAliases() { - this.cvaAlias = this.getAlias('cva') - this.cssAlias = this.getAlias('css') - this.svaAlias = this.getAlias('sva') - this.jsxFactoryAlias = this.getAlias(this.context.jsx.factoryName) - } - isEmpty = () => { return this.imports.length === 0 } @@ -109,8 +119,8 @@ export class FileMatcher { return this.find(id)?.name || id } - getAlias = (id: string) => { - return this.imports.find((o) => o.name === id)?.alias || id + getAliases = (id: string) => { + return this.imports.filter((o) => o.name === id).map((o) => o.alias || id) } isValidPattern = (id: string) => { @@ -133,7 +143,12 @@ export class FileMatcher { } isAliasFnName = memo((fnName: string) => { - return fnName === this.cvaAlias || fnName === this.cssAlias || fnName === this.svaAlias || this.isJsxFactory(fnName) + return ( + this.cvaAliases.has(fnName) || + this.cssAliases.has(fnName) || + this.svaAliases.has(fnName) || + this.isJsxFactory(fnName) + ) }) matchFn = memo((fnName: string) => { @@ -144,7 +159,11 @@ export class FileMatcher { isJsxFactory = memo((tagName: string) => { const { jsx } = this.context - return Boolean(jsx.isEnabled && tagName.startsWith(this.jsxFactoryAlias)) + if (!jsx.isEnabled) return false + + for (const alias of this.jsxFactoryAliases) { + if (tagName.startsWith(alias)) return true + } }) isPandaComponent = memo((tagName: string) => { diff --git a/packages/parser/__tests__/output.test.ts b/packages/parser/__tests__/output.test.ts index 01d83de2f..a679df51b 100644 --- a/packages/parser/__tests__/output.test.ts +++ b/packages/parser/__tests__/output.test.ts @@ -1714,25 +1714,6 @@ describe('extract to css output pipeline', () => { "name": "Stack", "type": "jsx-pattern", }, - { - "data": [ - { - "marginBottom": "42px", - "marginTop": "40px", - }, - ], - "name": "styled.button", - "type": "jsx-factory", - }, - { - "data": [ - { - "bg": "red.200", - }, - ], - "name": "styled.div", - "type": "jsx-factory", - }, { "data": [ { @@ -1805,21 +1786,9 @@ describe('extract to css output pipeline', () => { gap: 10px; } - .bg_red\\.200 { - background: var(--colors-red-200); - } - .flex_column { flex-direction: column; } - - .mt_40px { - margin-top: 40px; - } - - .mb_42px { - margin-bottom: 42px; - } }" `) }) @@ -3474,4 +3443,49 @@ describe('extract to css output pipeline', () => { }" `) }) + + test('multiple css alias', () => { + const code = ` + import { css } from '../styled-system/css' + import { css as css2 } from '../styled-system/css' + + css({ display: 'flex' }); + css2({ flexDirection: 'column' }); + ` + const result = parseAndExtract(code) + expect(result.json).toMatchInlineSnapshot(` + [ + { + "data": [ + { + "display": "flex", + }, + ], + "name": "css", + "type": "css", + }, + { + "data": [ + { + "flexDirection": "column", + }, + ], + "name": "css", + "type": "css", + }, + ] + `) + + expect(result.css).toMatchInlineSnapshot(` + "@layer utilities { + .d_flex { + display: flex; + } + + .flex_column { + flex-direction: column; + } + }" + `) + }) }) diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 037a30e94..1b2c49b15 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -79,7 +79,7 @@ export function createParser(context: ParserOptions) { matchProp: () => true, matchArg: (prop) => { // skip resolving `badge` here: `panda("span", badge)` - if (prop.fnName === file.jsxFactoryAlias && prop.index === 1 && Node.isIdentifier(prop.argNode)) return false + if (file.isJsxFactory(prop.fnName) && prop.index === 1 && Node.isIdentifier(prop.argNode)) return false return true }, },