Skip to content

Commit

Permalink
feat(core): add noMerge to variant context (#1525)
Browse files Browse the repository at this point in the history
  • Loading branch information
chu121su12 committed Sep 2, 2022
1 parent 3322f43 commit 6a47032
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 9 deletions.
19 changes: 10 additions & 9 deletions packages/core/src/generator/index.ts
Expand Up @@ -225,12 +225,12 @@ export class UnoGenerator {
const sorted: PreparedRule[] = items
.filter(i => (i[4]?.layer || LAYER_DEFAULT) === layer)
.sort((a, b) => a[0] - b[0] || (a[4]?.sort || 0) - (b[4]?.sort || 0) || a[1]?.localeCompare(b[1] || '') || a[2]?.localeCompare(b[2] || '') || 0)
.map(([, selector, body,, meta]) => {
.map(([, selector, body,, meta,, variantNoMerge]) => {
const scopedSelector = selector ? applyScope(selector, scope) : selector
return [
[[scopedSelector ?? '', meta?.sort ?? 0]],
body,
!!meta?.noMerge,
!!(variantNoMerge ?? meta?.noMerge),
]
})
if (!sorted.length)
Expand Down Expand Up @@ -384,6 +384,7 @@ export class UnoGenerator {
parent,
layer: variantContextResult.layer,
sort: variantContextResult.sort,
noMerge: variantContextResult.noMerge,
}

for (const p of this.config.postprocess)
Expand Down Expand Up @@ -478,9 +479,9 @@ export class UnoGenerator {
if (!parsed)
return
if (isRawUtil(parsed))
return [parsed[0], undefined, parsed[1], undefined, parsed[2], this.config.details ? context : undefined]
return [parsed[0], undefined, parsed[1], undefined, parsed[2], this.config.details ? context : undefined, undefined]

const { selector, entries, parent, layer: variantLayer, sort: variantSort } = this.applyVariants(parsed)
const { selector, entries, parent, layer: variantLayer, sort: variantSort, noMerge } = this.applyVariants(parsed)
const body = entriesToCss(entries)

if (!body)
Expand All @@ -492,7 +493,7 @@ export class UnoGenerator {
layer: variantLayer ?? metaLayer,
sort: variantSort ?? metaSort,
}
return [parsed[0], selector, body, parent, ruleMeta, this.config.details ? context : undefined]
return [parsed[0], selector, body, parent, ruleMeta, this.config.details ? context : undefined, noMerge]
}

expandShortcut(input: string, context: RuleContext, depth = 5): [ShortcutValue[], RuleMeta | undefined] | undefined {
Expand Down Expand Up @@ -585,15 +586,15 @@ export class UnoGenerator {
const rawStringfieldUtil: StringifiedUtil[] = []
for (const item of parsed) {
if (isRawUtil(item)) {
rawStringfieldUtil.push([item[0], undefined, item[1], undefined, item[2], context])
rawStringfieldUtil.push([item[0], undefined, item[1], undefined, item[2], context, undefined])
continue
}
const { selector, entries, parent, sort } = this.applyVariants(item, [...item[4], ...parentVariants], raw)
const { selector, entries, parent, sort, noMerge } = this.applyVariants(item, [...item[4], ...parentVariants], raw)

// find existing selector/mediaQuery pair and merge
const mapItem = selectorMap.getFallback(selector, parent, [[], item[0]])
// add entries
mapItem[0].push([entries, !!item[3]?.noMerge, sort ?? 0])
mapItem[0].push([entries, !!(noMerge ?? item[3]?.noMerge), sort ?? 0])
}
return rawStringfieldUtil.concat(selectorMap
.map(([e, index], selector, joinedParents) => {
Expand All @@ -603,7 +604,7 @@ export class UnoGenerator {
return (flatten ? [entriesList.flat(1)] : entriesList).map((entries: CSSEntries): StringifiedUtil | undefined => {
const body = entriesToCss(entries)
if (body)
return [index, selector, body, joinedParents, { ...meta, noMerge, sort: maxSort }, context]
return [index, selector, body, joinedParents, { ...meta, noMerge, sort: maxSort }, context, undefined]
return undefined
})
}
Expand Down
7 changes: 7 additions & 0 deletions packages/core/src/types.ts
Expand Up @@ -228,6 +228,11 @@ export interface VariantHandlerContext {
* Order in which the variant is sorted within single rule.
*/
sort?: number
/**
* Option to not merge the resulting entries even if the body are the same.
* @default false
*/
noMerge?: boolean
}

export interface VariantHandler {
Expand Down Expand Up @@ -655,6 +660,7 @@ export type StringifiedUtil = readonly [
parent: string | undefined,
meta: RuleMeta | undefined,
context: RuleContext | undefined,
noMerge: boolean | undefined,
]

export type PreparedRule = readonly [
Expand All @@ -669,6 +675,7 @@ export interface UtilObject {
parent: string | undefined
layer: string | undefined
sort: number | undefined
noMerge: boolean | undefined
}

export interface GenerateOptions {
Expand Down
15 changes: 15 additions & 0 deletions test/__snapshots__/variant-handler.test.ts.snap
@@ -1,5 +1,20 @@
// Vitest Snapshot v1

exports[`variants > noMerge on variant 1`] = `
"/* layer: default */
.foo,
.var-a\\\\:foo::a,
.var-b\\\\:foo::b{name:bar;}
.var-c\\\\:foo::c{name:bar;}"
`;

exports[`variants > noMerge variant with shortcut 1`] = `
"/* layer: shortcuts */
.bar::a,
.bar::b{name:bar;}
.bar::c{name:bar;}"
`;

exports[`variants > selector section is merged in order 1`] = `
"/* layer: default */
.prefix .pre\\\\:back\\\\:foo::pseudo,
Expand Down
68 changes: 68 additions & 0 deletions test/variant-handler.test.ts
Expand Up @@ -114,4 +114,72 @@ describe('variants', () => {

expect(css).toMatchSnapshot()
})

test('noMerge on variant', async () => {
const uno = createGenerator({
rules: [
['foo', { name: 'bar' }],
],
variants: [
{
match(input) {
const match = input.match(/^(var-([abc])):/)
if (match) {
return {
matcher: input.slice(match[0].length),
handle: (input, next) => next({
...input,
pseudo: `${input.pseudo}::${match[2]}`,
noMerge: match[2] === 'c',
}),
}
}
},
},
],
})

const { css } = await uno.generate([
'foo',
'var-a:foo',
'var-b:foo',
'var-c:foo',
].join(' '), { preflights: false })

expect(css).toMatchSnapshot()
})

test('noMerge variant with shortcut', async () => {
const uno = createGenerator({
rules: [
['foo', { name: 'bar' }],
],
shortcuts: [
['bar', 'var-a:foo var-b:foo var-c:foo'],
],
variants: [
{
match(input) {
const match = input.match(/^(var-([abc])):/)
if (match) {
return {
matcher: input.slice(match[0].length),
handle: (input, next) => next({
...input,
pseudo: `${input.pseudo}::${match[2]}`,
noMerge: match[2] === 'c',
}),
}
}
},
},
],
})

const { css } = await uno.generate([
'bar',
].join(' '), { preflights: false })

expect(css).toMatchSnapshot()
})
})

0 comments on commit 6a47032

Please sign in to comment.