flag-resizer 0.0.1

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.
Files changed (384) hide show
  1. package/ATTRIBUTION.txt +25 -0
  2. package/CHANGELOG.md +11 -0
  3. package/LICENSE +21 -0
  4. package/LICENSE-GRAPHICS +56 -0
  5. package/README.md +340 -0
  6. package/dist/cli.d.ts +1 -0
  7. package/dist/cli.js +219 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/generator.js +950 -0
  10. package/dist/generator.js.map +1 -0
  11. package/dist/index.d.ts +451 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +2 -0
  14. package/flags/README.md +1 -0
  15. package/flags/ac.svg +1 -0
  16. package/flags/ad.svg +1 -0
  17. package/flags/ae.svg +1 -0
  18. package/flags/af.svg +1 -0
  19. package/flags/ag.svg +1 -0
  20. package/flags/ai.svg +1 -0
  21. package/flags/al.svg +1 -0
  22. package/flags/am.svg +1 -0
  23. package/flags/ao.svg +1 -0
  24. package/flags/aq.svg +1 -0
  25. package/flags/ar.svg +1 -0
  26. package/flags/as.svg +1 -0
  27. package/flags/at.svg +1 -0
  28. package/flags/au-act.svg +12 -0
  29. package/flags/au-nsw.svg +232 -0
  30. package/flags/au-nt.svg +40 -0
  31. package/flags/au-qld.svg +12 -0
  32. package/flags/au-sa.svg +31 -0
  33. package/flags/au-tas.svg +114 -0
  34. package/flags/au-vic.svg +191 -0
  35. package/flags/au-wa.svg +393 -0
  36. package/flags/au.svg +1 -0
  37. package/flags/aw.svg +1 -0
  38. package/flags/ax.svg +1 -0
  39. package/flags/az.svg +1 -0
  40. package/flags/ba.svg +1 -0
  41. package/flags/bb.svg +1 -0
  42. package/flags/bd.svg +1 -0
  43. package/flags/be.svg +1 -0
  44. package/flags/bf.svg +1 -0
  45. package/flags/bg.svg +1 -0
  46. package/flags/bh.svg +1 -0
  47. package/flags/bi.svg +1 -0
  48. package/flags/bj.svg +1 -0
  49. package/flags/bl.svg +1 -0
  50. package/flags/bm.svg +1 -0
  51. package/flags/bn.svg +1 -0
  52. package/flags/bo.svg +1 -0
  53. package/flags/bq.svg +1 -0
  54. package/flags/br.svg +1 -0
  55. package/flags/bs.svg +1 -0
  56. package/flags/bt.svg +1 -0
  57. package/flags/bv.svg +1 -0
  58. package/flags/bw.svg +1 -0
  59. package/flags/by.svg +1 -0
  60. package/flags/bz.svg +1 -0
  61. package/flags/ca-ab.svg +100 -0
  62. package/flags/ca-bc.svg +34 -0
  63. package/flags/ca-mb.svg +99 -0
  64. package/flags/ca-nb.svg +244 -0
  65. package/flags/ca-nl.svg +16 -0
  66. package/flags/ca-ns.svg +155 -0
  67. package/flags/ca-nt.svg +45 -0
  68. package/flags/ca-nu.svg +16 -0
  69. package/flags/ca-on.svg +31 -0
  70. package/flags/ca-pe.svg +748 -0
  71. package/flags/ca-qc.svg +20 -0
  72. package/flags/ca-sk.svg +91 -0
  73. package/flags/ca-yt.svg +81 -0
  74. package/flags/ca.svg +1 -0
  75. package/flags/cc.svg +1 -0
  76. package/flags/cd.svg +1 -0
  77. package/flags/cf.svg +1 -0
  78. package/flags/cg.svg +1 -0
  79. package/flags/ch.svg +1 -0
  80. package/flags/ci.svg +1 -0
  81. package/flags/ck.svg +1 -0
  82. package/flags/cl.svg +1 -0
  83. package/flags/cm.svg +1 -0
  84. package/flags/cn.svg +1 -0
  85. package/flags/co.svg +1 -0
  86. package/flags/cp.svg +1 -0
  87. package/flags/cq.svg +1 -0
  88. package/flags/cr.svg +1 -0
  89. package/flags/cu.svg +1 -0
  90. package/flags/cv.svg +1 -0
  91. package/flags/cw.svg +1 -0
  92. package/flags/cx.svg +1 -0
  93. package/flags/cy.svg +1 -0
  94. package/flags/cz.svg +1 -0
  95. package/flags/de-bb.svg +76 -0
  96. package/flags/de-be.svg +17 -0
  97. package/flags/de-bw.svg +12 -0
  98. package/flags/de-by.svg +16 -0
  99. package/flags/de-hb.svg +12 -0
  100. package/flags/de-he.svg +14 -0
  101. package/flags/de-hh.svg +40 -0
  102. package/flags/de-mv.svg +12 -0
  103. package/flags/de-ni.svg +86 -0
  104. package/flags/de-nw.svg +15 -0
  105. package/flags/de-rp.svg +292 -0
  106. package/flags/de-sh.svg +14 -0
  107. package/flags/de-sl.svg +279 -0
  108. package/flags/de-sn.svg +13 -0
  109. package/flags/de-st.svg +207 -0
  110. package/flags/de-th.svg +17 -0
  111. package/flags/de.svg +1 -0
  112. package/flags/dg.svg +1 -0
  113. package/flags/dj.svg +1 -0
  114. package/flags/dk.svg +1 -0
  115. package/flags/dm.svg +1 -0
  116. package/flags/do.svg +1 -0
  117. package/flags/dz.svg +1 -0
  118. package/flags/ea.svg +1 -0
  119. package/flags/ec.svg +1 -0
  120. package/flags/ee.svg +1 -0
  121. package/flags/eg.svg +1 -0
  122. package/flags/eh.svg +1 -0
  123. package/flags/er.svg +1 -0
  124. package/flags/es-an.svg +215 -0
  125. package/flags/es-ar.svg +66 -0
  126. package/flags/es-as.svg +19 -0
  127. package/flags/es-cb.svg +590 -0
  128. package/flags/es-ce.svg +357 -0
  129. package/flags/es-cl.svg +473 -0
  130. package/flags/es-cm.svg +457 -0
  131. package/flags/es-cn.svg +200 -0
  132. package/flags/es-ct.svg +13 -0
  133. package/flags/es-ex.svg +251 -0
  134. package/flags/es-ga.svg +205 -0
  135. package/flags/es-ib.svg +104 -0
  136. package/flags/es-mc.svg +32 -0
  137. package/flags/es-md.svg +29 -0
  138. package/flags/es-ml.svg +717 -0
  139. package/flags/es-nc.svg +775 -0
  140. package/flags/es-pv.svg +14 -0
  141. package/flags/es-ri.svg +787 -0
  142. package/flags/es-vc.svg +21 -0
  143. package/flags/es.svg +1 -0
  144. package/flags/et.svg +1 -0
  145. package/flags/eu.svg +1 -0
  146. package/flags/fi.svg +1 -0
  147. package/flags/fj.svg +1 -0
  148. package/flags/fk.svg +1 -0
  149. package/flags/fm.svg +1 -0
  150. package/flags/fo.svg +1 -0
  151. package/flags/fr.svg +1 -0
  152. package/flags/ga.svg +1 -0
  153. package/flags/gb-eng.svg +1 -0
  154. package/flags/gb-nir.svg +141 -0
  155. package/flags/gb-sct.svg +1 -0
  156. package/flags/gb-wls.svg +1 -0
  157. package/flags/gb.svg +1 -0
  158. package/flags/gd.svg +1 -0
  159. package/flags/ge.svg +1 -0
  160. package/flags/gf.svg +1 -0
  161. package/flags/gg.svg +1 -0
  162. package/flags/gh.svg +1 -0
  163. package/flags/gi.svg +1 -0
  164. package/flags/gl.svg +1 -0
  165. package/flags/gm.svg +1 -0
  166. package/flags/gn.svg +1 -0
  167. package/flags/gp.svg +1 -0
  168. package/flags/gq.svg +1 -0
  169. package/flags/gr.svg +1 -0
  170. package/flags/gs.svg +1 -0
  171. package/flags/gt.svg +1 -0
  172. package/flags/gu.svg +1 -0
  173. package/flags/gw.svg +1 -0
  174. package/flags/gy.svg +1 -0
  175. package/flags/hk.svg +1 -0
  176. package/flags/hm.svg +1 -0
  177. package/flags/hn.svg +1 -0
  178. package/flags/hr.svg +1 -0
  179. package/flags/ht.svg +1 -0
  180. package/flags/hu.svg +1 -0
  181. package/flags/ic.svg +1 -0
  182. package/flags/id.svg +1 -0
  183. package/flags/ie.svg +1 -0
  184. package/flags/il.svg +1 -0
  185. package/flags/im.svg +1 -0
  186. package/flags/in.svg +1 -0
  187. package/flags/io.svg +1 -0
  188. package/flags/iq.svg +1 -0
  189. package/flags/ir.svg +42 -0
  190. package/flags/is.svg +1 -0
  191. package/flags/it.svg +1 -0
  192. package/flags/je.svg +1 -0
  193. package/flags/jm.svg +1 -0
  194. package/flags/jo.svg +1 -0
  195. package/flags/jp.svg +1 -0
  196. package/flags/ke.svg +1 -0
  197. package/flags/kg.svg +1 -0
  198. package/flags/kh.svg +1 -0
  199. package/flags/ki.svg +1 -0
  200. package/flags/km.svg +1 -0
  201. package/flags/kn.svg +1 -0
  202. package/flags/kp.svg +1 -0
  203. package/flags/kr.svg +1 -0
  204. package/flags/kw.svg +1 -0
  205. package/flags/ky.svg +1 -0
  206. package/flags/kz.svg +1 -0
  207. package/flags/la.svg +1 -0
  208. package/flags/lb.svg +1 -0
  209. package/flags/lc.svg +1 -0
  210. package/flags/li.svg +1 -0
  211. package/flags/lk.svg +1 -0
  212. package/flags/lr.svg +1 -0
  213. package/flags/ls.svg +1 -0
  214. package/flags/lt.svg +1 -0
  215. package/flags/lu.svg +1 -0
  216. package/flags/lv.svg +1 -0
  217. package/flags/ly.svg +1 -0
  218. package/flags/ma.svg +1 -0
  219. package/flags/mc.svg +1 -0
  220. package/flags/md.svg +1 -0
  221. package/flags/me.svg +1 -0
  222. package/flags/mf.svg +1 -0
  223. package/flags/mg.svg +1 -0
  224. package/flags/mh.svg +1 -0
  225. package/flags/mk.svg +1 -0
  226. package/flags/ml.svg +1 -0
  227. package/flags/mm.svg +1 -0
  228. package/flags/mn.svg +1 -0
  229. package/flags/mo.svg +1 -0
  230. package/flags/mp.svg +1 -0
  231. package/flags/mq.svg +1 -0
  232. package/flags/mr.svg +1 -0
  233. package/flags/ms.svg +1 -0
  234. package/flags/mt.svg +1 -0
  235. package/flags/mu.svg +1 -0
  236. package/flags/mv.svg +1 -0
  237. package/flags/mw.svg +1 -0
  238. package/flags/mx.svg +1 -0
  239. package/flags/my.svg +1 -0
  240. package/flags/mz.svg +1 -0
  241. package/flags/na.svg +1 -0
  242. package/flags/nc.svg +1 -0
  243. package/flags/ne.svg +1 -0
  244. package/flags/nf.svg +1 -0
  245. package/flags/ng.svg +1 -0
  246. package/flags/ni.svg +1 -0
  247. package/flags/nl.svg +1 -0
  248. package/flags/no.svg +1 -0
  249. package/flags/np.svg +1 -0
  250. package/flags/nr.svg +1 -0
  251. package/flags/nu.svg +1 -0
  252. package/flags/nz.svg +1 -0
  253. package/flags/om.svg +1 -0
  254. package/flags/pa.svg +1 -0
  255. package/flags/pe.svg +1 -0
  256. package/flags/pf.svg +1 -0
  257. package/flags/pg.svg +1 -0
  258. package/flags/ph.svg +1 -0
  259. package/flags/pk.svg +1 -0
  260. package/flags/pl.svg +1 -0
  261. package/flags/pm.svg +1 -0
  262. package/flags/pn.svg +1 -0
  263. package/flags/pr.svg +1 -0
  264. package/flags/ps.svg +1 -0
  265. package/flags/pt.svg +1 -0
  266. package/flags/pw.svg +1 -0
  267. package/flags/py.svg +1 -0
  268. package/flags/qa.svg +1 -0
  269. package/flags/re.svg +1 -0
  270. package/flags/ro.svg +1 -0
  271. package/flags/rs.svg +1 -0
  272. package/flags/ru.svg +1 -0
  273. package/flags/rw.svg +1 -0
  274. package/flags/sa.svg +1 -0
  275. package/flags/sb.svg +1 -0
  276. package/flags/sc.svg +1 -0
  277. package/flags/sd.svg +1 -0
  278. package/flags/se.svg +1 -0
  279. package/flags/sg.svg +1 -0
  280. package/flags/sh.svg +1 -0
  281. package/flags/si.svg +1 -0
  282. package/flags/sj.svg +1 -0
  283. package/flags/sk.svg +1 -0
  284. package/flags/sl.svg +1 -0
  285. package/flags/sm.svg +1 -0
  286. package/flags/sn.svg +1 -0
  287. package/flags/so.svg +1 -0
  288. package/flags/sr.svg +1 -0
  289. package/flags/ss.svg +1 -0
  290. package/flags/st.svg +1 -0
  291. package/flags/sv.svg +1 -0
  292. package/flags/sx.svg +1 -0
  293. package/flags/sy.svg +1 -0
  294. package/flags/sz.svg +1 -0
  295. package/flags/ta.svg +1 -0
  296. package/flags/tc.svg +1 -0
  297. package/flags/td.svg +1 -0
  298. package/flags/tf.svg +1 -0
  299. package/flags/tg.svg +1 -0
  300. package/flags/th.svg +1 -0
  301. package/flags/tj.svg +1 -0
  302. package/flags/tk.svg +1 -0
  303. package/flags/tl.svg +1 -0
  304. package/flags/tm.svg +1 -0
  305. package/flags/tn.svg +1 -0
  306. package/flags/to.svg +1 -0
  307. package/flags/tr.svg +1 -0
  308. package/flags/tt.svg +1 -0
  309. package/flags/tv.svg +1 -0
  310. package/flags/tw.svg +1 -0
  311. package/flags/tz.svg +1 -0
  312. package/flags/ua.svg +1 -0
  313. package/flags/ug.svg +1 -0
  314. package/flags/um.svg +1 -0
  315. package/flags/un.svg +1 -0
  316. package/flags/us-ak.svg +12 -0
  317. package/flags/us-al.svg +12 -0
  318. package/flags/us-ar.svg +12 -0
  319. package/flags/us-az.svg +12 -0
  320. package/flags/us-ca.svg +12 -0
  321. package/flags/us-co.svg +12 -0
  322. package/flags/us-ct.svg +12 -0
  323. package/flags/us-de.svg +12 -0
  324. package/flags/us-fl.svg +12 -0
  325. package/flags/us-ga.svg +12 -0
  326. package/flags/us-hi.svg +12 -0
  327. package/flags/us-ia.svg +12 -0
  328. package/flags/us-id.svg +12 -0
  329. package/flags/us-il.svg +12 -0
  330. package/flags/us-in.svg +12 -0
  331. package/flags/us-ks.svg +12 -0
  332. package/flags/us-ky.svg +12 -0
  333. package/flags/us-la.svg +12 -0
  334. package/flags/us-ma.svg +12 -0
  335. package/flags/us-md.svg +12 -0
  336. package/flags/us-me.svg +12 -0
  337. package/flags/us-mi.svg +12 -0
  338. package/flags/us-mn.svg +12 -0
  339. package/flags/us-mo.svg +12 -0
  340. package/flags/us-ms.svg +12 -0
  341. package/flags/us-mt.svg +12 -0
  342. package/flags/us-nc.svg +12 -0
  343. package/flags/us-nd.svg +12 -0
  344. package/flags/us-ne.svg +12 -0
  345. package/flags/us-nh.svg +12 -0
  346. package/flags/us-nj.svg +12 -0
  347. package/flags/us-nm.svg +12 -0
  348. package/flags/us-nv.svg +12 -0
  349. package/flags/us-ny.svg +12 -0
  350. package/flags/us-oh.svg +12 -0
  351. package/flags/us-ok.svg +12 -0
  352. package/flags/us-or.svg +12 -0
  353. package/flags/us-pa.svg +12 -0
  354. package/flags/us-ri.svg +12 -0
  355. package/flags/us-sc.svg +12 -0
  356. package/flags/us-sd.svg +12 -0
  357. package/flags/us-tn.svg +12 -0
  358. package/flags/us-tx.svg +12 -0
  359. package/flags/us-ut.svg +12 -0
  360. package/flags/us-va.svg +12 -0
  361. package/flags/us-vt.svg +12 -0
  362. package/flags/us-wa.svg +12 -0
  363. package/flags/us-wi.svg +12 -0
  364. package/flags/us-wv.svg +12 -0
  365. package/flags/us-wy.svg +12 -0
  366. package/flags/us.svg +1 -0
  367. package/flags/uy.svg +1 -0
  368. package/flags/uz.svg +1 -0
  369. package/flags/va.svg +1 -0
  370. package/flags/vc.svg +1 -0
  371. package/flags/ve.svg +1 -0
  372. package/flags/vg.svg +1 -0
  373. package/flags/vi.svg +1 -0
  374. package/flags/vn.svg +1 -0
  375. package/flags/vu.svg +1 -0
  376. package/flags/wf.svg +1 -0
  377. package/flags/ws.svg +1 -0
  378. package/flags/xk.svg +1 -0
  379. package/flags/ye.svg +1 -0
  380. package/flags/yt.svg +1 -0
  381. package/flags/za.svg +1 -0
  382. package/flags/zm.svg +1 -0
  383. package/flags/zw.svg +1 -0
  384. package/package.json +113 -0
@@ -0,0 +1,950 @@
1
+ import path from "node:path";
2
+ import { loadConfig } from "c12";
3
+ import { z } from "zod";
4
+ import { access, copyFile, mkdir, mkdtemp, readFile, rename, rm, rmdir, stat, unlink, writeFile } from "node:fs/promises";
5
+ import os, { availableParallelism } from "node:os";
6
+ import { fileURLToPath } from "node:url";
7
+ import { randomUUID } from "node:crypto";
8
+ import sharp from "sharp";
9
+ //#region src/data/flags.ts
10
+ const FLAGS = {
11
+ ac: "Ascension Island",
12
+ ad: "Andorra",
13
+ ae: "United Arab Emirates",
14
+ af: "Afghanistan",
15
+ ag: "Antigua and Barbuda",
16
+ ai: "Anguilla",
17
+ al: "Albania",
18
+ am: "Armenia",
19
+ ao: "Angola",
20
+ aq: "Antarctica",
21
+ ar: "Argentina",
22
+ as: "American Samoa",
23
+ at: "Austria",
24
+ au: "Australia",
25
+ "au-act": "Australian Capital Territory",
26
+ "au-nsw": "New South Wales",
27
+ "au-nt": "Northern Territory",
28
+ "au-qld": "Queensland",
29
+ "au-sa": "South Australia",
30
+ "au-tas": "Tasmania",
31
+ "au-vic": "Victoria",
32
+ "au-wa": "Western Australia",
33
+ aw: "Aruba",
34
+ ax: "Åland Islands",
35
+ az: "Azerbaijan",
36
+ ba: "Bosnia and Herzegovina",
37
+ bb: "Barbados",
38
+ bd: "Bangladesh",
39
+ be: "Belgium",
40
+ bf: "Burkina Faso",
41
+ bg: "Bulgaria",
42
+ bh: "Bahrain",
43
+ bi: "Burundi",
44
+ bj: "Benin",
45
+ bl: "Saint Barthélemy",
46
+ bm: "Bermuda",
47
+ bn: "Brunei",
48
+ bo: "Bolivia",
49
+ bq: "Caribbean Netherlands",
50
+ br: "Brazil",
51
+ bs: "Bahamas",
52
+ bt: "Bhutan",
53
+ bv: "Bouvet Island",
54
+ bw: "Botswana",
55
+ by: "Belarus",
56
+ bz: "Belize",
57
+ ca: "Canada",
58
+ "ca-ab": "Alberta",
59
+ "ca-bc": "British Columbia",
60
+ "ca-mb": "Manitoba",
61
+ "ca-nb": "New Brunswick",
62
+ "ca-nl": "Newfoundland and Labrador",
63
+ "ca-ns": "Nova Scotia",
64
+ "ca-nt": "Northwest Territories",
65
+ "ca-nu": "Nunavut",
66
+ "ca-on": "Ontario",
67
+ "ca-pe": "Prince Edward Island",
68
+ "ca-qc": "Quebec",
69
+ "ca-sk": "Saskatchewan",
70
+ "ca-yt": "Yukon",
71
+ cc: "Cocos (Keeling) Islands",
72
+ cd: "DR Congo",
73
+ cf: "Central African Republic",
74
+ cg: "Republic of the Congo",
75
+ ch: "Switzerland",
76
+ ci: "Côte d'Ivoire (Ivory Coast)",
77
+ ck: "Cook Islands",
78
+ cl: "Chile",
79
+ cm: "Cameroon",
80
+ cn: "China",
81
+ co: "Colombia",
82
+ cp: "Clipperton Island",
83
+ cq: "Sark",
84
+ cr: "Costa Rica",
85
+ cu: "Cuba",
86
+ cv: "Cape Verde",
87
+ cw: "Curaçao",
88
+ cx: "Christmas Island",
89
+ cy: "Cyprus",
90
+ cz: "Czechia",
91
+ de: "Germany",
92
+ "de-bb": "Brandenburg",
93
+ "de-be": "Berlin",
94
+ "de-bw": "Baden-Württemberg",
95
+ "de-by": "Bavaria",
96
+ "de-hb": "Bremen",
97
+ "de-he": "Hesse",
98
+ "de-hh": "Hamburg",
99
+ "de-mv": "Mecklenburg-Western Pomerania",
100
+ "de-ni": "Lower Saxony",
101
+ "de-nw": "North Rhine-Westphalia",
102
+ "de-rp": "Rhineland-Palatinate",
103
+ "de-sh": "Schleswig-Holstein",
104
+ "de-sl": "Saarland",
105
+ "de-sn": "Saxony",
106
+ "de-st": "Saxony-Anhalt",
107
+ "de-th": "Thuringia",
108
+ dg: "Diego Garcia",
109
+ dj: "Djibouti",
110
+ dk: "Denmark",
111
+ dm: "Dominica",
112
+ do: "Dominican Republic",
113
+ dz: "Algeria",
114
+ ea: "Ceuta & Melilla",
115
+ ec: "Ecuador",
116
+ ee: "Estonia",
117
+ eg: "Egypt",
118
+ eh: "Western Sahara",
119
+ er: "Eritrea",
120
+ es: "Spain",
121
+ "es-an": "Andalusia",
122
+ "es-ar": "Aragon",
123
+ "es-as": "Asturias",
124
+ "es-cb": "Cantabria",
125
+ "es-ce": "Ceuta",
126
+ "es-cl": "Castile and León",
127
+ "es-cm": "Castilla-La Mancha",
128
+ "es-cn": "Canary Islands",
129
+ "es-ct": "Catalonia",
130
+ "es-ex": "Extremadura",
131
+ "es-ga": "Galicia",
132
+ "es-ib": "Balearic Islands",
133
+ "es-mc": "Region of Murcia",
134
+ "es-md": "Community of Madrid",
135
+ "es-ml": "Melilla",
136
+ "es-nc": "Navarre",
137
+ "es-pv": "Basque Country",
138
+ "es-ri": "La Rioja",
139
+ "es-vc": "Valencian Community",
140
+ et: "Ethiopia",
141
+ eu: "European Union",
142
+ fi: "Finland",
143
+ fj: "Fiji",
144
+ fk: "Falkland Islands",
145
+ fm: "Micronesia",
146
+ fo: "Faroe Islands",
147
+ fr: "France",
148
+ ga: "Gabon",
149
+ gb: "United Kingdom",
150
+ "gb-eng": "England",
151
+ "gb-nir": "Northern Ireland",
152
+ "gb-sct": "Scotland",
153
+ "gb-wls": "Wales",
154
+ gd: "Grenada",
155
+ ge: "Georgia",
156
+ gf: "French Guiana",
157
+ gg: "Guernsey",
158
+ gh: "Ghana",
159
+ gi: "Gibraltar",
160
+ gl: "Greenland",
161
+ gm: "Gambia",
162
+ gn: "Guinea",
163
+ gp: "Guadeloupe",
164
+ gq: "Equatorial Guinea",
165
+ gr: "Greece",
166
+ gs: "South Georgia",
167
+ gt: "Guatemala",
168
+ gu: "Guam",
169
+ gw: "Guinea-Bissau",
170
+ gy: "Guyana",
171
+ hk: "Hong Kong",
172
+ hm: "Heard Island and McDonald Islands",
173
+ hn: "Honduras",
174
+ hr: "Croatia",
175
+ ht: "Haiti",
176
+ hu: "Hungary",
177
+ ic: "Canary Islands",
178
+ id: "Indonesia",
179
+ ie: "Ireland",
180
+ il: "Israel",
181
+ im: "Isle of Man",
182
+ in: "India",
183
+ io: "British Indian Ocean Territory",
184
+ iq: "Iraq",
185
+ ir: "Iran",
186
+ is: "Iceland",
187
+ it: "Italy",
188
+ je: "Jersey",
189
+ jm: "Jamaica",
190
+ jo: "Jordan",
191
+ jp: "Japan",
192
+ ke: "Kenya",
193
+ kg: "Kyrgyzstan",
194
+ kh: "Cambodia",
195
+ ki: "Kiribati",
196
+ km: "Comoros",
197
+ kn: "Saint Kitts and Nevis",
198
+ kp: "North Korea",
199
+ kr: "South Korea",
200
+ kw: "Kuwait",
201
+ ky: "Cayman Islands",
202
+ kz: "Kazakhstan",
203
+ la: "Laos",
204
+ lb: "Lebanon",
205
+ lc: "Saint Lucia",
206
+ li: "Liechtenstein",
207
+ lk: "Sri Lanka",
208
+ lr: "Liberia",
209
+ ls: "Lesotho",
210
+ lt: "Lithuania",
211
+ lu: "Luxembourg",
212
+ lv: "Latvia",
213
+ ly: "Libya",
214
+ ma: "Morocco",
215
+ mc: "Monaco",
216
+ md: "Moldova",
217
+ me: "Montenegro",
218
+ mf: "Saint Martin",
219
+ mg: "Madagascar",
220
+ mh: "Marshall Islands",
221
+ mk: "North Macedonia",
222
+ ml: "Mali",
223
+ mm: "Myanmar",
224
+ mn: "Mongolia",
225
+ mo: "Macau",
226
+ mp: "Northern Mariana Islands",
227
+ mq: "Martinique",
228
+ mr: "Mauritania",
229
+ ms: "Montserrat",
230
+ mt: "Malta",
231
+ mu: "Mauritius",
232
+ mv: "Maldives",
233
+ mw: "Malawi",
234
+ mx: "Mexico",
235
+ my: "Malaysia",
236
+ mz: "Mozambique",
237
+ na: "Namibia",
238
+ nc: "New Caledonia",
239
+ ne: "Niger",
240
+ nf: "Norfolk Island",
241
+ ng: "Nigeria",
242
+ ni: "Nicaragua",
243
+ nl: "Netherlands",
244
+ no: "Norway",
245
+ np: "Nepal",
246
+ nr: "Nauru",
247
+ nu: "Niue",
248
+ nz: "New Zealand",
249
+ om: "Oman",
250
+ pa: "Panama",
251
+ pe: "Peru",
252
+ pf: "French Polynesia",
253
+ pg: "Papua New Guinea",
254
+ ph: "Philippines",
255
+ pk: "Pakistan",
256
+ pl: "Poland",
257
+ pm: "Saint Pierre and Miquelon",
258
+ pn: "Pitcairn Islands",
259
+ pr: "Puerto Rico",
260
+ ps: "Palestine",
261
+ pt: "Portugal",
262
+ pw: "Palau",
263
+ py: "Paraguay",
264
+ qa: "Qatar",
265
+ re: "Réunion",
266
+ ro: "Romania",
267
+ rs: "Serbia",
268
+ ru: "Russia",
269
+ rw: "Rwanda",
270
+ sa: "Saudi Arabia",
271
+ sb: "Solomon Islands",
272
+ sc: "Seychelles",
273
+ sd: "Sudan",
274
+ se: "Sweden",
275
+ sg: "Singapore",
276
+ sh: "Saint Helena, Ascension and Tristan da Cunha",
277
+ si: "Slovenia",
278
+ sj: "Svalbard and Jan Mayen",
279
+ sk: "Slovakia",
280
+ sl: "Sierra Leone",
281
+ sm: "San Marino",
282
+ sn: "Senegal",
283
+ so: "Somalia",
284
+ sr: "Suriname",
285
+ ss: "South Sudan",
286
+ st: "São Tomé and Príncipe",
287
+ sv: "El Salvador",
288
+ sx: "Sint Maarten",
289
+ sy: "Syria",
290
+ sz: "Eswatini (Swaziland)",
291
+ ta: "Tristan da Cunha",
292
+ tc: "Turks and Caicos Islands",
293
+ td: "Chad",
294
+ tf: "French Southern and Antarctic Lands",
295
+ tg: "Togo",
296
+ th: "Thailand",
297
+ tj: "Tajikistan",
298
+ tk: "Tokelau",
299
+ tl: "Timor-Leste",
300
+ tm: "Turkmenistan",
301
+ tn: "Tunisia",
302
+ to: "Tonga",
303
+ tr: "Turkey",
304
+ tt: "Trinidad and Tobago",
305
+ tv: "Tuvalu",
306
+ tw: "Taiwan",
307
+ tz: "Tanzania",
308
+ ua: "Ukraine",
309
+ ug: "Uganda",
310
+ um: "United States Minor Outlying Islands",
311
+ un: "United Nations",
312
+ us: "United States",
313
+ "us-ak": "Alaska",
314
+ "us-al": "Alabama",
315
+ "us-ar": "Arkansas",
316
+ "us-az": "Arizona",
317
+ "us-ca": "California",
318
+ "us-co": "Colorado",
319
+ "us-ct": "Connecticut",
320
+ "us-de": "Delaware",
321
+ "us-fl": "Florida",
322
+ "us-ga": "Georgia",
323
+ "us-hi": "Hawaii",
324
+ "us-ia": "Iowa",
325
+ "us-id": "Idaho",
326
+ "us-il": "Illinois",
327
+ "us-in": "Indiana",
328
+ "us-ks": "Kansas",
329
+ "us-ky": "Kentucky",
330
+ "us-la": "Louisiana",
331
+ "us-ma": "Massachusetts",
332
+ "us-md": "Maryland",
333
+ "us-me": "Maine",
334
+ "us-mi": "Michigan",
335
+ "us-mn": "Minnesota",
336
+ "us-mo": "Missouri",
337
+ "us-ms": "Mississippi",
338
+ "us-mt": "Montana",
339
+ "us-nc": "North Carolina",
340
+ "us-nd": "North Dakota",
341
+ "us-ne": "Nebraska",
342
+ "us-nh": "New Hampshire",
343
+ "us-nj": "New Jersey",
344
+ "us-nm": "New Mexico",
345
+ "us-nv": "Nevada",
346
+ "us-ny": "New York",
347
+ "us-oh": "Ohio",
348
+ "us-ok": "Oklahoma",
349
+ "us-or": "Oregon",
350
+ "us-pa": "Pennsylvania",
351
+ "us-ri": "Rhode Island",
352
+ "us-sc": "South Carolina",
353
+ "us-sd": "South Dakota",
354
+ "us-tn": "Tennessee",
355
+ "us-tx": "Texas",
356
+ "us-ut": "Utah",
357
+ "us-va": "Virginia",
358
+ "us-vt": "Vermont",
359
+ "us-wa": "Washington",
360
+ "us-wi": "Wisconsin",
361
+ "us-wv": "West Virginia",
362
+ "us-wy": "Wyoming",
363
+ uy: "Uruguay",
364
+ uz: "Uzbekistan",
365
+ va: "Vatican City (Holy See)",
366
+ vc: "Saint Vincent and the Grenadines",
367
+ ve: "Venezuela",
368
+ vg: "British Virgin Islands",
369
+ vi: "United States Virgin Islands",
370
+ vn: "Vietnam",
371
+ vu: "Vanuatu",
372
+ wf: "Wallis and Futuna",
373
+ ws: "Samoa",
374
+ xk: "Kosovo",
375
+ ye: "Yemen",
376
+ yt: "Mayotte",
377
+ za: "South Africa",
378
+ zm: "Zambia",
379
+ zw: "Zimbabwe"
380
+ };
381
+ const COUNTRY_CODES = Object.keys(FLAGS);
382
+ //#endregion
383
+ //#region src/errors.ts
384
+ var FlagResizerError = class extends Error {
385
+ name = "FlagResizerError";
386
+ constructor(message, options) {
387
+ super(message, options);
388
+ }
389
+ };
390
+ //#endregion
391
+ //#region src/config.ts
392
+ const countryCodeSchema = z.enum(COUNTRY_CODES);
393
+ const filterPatternSchema = z.string().regex(/^(?=.*\*)[a-z*]+(?:-[a-z*]+)*$/u, "must be a lowercase flag code or a pattern using \"*\"");
394
+ const filterValueSchema = z.union([countryCodeSchema, filterPatternSchema]);
395
+ const formatSchema = z.enum(["png", "webp"]);
396
+ const sizeSchema = z.tuple([z.number().int().positive("width must be a positive integer"), z.number().int().positive("height must be a positive integer")]);
397
+ const formatOutputSchema = z.object({
398
+ dir: z.string().trim().min(1),
399
+ publicPath: z.string().trim().min(1)
400
+ }).strict();
401
+ const profileSchema = z.object({
402
+ filter: z.object({
403
+ type: z.enum(["whitelist", "blacklist"]),
404
+ values: z.array(filterValueSchema)
405
+ }).strict(),
406
+ sizes: z.array(sizeSchema).min(1),
407
+ quality: z.number().int().min(1).max(100),
408
+ formats: z.array(formatSchema).min(1),
409
+ output: z.object({
410
+ png: formatOutputSchema.optional(),
411
+ webp: formatOutputSchema.optional(),
412
+ ts: z.string().trim().min(1)
413
+ }).strict()
414
+ }).strict();
415
+ const configSchema = z.record(z.string().trim().min(1), profileSchema);
416
+ function defineConfig(config) {
417
+ return config;
418
+ }
419
+ function formatValidationError(error) {
420
+ return error.issues.map((issue) => {
421
+ const location = issue.path.length > 0 ? issue.path.join(".") : "config";
422
+ const received = issue.code === "invalid_value" ? ` (${String(issue.input)})` : "";
423
+ return `${location}: ${issue.message}${received}`;
424
+ }).join("\n");
425
+ }
426
+ function preflightFormatTypos(raw) {
427
+ if (typeof raw !== "object" || raw === null) return;
428
+ for (const [profileName, value] of Object.entries(raw)) {
429
+ if (typeof value !== "object" || value === null) continue;
430
+ const formats = Reflect.get(value, "formats");
431
+ if (Array.isArray(formats) && formats.includes("wepb")) throw new FlagResizerError(`Profile "${profileName}" contains format "wepb". Did you mean "webp"?`);
432
+ }
433
+ }
434
+ function normalizePublicPath(publicPath) {
435
+ const normalized = publicPath.replace(/\/+$/u, "");
436
+ return normalized === "" ? "/" : normalized;
437
+ }
438
+ function assertUniqueValues(profileName, profile) {
439
+ if (new Set(profile.formats).size !== profile.formats.length) throw new FlagResizerError(`Profile "${profileName}" contains duplicate formats.`);
440
+ if (new Set(profile.sizes.map(([width, height]) => `${width}x${height}`)).size !== profile.sizes.length) throw new FlagResizerError(`Profile "${profileName}" contains duplicate sizes.`);
441
+ if (new Set(profile.filter.values).size !== profile.filter.values.length) throw new FlagResizerError(`Profile "${profileName}" contains duplicate filter values.`);
442
+ }
443
+ function assertConsistentRatio(profileName, profile) {
444
+ const first = profile.sizes[0];
445
+ if (!first) return;
446
+ const [baseWidth, baseHeight] = first;
447
+ for (const [width, height] of profile.sizes.slice(1)) if (width * baseHeight !== height * baseWidth) throw new FlagResizerError(`Profile "${profileName}" mixes aspect ratios: ${baseWidth}x${baseHeight} and ${width}x${height}.`);
448
+ }
449
+ function matchesFilterValue(code, value) {
450
+ if (!value.includes("*")) return code === value;
451
+ return new RegExp(`^${value.split("*").join(".*")}$`, "u").test(code);
452
+ }
453
+ function assertFilterValuesMatch(profileName, profile) {
454
+ for (const value of profile.filter.values) if (!COUNTRY_CODES.some((code) => matchesFilterValue(code, value))) throw new FlagResizerError(`Profile "${profileName}" contains filter pattern "${value}" that matches no bundled flags.`);
455
+ }
456
+ function selectCountries(profile) {
457
+ return COUNTRY_CODES.filter((code) => {
458
+ const matches = profile.filter.values.some((value) => matchesFilterValue(code, value));
459
+ return profile.filter.type === "whitelist" ? matches : !matches;
460
+ });
461
+ }
462
+ function resolveProfile(name, profile, baseDir) {
463
+ assertUniqueValues(name, profile);
464
+ assertConsistentRatio(name, profile);
465
+ assertFilterValuesMatch(name, profile);
466
+ for (const format of profile.formats) if (!profile.output[format]) throw new FlagResizerError(`Profile "${name}" enables "${format}" but output.${format} is missing.`);
467
+ return {
468
+ ...profile,
469
+ name,
470
+ countries: selectCountries(profile),
471
+ output: {
472
+ ...profile.output.png ? { png: {
473
+ dir: path.resolve(baseDir, profile.output.png.dir),
474
+ publicPath: normalizePublicPath(profile.output.png.publicPath)
475
+ } } : {},
476
+ ...profile.output.webp ? { webp: {
477
+ dir: path.resolve(baseDir, profile.output.webp.dir),
478
+ publicPath: normalizePublicPath(profile.output.webp.publicPath)
479
+ } } : {},
480
+ ts: path.resolve(baseDir, profile.output.ts)
481
+ }
482
+ };
483
+ }
484
+ function profileTargets(profile) {
485
+ const targets = [profile.output.ts];
486
+ for (const format of profile.formats) {
487
+ const output = profile.output[format];
488
+ if (!output) continue;
489
+ for (const [width, height] of profile.sizes) for (const code of profile.countries) targets.push(path.join(output.dir, `${width}x${height}`, `${code}.${format}`));
490
+ }
491
+ return targets;
492
+ }
493
+ function assertNoTargetCollisions(profiles) {
494
+ const owners = /* @__PURE__ */ new Map();
495
+ for (const profile of profiles) for (const target of profileTargets(profile)) {
496
+ const owner = owners.get(target);
497
+ if (owner) throw new FlagResizerError(`Profiles "${owner}" and "${profile.name}" both generate ${target}.`);
498
+ owners.set(target, profile.name);
499
+ }
500
+ }
501
+ async function loadRawConfiguration(options) {
502
+ const cwd = path.resolve(options.cwd ?? process.cwd());
503
+ if ("config" in options) return {
504
+ raw: options.config,
505
+ baseDir: cwd
506
+ };
507
+ const requestedFile = options.configFile ? path.resolve(cwd, options.configFile) : void 0;
508
+ try {
509
+ const result = await loadConfig({
510
+ name: "flag-resizer",
511
+ cwd,
512
+ ...requestedFile ? { configFile: requestedFile } : {},
513
+ configFileRequired: true,
514
+ rcFile: false,
515
+ globalRc: false,
516
+ packageJson: false,
517
+ dotenv: false,
518
+ envName: false,
519
+ extend: false
520
+ });
521
+ const discoveredFile = typeof result.configFile === "string" ? path.resolve(result.configFile) : requestedFile;
522
+ return {
523
+ raw: result.config,
524
+ baseDir: discoveredFile ? path.dirname(discoveredFile) : cwd,
525
+ ...discoveredFile ? { configFile: discoveredFile } : {}
526
+ };
527
+ } catch (error) {
528
+ throw new FlagResizerError(`Unable to load flag-resizer configuration from ${requestedFile ?? path.join(cwd, "flag-resizer.config.*")}.`, { cause: error });
529
+ }
530
+ }
531
+ async function resolveConfiguration(options) {
532
+ const loaded = await loadRawConfiguration(options);
533
+ preflightFormatTypos(loaded.raw);
534
+ const parsed = configSchema.safeParse(loaded.raw);
535
+ if (!parsed.success) throw new FlagResizerError(`Invalid flag-resizer configuration:\n${formatValidationError(parsed.error)}`);
536
+ const entries = Object.entries(parsed.data);
537
+ if (entries.length === 0) throw new FlagResizerError("The configuration must contain at least one profile.");
538
+ const allProfiles = entries.map(([name, profile]) => resolveProfile(name, profile, loaded.baseDir));
539
+ assertNoTargetCollisions(allProfiles);
540
+ const requested = options.profiles;
541
+ const selected = requested && requested.length > 0 ? requested.map((name) => {
542
+ const profile = allProfiles.find((candidate) => candidate.name === name);
543
+ if (!profile) throw new FlagResizerError(`Unknown profile "${name}". Available profiles: ${allProfiles.map((candidate) => candidate.name).join(", ")}.`);
544
+ return profile;
545
+ }) : allProfiles;
546
+ if (new Set(selected.map((profile) => profile.name)).size !== selected.length) throw new FlagResizerError("A profile was selected more than once.");
547
+ return {
548
+ baseDir: loaded.baseDir,
549
+ profiles: selected,
550
+ ...loaded.configFile ? { configFile: loaded.configFile } : {}
551
+ };
552
+ }
553
+ //#endregion
554
+ //#region src/generated-typescript.ts
555
+ function quote(value) {
556
+ return JSON.stringify(value);
557
+ }
558
+ function propertyKey(value) {
559
+ return /^[A-Za-z_$][\w$]*$/u.test(value) ? value : quote(value);
560
+ }
561
+ function createTypeScriptManifest(profile) {
562
+ return `/**
563
+ * Generated by script 🍺
564
+ * Do not edit manually.
565
+ */
566
+
567
+ export const FLAGS = {
568
+ ${profile.countries.map((code) => ` ${propertyKey(code)}: ${quote(FLAGS[code])},`).join("\n")}
569
+ } as const;
570
+
571
+ export type CountryCode = keyof typeof FLAGS;
572
+
573
+ export const FLAG_SIZES = [
574
+ ${profile.sizes.map(([width, height]) => `${width}x${height}`).map((size) => ` ${quote(size)},`).join("\n")}
575
+ ] as const;
576
+
577
+ export type FlagSize = (typeof FLAG_SIZES)[number];
578
+
579
+ export const FLAG_DIMENSIONS = {
580
+ ${profile.sizes.map(([width, height]) => ` ${quote(`${width}x${height}`)}: { width: ${width}, height: ${height} },`).join("\n")}
581
+ } as const satisfies Record<FlagSize, { width: number; height: number }>;
582
+
583
+ export const FLAG_FORMATS = [
584
+ ${profile.formats.map((format) => ` ${quote(format)},`).join("\n")}
585
+ ] as const;
586
+
587
+ export type FlagFormat = (typeof FLAG_FORMATS)[number];
588
+
589
+ export const FLAG_PUBLIC_PATHS = {
590
+ ${profile.formats.map((format) => {
591
+ const output = profile.output[format];
592
+ if (!output) throw new Error(`Missing resolved output for ${format}.`);
593
+ return ` ${format}: ${quote(output.publicPath)},`;
594
+ }).join("\n")}
595
+ } as const satisfies Record<FlagFormat, string>;
596
+
597
+ export function getFlagPath(
598
+ code: CountryCode,
599
+ size: FlagSize,
600
+ format: FlagFormat,
601
+ ): string {
602
+ const publicPath = FLAG_PUBLIC_PATHS[format];
603
+ const basePath = publicPath === '/' ? '' : publicPath;
604
+ return \`\${basePath}/\${size}/\${code}.\${format}\`;
605
+ }
606
+ `;
607
+ }
608
+ //#endregion
609
+ //#region src/generator.ts
610
+ const PACKAGE_ROOT = fileURLToPath(new URL("../", import.meta.url));
611
+ const FLAGS_DIRECTORY = path.join(PACKAGE_ROOT, "flags");
612
+ const ATTRIBUTION_FILE = path.join(PACKAGE_ROOT, "ATTRIBUTION.txt");
613
+ const GRAPHICS_LICENSE_FILE = path.join(PACKAGE_ROOT, "LICENSE-GRAPHICS");
614
+ const MANIFEST_VERSION = 1;
615
+ function emptyManifest() {
616
+ return {
617
+ version: MANIFEST_VERSION,
618
+ profiles: {}
619
+ };
620
+ }
621
+ function entryTarget(entry) {
622
+ return path.resolve(entry.root, entry.relativePath);
623
+ }
624
+ function entryKey(entry) {
625
+ return entryTarget(entry);
626
+ }
627
+ function assertSafeManagedFile(entry) {
628
+ if (!path.isAbsolute(entry.root)) throw new FlagResizerError("The managed manifest contains a non-absolute output root.");
629
+ if (path.isAbsolute(entry.relativePath) || entry.relativePath.includes("\0")) throw new FlagResizerError("The managed manifest contains an unsafe file path.");
630
+ const target = entryTarget(entry);
631
+ const relative = path.relative(entry.root, target);
632
+ if (relative === "" || relative === ".." || relative.startsWith(`..${path.sep}`)) throw new FlagResizerError("The managed manifest contains a path outside its output root.");
633
+ const portable = entry.relativePath.split(path.sep).join("/");
634
+ if (!(entry.kind === "attribution" && portable === "ATTRIBUTION.txt" || entry.kind === "license" && portable === "LICENSE-GRAPHICS" || entry.kind === "typescript" && /^[^/]+\.ts$/u.test(portable) || entry.kind === "image" && /^[1-9]\d*x[1-9]\d*\/(?:[a-z]{2}|au-(?:act|nsw|nt|qld|sa|tas|vic|wa)|ca-(?:ab|bc|mb|nb|nl|ns|nt|nu|on|pe|qc|sk|yt)|de-(?:bb|be|bw|by|hb|he|hh|mv|ni|nw|rp|sh|sl|sn|st|th)|es-(?:an|ar|as|cb|ce|cl|cm|cn|ct|ex|ga|ib|mc|md|ml|nc|pv|ri|vc)|gb-(?:eng|nir|sct|wls)|us-(?:ak|al|ar|az|ca|co|ct|de|fl|ga|hi|ia|id|il|in|ks|ky|la|ma|md|me|mi|mn|mo|ms|mt|nc|nd|ne|nh|nj|nm|nv|ny|oh|ok|or|pa|ri|sc|sd|tn|tx|ut|va|vt|wa|wi|wv|wy))\.(?:png|webp)$/u.test(portable))) throw new FlagResizerError(`The managed manifest contains an invalid ${entry.kind} path: ${entry.relativePath}.`);
635
+ }
636
+ function managedFile(target, root, kind) {
637
+ const entry = {
638
+ root: path.resolve(root),
639
+ relativePath: path.relative(path.resolve(root), path.resolve(target)),
640
+ kind
641
+ };
642
+ assertSafeManagedFile(entry);
643
+ return entry;
644
+ }
645
+ function isRecord(value) {
646
+ return typeof value === "object" && value !== null && !Array.isArray(value);
647
+ }
648
+ function parseManifest(value) {
649
+ if (!isRecord(value) || value["version"] !== MANIFEST_VERSION || !isRecord(value["profiles"])) throw new FlagResizerError("The managed manifest has an unsupported or invalid structure.");
650
+ const profiles = {};
651
+ for (const [profileName, profileValue] of Object.entries(value["profiles"])) {
652
+ if (!isRecord(profileValue) || !Array.isArray(profileValue["files"])) throw new FlagResizerError(`The manifest entry for profile "${profileName}" is invalid.`);
653
+ profiles[profileName] = { files: profileValue["files"].map((file) => {
654
+ if (!isRecord(file) || typeof file["root"] !== "string" || typeof file["relativePath"] !== "string" || ![
655
+ "attribution",
656
+ "image",
657
+ "license",
658
+ "typescript"
659
+ ].includes(String(file["kind"]))) throw new FlagResizerError(`The manifest contains an invalid file owned by profile "${profileName}".`);
660
+ const entry = {
661
+ root: file["root"],
662
+ relativePath: file["relativePath"],
663
+ kind: file["kind"]
664
+ };
665
+ assertSafeManagedFile(entry);
666
+ return entry;
667
+ }) };
668
+ }
669
+ return {
670
+ version: MANIFEST_VERSION,
671
+ profiles
672
+ };
673
+ }
674
+ async function pathExists(file) {
675
+ try {
676
+ await access(file);
677
+ return true;
678
+ } catch {
679
+ return false;
680
+ }
681
+ }
682
+ async function readManifest(file) {
683
+ try {
684
+ return parseManifest(JSON.parse(await readFile(file, "utf8")));
685
+ } catch (error) {
686
+ if (isRecord(error) && error["code"] === "ENOENT") return emptyManifest();
687
+ if (error instanceof FlagResizerError) throw error;
688
+ throw new FlagResizerError(`Unable to read managed manifest ${file}.`, { cause: error });
689
+ }
690
+ }
691
+ function resolveConcurrency(value) {
692
+ if (value !== void 0 && (!Number.isInteger(value) || value < 1)) throw new FlagResizerError("concurrency must be a positive integer.");
693
+ return value ?? Math.max(1, Math.min(8, availableParallelism()));
694
+ }
695
+ async function runBounded(items, concurrency, worker) {
696
+ let nextIndex = 0;
697
+ async function runWorker() {
698
+ while (nextIndex < items.length) {
699
+ const index = nextIndex;
700
+ nextIndex += 1;
701
+ const item = items[index];
702
+ if (item) await worker(item, index);
703
+ }
704
+ }
705
+ await Promise.all(Array.from({ length: Math.min(concurrency, Math.max(1, items.length)) }, runWorker));
706
+ }
707
+ function svgDensity(width, height) {
708
+ const scale = Math.max(width, height) / 36;
709
+ return Math.max(72, Math.ceil(scale * 72));
710
+ }
711
+ async function createImage(svg, width, height, format, quality) {
712
+ const pipeline = sharp(svg, { density: svgDensity(width, height) }).resize(width, height, {
713
+ fit: "cover",
714
+ position: "centre"
715
+ }).ensureAlpha();
716
+ if (format === "png") return pipeline.png({
717
+ quality,
718
+ compressionLevel: 9,
719
+ adaptiveFiltering: true,
720
+ effort: 7
721
+ }).toBuffer();
722
+ return pipeline.webp({
723
+ quality,
724
+ effort: 4
725
+ }).toBuffer();
726
+ }
727
+ function addProfileFile(filesByProfile, profileName, entry) {
728
+ const entries = filesByProfile.get(profileName) ?? [];
729
+ entries.push(entry);
730
+ filesByProfile.set(profileName, entries);
731
+ }
732
+ function createGenerationPlan(profiles) {
733
+ const taskByTarget = /* @__PURE__ */ new Map();
734
+ const filesByProfile = /* @__PURE__ */ new Map();
735
+ const imageCountByProfile = /* @__PURE__ */ new Map();
736
+ const svgCache = /* @__PURE__ */ new Map();
737
+ let attributionContent;
738
+ let licenseContent;
739
+ const readSvg = (code) => {
740
+ let content = svgCache.get(code);
741
+ if (!content) {
742
+ content = readFile(path.join(FLAGS_DIRECTORY, `${code}.svg`));
743
+ svgCache.set(code, content);
744
+ }
745
+ return content;
746
+ };
747
+ const register = (profileName, entry, image, createContent) => {
748
+ const target = entryTarget(entry);
749
+ if (!taskByTarget.has(target)) taskByTarget.set(target, {
750
+ entry,
751
+ target,
752
+ image,
753
+ createContent
754
+ });
755
+ addProfileFile(filesByProfile, profileName, entry);
756
+ };
757
+ for (const profile of profiles) {
758
+ const typeScriptEntry = managedFile(profile.output.ts, path.dirname(profile.output.ts), "typescript");
759
+ register(profile.name, typeScriptEntry, false, () => Promise.resolve(Buffer.from(createTypeScriptManifest(profile))));
760
+ let imageCount = 0;
761
+ for (const format of profile.formats) {
762
+ const output = profile.output[format];
763
+ if (!output) throw new FlagResizerError(`Profile "${profile.name}" has no resolved output for ${format}.`);
764
+ const attributionEntry = managedFile(path.join(output.dir, "ATTRIBUTION.txt"), output.dir, "attribution");
765
+ register(profile.name, attributionEntry, false, () => {
766
+ attributionContent ??= readFile(ATTRIBUTION_FILE);
767
+ return attributionContent;
768
+ });
769
+ const licenseEntry = managedFile(path.join(output.dir, "LICENSE-GRAPHICS"), output.dir, "license");
770
+ register(profile.name, licenseEntry, false, () => {
771
+ licenseContent ??= readFile(GRAPHICS_LICENSE_FILE);
772
+ return licenseContent;
773
+ });
774
+ for (const [width, height] of profile.sizes) for (const code of profile.countries) {
775
+ const entry = managedFile(path.join(output.dir, `${width}x${height}`, `${code}.${format}`), output.dir, "image");
776
+ register(profile.name, entry, true, async () => createImage(await readSvg(code), width, height, format, profile.quality));
777
+ imageCount += 1;
778
+ }
779
+ }
780
+ imageCountByProfile.set(profile.name, imageCount);
781
+ }
782
+ return {
783
+ tasks: [...taskByTarget.values()].sort((left, right) => left.target.localeCompare(right.target)),
784
+ filesByProfile,
785
+ imageCountByProfile
786
+ };
787
+ }
788
+ async function buffersEqual(file, expected) {
789
+ try {
790
+ if ((await stat(file)).size !== expected.byteLength) return false;
791
+ return (await readFile(file)).equals(expected);
792
+ } catch (error) {
793
+ if (isRecord(error) && error["code"] === "ENOENT") return false;
794
+ throw error;
795
+ }
796
+ }
797
+ async function writeStagedFile(target, staged) {
798
+ await mkdir(path.dirname(target), { recursive: true });
799
+ const temporaryTarget = path.join(path.dirname(target), `.${path.basename(target)}.${process.pid}.${randomUUID()}.tmp`);
800
+ try {
801
+ await copyFile(staged, temporaryTarget);
802
+ await rename(temporaryTarget, target);
803
+ } finally {
804
+ await rm(temporaryTarget, { force: true });
805
+ }
806
+ }
807
+ async function writeAtomic(target, content) {
808
+ await mkdir(path.dirname(target), { recursive: true });
809
+ const temporaryTarget = path.join(path.dirname(target), `.${path.basename(target)}.${process.pid}.${randomUUID()}.tmp`);
810
+ try {
811
+ await writeFile(temporaryTarget, content);
812
+ await rename(temporaryTarget, target);
813
+ } finally {
814
+ await rm(temporaryTarget, { force: true });
815
+ }
816
+ }
817
+ async function removeEmptyParents(start, root) {
818
+ let directory = path.resolve(start);
819
+ const resolvedRoot = path.resolve(root);
820
+ while (directory !== resolvedRoot) {
821
+ const relative = path.relative(resolvedRoot, directory);
822
+ if (relative === ".." || relative.startsWith(`..${path.sep}`)) return;
823
+ try {
824
+ await rmdir(directory);
825
+ } catch {
826
+ return;
827
+ }
828
+ directory = path.dirname(directory);
829
+ }
830
+ }
831
+ async function pruneFile(entry) {
832
+ assertSafeManagedFile(entry);
833
+ const target = entryTarget(entry);
834
+ try {
835
+ await unlink(target);
836
+ await removeEmptyParents(path.dirname(target), entry.root);
837
+ return true;
838
+ } catch (error) {
839
+ if (isRecord(error) && error["code"] === "ENOENT") return false;
840
+ throw new FlagResizerError(`Unable to remove stale generated file ${target}.`, { cause: error });
841
+ }
842
+ }
843
+ function sortedManifest(manifest) {
844
+ return {
845
+ version: MANIFEST_VERSION,
846
+ profiles: Object.fromEntries(Object.entries(manifest.profiles).sort(([left], [right]) => left.localeCompare(right)).map(([profileName, profile]) => [profileName, { files: [...profile.files].sort((left, right) => entryTarget(left).localeCompare(entryTarget(right))) }]))
847
+ };
848
+ }
849
+ function nextManifest(previous, plan, selectedProfiles, fullRun) {
850
+ const profiles = fullRun ? {} : { ...previous.profiles };
851
+ for (const profile of selectedProfiles) profiles[profile.name] = { files: plan.filesByProfile.get(profile.name) ?? [] };
852
+ return sortedManifest({
853
+ version: MANIFEST_VERSION,
854
+ profiles
855
+ });
856
+ }
857
+ function staleEntries(previous, next) {
858
+ const retainedTargets = new Set(Object.values(next.profiles).flatMap((profile) => profile.files.map(entryKey)));
859
+ const stale = /* @__PURE__ */ new Map();
860
+ for (const profile of Object.values(previous.profiles)) for (const entry of profile.files) {
861
+ const target = entryKey(entry);
862
+ if (!retainedTargets.has(target)) stale.set(target, entry);
863
+ }
864
+ return [...stale.values()];
865
+ }
866
+ function removedOwnershipCount(previous, next, profileName) {
867
+ const nextFiles = new Set((next.profiles[profileName]?.files ?? []).map(entryKey));
868
+ return (previous.profiles[profileName]?.files ?? []).filter((entry) => !nextFiles.has(entryKey(entry))).length;
869
+ }
870
+ async function generate(options = {}) {
871
+ const started = performance.now();
872
+ const concurrency = resolveConcurrency(options.concurrency);
873
+ const resolved = await resolveConfiguration(options);
874
+ const manifestFile = path.join(resolved.baseDir, ".flag-resizer", "manifest.json");
875
+ const previousManifest = await readManifest(manifestFile);
876
+ const plan = createGenerationPlan(resolved.profiles);
877
+ const fullRun = !options.profiles || options.profiles.length === 0;
878
+ const manifest = nextManifest(previousManifest, plan, resolved.profiles, fullRun);
879
+ const stale = staleEntries(previousManifest, manifest);
880
+ const statuses = /* @__PURE__ */ new Map();
881
+ const dryRun = options.dryRun ?? false;
882
+ if (dryRun) await runBounded(plan.tasks, concurrency, async (task) => {
883
+ statuses.set(task.target, await pathExists(task.target) ? "updated" : "created");
884
+ });
885
+ else {
886
+ const stagingDirectory = await mkdtemp(path.join(os.tmpdir(), "flag-resizer-"));
887
+ const stagedFiles = /* @__PURE__ */ new Map();
888
+ try {
889
+ await runBounded(plan.tasks, concurrency, async (task, index) => {
890
+ const content = await task.createContent();
891
+ const exists = await pathExists(task.target);
892
+ if (exists && await buffersEqual(task.target, content)) {
893
+ statuses.set(task.target, "unchanged");
894
+ return;
895
+ }
896
+ statuses.set(task.target, exists ? "updated" : "created");
897
+ const staged = path.join(stagingDirectory, String(index));
898
+ await writeFile(staged, content);
899
+ stagedFiles.set(task.target, staged);
900
+ });
901
+ for (const task of plan.tasks) {
902
+ const staged = stagedFiles.get(task.target);
903
+ if (staged) await writeStagedFile(task.target, staged);
904
+ }
905
+ for (const entry of stale) await pruneFile(entry);
906
+ await writeAtomic(manifestFile, `${JSON.stringify(manifest, null, 2)}\n`);
907
+ } catch (error) {
908
+ throw new FlagResizerError("Flag generation failed before the manifest was committed.", { cause: error });
909
+ } finally {
910
+ await rm(stagingDirectory, {
911
+ recursive: true,
912
+ force: true
913
+ });
914
+ }
915
+ }
916
+ const profiles = resolved.profiles.map((profile) => {
917
+ const entries = plan.filesByProfile.get(profile.name) ?? [];
918
+ const counts = {
919
+ created: 0,
920
+ updated: 0,
921
+ unchanged: 0
922
+ };
923
+ for (const entry of entries) {
924
+ const status = statuses.get(entryTarget(entry));
925
+ if (status) counts[status] += 1;
926
+ }
927
+ return {
928
+ name: profile.name,
929
+ countries: profile.countries.length,
930
+ images: plan.imageCountByProfile.get(profile.name) ?? 0,
931
+ sizes: profile.sizes,
932
+ formats: profile.formats,
933
+ outputDirectories: Object.fromEntries(profile.formats.map((format) => [format, profile.output[format]?.dir])),
934
+ ...counts,
935
+ removed: removedOwnershipCount(previousManifest, manifest, profile.name),
936
+ typeScriptFile: profile.output.ts
937
+ };
938
+ });
939
+ return {
940
+ dryRun,
941
+ durationMs: Math.round(performance.now() - started),
942
+ ...resolved.configFile ? { configFile: resolved.configFile } : {},
943
+ manifestFile,
944
+ profiles
945
+ };
946
+ }
947
+ //#endregion
948
+ export { FLAGS as a, COUNTRY_CODES as i, defineConfig as n, FlagResizerError as r, generate as t };
949
+
950
+ //# sourceMappingURL=generator.js.map