From da9c9a5c4849e5138d5a68b48cf2be5949548796 Mon Sep 17 00:00:00 2001 From: Simon He <57086651+Simon-He95@users.noreply.github.com> Date: Sun, 12 May 2024 10:42:28 +0800 Subject: [PATCH] fix(transformer-attributify-jsx): matchedRule (#3791) --- packages/eslint-plugin/src/types.ts | 8 -- .../transformer-attributify-jsx/src/index.ts | 31 +++++-- test/transformer-attributify-jsx.test.ts | 80 ++++++++++++++----- 3 files changed, 87 insertions(+), 32 deletions(-) diff --git a/packages/eslint-plugin/src/types.ts b/packages/eslint-plugin/src/types.ts index 5e73010e76..f9a05e0935 100644 --- a/packages/eslint-plugin/src/types.ts +++ b/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?: { diff --git a/packages/transformer-attributify-jsx/src/index.ts b/packages/transformer-attributify-jsx/src/index.ts index 44d4f9f1ff..66a181d6b7 100644 --- a/packages/transformer-attributify-jsx/src/index.ts +++ b/packages/transformer-attributify-jsx/src/index.ts @@ -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 { @@ -75,8 +75,28 @@ 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)) @@ -84,8 +104,7 @@ export default function transformerAttributifyJsx(options: TransformerAttributif 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}=""`) } diff --git a/test/transformer-attributify-jsx.test.ts b/test/transformer-attributify-jsx.test.ts index 384538618a..f7a0a486ef 100644 --- a/test/transformer-attributify-jsx.test.ts +++ b/test/transformer-attributify-jsx.test.ts @@ -26,12 +26,12 @@ const originalCode = ` -
0 }, 'mr-10')} - mr-10 +
0 }, 'mr-10')} + mr-10 className={cn({ 'c-red': variable > 0 }, 'mr-10')} >
-
1 } @@ -40,8 +40,11 @@ const originalCode = ` on-demand · instant · fully customizable
}> +
+
flex
+
}>

h1

-
+
{ grid(); flex } }} flex />
@@ -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) @@ -92,12 +95,12 @@ describe('transformerAttributifyJsx', () => {
-
0 }, 'mr-10')} - mr-10="" +
0 }, 'mr-10')} + mr-10="" className={cn({ 'c-red': variable > 0 }, 'mr-10')} >
-
1 } @@ -106,14 +109,46 @@ describe('transformerAttributifyJsx', () => { on-demand · instant · fully customizable
}>
+
+
flex
+
}>

h1

-
+
{ grid(); flex } }} flex="" />
" `) }) + // #3754 + it('transform test2', async () => { + const code = new MagicString(` + const App: React.FC = () => { + return ( +
+
123
+
+ ) + } + export default App + `) + await transformerAttributifyJsx().transform(code, 'app.tsx', { uno, tokens: new Set() } as any) + + expect(code.toString()).toMatchInlineSnapshot(` + " + const App: React.FC = () => { + return ( +
+
123
+
+ ) + } + export default App + " + `) + }) it('blocklist', async () => { const code = new MagicString(originalCode) @@ -143,12 +178,12 @@ describe('transformerAttributifyJsx', () => {
-
0 }, 'mr-10')} - mr-10="" +
0 }, 'mr-10')} + mr-10="" className={cn({ 'c-red': variable > 0 }, 'mr-10')} >
-
1 } @@ -157,8 +192,11 @@ describe('transformerAttributifyJsx', () => { on-demand · instant · fully customizable
}>
+
+
flex
+
}>

h1

-
+
{ grid(); flex } }} flex />
@@ -231,10 +269,13 @@ describe('transformerAttributifyJsxBabel', () => { on-demand · instant · fully customizable
}>
+
+
flex
+
}>

h1

+ }} />
{ grid(); @@ -282,10 +323,13 @@ describe('transformerAttributifyJsxBabel', () => { on-demand · instant · fully customizable
}>
+
+
flex
+
}>

h1

+ }} />
{ grid();