Skip to content

Commit

Permalink
feat(core): support multiple prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jan 6, 2023
1 parent 2b8cc62 commit 233e7b1
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 28 deletions.
10 changes: 6 additions & 4 deletions packages/core/src/config.ts
Expand Up @@ -23,9 +23,9 @@ export function resolvePreset<Theme extends {} = {}>(preset: Preset<Theme>): Pre
i[2] = {}
const meta = i[2]
if (meta.prefix == null && preset.prefix)
meta.prefix = preset.prefix
meta.prefix = toArray(preset.prefix)
if (meta.layer == null && preset.layer)
meta.prefix = preset.layer
meta.layer = preset.layer
}
shortcuts?.forEach(apply)
preset.rules?.forEach(apply)
Expand Down Expand Up @@ -69,8 +69,10 @@ export function resolveConfig<Theme extends {} = {}>(
const rulesDynamic = rules
.map((rule, i) => {
if (isStaticRule(rule)) {
const prefix = rule[2]?.prefix || ''
rulesStaticMap[prefix + rule[0]] = [i, rule[1], rule[2], rule]
const prefixes = toArray(rule[2]?.prefix || '')
prefixes.forEach((prefix) => {
rulesStaticMap[prefix + rule[0]] = [i, rule[1], rule[2], rule]
})
// delete static rules so we can't skip them in matching
// but keep the order
return undefined
Expand Down
24 changes: 17 additions & 7 deletions packages/core/src/generator/index.ts
@@ -1,7 +1,7 @@
import { createNanoEvents } from '../utils/events'
import type { CSSEntries, CSSObject, DynamicRule, ExtractorContext, GenerateOptions, GenerateResult, ParsedUtil, PreflightContext, PreparedRule, RawUtil, ResolvedConfig, RuleContext, RuleMeta, Shortcut, ShortcutValue, StringifiedUtil, UserConfig, UserConfigDefaults, UtilObject, Variant, VariantContext, VariantHandler, VariantHandlerContext, VariantMatchedResult } from '../types'
import { resolveConfig } from '../config'
import { CONTROL_SHORTCUT_NO_MERGE, TwoKeyMap, e, entriesToCss, expandVariantGroup, isRawUtil, isStaticShortcut, isString, noop, normalizeCSSEntries, normalizeCSSValues, notNull, uniq, warnOnce } from '../utils'
import { CONTROL_SHORTCUT_NO_MERGE, TwoKeyMap, e, entriesToCss, expandVariantGroup, isRawUtil, isStaticShortcut, isString, noop, normalizeCSSEntries, normalizeCSSValues, notNull, toArray, uniq, warnOnce } from '../utils'
import { version } from '../../package.json'
import { LAYER_DEFAULT, LAYER_PREFLIGHTS } from '../constants'

Expand Down Expand Up @@ -394,7 +394,12 @@ export class UnoGenerator<Theme extends {} = {}> {
return cssBody
}

async parseUtil(input: string | VariantMatchedResult<Theme>, context: RuleContext<Theme>, internal = false, shortcutPrefix: string | undefined = undefined): Promise<(ParsedUtil | RawUtil)[] | undefined> {
async parseUtil(
input: string | VariantMatchedResult<Theme>,
context: RuleContext<Theme>,
internal = false,
shortcutPrefix?: string | string[] | undefined,
): Promise<(ParsedUtil | RawUtil)[] | undefined> {
const [raw, processed, variantHandlers] = isString(input)
? this.matchVariants(input)
: input
Expand Down Expand Up @@ -432,14 +437,17 @@ export class UnoGenerator<Theme extends {} = {}> {
// match prefix
let unprefixed = processed
if (meta?.prefix) {
const prefixes = toArray(meta.prefix)
if (shortcutPrefix) {
if (shortcutPrefix !== meta.prefix)
const shortcutPrefixes = toArray(shortcutPrefix)
if (!prefixes.some(i => shortcutPrefixes.includes(i)))
continue
}
else {
if (!processed.startsWith(meta.prefix))
const prefix = prefixes.find(i => processed.startsWith(i))
if (prefix == null)
continue
unprefixed = processed.slice(meta.prefix.length)
unprefixed = processed.slice(prefix.length)
}
}

Expand Down Expand Up @@ -504,9 +512,11 @@ export class UnoGenerator<Theme extends {} = {}> {
for (const s of this.config.shortcuts) {
let unprefixed = input
if (s[2]?.prefix) {
if (!input.startsWith(s[2].prefix))
const prefixes = toArray(s[2].prefix)
const prefix = prefixes.find(i => input.startsWith(i))
if (prefix == null)
continue
unprefixed = input.slice(s[2].prefix.length)
unprefixed = input.slice(prefix.length)
}
if (isStaticShortcut(s)) {
if (s[0] === unprefixed) {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/types.ts
Expand Up @@ -160,7 +160,7 @@ export interface RuleMeta {
/**
* Matching prefix before this util
*/
prefix?: string
prefix?: string | string[]

/**
* Internal rules will only be matched for shortcuts but not the user code.
Expand Down Expand Up @@ -463,7 +463,7 @@ export interface Preset<Theme extends {} = {}> extends ConfigBase<Theme> {
/**
* Apply prefix to all utilities and shortcuts
*/
prefix?: string
prefix?: string | string[]
/**
* Apply layer to all utilities and shortcuts
*/
Expand Down
2 changes: 1 addition & 1 deletion packages/preset-icons/src/types.ts
Expand Up @@ -25,7 +25,7 @@ export interface IconsOptions {
*
* @default `i-`
*/
prefix?: string
prefix?: string | string[]
/**
* Extra CSS properties applied to the generated CSS
*
Expand Down
2 changes: 1 addition & 1 deletion packages/preset-mini/src/index.ts
Expand Up @@ -51,7 +51,7 @@ export interface PresetMiniOptions extends PresetOptions {
*
* @default undefined
*/
prefix?: string
prefix?: string | string[]
/**
* Generate preflight
*
Expand Down
48 changes: 47 additions & 1 deletion test/__snapshots__/prefix.test.ts.snap
@@ -1,6 +1,52 @@
// Vitest Snapshot v1

exports[`prefix > preset prefix 2`] = `
exports[`prefix > multiple preset prefix 1`] = `
"/* layer: default */
.h-container{max-width:100%;}
.hover\\\\:h-p4:hover{padding:1rem;}
.h-text-red{--un-text-opacity:1;color:rgba(248,113,113,var(--un-text-opacity));}
.bar,
.bar-bar,
.bar-shortcut,
.foo-bar,
.x-shortcut{color:bar;}
.bar-regex,
.foo-regex,
.regex{color:regex;}
@media (min-width: 640px){
.h-container{max-width:640px;}
}
@media (min-width: 768px){
.h-container{max-width:768px;}
}
@media (min-width: 1024px){
.h-container{max-width:1024px;}
}
@media (min-width: 1280px){
.h-container{max-width:1280px;}
}
@media (min-width: 1024px){@media (min-width: 1536px){
.\\\\32 xl\\\\:h-container{max-width:1024px;}
}}
@media (min-width: 1280px){@media (min-width: 1536px){
.\\\\32 xl\\\\:h-container{max-width:1280px;}
}}
@media (min-width: 1536px){
.\\\\32 xl\\\\:h-container{max-width:100%;}
.h-container{max-width:1536px;}
}
@media (min-width: 1536px){@media (min-width: 1536px){
.\\\\32 xl\\\\:h-container{max-width:1536px;}
}}
@media (min-width: 640px){@media (min-width: 1536px){
.\\\\32 xl\\\\:h-container{max-width:640px;}
}}
@media (min-width: 768px){@media (min-width: 1536px){
.\\\\32 xl\\\\:h-container{max-width:768px;}
}}"
`;

exports[`prefix > preset prefix 1`] = `
"/* layer: default */
.h-container{max-width:100%;}
.hover\\\\:h-p4:hover{padding:1rem;}
Expand Down
70 changes: 58 additions & 12 deletions test/prefix.test.ts
Expand Up @@ -16,31 +16,77 @@ describe('prefix', () => {
],
})

const { css, matched } = await uno.generate(new Set([
const unexpected = [
'text-red',
'hover:p4',
'bar',
'shortcut',
// expected
]

const expected = [
'h-text-red',
'hover:h-p4',
'bar-bar',
'bar-shortcut',
'h-container',
'2xl:h-container',
]

const { css, matched } = await uno.generate(new Set([
...unexpected,
...expected,
]), { preflights: false })

expect(matched).toMatchInlineSnapshot(`
Set {
"bar-bar",
"h-text-red",
"hover:h-p4",
"bar-shortcut",
"h-container",
"2xl:h-container",
}
`)
expect([...matched].sort()).toEqual(expected.sort())
expect(css).toMatchSnapshot()
})

test('multiple preset prefix', async () => {
const uno = createGenerator({
presets: [
presetUno({ prefix: ['h-', 'x-'] }),
],
rules: [
['bar', { color: 'bar' }, { prefix: ['bar-', 'foo-', ''] }],
[/^regex$/, () => ({ color: 'regex' }), { prefix: ['bar-', 'foo-', ''] }],
],
shortcuts: [
['shortcut', 'bar-bar', { prefix: ['bar-', 'x-'] }],
],
})

const unexpected = [
'text-red',
'hover:p4',
'bar',
'shortcut',
]

const expected = [
'h-text-red',
'hover:h-p4',

'bar-bar',
'foo-bar',
'bar',

'bar-regex',
'foo-regex',
'regex',

'bar-shortcut',
'x-shortcut',

'h-container',
'2xl:h-container',
]

const { css, matched } = await uno.generate(new Set([
...unexpected,
...expected,
]), { preflights: false })

expect([...matched].sort()).toEqual(expected.sort())
expect(css).toMatchSnapshot()
})
})

0 comments on commit 233e7b1

Please sign in to comment.