-
-
Notifications
You must be signed in to change notification settings - Fork 130
/
loader.ts
126 lines (99 loc) 路 3.62 KB
/
loader.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import createDebugger from 'debug'
import { isPackageExists } from 'local-pkg'
import { ResolvedOptions } from '../types'
import { searchForLegacyIcon } from './legacy'
import { loadCollection, ResolvedIconPath, searchForIcon } from './modern'
import { compilers } from './compilers'
import { tryInstallPkg, warnOnce } from './utils'
import { getCustomIcon } from './custom'
export const debug = createDebugger('unplugin-icons:load')
const URL_PREFIXES = ['/~icons/', '~icons/', 'virtual:icons/', 'virtual/icons/']
const iconPathRE = new RegExp(`${URL_PREFIXES.map(v => `^${v}`).join('|')}`)
export function isIconPath(path: string) {
return iconPathRE.test(path)
}
export function normalizeIconPath(path: string) {
return path.replace(iconPathRE, URL_PREFIXES[0])
}
export function resolveIconsPath(path: string): ResolvedIconPath | null {
if (!isIconPath(path))
return null
path = path.replace(iconPathRE, '')
const query: ResolvedIconPath['query'] = {}
const queryIndex = path.indexOf('?')
if (queryIndex !== -1) {
const queryRaw = path.slice(queryIndex + 1)
path = path.slice(0, queryIndex)
new URLSearchParams(queryRaw).forEach((value, key) => {
query[value] = key
})
}
// remove extension
path = path.replace(/\.\w+$/, '')
const [collection, icon] = path.split('/')
return {
collection,
icon,
query,
}
}
export async function getIcon(collection: string, icon: string, options: ResolvedOptions) {
const custom = options.customCollections[collection]
if (custom) {
const result = await getCustomIcon(custom, collection, icon, options)
if (result)
return result
}
return await getBuiltinIcon(collection, icon, options)
}
let legacyExists = isPackageExists('@iconify/json')
export async function getBuiltinIcon(collection: string, icon: string, options?: ResolvedOptions, warn = true): Promise<string | null> {
// possible icon names
const ids = [
icon,
icon.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(),
icon.replace(/([a-z])(\d+)/g, '$1-$2'),
]
if (options?.iconSource !== 'legacy') {
const iconSet = await loadCollection(collection, options?.autoInstall && !legacyExists)
if (!iconSet) {
if (options?.iconSource === 'modern') {
if (warn)
warnOnce(`failed to load \`@iconify-json/${collection}\`, have you installed it?`)
return null
}
}
if (iconSet)
return searchForIcon(iconSet, collection, ids, options)
}
if (options?.iconSource === 'legacy') {
if (!legacyExists && options?.autoInstall) {
await tryInstallPkg('@iconify/json')
legacyExists = true
}
return await searchForLegacyIcon(collection, ids, options)
}
if (warn)
warnOnce(`failed to load \`@iconify-json/${collection}\`, have you installed it?`)
return null
}
export async function generateComponent({ collection, icon }: ResolvedIconPath, options: ResolvedOptions) {
let svg = await getIcon(collection, icon, options)
if (!svg)
throw new Error(`Icon \`${collection}:${icon}\` not found`)
const { defaultStyle, defaultClass } = options
if (defaultClass)
svg = svg.replace('<svg ', `<svg class="${defaultClass}" `)
if (defaultStyle)
svg = svg.replace('<svg ', `<svg style="${defaultStyle}" `)
const compiler = compilers[options.compiler]
if (!compiler)
throw new Error(`Unknown compiler: ${options.compiler}`)
return compiler(svg, collection, icon, options)
}
export async function generateComponentFromPath(path: string, options: ResolvedOptions) {
const resolved = resolveIconsPath(path)
if (!resolved)
return null
return generateComponent(resolved, options)
}