Skip to content

Commit

Permalink
feat(postprocess): createFilter for add important (#18)
Browse files Browse the repository at this point in the history
* feat(postprocess): createFilter for add important

* chore: update
  • Loading branch information
zyyv authored Dec 27, 2024
1 parent 343a5cc commit db5b86e
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 62 deletions.
35 changes: 35 additions & 0 deletions packages/core/src/core/postprocess/important.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Postprocessor } from '@unocss/core'
import type { FilterPattern, ImportantOptions } from '../../types'
import { toArray } from '@unocss/core'

function createFilter(
include: FilterPattern,
exclude: FilterPattern,
): (id: string) => boolean {
const includePattern = toArray(include || [])
const excludePattern = toArray(exclude || [])
return (id: string) => {
if (excludePattern.some(p => id.match(p)))
return false
return includePattern.some(p => id.match(p))
}
}

export function importantProcess(importantOptions: Required<ImportantOptions>): Postprocessor {
const keyFilter = createFilter(importantOptions.includes, importantOptions.excludes)

return (util) => {
for (const item of util.entries) {
if (keyFilter(item[0])) {
if (item[1] != null && !String(item[1]).includes('!important')) {
item[1] += ' !important'
}
}
else {
if (item[1] != null && String(item[1]).includes('!important')) {
item[1] = String(item[1]).replace(/\s*!important/g, '')
}
}
}
}
}
13 changes: 13 additions & 0 deletions packages/core/src/core/postprocess/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { Postprocessor } from '@unocss/core'
import type { ImportantOptions, ResolvedOptions } from '../../types'
import { importantProcess } from './important'
import { postprocessWithUnColor } from './uncolor'

export function postprocess(options: ResolvedOptions): Postprocessor[] {
const { unColor, important } = options

return [
unColor ? postprocessWithUnColor(unColor as string) : undefined,
important ? importantProcess(important as ImportantOptions) : undefined,
].filter(Boolean) as Postprocessor[]
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { Postprocessor } from '@unocss/core'
const rgbRE = /rgb\(([\d\s]+?)\s*\/\s*([^)]+)\)/
const rgbaRE = /rgba\(([\d\s,]+),\s*([^)]+)\)/

// IN-README-START
// https://github.com/unocss/unocss/discussions/2816
// Extract rgba color in css variable.
export function postprocessWithUnColor(unColor: string): Postprocessor {
Expand All @@ -27,13 +26,3 @@ export function postprocessWithUnColor(unColor: string): Postprocessor {
})
}
}

export function importantProcess(): Postprocessor {
return (util) => {
util.entries.forEach((i) => {
if (i[1] != null && !String(i[1]).includes('!important'))
i[1] += ' !important'
})
}
}
// IN-README-END
12 changes: 4 additions & 8 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import type { Postprocessor, Shortcut, UserConfig } from '@unocss/core'
import type { Shortcut, UserConfig } from '@unocss/core'
import type { UsefulOptions, UsefulTheme } from './types'
import { definePreset, mergeConfigs } from '@unocss/core'
import { extractors, preflights, rules, shortcuts, variants } from './core'
import { importantProcess, postprocessWithUnColor } from './core/postprocess'
import { extractors, postprocess, preflights, rules, shortcuts, variants } from './core'
import { PRESET_NAME } from './meta'
import { resolveOptions } from './resolve'

Expand All @@ -12,7 +11,7 @@ export type { UsefulOptions, UsefulTheme }

export const presetUseful = definePreset<UsefulOptions, UsefulTheme>(async (options) => {
const resolvedOptions = await resolveOptions(options ?? {})
const { enableDefaultShortcuts, unColor, theme, meta, important } = resolvedOptions
const { enableDefaultShortcuts, theme, meta } = resolvedOptions

return {
name: `unocss-preset-${PRESET_NAME}`,
Expand All @@ -24,10 +23,7 @@ export const presetUseful = definePreset<UsefulOptions, UsefulTheme>(async (opti
variants: variants(resolvedOptions),
shortcuts: [...enableDefaultShortcuts ? shortcuts : [], ...meta.shortcuts] as Shortcut[],
extractors,
postprocess: [
unColor ? postprocessWithUnColor(unColor as string) : undefined,
important ? importantProcess() : undefined,
].filter(Boolean) as Postprocessor[],
postprocess: postprocess(resolvedOptions),
presets: meta.presets,
transformers: meta.transformers,
preflights: preflights(resolvedOptions),
Expand Down
99 changes: 61 additions & 38 deletions packages/core/src/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,50 +42,25 @@ const defaultPresetOptions: Record<string, any> = {
} as WebFontsOptions,
}

const defaultImportantOptions = {
excludes: [],
includes: [/.*/g],
}

export async function resolveOptions(options: UsefulOptions) {
const optionsWithDefault = Object.assign({}, defaultOptions, options) as Required<UsefulOptions>
optionsWithDefault.unColor = typeof optionsWithDefault.unColor === 'string'
? optionsWithDefault.unColor
: optionsWithDefault.unColor ? '--un-color' : false

const presets = []
const transformers = []
const presetMap = {
uno: import('@unocss/preset-uno').then(m => m.presetUno),
attributify: import('@unocss/preset-attributify').then(m => m.presetAttributify),
icons: import('@unocss/preset-icons').then(m => m.presetIcons),
webFonts: import('@unocss/preset-web-fonts').then(m => m.presetWebFonts),
typography: import('@unocss/preset-typography').then(m => m.presetTypography),
tagify: import('@unocss/preset-tagify').then(m => m.presetTagify),
remToPx: import('@unocss/preset-rem-to-px').then(m => m.default),
scrollbar: import('unocss-preset-scrollbar').then(m => m.presetScrollbar),
magicss: import('unocss-preset-magicss').then(m => m.presetMagicss),
}
const transformerMap = {
directives: import('unocss').then(m => m.transformerDirectives),
variantGroup: import('unocss').then(m => m.transformerVariantGroup),
compileClass: import('unocss').then(m => m.transformerCompileClass),
}

for (const [key, preset] of Object.entries(presetMap)) {
const option = optionsWithDefault[key as keyof typeof presetMap]
if (option) {
const p = await preset as any
const presetOptions = defaultPresetOptions[key as keyof typeof defaultPresetOptions]
if (typeof option === 'object')
presets.push(p({ ...presetOptions, ...option }))
else
presets.push(p(presetOptions ?? {}))
}
}
for (const [key, transformer] of Object.entries(transformerMap)) {
const option = optionsWithDefault[key as keyof typeof transformerMap]
if (option) {
const t = await transformer as any
transformers.push(t(typeof option === 'boolean' ? {} as any : option))
}
}
optionsWithDefault.important = typeof optionsWithDefault.important === 'object'
? Object.assign({}, defaultImportantOptions, optionsWithDefault.important)
: optionsWithDefault.important === true
? defaultImportantOptions
: false

const presets = await resolvePresets(optionsWithDefault)
const transformers = await resolveTransformers(optionsWithDefault)
const { theme: t_theme, shortcuts } = resolveExtend(optionsWithDefault.theme.extend ?? {})
const _theme = deepMerge(optionsWithDefault.theme, t_theme)

Expand All @@ -100,7 +75,7 @@ export async function resolveOptions(options: UsefulOptions) {
} as ResolvedOptions
}

export function resolveExtend(extend: UsefulTheme['extend']) {
function resolveExtend(extend: UsefulTheme['extend']) {
const _shortcuts: CustomStaticShortcuts = []
const { animation, keyframes } = extend!

Expand All @@ -118,3 +93,51 @@ export function resolveExtend(extend: UsefulTheme['extend']) {
shortcuts: _shortcuts,
}
}

async function resolvePresets(options: Required<UsefulOptions>) {
const presets = []
const presetMap = {
uno: import('@unocss/preset-uno').then(m => m.presetUno),
attributify: import('@unocss/preset-attributify').then(m => m.presetAttributify),
icons: import('@unocss/preset-icons').then(m => m.presetIcons),
webFonts: import('@unocss/preset-web-fonts').then(m => m.presetWebFonts),
typography: import('@unocss/preset-typography').then(m => m.presetTypography),
tagify: import('@unocss/preset-tagify').then(m => m.presetTagify),
remToPx: import('@unocss/preset-rem-to-px').then(m => m.default),
scrollbar: import('unocss-preset-scrollbar').then(m => m.presetScrollbar),
magicss: import('unocss-preset-magicss').then(m => m.presetMagicss),
}

for (const [key, preset] of Object.entries(presetMap)) {
const option = options[key as keyof typeof presetMap]
if (option) {
const p = await preset as any
const presetOptions = defaultPresetOptions[key as keyof typeof defaultPresetOptions]
if (typeof option === 'object')
presets.push(p({ ...presetOptions, ...option }))
else
presets.push(p(presetOptions ?? {}))
}
}

return presets
}

async function resolveTransformers(options: Required<UsefulOptions>) {
const transformers = []
const transformerMap = {
directives: import('unocss').then(m => m.transformerDirectives),
variantGroup: import('unocss').then(m => m.transformerVariantGroup),
compileClass: import('unocss').then(m => m.transformerCompileClass),
}

for (const [key, transformer] of Object.entries(transformerMap)) {
const option = options[key as keyof typeof transformerMap]
if (option) {
const t = await transformer as any
transformers.push(t(typeof option === 'boolean' ? {} as any : option))
}
}

return transformers
}
18 changes: 17 additions & 1 deletion packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,29 @@ interface PreflightOptions {
reset?: boolean
}

export type FilterPattern = Array<string | RegExp> | string | RegExp | null

export interface ImportantOptions {
/**
* Make all unitilities important.
*
*/
includes?: FilterPattern

/**
* Make all unitilities important.
*
*/
excludes?: FilterPattern
}

export interface UsefulOptions {
/**
* Make all unitilities important.
*
* @default false
*/
important?: boolean
important?: boolean | ImportantOptions

/**
* Enable default shortcuts
Expand Down
3 changes: 2 additions & 1 deletion test/extractor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ describe('presetUseful extractor', async () => {
expect(matched.size).toBe(1)
expect(css).toMatchInlineSnapshot(`
"/* layer: default */
.bg-\\[url\\(data\\:image\\/png\\;base64\\,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIwAAAABJRU5ErkJggg\\=\\=\\)\\]{--un-url:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIwAAAABJRU5ErkJggg==);background-image:var(--un-url);}"`)
.bg-\\[url\\(data\\:image\\/png\\;base64\\,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIwAAAABJRU5ErkJggg\\=\\=\\)\\]{--un-url:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIwAAAABJRU5ErkJggg==);background-image:var(--un-url);}"
`)
})
})
49 changes: 46 additions & 3 deletions test/postprocess.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,15 @@ describe('presetUseful postprocess with unColor', () => {
})

describe('presetUseful postprocess with important', () => {
const withOutImport = ['bg-red', 'text-blue']
const withInImport = ['!text-xl', 'sm:text-sm!', 'important-ma']
const tokens = ['bg-red', 'text-blue', '!text-xl', 'sm:text-sm!', 'important-ma']

it('base', async () => {
const uno = await generateUno({
important: true,
preflights: false,
})

const { css } = await uno.generate([...withInImport, ...withOutImport])
const { css } = await uno.generate(tokens)

expect(css).toMatchInlineSnapshot(`
"/* layer: default */
Expand All @@ -91,4 +90,48 @@ describe('presetUseful postprocess with important', () => {
}"
`)
})

it('base with excludes', async () => {
const uno = await generateUno({
preflights: false,
important: {
excludes: ['color', /bg-/, 'margin'],
},
})

const { css } = await uno.generate(tokens)

expect(css).toMatchInlineSnapshot(`
"/* layer: default */
.important-ma{margin:auto;}
.bg-red{--un-bg-opacity:1;background-color:rgb(248 113 113 / var(--un-bg-opacity));}
.\\!text-xl{font-size:1.25rem !important;line-height:1.75rem !important;}
.text-blue{--un-text-opacity:1 !important;color:rgb(96 165 250 / var(--un-text-opacity));}
@media (min-width: 640px){
.sm\\:text-sm\\!{font-size:0.875rem !important;line-height:1.25rem !important;}
}"
`)
})

it('base with includes', async () => {
const uno = await generateUno({
preflights: false,
important: {
includes: ['color', /bg-/, 'margin'],
},
})

const { css } = await uno.generate(tokens)

expect(css).toMatchInlineSnapshot(`
"/* layer: default */
.important-ma{margin:auto !important;}
.bg-red{--un-bg-opacity:1 !important;background-color:rgb(248 113 113 / var(--un-bg-opacity)) !important;}
.\\!text-xl{font-size:1.25rem;line-height:1.75rem;}
.text-blue{--un-text-opacity:1;color:rgb(96 165 250 / var(--un-text-opacity)) !important;}
@media (min-width: 640px){
.sm\\:text-sm\\!{font-size:0.875rem;line-height:1.25rem;}
}"
`)
})
})

0 comments on commit db5b86e

Please sign in to comment.