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: expose theme type var #1394

Closed
wants to merge 35 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
78d52ab
feat(preset-attributify): expose `Preset` config type var
equt Aug 9, 2022
486d162
feat(preset-icons): expose `Preset` config type var
equt Aug 9, 2022
24270a9
feat(preset-rem-to-px): expose `Preset` config type var
equt Aug 9, 2022
2820663
feat(preset-tagify): expose `Preset` config type var
equt Aug 9, 2022
f168cc5
feat(core): expose `Preset` config type var
equt Aug 9, 2022
94edfb9
feat(preset-typography): expose `Preset` config type var
equt Aug 9, 2022
3c0f958
feat(inspector): expose `Preset` config type var
equt Aug 9, 2022
49c4392
feat(config): expose `Preset` config type var
equt Aug 9, 2022
2bac171
feat(preset-attributify): expose `Preset` config type var
equt Aug 9, 2022
d7666ed
fix(autocomplete): add missing theme type var
equt Aug 10, 2022
bac6e68
feat(core): do not set theme default type
equt Aug 10, 2022
3405ac5
fix(cli): use `Theme` from `@unocss/preset-uno`
equt Aug 10, 2022
5d31d8a
fix(inspector): add missing theme type var
equt Aug 10, 2022
286bb06
fix(preset-mini): type theme everywhere
equt Aug 10, 2022
ca40915
fix(preset-tagify): add missing theme type var
equt Aug 10, 2022
b959aa8
fix(preset-uno): add missing theme type var
equt Aug 10, 2022
d9a807b
fix(preset-wind): add missing theme type var
equt Aug 10, 2022
2884224
fix(runtime): add missing theme type var
equt Aug 10, 2022
8c3af65
fix(shared-docs): add missing theme type var
equt Aug 10, 2022
5ef8101
fix(shared-integration): add missing theme type var
equt Aug 10, 2022
e028b5d
fix(transformer-attributify-jsx): add missing theme type var
equt Aug 10, 2022
93adc20
fix(transformer-compile-class): add missing theme type var
equt Aug 10, 2022
3086dd1
fix(transformer-directives): add missing theme type var
equt Aug 10, 2022
97f3fef
fix(transformer-variant-group): add missing theme type var
equt Aug 10, 2022
a1b78d8
feat(unocss): relax restriction on theme type var
equt Aug 10, 2022
75ec591
fix(vite): add missing theme type var
equt Aug 10, 2022
78ad72a
fix(shared-integration): misplaced type var
equt Aug 10, 2022
ca78a60
fix(vscode): add missing theme type var
equt Aug 10, 2022
b9a3088
fix(webpack): add missing theme type var
equt Aug 10, 2022
d2a914a
fix(preset-web-fonts): add missing theme type var
equt Aug 10, 2022
9067413
fix(nuxt): add missing theme type var
equt Aug 10, 2022
273cb65
fix(preset-tagify): add missing theme type var
equt Aug 10, 2022
5e9ef80
fix(preset-mini): add missing theme type var
equt Aug 10, 2022
ec5013a
refactor: tagless final
equt Aug 10, 2022
bc50a65
feat(vite): relax restriction on theme type var
equt Aug 10, 2022
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
8 changes: 5 additions & 3 deletions packages/autocomplete/src/create.ts
Expand Up @@ -5,7 +5,7 @@ import { parseAutocomplete } from './parse'
import type { ParsedAutocompleteTemplate, UnocssAutocomplete } from './types'
import { searchUsageBoundary } from './utils'

export function createAutocomplete(uno: UnoGenerator): UnocssAutocomplete {
export function createAutocomplete<T>(uno: UnoGenerator<T>): UnocssAutocomplete {
const templateCache = new Map<string, ParsedAutocompleteTemplate>()
const cache = new LRU<string, string[]>({ max: 5000 })

Expand Down Expand Up @@ -147,9 +147,11 @@ export function createAutocomplete(uno: UnoGenerator): UnocssAutocomplete {
) || []
}

function suggestVariant(input: string, used: Set<Variant>) {
function suggestVariant<T>(input: string, used: Set<Variant<T>>) {
return uno.config.variants
.filter(v => v.autocomplete && (v.multiPass || !used.has(v)))
.filter(v =>
v.autocomplete && (v.multiPass || !used.has(v as unknown as Variant<T>)), // HACK
)
.flatMap(v => toArray(v.autocomplete || []))
.map(fn =>
typeof fn === 'function'
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/config.ts
@@ -1,7 +1,8 @@
import type { Theme } from '@unocss/preset-uno'
import presetUno from '@unocss/preset-uno'
import type { UserConfig } from '@unocss/core'

export const defaultConfig: UserConfig = {
export const defaultConfig: UserConfig<Theme> = {
envMode: 'build',
presets: [
presetUno(),
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/index.ts
Expand Up @@ -4,7 +4,9 @@ import fg from 'fast-glob'
import consola from 'consola'
import { cyan, dim, green } from 'colorette'
import { debounce } from 'perfect-debounce'
import type { UserConfig } from '@unocss/core'
import { createGenerator, toArray } from '@unocss/core'
import type { Theme } from '@unocss/preset-uno'
import { loadConfig } from '@unocss/config'
import { version } from '../package.json'
import { PrettyError, handleError } from './errors'
Expand All @@ -28,7 +30,7 @@ export async function build(_options: CliOptions) {

const cwd = _options.cwd || process.cwd()
const options = await resolveOptions(_options)
const { config, sources: configSources } = await loadConfig(cwd, options.config)
const { config, sources: configSources } = await loadConfig<Theme, UserConfig<Theme>>(cwd, options.config)

const uno = createGenerator(
config,
Expand Down Expand Up @@ -72,7 +74,7 @@ export async function build(_options: CliOptions) {

watcher.on('all', async (type, file) => {
if (configSources.includes(file)) {
uno.setConfig((await loadConfig()).config)
uno.setConfig((await loadConfig<Theme, UserConfig<Theme>>()).config)
consola.info(`${cyan(basename(file))} changed, setting new config`)
}
else {
Expand Down
2 changes: 1 addition & 1 deletion packages/config/src/index.ts
Expand Up @@ -6,7 +6,7 @@ import { createConfigLoader as createLoader } from 'unconfig'

export type { LoadConfigResult, LoadConfigSource }

export async function loadConfig<U extends UserConfig>(
export async function loadConfig<T, U extends UserConfig<T>>(
cwd = process.cwd(),
configOrPath: string | U = cwd,
extraConfigSources: LoadConfigSource[] = [],
Expand Down
41 changes: 21 additions & 20 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 { DEAFULT_LAYERS } from './constants'

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

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

if (preset.prefix || preset.layer) {
const apply = (i: Rule | Shortcut) => {
const apply = (i: Rule<T> | Shortcut<T>) => {
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<T>(
userConfig: UserConfig<T> = {},
defaults: UserConfigDefaults<T> = {},
): ResolvedConfig<T> {
const config: UserConfigDefaults<T> = Object.assign({}, defaults, userConfig)
const rawPresets = (config.presets || []).flatMap(toArray).map(resolvePreset)

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

const layers = Object.assign(DEAFULT_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<Theme, 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 @@ -61,8 +61,8 @@ export function resolveConfig(
extractors.push(extractorSplit)
extractors.sort((a, b) => (a.order || 0) - (b.order || 0))

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

const rulesSize = rules.length

Expand All @@ -76,10 +76,11 @@ export function resolveConfig(
}
})

const theme = clone([
...sortedPresets.map(p => p.theme || {}),
config.theme || {},
].reduce((a, p) => mergeDeep(a, p), {}))
// HACK What if theme is not an object?
const theme = clone<T>([
...sortedPresets.map(p => p.theme || {} as T),
config.theme || {} as T,
].reduce<T>((a, p) => mergeDeep<T>(a, p), {} as T))

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

Expand All @@ -101,14 +102,14 @@ export function resolveConfig(
layers,
theme,
rulesSize,
rulesDynamic: rules as ResolvedConfig['rulesDynamic'],
rulesDynamic: rules as ResolvedConfig<T>['rulesDynamic'],
rulesStaticMap,
preprocess: mergePresets('preprocess') as Preprocessor[],
postprocess: mergePresets('postprocess') as Postprocessor[],
preflights: mergePresets('preflights'),
preflights: mergePresets<T, 'preflights'>('preflights'),
autocomplete,
variants: mergePresets('variants').map(normalizeVariant),
shortcuts: resolveShortcuts(mergePresets('shortcuts')),
variants: mergePresets<T, 'variants'>('variants').map(normalizeVariant),
shortcuts: resolveShortcuts(mergePresets<T, 'shortcuts'>('shortcuts')),
extractors,
safelist: mergePresets('safelist'),
}
Expand Down
56 changes: 28 additions & 28 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<T> {
public version = version
private _cache = new Map<string, StringifiedUtil[] | null>()
public config: ResolvedConfig
private _cache = new Map<string, StringifiedUtil<T>[] | null>()
public config: ResolvedConfig<T>
public blocked = new Set<string>()
public parentOrders = new Map<string, number>()
public events = createNanoEvents<{
config: (config: ResolvedConfig) => void
config: (config: ResolvedConfig<T>) => void
}>()

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

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

makeContext(raw: string, applied: VariantMatchedResult) {
const context: RuleContext = {
makeContext(raw: string, applied: VariantMatchedResult<T>) {
const context: RuleContext<T> = {
rawSelector: raw,
currentSelector: applied[1],
theme: this.config.theme,
Expand Down Expand Up @@ -147,7 +147,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<T>[]>()
let preflightsMap: Record<string, string> = {}

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

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

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

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

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

async parseUtil(input: string | VariantMatchedResult, context: RuleContext, internal = false): Promise<(ParsedUtil | RawUtil)[] | undefined> {
async parseUtil(input: string | VariantMatchedResult<T>, context: RuleContext<T>, internal = false): Promise<(ParsedUtil | RawUtil)[] | undefined> {
const [raw, processed, variantHandlers] = isString(input)
? this.matchVariants(input)
: input

const recordRule = this.config.details
? (r: Rule) => {
? (r: Rule<T>) => {
context.rules = context.rules ?? []
context.rules.push(r)
}
Expand Down Expand Up @@ -474,7 +474,7 @@ export class UnoGenerator {
}
}

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

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

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

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

const [raw, , parentVariants] = parent
const rawStringfieldUtil: StringifiedUtil[] = []
const rawStringfieldUtil: StringifiedUtil<T>[] = []
for (const item of parsed) {
if (isRawUtil(item)) {
rawStringfieldUtil.push([item[0], undefined, item[1], undefined, item[2], context])
Expand All @@ -597,10 +597,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<T> | 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<T> | undefined => {
const body = entriesToCss(entries)
if (body)
return [index, selector, body, joinedParents, { ...meta, noMerge, sort: maxSort }, context]
Expand All @@ -619,15 +619,15 @@ export class UnoGenerator {
])
})
.flat(2)
.filter(Boolean) as StringifiedUtil[])
.filter(Boolean) as StringifiedUtil<T>[])
}

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

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

Expand Down