Skip to content

Commit

Permalink
feat(core): support safelist access to RuleContext (#3693)
Browse files Browse the repository at this point in the history
Co-authored-by: Chris <hizyyv@gmail.com>
Co-authored-by: Chris <1633711653@qq.com>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
  • Loading branch information
4 people committed Apr 18, 2024
1 parent 7c8641a commit 04c2775
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 16 deletions.
25 changes: 16 additions & 9 deletions packages/core/src/generator/index.ts
@@ -1,5 +1,5 @@
import { createNanoEvents } from '../utils/events'
import type { CSSEntries, CSSObject, DynamicRule, ExtendedTokenInfo, ExtractorContext, GenerateOptions, GenerateResult, ParsedUtil, PreflightContext, PreparedRule, RawUtil, ResolvedConfig, RuleContext, RuleMeta, Shortcut, ShortcutValue, StringifiedUtil, UserConfig, UserConfigDefaults, UtilObject, Variant, VariantContext, VariantHandler, VariantHandlerContext, VariantMatchedResult } from '../types'
import type { CSSEntries, CSSObject, DynamicRule, ExtendedTokenInfo, ExtractorContext, GenerateOptions, GenerateResult, ParsedUtil, PreflightContext, PreparedRule, RawUtil, ResolvedConfig, RuleContext, RuleMeta, SafeListContext, Shortcut, ShortcutValue, StringifiedUtil, UserConfig, UserConfigDefaults, UtilObject, Variant, VariantContext, VariantHandler, VariantHandlerContext, VariantMatchedResult } from '../types'
import { resolveConfig } from '../config'
import { BetterMap, CONTROL_SHORTCUT_NO_MERGE, CountableSet, TwoKeyMap, e, entriesToCss, expandVariantGroup, isCountableSet, isRawUtil, isStaticShortcut, isString, noop, normalizeCSSEntries, normalizeCSSValues, notNull, toArray, uniq, warnOnce } from '../utils'
import { version } from '../../package.json'
Expand Down Expand Up @@ -182,11 +182,18 @@ export class UnoGenerator<Theme extends object = object> {
: input

if (safelist) {
this.config.safelist.forEach((s) => {
// We don't want to increment count if token is already in the set
if (!tokens.has(s))
tokens.add(s)
})
const safelistContext: SafeListContext<Theme> = {
generator: this,
theme: this.config.theme,
}

this.config.safelist
.flatMap(s => typeof s === 'function' ? s(safelistContext) : s)
.forEach((s) => {
// We don't want to increment count if token is already in the set
if (!tokens.has(s))
tokens.add(s)
})
}

const nl = minify ? '' : '\n'
Expand Down Expand Up @@ -284,7 +291,7 @@ export class UnoGenerator<Theme extends object = object> {
|| a[2]?.localeCompare(b[2] || '') // body
|| 0
})
.map(([, selector, body,, meta,, variantNoMerge]) => {
.map(([, selector, body, , meta, , variantNoMerge]) => {
const scopedSelector = selector ? applyScope(selector, scope) : selector
return [
[[scopedSelector ?? '', meta?.sort ?? 0]],
Expand Down Expand Up @@ -725,8 +732,8 @@ export class UnoGenerator<Theme extends object = object> {
}

const merges = [
[e.filter(([, noMerge]) => noMerge).map(([entries,, sort]) => [entries, sort]), true],
[e.filter(([, noMerge]) => !noMerge).map(([entries,, sort]) => [entries, sort]), false],
[e.filter(([, noMerge]) => noMerge).map(([entries, , sort]) => [entries, sort]), true],
[e.filter(([, noMerge]) => !noMerge).map(([entries, , sort]) => [entries, sort]), false],
] as [[CSSEntries, number][], boolean][]

return merges.map(([e, noMerge]) => [
Expand Down
16 changes: 9 additions & 7 deletions packages/core/src/types.ts
Expand Up @@ -131,6 +131,8 @@ export interface PreflightContext<Theme extends object = object> {
theme: Theme
}

export interface SafeListContext<Theme extends object = object> extends PreflightContext<Theme> { }

export interface Extractor {
name: string
order?: number
Expand Down Expand Up @@ -359,7 +361,7 @@ export interface ConfigBase<Theme extends object = object> {
/**
* Utilities that always been included
*/
safelist?: string[]
safelist?: (string | ((context: SafeListContext<Theme>) => Arrayable<string>))[]

/**
* Extractors to handle the source file and outputs possible classes/selectors
Expand Down Expand Up @@ -686,7 +688,7 @@ export interface ContentOptions {
/**
* Inline text to be extracted
*/
inline?: (string | { code: string, id?: string } | (() => Awaitable<string | { code: string, id?: string }>)) []
inline?: (string | { code: string, id?: string } | (() => Awaitable<string | { code: string, id?: string }>))[]

/**
* Filters to determine whether to extract certain modules from the build tools' transformation pipeline.
Expand Down Expand Up @@ -722,7 +724,7 @@ export interface ContentOptions {
/**
* @deprecated Renamed to `inline`
*/
plain?: (string | { code: string, id?: string }) []
plain?: (string | { code: string, id?: string })[]
}

/**
Expand Down Expand Up @@ -778,12 +780,12 @@ export interface PluginOptions {
exclude?: FilterPattern
}

export interface UserConfig<Theme extends object = object> extends ConfigBase<Theme>, UserOnlyOptions<Theme>, GeneratorOptions, PluginOptions, CliOptions {}
export interface UserConfigDefaults<Theme extends object = object> extends ConfigBase<Theme>, UserOnlyOptions<Theme> {}
export interface UserConfig<Theme extends object = object> extends ConfigBase<Theme>, UserOnlyOptions<Theme>, GeneratorOptions, PluginOptions, CliOptions { }
export interface UserConfigDefaults<Theme extends object = object> extends ConfigBase<Theme>, UserOnlyOptions<Theme> { }

export interface ResolvedConfig<Theme extends object = object> extends Omit<
RequiredByKey<UserConfig<Theme>, 'mergeSelectors' | 'theme' | 'rules' | 'variants' | 'layers' | 'extractors' | 'blocklist' | 'safelist' | 'preflights' | 'sortLayers'>,
'rules' | 'shortcuts' | 'autocomplete'
RequiredByKey<UserConfig<Theme>, 'mergeSelectors' | 'theme' | 'rules' | 'variants' | 'layers' | 'extractors' | 'blocklist' | 'safelist' | 'preflights' | 'sortLayers'>,
'rules' | 'shortcuts' | 'autocomplete'
> {
presets: Preset<Theme>[]
shortcuts: Shortcut<Theme>[]
Expand Down
3 changes: 3 additions & 0 deletions test/safelist.test.ts
Expand Up @@ -10,10 +10,13 @@ describe('safelist', () => {
],
safelist: [
'm1',
() => ['m3', 'm4'],
],
})
const { css } = await uno.generate('m2')
expect(css).toContain('.m1')
expect(css).toContain('.m2')
expect(css).toContain('.m3')
expect(css).toContain('.m4')
})
})

0 comments on commit 04c2775

Please sign in to comment.