Skip to content

Commit f0b60cc

Browse files
committed
Directly encode dynamic attribute rules
Dynamic attribute names have definite rules in Vue and Angular. Testing those rules directly and matching the actual “name” portion against the regex is a better option.
1 parent 26566b6 commit f0b60cc

File tree

1 file changed

+37
-12
lines changed

1 file changed

+37
-12
lines changed

src/options.ts

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ export function createMatcher(options: RequiredOptions, parser: string, defaults
7272
let dynamicAttrs = new Set<string>(defaults.dynamicAttrs)
7373
let functions = new Set<string>(defaults.functions)
7474
let staticAttrsRegex: RegExp[] = [...defaults.staticAttrsRegex]
75-
let dynamicAttrsRegex: RegExp[] = [...defaults.dynamicAttrsRegex]
7675
let functionsRegex: RegExp[] = [...defaults.functionsRegex]
7776

7877
// Create a list of "static" attributes
@@ -104,15 +103,6 @@ export function createMatcher(options: RequiredOptions, parser: string, defaults
104103
}
105104
}
106105

107-
for (let regex of staticAttrsRegex) {
108-
if (parser === 'vue') {
109-
dynamicAttrsRegex.push(new RegExp(`:${regex.source}`, regex.flags))
110-
dynamicAttrsRegex.push(new RegExp(`v-bind:${regex.source}`, regex.flags))
111-
} else if (parser === 'angular') {
112-
dynamicAttrsRegex.push(new RegExp(`\\[${regex.source}\\]`, regex.flags))
113-
}
114-
}
115-
116106
// Generate a list of supported functions
117107
for (let fn of options.tailwindFunctions ?? []) {
118108
let regex = parseRegex(fn)
@@ -125,12 +115,47 @@ export function createMatcher(options: RequiredOptions, parser: string, defaults
125115
}
126116

127117
return {
128-
hasStaticAttr: (name: string) => hasMatch(name, staticAttrs, staticAttrsRegex),
129-
hasDynamicAttr: (name: string) => hasMatch(name, dynamicAttrs, dynamicAttrsRegex),
118+
hasStaticAttr: (name: string) => {
119+
// If the name looks like a dynamic attribute we're not a static attr
120+
// Only applies to Vue and Angular
121+
let newName = nameFromDynamicAttr(name, parser)
122+
if (newName) return false
123+
124+
return hasMatch(name, staticAttrs, staticAttrsRegex)
125+
},
126+
127+
hasDynamicAttr: (name: string) => {
128+
// This is definitely a dynamic attribute
129+
if (hasMatch(name, dynamicAttrs, [])) return true
130+
131+
// If the name looks like a dynamic attribute compare the actual name
132+
// Only applies to Vue and Angular
133+
let newName = nameFromDynamicAttr(name, parser)
134+
if (!newName) return false
135+
136+
return hasMatch(newName, staticAttrs, staticAttrsRegex)
137+
},
138+
130139
hasFunction: (name: string) => hasMatch(name, functions, functionsRegex),
131140
}
132141
}
133142

143+
function nameFromDynamicAttr(name: string, parser: string) {
144+
if (parser === 'vue') {
145+
if (name.startsWith(':')) return name.slice(1)
146+
if (name.startsWith('v-bind:')) return name.slice(7)
147+
if (name.startsWith('v-')) return name
148+
return null
149+
}
150+
151+
if (parser === 'angular') {
152+
if (name.startsWith('[') && name.endsWith(']')) return name.slice(1, -1)
153+
return null
154+
}
155+
156+
return null
157+
}
158+
134159
/**
135160
* Check for matches against a static list or possible regex patterns
136161
*/

0 commit comments

Comments
 (0)