1
1
import yauzl from 'yauzl-promise'
2
2
import { validate , valueSchemas } from '@mapeo/schema'
3
3
import { json , buffer } from 'node:stream/consumers'
4
- import { assert } from './utils.js'
4
+ import { assert , isDefined } from './utils.js'
5
5
import path from 'node:path'
6
6
import { parse as parseBCP47 } from 'bcp-47'
7
7
import { SUPPORTED_CONFIG_VERSION } from './constants.js'
8
8
9
9
// Throw error if a zipfile contains more than 10,000 entries
10
10
const MAX_ENTRIES = 10_000
11
11
const MAX_ICON_SIZE = 10_000_000
12
+ const ICON_NAME_REGEX = / ( [ a - z A - Z 0 - 9 - ] + ) - ( [ a - z A - Z ] + ) @ ( \d + ) x \. [ a - z A - Z ] + $ /
12
13
13
14
/**
14
15
* @typedef {yauzl.Entry } Entry
@@ -50,6 +51,7 @@ export async function readConfig(configPath) {
50
51
const presetsFile = await findPresetsFile ( entries )
51
52
const translationsFile = await findTranslationsFile ( entries )
52
53
const metadataFile = await findMetadataFile ( entries )
54
+ const iconEntries = getIconEntries ( entries )
53
55
assert (
54
56
isValidConfigFile ( metadataFile ) ,
55
57
`invalid or missing config file version ${ metadataFile . fileVersion } . We support version ${ SUPPORTED_CONFIG_VERSION } }`
@@ -75,13 +77,6 @@ export async function readConfig(configPath) {
75
77
/** @type {IconData | undefined } */
76
78
let icon
77
79
78
- // we sort the icons by filename so we can group variants together
79
- const iconEntries = entries
80
- . filter ( ( entry ) => entry . filename . match ( / ^ i c o n s \/ ( [ ^ / ] + ) $ / ) )
81
- . sort ( ( icon , nextIcon ) =>
82
- icon . filename . localeCompare ( nextIcon . filename )
83
- )
84
-
85
80
for ( const entry of iconEntries ) {
86
81
if ( entry . uncompressedSize > MAX_ICON_SIZE ) {
87
82
warnings . push (
@@ -177,6 +172,18 @@ export async function readConfig(configPath) {
177
172
return sort - nextSort
178
173
} )
179
174
175
+ const iconFilenames = new Set (
176
+ iconEntries
177
+ . map ( ( icon ) => {
178
+ const matches = path . basename ( icon . filename ) . match ( ICON_NAME_REGEX )
179
+ if ( matches ) {
180
+ const [ _ , name ] = matches
181
+ return name
182
+ }
183
+ } )
184
+ . filter ( isDefined )
185
+ )
186
+
180
187
// 5. for each preset get the corresponding fieldId and iconId, add them to the db
181
188
for ( const { preset, name } of sortedPresets ) {
182
189
/** @type {Record<string, unknown> } */
@@ -193,6 +200,20 @@ export async function readConfig(configPath) {
193
200
presetValue [ key ] = preset [ key ]
194
201
}
195
202
}
203
+
204
+ if ( ! ( 'icon' in preset ) || typeof preset . icon !== 'string' ) {
205
+ warnings . push ( new Error ( `Preset ${ preset . name } doesn't have an icon` ) )
206
+ return
207
+ }
208
+ if ( ! iconFilenames . has ( preset . icon ) ) {
209
+ warnings . push (
210
+ new Error (
211
+ `preset references icon with name ${ preset . icon } but file doesn't exist`
212
+ )
213
+ )
214
+ return
215
+ }
216
+
196
217
if ( ! validate ( 'preset' , presetValue ) ) {
197
218
warnings . push ( new Error ( `Invalid preset ${ preset . name } ` ) )
198
219
continue
@@ -472,16 +493,23 @@ function translateMessageObject(warnings) {
472
493
}
473
494
}
474
495
496
+ /**
497
+ * @param {ReadonlyArray<Entry> } entries
498
+ */
499
+ function getIconEntries ( entries ) {
500
+ return entries
501
+ . filter ( ( entry ) => entry . filename . match ( / ^ i c o n s \/ ( [ ^ / ] + ) $ / ) )
502
+ . sort ( ( icon , nextIcon ) => icon . filename . localeCompare ( nextIcon . filename ) )
503
+ }
504
+
475
505
/**
476
506
* @param {string } filename
477
507
* @param {Buffer } buf
478
508
* @returns {{ name: string, variant: IconData['variants'][Number] } }}
479
509
*/
480
510
function parseIcon ( filename , buf ) {
481
511
const parsedFilename = path . parse ( filename )
482
- const matches = parsedFilename . base . match (
483
- / ( [ a - z A - Z 0 - 9 - ] + ) - ( [ a - z A - Z ] + ) @ ( \d + ) x \. [ a - z A - Z ] + $ /
484
- )
512
+ const matches = parsedFilename . base . match ( ICON_NAME_REGEX )
485
513
if ( ! matches ) {
486
514
throw new Error ( `Unexpected icon filename ${ filename } ` )
487
515
}
0 commit comments