Skip to content

Commit

Permalink
fix: some fuzzy class names will also be incorrectly matched (close #484
Browse files Browse the repository at this point in the history
) (#486)
  • Loading branch information
voorjaar committed Oct 27, 2021
1 parent 0910829 commit 7dd80bd
Show file tree
Hide file tree
Showing 8 changed files with 794 additions and 621 deletions.
3 changes: 1 addition & 2 deletions src/lib/extract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ export default function extract(
}

// handle dynamic base utilities
const matches = className.match(/\w+/);
const key = matches ? matches[0] : undefined;
const key = className.replace(/^-/, '').match(/^\w+/)?.[0];
// eslint-disable-next-line no-prototype-builtins
if (key && dynamicUtilities.hasOwnProperty(key)) {
let style = dynamicUtilities[key](utility, processor.pluginUtils);
Expand Down
1,189 changes: 602 additions & 587 deletions src/lib/utilities/dynamic.ts

Large diffs are not rendered by default.

122 changes: 107 additions & 15 deletions src/lib/utilities/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import { toColor } from '../../utils/color';
import { cssEscape } from '../../utils/algorithm';
import {
isNumber,
isFraction,
isSize,
roundUp,
fracToPercent,
hex2RGB,
Expand All @@ -16,16 +14,32 @@ import {

import type { colorCallback, colorObject, DictStr, Handlers } from '../../interfaces';

type emptyCallback = () => Property | Style | Style[] | undefined
type valueCallback = (value: string) => Property | Style | Style[] | undefined
type handlerCallback = (handler: Handler) => Property | Style | Style[] | undefined

export type Handler = {
utility: Utility
value?: string
prefix?: string
_amount: string
_slices: string[]
_prefix_expr?: string
opacity?: string | undefined
color?: colorCallback
catchPrefix: (regex: RegExp, match?: boolean) => Handler | undefined,
isStatic: (map: { [key: string]: string | string[] }, amount?: string) => boolean,
isTime: (start: number, end: number, type: 'int' | 'float') => boolean,
isNumber: (start: number, end: number, type: 'int' | 'float') => boolean,
isFraction: () => boolean,
isSize: () => boolean,
isNxl: () => boolean,
isVariable: () => boolean,
isSquareBracket: () => boolean,
handleStatic: (
map?: { [key: string]: string | string[] } | unknown,
callback?: (str: string) => string | undefined
)=> Handler
) => Handler
handleBody: (
map?: { [key: string]: string | string[] } | unknown,
callback?: (str: string) => string | undefined
Expand Down Expand Up @@ -82,9 +96,8 @@ export type Handler = {
opacityVariable?: string | undefined,
wrapRGB?: boolean
) => Style | undefined
callback: (
func: (value: string) => Property | Style | Style[] | undefined
) => Property | Style | Style[] | undefined
callback: (func: valueCallback) => Property | Style | Style[] | undefined
then: (func: (handlerCallback | emptyCallback)) => Property | Style | Style[] | undefined
}

export type HandlerCreator = (utility: Utility, value?: string | undefined, color?: colorCallback | undefined) => Handler;
Expand All @@ -96,13 +109,87 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre
value,
color,
_amount: utility.amount,
_slices: utility.slices,

catchPrefix: (regex, match = false) => {
handler._prefix_expr = regex.source;

if (match) {
const matched = utility.raw.match(regex);
if (!matched) return;
handler.prefix = matched[0];
}
return handler;
},

isStatic: (map, amount = handler._amount) => {
return amount in map && new RegExp(`${handler._prefix_expr ?? ''}-?${amount}$`).test(handler.utility.raw);
},

isNumber: (
start = -Infinity,
end = Infinity,
type = 'int'
) => {
const prefix = handler._prefix_expr;
const utility = handler.utility.raw;
if (!prefix) return isNumber(handler._amount, start, end, type);
const isInt = new RegExp(`${prefix}-\\d+$`).test(utility);
if (type === 'int') {
if (!isInt) return false;
} else {
const isFloat = new RegExp(`${prefix}-\\d+\\.\\d+$`).test(utility);
if (!(isInt || isFloat)) return false;
}
const num = parseFloat(handler._amount);
return num >= start && num <= end;
},

isTime: (
start = -Infinity,
end = Infinity,
type = 'int'
) => {
const prefix = handler._prefix_expr;
const utility = handler.utility.raw;
if (!prefix) return isNumber(handler._amount, start, end, type);
const isInt = new RegExp(`${prefix}-\\d+(s|ms)$`).test(utility);
if (type === 'int') {
if (!isInt) return false;
} else {
const isFloat = new RegExp(`${prefix}-\\d+\\.\\d+(s|ms)$`).test(utility);
if (!(isInt || isFloat)) return false;
}
const num = parseFloat(handler._amount);
return num >= start && num <= end;
},

isFraction: () => {
return handler._prefix_expr ? new RegExp(`${handler._prefix_expr}-\\d+\\/\\d+$`).test(handler.utility.raw) : /^\d+\/\d+$/.test(handler._amount);
},

isSize: () => {
return handler._prefix_expr ? new RegExp(`${handler._prefix_expr}-(\\d+(\\.\\d+)?)+(rem|em|px|rpx|vh|vw|ch|ex)$`).test(handler.utility.raw) : /^-?(\d+(\.\d+)?)+(rem|em|px|rpx|vh|vw|ch|ex)$/.test(handler._amount);
},

isNxl: () => {
return handler._prefix_expr ? new RegExp(`${handler._prefix_expr}-\\d*xl$`).test(handler.utility.raw) : /^\d*xl$/.test(handler._amount);
},

isVariable: () => {
return new RegExp(`${handler._prefix_expr ?? ''}-\\$[\\w-]+`).test(handler.utility.raw);
},

isSquareBracket: () => {
return new RegExp(`${handler._prefix_expr ?? ''}-\\[.+\\]`).test(handler.utility.raw);
},

handleStatic: handlers.static ? (map, callback) => {
if (handler.value) return handler;
if (map && typeof map === 'object') {
const knownMap = map as { [key: string]: string | string[] };
if (knownMap.DEFAULT) knownMap[handler.utility.raw] = knownMap.DEFAULT;
if (handler._amount in knownMap)
if (knownMap.DEFAULT) knownMap[''] = knownMap.DEFAULT;
if (handler.isStatic(knownMap))
handler.value = callback
? callback(handler._amount)
: `${knownMap[handler._amount]}`;
Expand All @@ -124,7 +211,7 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre

handleNumber: handlers.number ? (start = -Infinity, end = Infinity, type = 'int', callback) => {
if (handler.value) return handler;
if (isNumber(handler._amount, start, end, type))
if (handler.isNumber(start, end, type))
handler.value = callback ? callback(+handler._amount) : handler._amount;
return handler;
} : () => handler,
Expand Down Expand Up @@ -154,7 +241,7 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre

handleSquareBrackets: handlers.bracket ? (callback) => {
if (handler.value) return handler;
if (handler._amount[0] === '[' && handler._amount[handler._amount.length-1] === ']') {
if (handler._amount[0] === '[' && handler._amount[handler._amount.length-1] === ']' && handler.isSquareBracket()) {
let value = handler._amount.slice(1, -1).replace(/_/g, ' '); // replace _ to space
if (value.indexOf('calc(') > -1) {
value = value.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ');
Expand All @@ -175,7 +262,7 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre

handleNxl: handlers.nxl ? (callback) => {
if (handler.value) return handler;
if (/^\d*xl$/.test(handler._amount))
if (handler.isNxl())
handler.value = callback
? callback(handler._amount === 'xl' ? 1 : parseInt(handler._amount))
: parseInt(handler._amount).toString();
Expand All @@ -184,7 +271,7 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre

handleFraction: handlers.fraction ? (callback) => {
if (handler.value) return handler;
if (isFraction(handler._amount))
if (handler.isFraction())
handler.value = callback
? callback(handler._amount)
: fracToPercent(handler._amount);
Expand All @@ -193,15 +280,15 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre

handleSize: handlers.size ? (callback) => {
if (handler.value) return handler;
if (isSize(handler._amount))
if (handler.isSize())
handler.value = callback ? callback(handler._amount) : handler._amount;
return handler;
} : () => handler,

handleVariable: handlers.variable ? (callback) => {
if (handler.value) return handler;
const matchVariable = handler.utility.raw.match(/-\$[\w-]+/);
if (matchVariable) {
if (matchVariable && handler.isVariable()) {
const variableName = matchVariable[0].substring(2);
handler.value = callback ? callback(variableName) : `var(--${variableName})`;
}
Expand Down Expand Up @@ -304,6 +391,8 @@ export function createHandler(handlers: Handlers = { static: true }): HandlerCre
if (!handler.value) return;
return func(handler.value);
},

then: (func) => func(handler),
};
return handler;
};
Expand Down Expand Up @@ -342,11 +431,14 @@ export class Utility {
return this.match(/-.+(?=-)/).substring(1); // real-gray
}
get amount(): string {
return this.match(/(?:[^-]+|\[[\s\S]*?\])$/); // 300
return this.match(/-(?:[^-]+|\[[\s\S]*?\])$/).substring(1); // 300
}
get body(): string {
return this.match(/-.+/).substring(1); // real-gray-300
}
get slices(): string[] {
return this.absolute.split('-'); // ['placeholder', 'real', 'gray', '300']
}
get handler(): Handler {
return this._h(this);
}
Expand Down
24 changes: 12 additions & 12 deletions test/processor/__snapshots__/attributify.test.ts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1597,30 +1597,30 @@ Tools / with margin padding space_between / css / 0: |-
[m~="4"] {
margin: 1rem;
}
[m~="x-2"] {
margin-left: 0.5rem;
margin-right: 0.5rem;
[m~="-x-2"] {
margin-left: -0.5rem;
margin-right: -0.5rem;
}
[m~="y-3"] {
margin-top: 0.75rem;
margin-bottom: 0.75rem;
[m~="-y-3"] {
margin-top: -0.75rem;
margin-bottom: -0.75rem;
}
[m~="t-4"] {
margin-top: 1rem;
[m~="r-px"] {
margin-right: 1px;
}
[p~="4"] {
padding: 1rem;
}
[p~="-x-2"] {
[p~="x-2"] {
padding-left: 0.5rem;
padding-right: 0.5rem;
}
[p~="-y-3"] {
[p~="y-3"] {
padding-top: 0.75rem;
padding-bottom: 0.75rem;
}
[p~="r-px"] {
padding-right: 1px;
[p~="t-4"] {
padding-top: 1rem;
}
Tools / with negative utility / css / 0: |-
[m~="-x-4"] {
Expand Down
2 changes: 1 addition & 1 deletion test/processor/__snapshots__/interpret.test.ts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ Tools / interpret square brackets / square brackets / 0: |-
}
.border-l-\[\#342\] {
--tw-border-opacity: 1;
border-color: rgba(51, 68, 34, var(--tw-border-opacity));
border-left-color: rgba(51, 68, 34, var(--tw-border-opacity));
}
.rounded-\[11px\] {
border-radius: 11px;
Expand Down
52 changes: 51 additions & 1 deletion test/processor/__snapshots__/utilities.test.ts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -784,7 +784,10 @@ Tools / content utilities / css / 0: |-
.after\:content-\[attr\(value\)\]::after {
content: attr(value);
}
Tools / content utilities false / css / 0: ''
.content {
content: "";
}
Tools / content utilities startsWith symbol / css / 0: ''
Tools / fill-none and stroke-none is wrong / css / 0: |-
.fill-none {
fill: none;
Expand Down Expand Up @@ -883,6 +886,33 @@ Tools / grid template test / grid template / 0: |-
.grid-rows-4 {
grid-template-rows: repeat(4, minmax(0, 1fr));
}
Tools / inset exact match / css / 0: |-
.inset-auto {
top: auto;
right: auto;
bottom: auto;
left: auto;
}
.inset-4 {
top: 1rem;
right: 1rem;
bottom: 1rem;
left: 1rem;
}
.inset-x-13 {
right: 3.25rem;
left: 3.25rem;
}
.top-1\/3 {
top: 33.333333%;
}
Tools / lineHeight exact match / css / 0: |-
.leading-4 {
line-height: 1rem;
}
.leading-\[1\.25rem\] {
line-height: 1.25rem;
}
Tools / list style type / css / 0: |-
.list-disc {
list-style-type: disc;
Expand Down Expand Up @@ -924,6 +954,13 @@ Tools / more color opacity group utilities / css / 0: |-
--tw-text-stroke-opacity: 0.5;
-webkit-text-stroke-color: rgba(16, 185, 129, var(--tw-text-stroke-opacity));
}
Tools / padding exact match / css / 0: |-
.p-4 {
padding: 1rem;
}
.p-12\.5 {
padding: 3.125rem;
}
Tools / prespective and perspective origin / css / 0: |-
.perspect-none {
-webkit-perspective: none;
Expand Down Expand Up @@ -1306,3 +1343,16 @@ Tools / wrap container / small container / 0: |-
}
}
}
Tools / zIndex exact match / css / 0: |-
.z-auto {
z-index: auto;
}
.z-20 {
z-index: 20;
}
.-z-10 {
z-index: -10;
}
.z-\$var-name {
z-index: var(--var-name);
}
4 changes: 2 additions & 2 deletions test/processor/attributify.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,8 @@ describe('Attributify Mode', () => {

it('with margin padding space_between', () => {
const result = processor.attributify({
'm': ['4', 'x-2', 'y-3', 't-4'],
'p': ['4', '-x-2', '-y-3', 'r-px'],
'p': ['4', 'x-2', 'y-3', 't-4'],
'm': ['4', '-x-2', '-y-3', 'r-px'],
'space': ['x-4', 'y-2', '-x-4'],
});
expect(result.ignored.length).toEqual(0);
Expand Down

0 comments on commit 7dd80bd

Please sign in to comment.