Skip to content

Commit 298de3e

Browse files
Mencizyyv
andauthored
feat(core): allow postprocessors to append or remove rules (#5010)
Co-authored-by: Chris <[email protected]>
1 parent dba521e commit 298de3e

File tree

3 files changed

+80
-41
lines changed

3 files changed

+80
-41
lines changed

packages-engine/core/src/generator.ts

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ class UnoGeneratorInternal<Theme extends object = object> {
156156
const utils = expanded
157157
? await this.stringifyShortcuts(context.variantMatch, context, expanded[0], expanded[1])
158158
// no shortcuts
159-
: (await this.parseUtil(context.variantMatch, context))?.map(i => this.stringifyUtil(i, context)).filter(notNull)
159+
: (await this.parseUtil(context.variantMatch, context))?.flatMap(i => this.stringifyUtil(i, context)).filter(notNull)
160160

161161
return utils
162162
}
@@ -496,7 +496,7 @@ class UnoGeneratorInternal<Theme extends object = object> {
496496
parsed: ParsedUtil,
497497
variantHandlers = parsed[4],
498498
raw = parsed[1],
499-
): UtilObject {
499+
): UtilObject[] {
500500
const handler = variantHandlers.slice()
501501
.sort((a, b) => (a.order || 0) - (b.order || 0))
502502
.reduceRight(
@@ -545,10 +545,22 @@ class UnoGeneratorInternal<Theme extends object = object> {
545545
noMerge: variantContextResult.noMerge,
546546
}
547547

548-
for (const p of this.config.postprocess)
549-
p(obj)
550-
551-
return obj
548+
return this.config.postprocess.reduce<UtilObject[]>(
549+
(utilities, p) => {
550+
const result: UtilObject[] = []
551+
for (const util of utilities) {
552+
const processed = p(util)
553+
if (Array.isArray(processed)) {
554+
result.push(...processed.filter(notNull))
555+
}
556+
else {
557+
result.push(processed || util)
558+
}
559+
}
560+
return result
561+
},
562+
[obj],
563+
)
552564
}
553565

554566
constructCustomCSS(
@@ -560,11 +572,14 @@ class UnoGeneratorInternal<Theme extends object = object> {
560572
if (isString(normalizedBody))
561573
return normalizedBody
562574

563-
const { selector, entries, parent } = this.applyVariants([0, overrideSelector || context.rawSelector, normalizedBody, undefined, context.variantHandlers])
564-
const cssBody = `${selector}{${entriesToCss(entries)}}`
565-
if (parent)
566-
return `${parent}{${cssBody}}`
567-
return cssBody
575+
return this.applyVariants([0, overrideSelector || context.rawSelector, normalizedBody, undefined, context.variantHandlers])
576+
.map(({ selector, entries, parent }) => {
577+
const cssBody = `${selector}{${entriesToCss(entries)}}`
578+
if (parent)
579+
return `${parent}{${cssBody}}`
580+
return cssBody
581+
})
582+
.join('')
568583
}
569584

570585
async parseUtil(
@@ -736,32 +751,37 @@ class UnoGeneratorInternal<Theme extends object = object> {
736751
stringifyUtil(
737752
parsed?: ParsedUtil | RawUtil,
738753
context?: RuleContext<Theme>,
739-
): StringifiedUtil<Theme> | undefined {
754+
): StringifiedUtil<Theme>[] | undefined {
740755
if (!parsed)
741756
return
742757
if (isRawUtil(parsed))
743-
return [parsed[0], undefined, parsed[1], undefined, parsed[2], this.config.details ? context : undefined, undefined]
744-
745-
const {
746-
selector,
747-
entries,
748-
parent,
749-
layer: variantLayer,
750-
sort: variantSort,
751-
noMerge,
752-
} = this.applyVariants(parsed)
753-
const body = entriesToCss(entries)
754-
755-
if (!body)
756-
return
758+
return [[parsed[0], undefined, parsed[1], undefined, parsed[2], this.config.details ? context : undefined, undefined]]
759+
760+
const utilities = this.applyVariants(parsed)
761+
const result: StringifiedUtil<Theme>[] = []
762+
for (const util of utilities) {
763+
const {
764+
selector,
765+
entries,
766+
parent,
767+
layer: variantLayer,
768+
sort: variantSort,
769+
noMerge,
770+
} = util
771+
const body = entriesToCss(entries)
772+
773+
if (!body)
774+
continue
757775

758-
const { layer: metaLayer, sort: metaSort, ...meta } = parsed[3] ?? {}
759-
const ruleMeta = {
760-
...meta,
761-
layer: variantLayer ?? metaLayer,
762-
sort: variantSort ?? metaSort,
776+
const { layer: metaLayer, sort: metaSort, ...meta } = parsed[3] ?? {}
777+
const ruleMeta = {
778+
...meta,
779+
layer: variantLayer ?? metaLayer,
780+
sort: variantSort ?? metaSort,
781+
}
782+
result.push([parsed[0], selector, body, parent, ruleMeta, this.config.details ? context : undefined, noMerge])
763783
}
764-
return [parsed[0], selector, body, parent, ruleMeta, this.config.details ? context : undefined, noMerge]
784+
return result
765785
}
766786

767787
async expandShortcut(
@@ -882,14 +902,14 @@ class UnoGeneratorInternal<Theme extends object = object> {
882902

883903
const isNoMerge = Object.fromEntries(item[2])[symbols.shortcutsNoMerge]
884904
const variants = [...item[4], ...(!isNoMerge ? parentVariants : [])]
885-
const { selector, entries, parent, sort, noMerge, layer } = this.applyVariants(item, variants, raw)
886-
887-
// find existing layer and merge
888-
const selectorMap = layerMap.getFallback(layer ?? meta.layer, new TwoKeyMap())
889-
// find existing selector/mediaQuery pair and merge
890-
const mapItem = selectorMap.getFallback(selector, parent, [[], item[0]])
891-
// add entries
892-
mapItem[0].push([entries, !!(noMerge ?? item[3]?.noMerge), sort ?? 0])
905+
for (const { selector, entries, parent, sort, noMerge, layer } of this.applyVariants(item, variants, raw)) {
906+
// find existing layer and merge
907+
const selectorMap = layerMap.getFallback(layer ?? meta.layer, new TwoKeyMap())
908+
// find existing selector/mediaQuery pair and merge
909+
const mapItem = selectorMap.getFallback(selector, parent, [[], item[0]])
910+
// add entries
911+
mapItem[0].push([entries, !!(noMerge ?? item[3]?.noMerge), sort ?? 0])
912+
}
893913
}
894914
return rawStringifiedUtil.concat(layerMap
895915
.flatMap((selectorMap, layer) =>

packages-engine/core/src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ export interface VariantObject<Theme extends object = object> {
390390
export type Variant<Theme extends object = object> = VariantFunction<Theme> | VariantObject<Theme>
391391

392392
export type Preprocessor = (matcher: string) => string | undefined
393-
export type Postprocessor = (util: UtilObject) => void
393+
export type Postprocessor = (util: UtilObject) => void | UtilObject | (UtilObject | null | undefined)[]
394394
export type ThemeExtender<Theme extends object = object> = (theme: Theme, config: Readonly<ResolvedConfig<Theme>>) => Theme | void
395395

396396
export interface ConfigBase<Theme extends object = object> {

packages-engine/core/test/postprocess.test.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,22 @@ it('postprocess', async () => {
4242
.text-opacity-50{--hi-text-opacity:0.5;}"
4343
`)
4444
})
45+
46+
it('postprocess can expand utilities', async () => {
47+
const uno = await createGenerator({
48+
rules: [
49+
['foo', { color: 'red' }],
50+
],
51+
postprocess: [
52+
(util) => {
53+
if (util.selector === '.foo')
54+
return [util, { ...util, selector: `${util.selector}::after` }]
55+
},
56+
],
57+
})
58+
59+
const { css } = await uno.generate('foo', { preflights: false })
60+
expect(css).toMatchInlineSnapshot(`
61+
"/* layer: default */\n.foo,\n.foo::after{color:red;}"
62+
`)
63+
})

0 commit comments

Comments
 (0)