UNPKG

5.39 kBJavaScriptView Raw
1const isPng = require('is-png'),
2 readChunk = require('read-chunk'),
3 { createHmac } = require('crypto'),
4 path = require('path'),
5 join = path.join,
6 { options } = require('../../lib/settings'),
7 { access, writeFile, readFile, ReadStream, existsSync } = require('fs-extra'),
8 fileName = './quasar.icon-factory.json'
9
10
11
12/**
13 * Find the App Dir - cloned from Quasar Core
14 *
15 * @returns {string | any}
16 * @private
17 */
18const getAppDir = function () {
19 let dir = process.cwd()
20
21 while (dir.length && dir[dir.length - 1] !== path.sep) {
22 if (existsSync(join(dir, 'quasar.conf.js'))) {
23 return dir
24 }
25
26 dir = path.normalize(join(dir, '..'))
27 }
28}
29
30/**
31 * Check if a given file exists and if the current user has access
32 *
33 * @param {string} file - the path of the file to be checked
34 * @returns {Promise<boolean>} the result of the operation
35 */
36const exists = async function (file) {
37 try {
38 await access(file)
39 return true
40 } catch (err) {
41 return false
42 }
43}
44
45/**
46 * validate if the `fileName` is a valid png file.
47 * be sure to only pass a scoped file here
48 *
49 * @param {String} fileName the path to the png file to be validated
50 * @returns {Promise<Boolean>} the result of the validation
51 */
52const validatePng = async function (fileName) {
53 let fileExists = await exists(fileName)
54 if (!fileExists) {
55 throw new Error('File not found. Are you in the root folder of your project?')
56 }
57 let data = await readChunk(fileName, 0, 8)
58 if (!isPng(data)) {
59 throw new Error('The selected file is not a valid png.')
60 }
61 return true
62}
63
64/**
65 * make sure the prompted RGB HEX really is valid
66 *
67 * @param {String} hex - the answer given by the user while installing the extension
68 * @returns {Boolean} true if it is a valid 3 or 6 letter RGB HEX
69 */
70const validateHexRGB = async function (hex) {
71 return typeof hex === "string" && /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(hex)
72}
73
74/**
75 * generating the `algorithm` sum of the `fileName`
76 *
77 * @param {String} fileName the path to the png file to be validated
78 * @param {String} algorithm algorithm used to generate the hash
79 * @param {String | Buffer} secret the secret used while generating the hash
80 * @returns {Promise<String>} the hash of the given file
81 */
82const computeHash = async function (fileName, algorithm, secret) {
83 if (!Buffer.isBuffer(secret))
84 secret = Buffer.from(secret)
85 let hmac = createHmac(algorithm, secret)
86 await validatePng(fileName)
87 return new Promise(resolve => {
88 let stream = ReadStream(fileName)
89 stream.on('data', function (data) {
90 hmac.update(data)
91 })
92 stream.on('end', function () {
93 let hash = hmac.digest('hex')
94 return resolve(hash)
95 })
96 })
97}
98
99/**
100 * clone the `options` to the `settings` object, inject color choices
101 *
102 * @param {Object} prompts - the settings object to be saved
103 * @returns {undefined}
104 */
105const mapOptions = function (api) {
106 return {
107 background_color: api.prompts.background_color,
108 //theme_color: prompts.theme_color,
109 splashscreen_type: api.prompts.generate,
110 spa: options.spa,
111 pwa: options.pwa,
112 electron: options.electron,
113 cordova: options.cordova
114 }
115}
116
117/**
118 * save the settings object to the disk
119 *
120 * @param {Object} settings - the settings object to be saved
121 * @returns {undefined}
122 */
123const saveConfig = async function (settings) {
124 await writeFile(fileName, JSON.stringify(settings, null, 2))
125}
126
127/**
128 * create the json file that will hold the hash of the generated icons
129 *
130 * @param {Object} api - an object with the answers given by the user while inquired
131 * @returns {Promise<Object>} an object that holds the hash of the generated icons
132 */
133const createConfig = async function (api) {
134 // wish there was another way to do this
135
136
137 const iconHash = await computeHash(api.resolve.app('app-icon.png'), 'md5', 'icon-factory!!!')
138 const splashscreenHash = await computeHash(api.resolve.app('app-splashscreen.png'), 'md5', 'icon-factory!!!')
139 const splashType = api.prompts.splash_type || 'generate'
140 /*
141 api.extendJsonFile('quasar.extensions.json', {
142 '@quasar/icon-factory': {
143 source: iconHash,
144 source_splashscreen: splashscreenHash
145 }
146 })
147 */
148
149 const modes = { dev: null, build: null }
150 for (var key in modes) {
151 modes[key] = {
152 source: iconHash,
153 source_splashscreen: splashscreenHash,
154 splash_type: splashType,
155 targets: {
156 spa: null,
157 pwa: null,
158 cordova: null,
159 electron: null
160 }
161 }
162 }
163
164 let settings = {
165 modes: modes,
166 options: mapOptions(api)
167 }
168
169 await saveConfig(settings)
170 return settings
171}
172
173/**
174 * get the settings from the disk
175 *
176 * @param {Object} api - pass the api object and prompts
177 * @returns {Object} an object with the current `settings`
178 */
179const getConfig = async function (api) {
180 if (await exists(fileName)) {
181 let data = await readFile(fileName, 'utf8')
182 let settings = JSON.parse(data)
183 if (!settings.options) {
184 settings.options = mapOptions(api)
185 await saveConfig(settings)
186 }
187 return settings
188 } else {
189 return createConfig(api)
190 }
191}
192
193exports.getAppDir = getAppDir
194exports.exists = exists
195exports.validatePng = validatePng
196exports.validateHexRGB = validateHexRGB
197exports.computeHash = computeHash
198exports.createConfig = createConfig
199exports.saveConfig = saveConfig
200exports.getConfig = getConfig