Skip to content

Commit

Permalink
fix(transformer-attributify-jsx): matchedRule (#3791)
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon-He95 committed May 12, 2024
1 parent fa49753 commit da9c9a5
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 32 deletions.
8 changes: 0 additions & 8 deletions packages/eslint-plugin/src/types.ts
@@ -1,11 +1,3 @@
declare module 'eslint' {
interface SharedConfigurationSettings {
unocss?: {
configPath?: string
}
}
}

declare module '@typescript-eslint/utils/ts-eslint' {
interface SharedConfigurationSettings {
unocss?: {
Expand Down
31 changes: 25 additions & 6 deletions packages/transformer-attributify-jsx/src/index.ts
Expand Up @@ -37,9 +37,9 @@ export interface TransformerAttributifyJsxOptions {
exclude?: FilterPattern
}

const elementRE = /(<\w[\w:\.$-]*\s)([\s\S]*?)(?=>[\s\S]?<\/[\s\w:\.$-]*>|\/>)/g
const elementRE = /<([^\/?<>0-9$_!][^\s>]*)\s+((?:"[^"]*"|'[^"]*'|({[^}]*})|[^{>])+)>/g
const attributeRE = /(?<![~`!$%^&*()_+\-=[{;':"|,.<>/?]\s*)([a-zA-Z()#][\[?a-zA-Z0-9-_:()#%\]?]*)(?:\s*=\s*((?:'[^']*')|(?:"[^"]*")|\S+))?/g
const valuedAttributeRE = /((?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:!%-.~<]+)=(?:["]([^"]*)["]|[']([^']*)[']|[{]((?:[`(](?:[^`)]*)[`)]|[^}])+)[}])/gms
const valuedAttributeRE = /((?!\d|-{2}|-\d)[a-zA-Z0-9\u00A0-\uFFFF-_:!%-.~<]+)=(?:["](?:[^"]*)["]|['](?:[^']*)[']|([{])((?:[`(](?:[^`)]*)[`)]|[^}])+)([}]))/gms

export default function transformerAttributifyJsx(options: TransformerAttributifyJsxOptions = {}): SourceCodeTransformer {
const {
Expand Down Expand Up @@ -75,17 +75,36 @@ export default function transformerAttributifyJsx(options: TransformerAttributif
for (const item of Array.from(code.original.matchAll(elementRE))) {
// Get the length of the className part, and replace it with the equal length of empty string
let attributifyPart = item[2]
if (valuedAttributeRE.test(attributifyPart))
attributifyPart = attributifyPart.replace(valuedAttributeRE, match => ' '.repeat(match.length))
if (valuedAttributeRE.test(attributifyPart)) {
attributifyPart = attributifyPart.replace(valuedAttributeRE, (match, _, dynamicFlagStart) => {
if (!dynamicFlagStart)
return ' '.repeat(match.length)
let preLastModifierIndex = 0
let temp = match
// No more recursively processing the more complex situations of jsx in attributes.
for (const _item of match.matchAll(elementRE)) {
const attrAttributePart = _item[2]
if (valuedAttributeRE.test(attrAttributePart))
attrAttributePart.replace(valuedAttributeRE, (m: string) => ' '.repeat(m.length))

const pre = temp.slice(0, preLastModifierIndex) + ' '.repeat(_item.index + _item[0].indexOf(_item[2]) - preLastModifierIndex) + attrAttributePart
temp = pre + ' '.repeat(_item.input.length - pre.length)
preLastModifierIndex = pre.length
}
if (preLastModifierIndex !== 0)
return temp

return ' '.repeat(match.length)
})
}
for (const attr of attributifyPart.matchAll(attributeRE)) {
const matchedRule = attr[0].replace(/\:/i, '-')
if (matchedRule.includes('=') || isBlocked(matchedRule))
continue

tasks.push(uno.parseToken(matchedRule).then((matched) => {
if (matched) {
const tag = item[1]
const startIdx = (item.index || 0) + (attr.index || 0) + tag.length
const startIdx = (item.index || 0) + (attr.index || 0) + item[0].indexOf(item[2])
const endIdx = startIdx + matchedRule.length
code.overwrite(startIdx, endIdx, `${matchedRule}=""`)
}
Expand Down
80 changes: 62 additions & 18 deletions test/transformer-attributify-jsx.test.ts
Expand Up @@ -26,12 +26,12 @@ const originalCode = `
<router-link to={\`/path/\${1}\`}/>
</div>
</div>
<section
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
mr-10
<section
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
mr-10
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
></section>
<div
<div
label={
<b>1</b>
}
Expand All @@ -40,8 +40,11 @@ const originalCode = `
on-demand · instant · fully customizable
</div>
<div components={<div absolute bottom-5></div>}></div>
<div components={() => <div left-0 bottom-5>
<div text-center> flex </div>
</div>}></div>
<h1 flex>h1</h1>
<div {...{ flex }} />
<div {...{ flex }} />
<div {...{ onClick: () => { grid(); flex } }} flex />
<div {...true ? flex : props.grid } {...grid || ( block ) && $flex } />
<div {...[, flex, [flex], !flex, -flex, +flex, ~flex, "flex", \`flex\` ] } />
Expand All @@ -68,7 +71,7 @@ describe('transformerAttributifyJsx', () => {
],
})

it('transform', async () => {
it('transform test1', async () => {
const code = new MagicString(originalCode)
await transformerAttributifyJsx().transform(code, 'app.tsx', { uno, tokens: new Set() } as any)

Expand All @@ -92,12 +95,12 @@ describe('transformerAttributifyJsx', () => {
<router-link to={\`/path/\${1}\`}/>
</div>
</div>
<section
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
mr-10=""
<section
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
mr-10=""
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
></section>
<div
<div
label={
<b>1</b>
}
Expand All @@ -106,14 +109,46 @@ describe('transformerAttributifyJsx', () => {
on-demand · instant · fully customizable
</div>
<div components={<div absolute="" bottom-5=""></div>}></div>
<div components={() => <div left-0="" bottom-5="">
<div text-center=""> flex </div>
</div>}></div>
<h1 flex="">h1</h1>
<div {...{ flex }} />
<div {...{ flex }} />
<div {...{ onClick: () => { grid(); flex } }} flex="" />
<div {...true ? flex : props.grid } {...grid || ( block ) && $flex } />
<div {...[, flex, [flex], !flex, -flex, +flex, ~flex, "flex", \`flex\` ] } />
</div>"
`)
})
// #3754
it('transform test2', async () => {
const code = new MagicString(`
const App: React.FC = () => {
return (
<div w-full h-full bg-gray-300
>
<div>123</div>
</div>
)
}
export default App
`)
await transformerAttributifyJsx().transform(code, 'app.tsx', { uno, tokens: new Set() } as any)

expect(code.toString()).toMatchInlineSnapshot(`
"
const App: React.FC = () => {
return (
<div w-full="" h-full="" bg-gray-300=""
>
<div>123</div>
</div>
)
}
export default App
"
`)
})

it('blocklist', async () => {
const code = new MagicString(originalCode)
Expand Down Expand Up @@ -143,12 +178,12 @@ describe('transformerAttributifyJsx', () => {
<router-link to={\`/path/\${1}\`}/>
</div>
</div>
<section
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
mr-10=""
<section
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
mr-10=""
className={cn({ 'c-red': variable > 0 }, 'mr-10')}
></section>
<div
<div
label={
<b>1</b>
}
Expand All @@ -157,8 +192,11 @@ describe('transformerAttributifyJsx', () => {
on-demand · instant · fully customizable
</div>
<div components={<div absolute bottom-5=""></div>}></div>
<div components={() => <div left-0="" bottom-5="">
<div text-center=""> flex </div>
</div>}></div>
<h1 flex>h1</h1>
<div {...{ flex }} />
<div {...{ flex }} />
<div {...{ onClick: () => { grid(); flex } }} flex />
<div {...true ? flex : props.grid } {...grid || ( block ) && $flex } />
<div {...[, flex, [flex], !flex, -flex, +flex, ~flex, "flex", \`flex\` ] } />
Expand Down Expand Up @@ -231,10 +269,13 @@ describe('transformerAttributifyJsxBabel', () => {
on-demand · instant · fully customizable
</div>
<div components={<div absolute="" bottom-5=""></div>}></div>
<div components={() => <div left-0="" bottom-5="">
<div text-center=""> flex </div>
</div>}></div>
<h1 flex="">h1</h1>
<div {...{
flex
}} />
}} />
<div {...{
onClick: () => {
grid();
Expand Down Expand Up @@ -282,10 +323,13 @@ describe('transformerAttributifyJsxBabel', () => {
on-demand · instant · fully customizable
</div>
<div components={<div absolute bottom-5=""></div>}></div>
<div components={() => <div left-0="" bottom-5="">
<div text-center=""> flex </div>
</div>}></div>
<h1 flex>h1</h1>
<div {...{
flex
}} />
}} />
<div {...{
onClick: () => {
grid();
Expand Down

0 comments on commit da9c9a5

Please sign in to comment.