Skip to content

Commit

Permalink
fix: allow multiple aliases from /css entrypoint (#2232)
Browse files Browse the repository at this point in the history
  • Loading branch information
astahmer authored Feb 21, 2024
1 parent ba06cb2 commit f419993
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 61 deletions.
16 changes: 16 additions & 0 deletions .changeset/shiny-eagles-love.md
Original file line number Diff line number Diff line change
@@ -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
```
23 changes: 16 additions & 7 deletions packages/core/__tests__/file-matcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"')
})

Expand Down Expand Up @@ -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', () => {
Expand Down
63 changes: 41 additions & 22 deletions packages/core/src/file-matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ export class FileMatcher {
imports: ImportResult[]
private importMap: ImportMapOutput<string>

private cssAliases = new Set<string>()
private cvaAliases = new Set<string>()
private svaAliases = new Set<string>()
private jsxFactoryAliases = new Set<string>()

private recipeAliases = new Set<string>()
private patternAliases = new Set<string>()

private propertiesMap = new Map<string, boolean>()
private functions = new Map<string, Map<string, boolean>>()
private components = new Map<string, Map<string, boolean>>()

cvaAlias = 'cva'
cssAlias = 'css'
svaAlias = 'sva'
jsxFactoryAlias = 'styled'

constructor(
private context: Pick<Context, 'jsx' | 'patterns' | 'recipes' | 'isValidProperty'>,
opts: FileMatcherOptions,
Expand All @@ -47,7 +47,6 @@ export class FileMatcher {

this.assignAliases()
this.assignProperties()
this.assignImportAliases()
}

private assignAliases() {
Expand All @@ -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
}
Expand Down Expand Up @@ -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) => {
Expand All @@ -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) => {
Expand All @@ -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) => {
Expand Down
76 changes: 45 additions & 31 deletions packages/parser/__tests__/output.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
{
Expand Down Expand Up @@ -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;
}
}"
`)
})
Expand Down Expand Up @@ -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;
}
}"
`)
})
})
2 changes: 1 addition & 1 deletion packages/parser/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
},
Expand Down

0 comments on commit f419993

Please sign in to comment.