Skip to content

Commit 85ac8d8

Browse files
committed
feat(ui): lang/icon-set support for q/app-vite on SSR quasarframework#12790
1 parent 2083353 commit 85ac8d8

File tree

181 files changed

+10742
-540
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

181 files changed

+10742
-540
lines changed

ui/build/build.icon-sets.js

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
const path = require('path')
2+
const fs = require('fs')
3+
const glob = require('glob')
4+
5+
const { writeFile, convertToCjs, logError } = require('./build.utils')
6+
7+
function resolve (_path) {
8+
return path.resolve(__dirname, '..', _path)
9+
}
10+
11+
const cjsBanner = setName => `/**
12+
* DO NOT EDIT THIS FILE. It is automatically generated
13+
* from its .mjs counterpart (same filename but with .mjs extension).
14+
* Edit that file instead (${ setName }).
15+
*/
16+
`
17+
18+
const svgIconSetBanner = setName => `
19+
/*
20+
* DO NOT EDIT THIS FILE. It is automatically generated
21+
* from its webfont counterpart (same filename without "svg-" prefix).
22+
* Edit that file instead (${ setName }.mjs).
23+
*/`
24+
25+
// generic conversion
26+
const convert = str => str.replace(/(-\w)/g, m => m[ 1 ].toUpperCase())
27+
const materialConvert = (str, old, prefix) => {
28+
if (old !== '') {
29+
str = str.substr(old.length)
30+
}
31+
return (prefix + str).replace(/(_\w)/g, m => m[ 1 ].toUpperCase())
32+
}
33+
34+
const iconTypes = [
35+
{
36+
name: 'material-icons-outlined',
37+
regex: /^o_/,
38+
convert: str => materialConvert(str, 'o_', 'outlined_')
39+
},
40+
{
41+
name: 'material-icons-round',
42+
regex: /^r_/,
43+
convert: str => materialConvert(str, 'r_', 'round_')
44+
},
45+
{
46+
name: 'material-icons-sharp',
47+
regex: /^s_/,
48+
convert: str => materialConvert(str, 's_', 'sharp_')
49+
},
50+
{
51+
name: 'mdi-v6',
52+
regex: /^mdi-/,
53+
convert
54+
},
55+
{
56+
name: 'ionicons-v4',
57+
regex: /^ion-/,
58+
convert: str => convert(
59+
/ion-(md|ios)-/.test(str) === true
60+
? str
61+
: str.replace(/ion-/, 'ion-md-')
62+
)
63+
},
64+
{
65+
name: 'fontawesome-v6',
66+
regex: /^fa[brs] fa-/,
67+
convert: str => convert(str.replace(' fa-', '-'))
68+
},
69+
{
70+
name: 'eva-icons',
71+
regex: /^eva-/,
72+
convert
73+
},
74+
{
75+
name: 'themify',
76+
regex: /^ti-/,
77+
convert
78+
},
79+
{
80+
name: 'line-awesome',
81+
regex: /^la[brs] la-/,
82+
convert: str => convert(
83+
(str.startsWith('las la-') === true ? str + '-solid' : str)
84+
.replace(/^la[brs] la-/, 'la-')
85+
)
86+
},
87+
{
88+
name: 'bootstrap-icons',
89+
regex: /^bi-/,
90+
convert
91+
},
92+
// must be last as it's a catch-all
93+
{
94+
name: 'material-icons',
95+
regex: /./,
96+
convert: str => materialConvert(str, '', 'mat_')
97+
}
98+
]
99+
100+
function convertWebfont (name) {
101+
const type = iconTypes.find(type => type.regex.test(name)) || iconTypes[ 0 ]
102+
103+
return {
104+
importName: type.name,
105+
variableName: type.convert(name)
106+
}
107+
}
108+
109+
function toObject (arr) {
110+
const obj = {}
111+
arr.forEach(item => {
112+
obj[ item ] = []
113+
})
114+
return obj
115+
}
116+
117+
const iconNames = iconTypes.map(type => type.name)
118+
119+
const splitDelimiter = 'export default {'
120+
121+
function splitContent (str) {
122+
const content = str.split(splitDelimiter)
123+
124+
return {
125+
outsideOfExport: content[ 0 ],
126+
insideOfExport: splitDelimiter + content[ 1 ]
127+
}
128+
}
129+
130+
function generateSvgFile (type) {
131+
const original = fs.readFileSync(resolve(`icon-set/${ type.name }.mjs`), 'utf-8')
132+
const { outsideOfExport, insideOfExport } = splitContent(original)
133+
134+
const importList = toObject(iconNames)
135+
136+
const contentString = insideOfExport
137+
.replace(/name: '(.+)'/, 'name: ""')
138+
.replace(/'(.+)'/g, m => {
139+
const { importName, variableName } = convertWebfont(m.substring(1, m.length - 1))
140+
if (!importList[ importName ].includes(variableName)) {
141+
importList[ importName ].push(variableName)
142+
}
143+
return variableName
144+
})
145+
.replace(/name: ""/, `name: 'svg-${ type.name }'`)
146+
147+
const importString = Object.keys(importList)
148+
.filter(listName => importList[ listName ].length > 0)
149+
.map(listName => 'import {\n ' + importList[ listName ].join(',\n ') + `\n} from '@quasar/extras/${ listName }'`)
150+
.join('\n\n')
151+
152+
const content = [
153+
svgIconSetBanner(type.name),
154+
importString,
155+
outsideOfExport,
156+
contentString
157+
].filter(str => str).join('\n\n')
158+
159+
const iconFile = resolve(`icon-set/svg-${ type.name }.mjs`)
160+
161+
let oldContent = ''
162+
163+
try {
164+
oldContent = fs.readFileSync(iconFile, 'utf-8')
165+
}
166+
catch (e) {}
167+
168+
return content.split(/[\n\r]+/).join('\n') !== oldContent.split(/[\n\r]+/).join('\n')
169+
? writeFile(iconFile, content)
170+
: Promise.resolve()
171+
}
172+
173+
function generateCjsCounterparts () {
174+
const promises = []
175+
176+
try {
177+
glob.sync(resolve('icon-set/*.mjs'))
178+
.forEach(file => {
179+
const content = fs.readFileSync(file, 'utf-8')
180+
const cjsFile = file.replace('.mjs', '.js')
181+
const banner = file.indexOf('svg') !== -1
182+
? ''
183+
: cjsBanner(path.basename(file))
184+
185+
promises.push(
186+
writeFile(cjsFile, convertToCjs(content, banner))
187+
)
188+
})
189+
190+
return Promise.all(promises)
191+
}
192+
catch (err) {
193+
logError('build.icon-sets.js: something went wrong...')
194+
console.log()
195+
console.error(err)
196+
console.log()
197+
process.exit(1)
198+
}
199+
}
200+
201+
module.exports.generate = async function () {
202+
await Promise.all(
203+
iconTypes.map(generateSvgFile)
204+
)
205+
206+
await generateCjsCounterparts()
207+
}
Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ const glob = require('glob')
22
const path = require('path')
33
const fs = require('fs')
44

5-
const { logError, writeFile } = require('./build.utils')
5+
const { logError, writeFileIfChanged, convertToCjs } = require('./build.utils')
66

77
const
88
root = path.resolve(__dirname, '..'),
99
resolve = file => path.resolve(root, file)
1010

11+
const cjsBanner = setName => `/**
12+
* DO NOT EDIT THIS FILE. It is automatically generated
13+
* from its .mjs counterpart (same filename but with .mjs extension).
14+
* Edit that file instead (${ setName }).
15+
*/
16+
`
17+
1118
function parse (prop, txt) {
1219
const
1320
propIndex = txt.indexOf(prop),
@@ -24,34 +31,35 @@ function parse (prop, txt) {
2431

2532
module.exports.generate = function () {
2633
const languages = []
34+
const promises = []
2735

2836
try {
29-
glob.sync(resolve('lang/*.js'))
30-
.filter(file => file.endsWith('.js'))
37+
glob.sync(resolve('lang/*.mjs'))
3138
.forEach(file => {
3239
const content = fs.readFileSync(file, 'utf-8')
3340
const isoName = parse('isoName', content)
3441
const nativeName = parse('nativeName', content)
3542
languages.push({ isoName, nativeName })
43+
44+
const cjsFile = file.replace('.mjs', '.js')
45+
const banner = cjsBanner(path.basename(file))
46+
promises.push(
47+
writeFileIfChanged(cjsFile, convertToCjs(content, banner))
48+
)
3649
})
3750

3851
const
3952
langFile = resolve('lang/index.json'),
4053
newLangJson = JSON.stringify(languages, null, 2)
4154

42-
let oldLangJson = ''
43-
44-
try {
45-
oldLangJson = fs.readFileSync(langFile, 'utf-8')
46-
}
47-
catch (e) {}
55+
promises.push(
56+
writeFileIfChanged(langFile, newLangJson)
57+
)
4858

49-
return newLangJson.split(/[\n\r]+/).join('\n') !== oldLangJson.split(/[\n\r]+/).join('\n')
50-
? writeFile(langFile, newLangJson)
51-
: Promise.resolve()
59+
return Promise.all(promises)
5260
}
5361
catch (err) {
54-
logError('build.lang-index.js: something went wrong...')
62+
logError('build.lang.js: something went wrong...')
5563
console.log()
5664
console.error(err)
5765
console.log()

0 commit comments

Comments
 (0)