Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improving some types #1851

Merged
merged 5 commits into from Nov 9, 2022
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 13 additions & 13 deletions packages/core/src/config.ts
Expand Up @@ -3,22 +3,22 @@ import { clone, isStaticRule, mergeDeep, normalizeVariant, toArray, uniq } from
import { extractorSplit } from './extractors'
import { DEFAULT_LAYERS } from './constants'

export function resolveShortcuts(shortcuts: UserShortcuts): Shortcut[] {
export function resolveShortcuts<Theme extends {} = {}>(shortcuts: UserShortcuts<Theme>): Shortcut<Theme>[] {
return toArray(shortcuts).flatMap((s) => {
if (Array.isArray(s))
return [s]
return Object.entries(s)
})
}

export function resolvePreset(preset: Preset): Preset {
export function resolvePreset<Theme extends {} = {}>(preset: Preset<Theme>): Preset<Theme> {
const shortcuts = preset.shortcuts
? resolveShortcuts(preset.shortcuts)
: undefined
preset.shortcuts = shortcuts as any

if (preset.prefix || preset.layer) {
const apply = (i: Rule | Shortcut) => {
const apply = (i: Rule<Theme> | Shortcut) => {
if (!i[2])
i[2] = {}
const meta = i[2]
Expand All @@ -34,11 +34,11 @@ export function resolvePreset(preset: Preset): Preset {
return preset
}

export function resolveConfig(
userConfig: UserConfig = {},
defaults: UserConfigDefaults = {},
): ResolvedConfig {
const config = Object.assign({}, defaults, userConfig) as UserConfigDefaults
export function resolveConfig<Theme extends {} = {}>(
userConfig: UserConfig<Theme> = {},
defaults: UserConfigDefaults<Theme> = {},
): ResolvedConfig<Theme> {
const config = Object.assign({}, defaults, userConfig) as UserConfigDefaults<Theme>
const rawPresets = (config.presets || []).flatMap(toArray).map(resolvePreset)

const sortedPresets = [
Expand All @@ -49,7 +49,7 @@ export function resolveConfig(

const layers = Object.assign(DEFAULT_LAYERS, ...rawPresets.map(i => i.layers), userConfig.layers)

function mergePresets<T extends 'rules' | 'variants' | 'extractors' | 'shortcuts' | 'preflights' | 'preprocess' | 'postprocess' | 'extendTheme' | 'safelist'>(key: T): Required<UserConfig>[T] {
function mergePresets<T extends 'rules' | 'variants' | 'extractors' | 'shortcuts' | 'preflights' | 'preprocess' | 'postprocess' | 'extendTheme' | 'safelist'>(key: T): Required<UserConfig<Theme>>[T] {
return uniq([
...sortedPresets.flatMap(p => toArray(p[key] || []) as any[]),
...toArray(config[key] || []) as any[],
Expand All @@ -62,7 +62,7 @@ export function resolveConfig(
extractors.sort((a, b) => (a.order || 0) - (b.order || 0))

const rules = mergePresets('rules')
const rulesStaticMap: ResolvedConfig['rulesStaticMap'] = {}
const rulesStaticMap: ResolvedConfig<Theme>['rulesStaticMap'] = {}

const rulesSize = rules.length

Expand All @@ -78,12 +78,12 @@ export function resolveConfig(
return [i, ...rule]
})
.filter(Boolean)
.reverse() as ResolvedConfig['rulesDynamic']
.reverse() as ResolvedConfig<Theme>['rulesDynamic']

const theme = clone([
const theme: Theme = clone([
...sortedPresets.map(p => p.theme || {}),
config.theme || {},
].reduce((a, p) => mergeDeep(a, p), {}))
].reduce<Theme>((a, p) => mergeDeep(a, p), {} as Theme))

;(mergePresets('extendTheme') as ThemeExtender<any>[]).forEach(extendTheme => extendTheme(theme))

Expand Down
58 changes: 29 additions & 29 deletions packages/core/src/generator/index.ts
Expand Up @@ -5,25 +5,25 @@ import { CONTROL_SHORTCUT_NO_MERGE, TwoKeyMap, e, entriesToCss, expandVariantGro
import { version } from '../../package.json'
import { LAYER_DEFAULT, LAYER_PREFLIGHTS } from '../constants'

export class UnoGenerator {
export class UnoGenerator<Theme extends {} = {}> {
public version = version
private _cache = new Map<string, StringifiedUtil[] | null>()
public config: ResolvedConfig
private _cache = new Map<string, StringifiedUtil<Theme>[] | null>()
public config: ResolvedConfig<Theme>
public blocked = new Set<string>()
public parentOrders = new Map<string, number>()
public events = createNanoEvents<{
config: (config: ResolvedConfig) => void
config: (config: ResolvedConfig<Theme>) => void
}>()

constructor(
public userConfig: UserConfig = {},
public defaults: UserConfigDefaults = {},
public userConfig: UserConfig<Theme> = {},
public defaults: UserConfigDefaults<Theme> = {},
) {
this.config = resolveConfig(userConfig, defaults)
this.events.emit('config', this.config)
}

setConfig(userConfig?: UserConfig, defaults?: UserConfigDefaults) {
setConfig(userConfig?: UserConfig<Theme>, defaults?: UserConfigDefaults<Theme>) {
if (!userConfig)
return
if (defaults)
Expand Down Expand Up @@ -54,8 +54,8 @@ export class UnoGenerator {
return set
}

makeContext(raw: string, applied: VariantMatchedResult) {
const context: RuleContext = {
makeContext(raw: string, applied: VariantMatchedResult<Theme>) {
const context: RuleContext<Theme> = {
rawSelector: raw,
currentSelector: applied[1],
theme: this.config.theme,
Expand Down Expand Up @@ -141,7 +141,7 @@ export class UnoGenerator {

const layerSet = new Set<string>([LAYER_DEFAULT])
const matched = new Set<string>()
const sheet = new Map<string, StringifiedUtil[]>()
const sheet = new Map<string, StringifiedUtil<Theme>[]>()
let preflightsMap: Record<string, string> = {}

const tokenPromises = Array.from(tokens).map(async (raw) => {
Expand Down Expand Up @@ -170,7 +170,7 @@ export class UnoGenerator {
if (!preflights)
return

const preflightContext: PreflightContext = {
const preflightContext: PreflightContext<Theme> = {
generator: this,
theme: this.config.theme,
}
Expand Down Expand Up @@ -292,14 +292,14 @@ export class UnoGenerator {
}
}

matchVariants(raw: string, current?: string): VariantMatchedResult {
matchVariants(raw: string, current?: string): VariantMatchedResult<Theme> {
// process variants
const variants = new Set<Variant>()
const variants = new Set<Variant<Theme>>()
const handlers: VariantHandler[] = []
let processed = current || raw
let applied = false

const context: VariantContext = {
const context: VariantContext<Theme> = {
rawSelector: raw,
theme: this.config.theme,
generator: this,
Expand Down Expand Up @@ -382,7 +382,7 @@ export class UnoGenerator {
return obj
}

constructCustomCSS(context: Readonly<RuleContext>, body: CSSObject | CSSEntries, overrideSelector?: string) {
constructCustomCSS(context: Readonly<RuleContext<Theme>>, body: CSSObject | CSSEntries, overrideSelector?: string) {
const normalizedBody = normalizeCSSEntries(body)
if (isString(normalizedBody))
return normalizedBody
Expand All @@ -394,7 +394,7 @@ export class UnoGenerator {
return cssBody
}

async parseUtil(input: string | VariantMatchedResult, context: RuleContext, internal = false, shortcutPrefix: string | undefined = undefined): Promise<(ParsedUtil | RawUtil)[] | undefined> {
async parseUtil(input: string | VariantMatchedResult<Theme>, context: RuleContext<Theme>, internal = false, shortcutPrefix: string | undefined = undefined): Promise<(ParsedUtil | RawUtil)[] | undefined> {
const [raw, processed, variantHandlers] = isString(input)
? this.matchVariants(input)
: input
Expand Down Expand Up @@ -453,7 +453,7 @@ export class UnoGenerator {
continue

if (this.config.details)
context.rules!.push([matcher, handler, meta] as DynamicRule)
context.rules!.push([matcher, handler, meta] as DynamicRule<Theme>)

const entries = normalizeCSSValues(result).filter(i => i.length)
if (entries.length) {
Expand All @@ -467,7 +467,7 @@ export class UnoGenerator {
}
}

stringifyUtil(parsed?: ParsedUtil | RawUtil, context?: RuleContext): StringifiedUtil | undefined {
stringifyUtil(parsed?: ParsedUtil | RawUtil, context?: RuleContext<Theme>): StringifiedUtil<Theme> | undefined {
if (!parsed)
return
if (isRawUtil(parsed))
Expand All @@ -488,12 +488,12 @@ export class UnoGenerator {
return [parsed[0], selector, body, parent, ruleMeta, this.config.details ? context : undefined, noMerge]
}

expandShortcut(input: string, context: RuleContext, depth = 5): [ShortcutValue[], RuleMeta | undefined] | undefined {
expandShortcut(input: string, context: RuleContext<Theme>, depth = 5): [ShortcutValue[], RuleMeta | undefined] | undefined {
if (depth === 0)
return

const recordShortcut = this.config.details
? (s: Shortcut) => {
? (s: Shortcut<Theme>) => {
context.shortcuts = context.shortcuts ?? []
context.shortcuts.push(s)
}
Expand Down Expand Up @@ -554,11 +554,11 @@ export class UnoGenerator {
}

async stringifyShortcuts(
parent: VariantMatchedResult,
context: RuleContext,
parent: VariantMatchedResult<Theme>,
context: RuleContext<Theme>,
expanded: ShortcutValue[],
meta: RuleMeta = { layer: this.config.shortcutsLayer },
): Promise<StringifiedUtil[] | undefined> {
): Promise<StringifiedUtil<Theme>[] | undefined> {
const selectorMap = new TwoKeyMap<string, string | undefined, [[CSSEntries, boolean, number][], number]>()
const parsed = (
await Promise.all(uniq(expanded)
Expand All @@ -578,7 +578,7 @@ export class UnoGenerator {
.sort((a, b) => a[0] - b[0])

const [raw, , parentVariants] = parent
const rawStringfieldUtil: StringifiedUtil[] = []
const rawStringfieldUtil: StringifiedUtil<Theme>[] = []
for (const item of parsed) {
if (isRawUtil(item)) {
rawStringfieldUtil.push([item[0], undefined, item[1], undefined, item[2], context, undefined])
Expand All @@ -593,10 +593,10 @@ export class UnoGenerator {
}
return rawStringfieldUtil.concat(selectorMap
.map(([e, index], selector, joinedParents) => {
const stringify = (flatten: boolean, noMerge: boolean, entrySortPair: [CSSEntries, number][]): (StringifiedUtil | undefined)[] => {
const stringify = (flatten: boolean, noMerge: boolean, entrySortPair: [CSSEntries, number][]): (StringifiedUtil<Theme> | undefined)[] => {
const maxSort = Math.max(...entrySortPair.map(e => e[1]))
const entriesList = entrySortPair.map(e => e[0])
return (flatten ? [entriesList.flat(1)] : entriesList).map((entries: CSSEntries): StringifiedUtil | undefined => {
return (flatten ? [entriesList.flat(1)] : entriesList).map((entries: CSSEntries): StringifiedUtil<Theme> | undefined => {
const body = entriesToCss(entries)
if (body)
return [index, selector, body, joinedParents, { ...meta, noMerge, sort: maxSort }, context, undefined]
Expand All @@ -615,16 +615,16 @@ export class UnoGenerator {
])
})
.flat(2)
.filter(Boolean) as StringifiedUtil[])
.filter(Boolean) as StringifiedUtil<Theme>[])
}

isBlocked(raw: string) {
return !raw || this.config.blocklist.some(e => isString(e) ? e === raw : e.test(raw))
}
}

export function createGenerator(config?: UserConfig, defaults?: UserConfigDefaults) {
return new UnoGenerator(config, defaults)
export function createGenerator<Theme extends {} = {}>(config?: UserConfig<Theme>, defaults?: UserConfigDefaults<Theme>) {
return new UnoGenerator<Theme>(config, defaults)
}

export const regexScopePlaceholder = / \$\$ /
Expand Down
36 changes: 18 additions & 18 deletions packages/core/src/types.ts
Expand Up @@ -64,7 +64,7 @@ export interface RuleContext<Theme extends {} = {}> {
/**
* UnoCSS generator instance
*/
generator: UnoGenerator
generator: UnoGenerator<Theme>
/**
* The theme object
*/
Expand All @@ -76,7 +76,7 @@ export interface RuleContext<Theme extends {} = {}> {
/**
* The result of variant matching.
*/
variantMatch: VariantMatchedResult
variantMatch: VariantMatchedResult<Theme>
/**
* Construct a custom CSS rule.
* Variants and selector escaping will be handled automatically.
Expand All @@ -85,15 +85,15 @@ export interface RuleContext<Theme extends {} = {}> {
/**
* Available only when `details` option is enabled.
*/
rules?: Rule[]
rules?: Rule<Theme>[]
/**
* Available only when `details` option is enabled.
*/
shortcuts?: Shortcut[]
shortcuts?: Shortcut<Theme>[]
/**
* Available only when `details` option is enabled.
*/
variants?: Variant[]
variants?: Variant<Theme>[]
}

export interface VariantContext<Theme extends {} = {}> {
Expand All @@ -104,7 +104,7 @@ export interface VariantContext<Theme extends {} = {}> {
/**
* UnoCSS generator instance
*/
generator: UnoGenerator
generator: UnoGenerator<Theme>
/**
* The theme object
*/
Expand All @@ -121,7 +121,7 @@ export interface PreflightContext<Theme extends {} = {}> {
/**
* UnoCSS generator instance
*/
generator: UnoGenerator
generator: UnoGenerator<Theme>
/**
* The theme object
*/
Expand Down Expand Up @@ -616,18 +616,18 @@ export interface PluginOptions {
export interface UserConfig<Theme extends {} = {}> extends ConfigBase<Theme>, UserOnlyOptions<Theme>, GeneratorOptions, PluginOptions, CliOptions {}
export interface UserConfigDefaults<Theme extends {} = {}> extends ConfigBase<Theme>, UserOnlyOptions<Theme> {}

export interface ResolvedConfig extends Omit<
RequiredByKey<UserConfig, 'mergeSelectors' | 'theme' | 'rules' | 'variants' | 'layers' | 'extractors' | 'blocklist' | 'safelist' | 'preflights' | 'sortLayers'>,
export interface ResolvedConfig<Theme extends {} = {}> extends Omit<
RequiredByKey<UserConfig<Theme>, 'mergeSelectors' | 'theme' | 'rules' | 'variants' | 'layers' | 'extractors' | 'blocklist' | 'safelist' | 'preflights' | 'sortLayers'>,
'rules' | 'shortcuts' | 'autocomplete'
> {
presets: Preset[]
shortcuts: Shortcut[]
variants: VariantObject[]
presets: Preset<Theme>[]
shortcuts: Shortcut<Theme>[]
variants: VariantObject<Theme>[]
preprocess: Preprocessor[]
postprocess: Postprocessor[]
rulesSize: number
rulesDynamic: [number, ...DynamicRule][]
rulesStaticMap: Record<string, [number, CSSObject | CSSEntries, RuleMeta | undefined, Rule] | undefined>
rulesDynamic: [number, ...DynamicRule<Theme>][]
rulesStaticMap: Record<string, [number, CSSObject | CSSEntries, RuleMeta | undefined, Rule<Theme>] | undefined>
autocomplete: {
templates: (AutoCompleteFunction | AutoCompleteTemplate)[]
extractors: AutoCompleteExtractor[]
Expand All @@ -642,11 +642,11 @@ export interface GenerateResult {
matched: Set<string>
}

export type VariantMatchedResult = readonly [
export type VariantMatchedResult<Theme extends {} = {}> = readonly [
raw: string,
current: string,
variantHandlers: VariantHandler[],
variants: Set<Variant>,
variants: Set<Variant<Theme>>,
]

export type ParsedUtil = readonly [
Expand All @@ -663,13 +663,13 @@ export type RawUtil = readonly [
meta: RuleMeta | undefined,
]

export type StringifiedUtil = readonly [
export type StringifiedUtil<Theme extends {} = {}> = readonly [
index: number,
selector: string | undefined,
body: string,
parent: string | undefined,
meta: RuleMeta | undefined,
context: RuleContext | undefined,
context: RuleContext<Theme> | undefined,
noMerge: boolean | undefined,
]

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/utils/helpers.ts
Expand Up @@ -13,7 +13,7 @@ export function isValidSelector(selector = ''): selector is string {
return validateFilterRE.test(selector)
}

export function normalizeVariant(variant: Variant): VariantObject {
export function normalizeVariant(variant: Variant<any>): VariantObject<any> {
return typeof variant === 'function'
? { match: variant }
: variant
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/utils/object.ts
Expand Up @@ -98,10 +98,10 @@ export function clone<T>(val: T): T {
return val
}

export function isStaticRule(rule: Rule): rule is StaticRule {
export function isStaticRule(rule: Rule<any>): rule is StaticRule {
return isString(rule[0])
}

export function isStaticShortcut(sc: Shortcut): sc is StaticShortcut {
export function isStaticShortcut(sc: Shortcut<any>): sc is StaticShortcut {
return isString(sc[0])
}