@quasar/icongenie 2.5.2 → 2.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/cmd/verify.js CHANGED
@@ -1,148 +1,99 @@
1
- const { existsSync } = require('fs')
2
- const { green, red, underline } = require('kolorist')
3
1
 
4
- const { appDir, resolveDir } = require('../utils/app-paths')
5
- const { warn } = require('../utils/logger')
6
-
7
- const modes = require('../modes')
8
- const { verifyMount } = require('../mount')
9
- const getAssetsFiles = require('../utils/get-assets-files')
10
- const getPngSize = require('../utils/get-png-size')
11
- const parseArgv = require('../utils/parse-argv')
12
- const mergeObjects = require('../utils/merge-objects')
13
- const getProfileContent = require('../utils/get-profile-content')
14
- const validateProfileObject = require('../utils/validate-profile-object')
15
-
16
- function getFileStatus (file) {
17
- if (!existsSync(file.absoluteName)) {
18
- return red('ERROR: missing!')
19
- }
20
-
21
- if (file.generator === 'png' || file.generator === 'splashscreen') {
22
- const { width, height } = getPngSize(file.absoluteName)
23
-
24
- if (width === 0 && height === 0) {
25
- return red('ERROR: not a png!')
26
- }
27
-
28
- if (width !== file.width || height !== file.height) {
29
- return red(`ERROR: incorrect resolution! ${width}x${height}`)
30
- }
31
- }
32
-
33
- return green('SIZE OK')
2
+ const parseArgs = require('minimist')
3
+
4
+ const argv = parseArgs(process.argv.slice(2), {
5
+ alias: {
6
+ m: 'mode',
7
+ p: 'profile',
8
+ f: 'filter',
9
+ h: 'help'
10
+ },
11
+ boolean: ['h']
12
+ })
13
+
14
+ if (argv.help) {
15
+ const modes = Object.keys(require('../modes')).join('|')
16
+ const generators = Object.keys(require('../generators')).join('|')
17
+
18
+ console.log(`
19
+ Description
20
+ Verifies your Quasar App's icons and splashscreens
21
+ for all installed modes.
22
+
23
+ Usage
24
+ $ icongenie verify [options]
25
+
26
+ # verify all Quasar modes
27
+ $ icongenie verify
28
+
29
+ # verify specific mode
30
+ $ icongenie verify -m spa
31
+
32
+ # verify with specific filter
33
+ $ icongenie verify -f ico
34
+
35
+ # verify by using a profile file
36
+ $ icongenie verify -p ./icongenie-profile.json
37
+
38
+ # verify by using batch of profile files
39
+ $ icongenie verify -p ./folder-containing-profile-files
40
+
41
+ Options
42
+ --mode, -m For which Quasar mode(s) to verify the assets;
43
+ Default: all
44
+ [all|${modes}]
45
+ Multiple can be specified, separated by ",":
46
+ spa,cordova,capacitor
47
+
48
+ --filter, -f Filter the available generators; when used, it verifies
49
+ only one type of asset instead of all
50
+ [${generators}]
51
+
52
+ --profile Use JSON profile file(s) to extract the asset list to verify:
53
+ - path to folder (absolute or relative to current folder)
54
+ that contains JSON profile files (icongenie-*.json)
55
+ - path to a single *.json profile file (absolute or relative
56
+ to current folder)
57
+ Structure of a JSON profile file:
58
+ {
59
+ "params": {
60
+ "include": [ ... ], /* optional */
61
+ ...
62
+ },
63
+ "assets": [ /* list of custom assets */ ]
64
+ }
65
+
66
+ --help, -h Displays this message
67
+ `)
68
+ process.exit(0)
34
69
  }
35
70
 
36
- function printMode (modeName, files) {
37
- console.log(` ${green(underline(`Mode ${modeName.toUpperCase()}`))} \n`)
38
-
39
- files.forEach(file => {
40
- console.log(` ${getFileStatus(file)} - ${(file.generator + ':').padEnd(13, ' ')} ${file.relativeName} ${verifyMount(file)}`)
41
- })
42
-
43
- console.log()
44
- }
45
-
46
- function printBanner (assetsOf, params) {
47
- console.log(` VERIFYING with the following options:
48
- ================
49
- Root folder..... ${green(appDir)}
50
- Assets of....... ${green(assetsOf)}
51
- Assets filter... ${!params.filter ? 'none' : green(params.filter)}
52
- ================
53
- `)
54
- }
55
-
56
- function parseAssets (assets, include) {
57
- let filesMap = []
58
- let assetsOf = []
59
-
60
- if (include) {
61
- const embeddedModes = include.filter(
62
- mode => existsSync(resolveDir(modes[mode].folder))
63
- )
64
-
65
- embeddedModes.forEach(mode => {
66
- filesMap.push({
67
- name: mode,
68
- files: getAssetsFiles(modes[mode].assets)
69
- })
70
- })
71
-
72
- assetsOf = assetsOf.concat(embeddedModes)
73
- }
74
-
75
- if (assets && assets.length > 0) {
76
- filesMap.push({
77
- name: 'profile assets',
78
- files: getAssetsFiles(assets)
79
- })
80
-
81
- assetsOf.push('profile')
82
- }
83
-
84
- return {
85
- filesMap,
86
- assetsOf: assetsOf.join(' | ')
71
+ const parseArgv = require('../utils/parse-argv')
72
+ const verify = require('../runner/verify')
73
+ const getProfileFiles = require('../utils/get-profile-files')
74
+ const filterArgvParams = require('../utils/filter-argv-params')
75
+ const { log } = require('../utils/logger')
76
+
77
+ async function runProfiles (params, profileFiles) {
78
+ for (let i = 0; i < profileFiles.length; i++) {
79
+ const profile = profileFiles[i]
80
+
81
+ console.log(`\n`)
82
+ log(`--------------------`)
83
+ log(`Verifying by profile: ${profile}`)
84
+ log(`--------------------`)
85
+ console.log(`\n`)
86
+
87
+ await verify({ ...params, profile })
87
88
  }
88
89
  }
89
90
 
90
- function verifyProfile (profile) {
91
- const params = profile.params
92
- const { assetsOf, filesMap } = parseAssets(profile.assets, params.include)
93
-
94
- if (assetsOf.length === 0) {
95
- warn(`No assets to generate! No mode/include specified, filter too specific or the respective Quasar mode(s) are not installed`)
96
- return
97
- }
98
-
99
- printBanner(assetsOf, params)
100
-
101
- filesMap.forEach(entry => {
102
- const files = params.filter
103
- ? entry.files.filter(file => file.generator === params.filter)
104
- : entry.files
91
+ const params = filterArgvParams(argv)
105
92
 
106
- if (files.length > 0) {
107
- printMode(entry.name, files)
108
- }
109
- })
93
+ if (params.profile) {
94
+ parseArgv(params, [ 'profile' ])
95
+ runProfiles(params, getProfileFiles(params.profile))
110
96
  }
111
-
112
- module.exports = function verify (argv) {
113
- const profile = {
114
- params: {},
115
- assets: []
116
- }
117
-
118
- if (argv.profile) {
119
- parseArgv(argv, [ 'profile' ])
120
-
121
- const userProfile = getProfileContent(argv.profile)
122
-
123
- if (userProfile.params) {
124
- const { profile: _, ...params } = argv
125
-
126
- profile.params = mergeObjects(userProfile.params, params)
127
- parseArgv(profile.params, [ 'include' ])
128
- }
129
- if (userProfile.assets) {
130
- profile.assets = userProfile.assets
131
- }
132
- }
133
- else {
134
- parseArgv(argv, [ 'mode' ])
135
-
136
- const { mode, ...params } = argv
137
-
138
- profile.params = params
139
- profile.params.include = mode
140
- }
141
-
142
- parseArgv(profile.params, [ 'filter' ])
143
-
144
- // final thorough validation
145
- validateProfileObject(profile)
146
-
147
- verifyProfile(profile)
97
+ else {
98
+ verify(params)
148
99
  }
@@ -0,0 +1,171 @@
1
+ const { existsSync } = require('fs')
2
+ const { ensureFileSync } = require('fs-extra')
3
+ const { green, gray } = require('kolorist')
4
+
5
+ const { appDir, resolveDir } = require('../utils/app-paths')
6
+ const { log, warn } = require('../utils/logger')
7
+
8
+ const modes = require('../modes')
9
+ const generators = require('../generators')
10
+ const { mount } = require('../mount')
11
+
12
+ const getAssetsFiles = require('../utils/get-assets-files')
13
+ const getFilesOptions = require('../utils/get-files-options')
14
+ const parseArgv = require('../utils/parse-argv')
15
+ const mergeObjects = require('../utils/merge-objects')
16
+ const getProfileContent = require('../utils/get-profile-content')
17
+ const getFileSize = require('../utils/get-file-size')
18
+ const validateProfileObject = require('../utils/validate-profile-object')
19
+
20
+ function printBanner (assetsOf, params) {
21
+ console.log(` Generating files with the following options:
22
+ ==========================
23
+ Quasar project folder..... ${green(appDir)}
24
+ ${green(`Quality level............. ${params.quality}/12`)}
25
+ Icon source file.......... ${green(params.icon)}
26
+ Icon trimming............. ${params.skipTrim ? 'no' : green('yes')}
27
+ Icon padding.............. ${green(`horizontal: ${params.padding[0]}; vertical: ${params.padding[1]}`)}
28
+ Background source file.... ${params.background ? green(params.background) : 'none'}
29
+ Assets of................. ${green(assetsOf)}
30
+ Generator filter.......... ${params.filter ? green(params.filter) : 'none'}
31
+ Svg color................. ${green(params.svgColor)}
32
+ Png color................. ${green(params.pngColor)}
33
+ Splashscreen color........ ${green(params.splashscreenColor)}
34
+ Splashscreen icon ratio... ${green(params.splashscreenIconRatio)}%
35
+ ==========================
36
+ `)
37
+ }
38
+
39
+ function parseAssets (assets, include) {
40
+ let files = []
41
+ let assetsOf = []
42
+
43
+ if (include) {
44
+ const embeddedModes = include.filter(
45
+ mode => existsSync(resolveDir(modes[mode].folder))
46
+ )
47
+
48
+ embeddedModes.forEach(mode => {
49
+ files = files.concat(
50
+ getAssetsFiles(modes[mode].assets)
51
+ )
52
+ })
53
+
54
+ assetsOf = assetsOf.concat(embeddedModes)
55
+ }
56
+
57
+ if (assets && assets.length > 0) {
58
+ files = files.concat(getAssetsFiles(assets))
59
+ assetsOf.push('profile')
60
+ }
61
+
62
+ return {
63
+ files,
64
+ assetsOf: assetsOf.join(' | ')
65
+ }
66
+ }
67
+
68
+ function getUniqueFiles (files) {
69
+ const filePaths = {}
70
+ const uniqueFiles = []
71
+
72
+ files.forEach(file => {
73
+ if (filePaths[file.absoluteName] === void 0) {
74
+ filePaths[file.absoluteName] = true
75
+ uniqueFiles.push(file)
76
+ }
77
+ })
78
+
79
+ return uniqueFiles
80
+ }
81
+
82
+ function generateFile (file, opts) {
83
+ // ensure that the file (and its folder) exists
84
+ ensureFileSync(file.absoluteName)
85
+
86
+ return new Promise(resolve => {
87
+ // use the appropriate generator to handle the file creation
88
+ generators[file.generator](file, opts, () => {
89
+ const size = `(${getFileSize(file.absoluteName)})`
90
+ const type = (file.generator + ':').padEnd(13, ' ')
91
+
92
+ log(`Generated ${type} ${green(file.relativeName)} ${gray(size)}`)
93
+ resolve()
94
+ })
95
+ })
96
+ }
97
+
98
+ async function generateFromProfile (profile) {
99
+ const params = profile.params
100
+ const { assetsOf, files } = parseAssets(profile.assets, params.include)
101
+
102
+ const fileOptions = await getFilesOptions(params)
103
+ let uniqueFiles = getUniqueFiles(files)
104
+
105
+ if (params.filter) {
106
+ uniqueFiles = uniqueFiles.filter(
107
+ file => file.generator === params.filter
108
+ )
109
+ }
110
+
111
+ if (uniqueFiles.length === 0) {
112
+ warn(`No assets to generate! No mode/include specified, filter too specific or the respective Quasar mode(s) are not installed`)
113
+ return Promise.resolve(0)
114
+ }
115
+
116
+ printBanner(assetsOf, params)
117
+
118
+ return Promise
119
+ .all(uniqueFiles.map(file => generateFile(file, fileOptions)))
120
+ .then(() => { mount(uniqueFiles) })
121
+ .then(() => uniqueFiles.length)
122
+ }
123
+
124
+ module.exports = function generate (argv) {
125
+ const profile = {
126
+ params: {},
127
+ assets: []
128
+ }
129
+
130
+ if (argv.profile) {
131
+ parseArgv(argv, [ 'profile' ])
132
+
133
+ const userProfile = getProfileContent(argv.profile)
134
+
135
+ if (userProfile.params) {
136
+ const { profile: _, ...params } = argv
137
+
138
+ profile.params = mergeObjects(userProfile.params, params)
139
+ parseArgv(profile.params, [ 'include' ])
140
+ }
141
+ if (userProfile.assets) {
142
+ profile.assets = userProfile.assets
143
+ }
144
+ }
145
+ else {
146
+ parseArgv(argv, [ 'mode' ])
147
+
148
+ const { mode, ...params } = argv
149
+
150
+ profile.params = params
151
+ profile.params.include = mode
152
+ }
153
+
154
+ profile.params = mergeObjects({}, profile.params)
155
+
156
+ parseArgv(profile.params, [
157
+ 'quality', 'filter', 'padding',
158
+ 'icon', 'background',
159
+ 'splashscreenIconRatio',
160
+ // order matters:
161
+ 'themeColor', 'pngColor', 'splashscreenColor', 'svgColor'
162
+ ])
163
+
164
+ // final thorough validation
165
+ validateProfileObject(profile)
166
+
167
+ return generateFromProfile(profile)
168
+ .then(numberOfFiles => {
169
+ console.log(`\n Task done - generated ${numberOfFiles} file(s)!\n`)
170
+ })
171
+ }
@@ -0,0 +1,69 @@
1
+ const { resolve, dirname, basename, isAbsolute, relative } = require('path')
2
+ const { writeFileSync } = require('fs')
3
+ const { ensureDir } = require('fs-extra')
4
+
5
+ const { log } = require('../utils/logger')
6
+ const modes = require('../modes')
7
+ const validateProfileObject = require('../utils/validate-profile-object')
8
+
9
+ function getParams ({ include, ...props }) {
10
+ if (include) {
11
+ props.include = include.split(',')
12
+ }
13
+
14
+ return props
15
+ }
16
+
17
+ function getAssets (assets) {
18
+ let list = []
19
+
20
+ assets.forEach(name => {
21
+ list = list.concat(modes[name].assets)
22
+ })
23
+
24
+ return list
25
+ }
26
+
27
+ function getTargetFilepath (output) {
28
+ const folder = dirname(output)
29
+ const name = basename(output)
30
+
31
+ const prefix = name.startsWith('icongenie-')
32
+ ? ''
33
+ : 'icongenie-'
34
+
35
+ const suffix = name.endsWith('.json')
36
+ ? ''
37
+ : '.json'
38
+
39
+ const filename = `${prefix}${name}${suffix}`
40
+ return resolve(process.cwd(), folder || '', filename)
41
+ }
42
+
43
+ module.exports = function profile ({ output, assets, ...params }) {
44
+ const profile = {
45
+ params: getParams(params),
46
+ assets: getAssets(assets)
47
+ }
48
+
49
+ validateProfileObject(profile, true)
50
+
51
+ if (profile.params.icon && isAbsolute(profile.params.icon) === false) {
52
+ // generate icon path relative to app root
53
+ // so it won't matter from where the profile file is run
54
+ const { appDir } = require('../utils/app-paths')
55
+ profile.params.icon = relative(appDir, profile.params.icon)
56
+ }
57
+
58
+ const targetFile = getTargetFilepath(output)
59
+ const folderName = dirname(targetFile)
60
+
61
+ if (folderName) {
62
+ ensureDir(folderName)
63
+ }
64
+
65
+ writeFileSync(targetFile, JSON.stringify(profile, null, 2), 'utf-8')
66
+
67
+ console.log(` Generated Icon Genie profile file:`)
68
+ log(`${targetFile}\n`)
69
+ }
@@ -0,0 +1,148 @@
1
+ const { existsSync } = require('fs')
2
+ const { green, red, underline } = require('kolorist')
3
+
4
+ const { appDir, resolveDir } = require('../utils/app-paths')
5
+ const { warn } = require('../utils/logger')
6
+
7
+ const modes = require('../modes')
8
+ const { verifyMount } = require('../mount')
9
+ const getAssetsFiles = require('../utils/get-assets-files')
10
+ const getPngSize = require('../utils/get-png-size')
11
+ const parseArgv = require('../utils/parse-argv')
12
+ const mergeObjects = require('../utils/merge-objects')
13
+ const getProfileContent = require('../utils/get-profile-content')
14
+ const validateProfileObject = require('../utils/validate-profile-object')
15
+
16
+ function getFileStatus (file) {
17
+ if (!existsSync(file.absoluteName)) {
18
+ return red('ERROR: missing!')
19
+ }
20
+
21
+ if (file.generator === 'png' || file.generator === 'splashscreen') {
22
+ const { width, height } = getPngSize(file.absoluteName)
23
+
24
+ if (width === 0 && height === 0) {
25
+ return red('ERROR: not a png!')
26
+ }
27
+
28
+ if (width !== file.width || height !== file.height) {
29
+ return red(`ERROR: incorrect resolution! ${width}x${height}`)
30
+ }
31
+ }
32
+
33
+ return green('SIZE OK')
34
+ }
35
+
36
+ function printMode (modeName, files) {
37
+ console.log(` ${green(underline(`Mode ${modeName.toUpperCase()}`))} \n`)
38
+
39
+ files.forEach(file => {
40
+ console.log(` ${getFileStatus(file)} - ${(file.generator + ':').padEnd(13, ' ')} ${file.relativeName} ${verifyMount(file)}`)
41
+ })
42
+
43
+ console.log()
44
+ }
45
+
46
+ function printBanner (assetsOf, params) {
47
+ console.log(` VERIFYING with the following options:
48
+ ================
49
+ Root folder..... ${green(appDir)}
50
+ Assets of....... ${green(assetsOf)}
51
+ Assets filter... ${!params.filter ? 'none' : green(params.filter)}
52
+ ================
53
+ `)
54
+ }
55
+
56
+ function parseAssets (assets, include) {
57
+ let filesMap = []
58
+ let assetsOf = []
59
+
60
+ if (include) {
61
+ const embeddedModes = include.filter(
62
+ mode => existsSync(resolveDir(modes[mode].folder))
63
+ )
64
+
65
+ embeddedModes.forEach(mode => {
66
+ filesMap.push({
67
+ name: mode,
68
+ files: getAssetsFiles(modes[mode].assets)
69
+ })
70
+ })
71
+
72
+ assetsOf = assetsOf.concat(embeddedModes)
73
+ }
74
+
75
+ if (assets && assets.length > 0) {
76
+ filesMap.push({
77
+ name: 'profile assets',
78
+ files: getAssetsFiles(assets)
79
+ })
80
+
81
+ assetsOf.push('profile')
82
+ }
83
+
84
+ return {
85
+ filesMap,
86
+ assetsOf: assetsOf.join(' | ')
87
+ }
88
+ }
89
+
90
+ function verifyProfile (profile) {
91
+ const params = profile.params
92
+ const { assetsOf, filesMap } = parseAssets(profile.assets, params.include)
93
+
94
+ if (assetsOf.length === 0) {
95
+ warn(`No assets to generate! No mode/include specified, filter too specific or the respective Quasar mode(s) are not installed`)
96
+ return
97
+ }
98
+
99
+ printBanner(assetsOf, params)
100
+
101
+ filesMap.forEach(entry => {
102
+ const files = params.filter
103
+ ? entry.files.filter(file => file.generator === params.filter)
104
+ : entry.files
105
+
106
+ if (files.length > 0) {
107
+ printMode(entry.name, files)
108
+ }
109
+ })
110
+ }
111
+
112
+ module.exports = function verify (argv) {
113
+ const profile = {
114
+ params: {},
115
+ assets: []
116
+ }
117
+
118
+ if (argv.profile) {
119
+ parseArgv(argv, [ 'profile' ])
120
+
121
+ const userProfile = getProfileContent(argv.profile)
122
+
123
+ if (userProfile.params) {
124
+ const { profile: _, ...params } = argv
125
+
126
+ profile.params = mergeObjects(userProfile.params, params)
127
+ parseArgv(profile.params, [ 'include' ])
128
+ }
129
+ if (userProfile.assets) {
130
+ profile.assets = userProfile.assets
131
+ }
132
+ }
133
+ else {
134
+ parseArgv(argv, [ 'mode' ])
135
+
136
+ const { mode, ...params } = argv
137
+
138
+ profile.params = params
139
+ profile.params.include = mode
140
+ }
141
+
142
+ parseArgv(profile.params, [ 'filter' ])
143
+
144
+ // final thorough validation
145
+ validateProfileObject(profile)
146
+
147
+ verifyProfile(profile)
148
+ }
@@ -1,5 +1,5 @@
1
1
  const { existsSync, lstatSync } = require('fs')
2
- const { resolve, normalize, join } = require('path')
2
+ const { resolve, normalize, join, isAbsolute } = require('path')
3
3
  const untildify = require('untildify')
4
4
 
5
5
  const getPngSize = require('./get-png-size')
@@ -124,6 +124,27 @@ function padding (value, argv) {
124
124
  : sizes
125
125
  }
126
126
 
127
+ function parseIconPath (value) {
128
+ const __path = untildify(value)
129
+
130
+ if (isAbsolute(__path)) {
131
+ return existsSync(__path) === true
132
+ ? __path
133
+ : null
134
+ }
135
+
136
+ let icon = resolve(process.cwd(), __path)
137
+
138
+ if (existsSync(icon)) {
139
+ return icon
140
+ }
141
+
142
+ const { appDir } = require('./app-paths')
143
+ icon = resolve(appDir, __path)
144
+
145
+ return existsSync(icon) ? icon : null
146
+ }
147
+
127
148
  function icon (value, argv) {
128
149
  if (!value) {
129
150
  warn(`No source icon file specified, so using the sample one`)
@@ -131,12 +152,9 @@ function icon (value, argv) {
131
152
  return
132
153
  }
133
154
 
155
+ argv.icon = parseIconPath(value)
134
156
 
135
- const { appDir } = require('./app-paths')
136
-
137
- argv.icon = resolve(appDir, untildify(value))
138
-
139
- if (!existsSync(argv.icon)) {
157
+ if (!argv.icon) {
140
158
  die(`Path to source icon file does not exists: "${value}"`)
141
159
  }
142
160
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quasar/icongenie",
3
- "version": "2.5.2",
3
+ "version": "2.5.3",
4
4
  "description": "A Quasar tool for generating all your Quasar App's icons and splashscreens",
5
5
  "bin": {
6
6
  "icongenie": "./bin/icongenie"