| 
									
										
										
										
											2021-04-10 03:18:32 +02:00
										 |  |  | import ScriptUtils from "./ScriptUtils"; | 
					
						
							| 
									
										
										
										
											2022-01-16 02:45:07 +01:00
										 |  |  | import {existsSync, mkdirSync, readFileSync, writeFileSync} from "fs"; | 
					
						
							| 
									
										
										
										
											2021-04-10 03:18:32 +02:00
										 |  |  | import * as licenses from "../assets/generated/license_info.json" | 
					
						
							| 
									
										
										
										
											2021-08-07 23:11:34 +02:00
										 |  |  | import {LayoutConfigJson} from "../Models/ThemeConfig/Json/LayoutConfigJson"; | 
					
						
							|  |  |  | import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  | import Constants from "../Models/Constants"; | 
					
						
							| 
									
										
										
										
											2022-02-04 00:45:22 +01:00
										 |  |  | import {PrevalidateTheme, ValidateLayer, ValidateThemeAndLayers} from "../Models/ThemeConfig/Conversion/Validation"; | 
					
						
							| 
									
										
										
										
											2021-10-01 04:49:19 +02:00
										 |  |  | import {Translation} from "../UI/i18n/Translation"; | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  | import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson"; | 
					
						
							|  |  |  | import * as questions from "../assets/tagRenderings/questions.json"; | 
					
						
							|  |  |  | import * as icons from "../assets/tagRenderings/icons.json"; | 
					
						
							| 
									
										
										
										
											2022-01-16 02:45:07 +01:00
										 |  |  | import PointRenderingConfigJson from "../Models/ThemeConfig/Json/PointRenderingConfigJson"; | 
					
						
							| 
									
										
										
										
											2022-01-21 01:57:16 +01:00
										 |  |  | import {PrepareLayer} from "../Models/ThemeConfig/Conversion/PrepareLayer"; | 
					
						
							|  |  |  | import {PrepareTheme} from "../Models/ThemeConfig/Conversion/PrepareTheme"; | 
					
						
							|  |  |  | import {DesugaringContext} from "../Models/ThemeConfig/Conversion/Conversion"; | 
					
						
							| 
									
										
										
										
											2021-06-23 02:41:30 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-10 03:18:32 +02:00
										 |  |  | // This scripts scans 'assets/layers/*.json' for layer definition files and 'assets/themes/*.json' for theme definition files.
 | 
					
						
							|  |  |  | // It spits out an overview of those to be used to load them
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-19 23:31:00 +02:00
										 |  |  | class LayerOverviewUtils { | 
					
						
							| 
									
										
										
										
											2021-05-19 20:47:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |     writeSmallOverview(themes: { id: string, title: any, shortDescription: any, icon: string, hideFromOverview: boolean }[]) { | 
					
						
							|  |  |  |         const perId = new Map<string, any>(); | 
					
						
							|  |  |  |         for (const theme of themes) { | 
					
						
							|  |  |  |             const data = { | 
					
						
							|  |  |  |                 id: theme.id, | 
					
						
							|  |  |  |                 title: theme.title, | 
					
						
							|  |  |  |                 shortDescription: theme.shortDescription, | 
					
						
							|  |  |  |                 icon: theme.icon, | 
					
						
							|  |  |  |                 hideFromOverview: theme.hideFromOverview | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             perId.set(theme.id, data); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const sorted = Constants.themeOrder.map(id => { | 
					
						
							|  |  |  |             if (!perId.has(id)) { | 
					
						
							|  |  |  |                 throw "Ordered theme id " + id + " not found" | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             return perId.get(id); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         perId.forEach((value) => { | 
					
						
							|  |  |  |             if (Constants.themeOrder.indexOf(value.id) >= 0) { | 
					
						
							|  |  |  |                 return; // actually a continue
 | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             sorted.push(value) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writeFileSync("./assets/generated/theme_overview.json", JSON.stringify(sorted, null, "  "), "UTF8"); | 
					
						
							| 
									
										
										
										
											2021-04-10 03:18:32 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-10 03:50:44 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |     writeTheme(theme: LayoutConfigJson) { | 
					
						
							|  |  |  |         if (!existsSync("./assets/generated/themes")) { | 
					
						
							|  |  |  |             mkdirSync("./assets/generated/themes"); | 
					
						
							| 
									
										
										
										
											2021-05-19 20:47:41 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         writeFileSync(`./assets/generated/themes/${theme.id}.json`, JSON.stringify(theme, null, "  "), "UTF8"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     writeLayer(layer: LayerConfigJson) { | 
					
						
							|  |  |  |         if (!existsSync("./assets/generated/layers")) { | 
					
						
							|  |  |  |             mkdirSync("./assets/generated/layers"); | 
					
						
							| 
									
										
										
										
											2021-11-07 21:20:05 +01:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         writeFileSync(`./assets/generated/layers/${layer.id}.json`, JSON.stringify(layer, null, "  "), "UTF8"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getSharedTagRenderings(): Map<string, TagRenderingConfigJson> { | 
					
						
							|  |  |  |         const dict = new Map<string, TagRenderingConfigJson>(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         for (const key in questions["default"]) { | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             if (key === "id") { | 
					
						
							| 
									
										
										
										
											2022-01-22 02:56:35 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             questions[key].id = key; | 
					
						
							|  |  |  |             dict.set(key, <TagRenderingConfigJson>questions[key]) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         for (const key in icons["default"]) { | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             if (key === "id") { | 
					
						
							| 
									
										
										
										
											2022-01-22 02:56:35 +01:00
										 |  |  |                 continue | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |             if (typeof icons[key] !== "object") { | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |                 continue | 
					
						
							| 
									
										
										
										
											2021-09-04 18:59:51 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             icons[key].id = key; | 
					
						
							|  |  |  |             dict.set(key, <TagRenderingConfigJson>icons[key]) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-09-04 18:59:51 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         dict.forEach((value, key) => { | 
					
						
							| 
									
										
										
										
											2022-01-26 21:40:38 +01:00
										 |  |  |             if (key === "id") { | 
					
						
							| 
									
										
										
										
											2022-01-24 00:24:51 +01:00
										 |  |  |                 return | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             value.id = value.id ?? key; | 
					
						
							|  |  |  |         }) | 
					
						
							| 
									
										
										
										
											2021-05-19 20:47:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         return dict; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-05-19 20:47:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-10 23:10:39 +01:00
										 |  |  |     checkAllSvgs() { | 
					
						
							| 
									
										
										
										
											2022-02-06 03:02:45 +01:00
										 |  |  |         const allSvgs = ScriptUtils.readDirRecSync("./assets") | 
					
						
							|  |  |  |             .filter(path => path.endsWith(".svg")) | 
					
						
							|  |  |  |             .filter(path => !path.startsWith("./assets/generated")) | 
					
						
							|  |  |  |         let errCount = 0; | 
					
						
							|  |  |  |         for (const path of allSvgs) { | 
					
						
							|  |  |  |             const contents = readFileSync(path, "UTF8") | 
					
						
							|  |  |  |             if (contents.indexOf("data:image/png;") < 0) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             console.warn("The SVG at " + path + " is a fake SVG: it contains PNG data!") | 
					
						
							|  |  |  |             errCount++; | 
					
						
							| 
									
										
										
										
											2022-02-10 23:10:39 +01:00
										 |  |  |             if (path.startsWith("./assets/svg")) { | 
					
						
							| 
									
										
										
										
											2022-02-06 03:02:45 +01:00
										 |  |  |                 throw "A core SVG is actually a PNG. Don't do this!" | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-10 23:10:39 +01:00
										 |  |  |         if (errCount > 0) { | 
					
						
							|  |  |  |             throw `There are ${errCount} fake svgs` | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-06 03:02:45 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |     main(_: string[]) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const licensePaths = new Set<string>() | 
					
						
							|  |  |  |         for (const i in licenses) { | 
					
						
							|  |  |  |             licensePaths.add(licenses[i].path) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const sharedLayers = this.buildLayerIndex(licensePaths); | 
					
						
							|  |  |  |         const sharedThemes = this.buildThemeIndex(licensePaths, sharedLayers) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         writeFileSync("./assets/generated/known_layers_and_themes.json", JSON.stringify({ | 
					
						
							|  |  |  |             "layers": Array.from(sharedLayers.values()), | 
					
						
							|  |  |  |             "themes": Array.from(sharedThemes.values()) | 
					
						
							|  |  |  |         })) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-22 02:56:35 +01:00
										 |  |  |         writeFileSync("./assets/generated/known_layers.json", JSON.stringify({layers: Array.from(sharedLayers.values())})) | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-16 02:45:07 +01:00
										 |  |  |         { | 
					
						
							|  |  |  |             // mapcomplete-changes shows an icon for each corresponding mapcomplete-theme
 | 
					
						
							|  |  |  |             const iconsPerTheme = | 
					
						
							|  |  |  |                 Array.from(sharedThemes.values()).map(th => ({ | 
					
						
							|  |  |  |                     if: "theme=" + th.id, | 
					
						
							|  |  |  |                     then: th.icon | 
					
						
							|  |  |  |                 })) | 
					
						
							|  |  |  |             const proto: LayoutConfigJson = JSON.parse(readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", "UTF8")); | 
					
						
							|  |  |  |             const protolayer = <LayerConfigJson>(proto.layers.filter(l => l["id"] === "mapcomplete-changes")[0]) | 
					
						
							|  |  |  |             const rendering = (<PointRenderingConfigJson>protolayer.mapRendering[0]) | 
					
						
							|  |  |  |             rendering.icon["mappings"] = iconsPerTheme | 
					
						
							|  |  |  |             writeFileSync('./assets/themes/mapcomplete-changes/mapcomplete-changes.json', JSON.stringify(proto, null, "  ")) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-10 23:10:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-06 03:02:45 +01:00
										 |  |  |         this.checkAllSvgs() | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     private buildLayerIndex(knownImagePaths: Set<string>): Map<string, LayerConfigJson> { | 
					
						
							|  |  |  |         // First, we expand and validate all builtin layers. These are written to assets/generated/layers
 | 
					
						
							|  |  |  |         // At the same time, an index of available layers is built.
 | 
					
						
							|  |  |  |         console.log("   ---------- VALIDATING BUILTIN LAYERS ---------") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const sharedTagRenderings = this.getSharedTagRenderings(); | 
					
						
							|  |  |  |         const layerFiles = ScriptUtils.getLayerFiles(); | 
					
						
							|  |  |  |         const sharedLayers = new Map<string, LayerConfigJson>() | 
					
						
							|  |  |  |         const state: DesugaringContext = { | 
					
						
							|  |  |  |             tagRenderings: sharedTagRenderings, | 
					
						
							|  |  |  |             sharedLayers | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-02-04 01:05:35 +01:00
										 |  |  |         const prepLayer = new PrepareLayer(state); | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         for (const sharedLayerJson of layerFiles) { | 
					
						
							|  |  |  |             const context = "While building builtin layer " + sharedLayerJson.path | 
					
						
							| 
									
										
										
										
											2022-02-04 01:05:35 +01:00
										 |  |  |             const fixed = prepLayer.convertStrict(sharedLayerJson.parsed, context) | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             const validator = new ValidateLayer(knownImagePaths, sharedLayerJson.path, true); | 
					
						
							| 
									
										
										
										
											2022-02-04 01:05:35 +01:00
										 |  |  |             validator.convertStrict(fixed, context) | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |             if (sharedLayers.has(fixed.id)) { | 
					
						
							|  |  |  |                 throw "There are multiple layers with the id " + fixed.id | 
					
						
							| 
									
										
										
										
											2021-05-19 20:47:41 +02:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             sharedLayers.set(fixed.id, fixed) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.writeLayer(fixed) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         return sharedLayers; | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-10 03:18:32 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |     private buildThemeIndex(knownImagePaths: Set<string>, sharedLayers: Map<string, LayerConfigJson>): Map<string, LayoutConfigJson> { | 
					
						
							|  |  |  |         console.log("   ---------- VALIDATING BUILTIN THEMES ---------") | 
					
						
							| 
									
										
										
										
											2021-07-26 10:13:50 +02:00
										 |  |  |         const themeFiles = ScriptUtils.getThemeFiles(); | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         const fixed = new Map<string, LayoutConfigJson>(); | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         const convertState: DesugaringContext = { | 
					
						
							|  |  |  |             sharedLayers, | 
					
						
							|  |  |  |             tagRenderings: this.getSharedTagRenderings() | 
					
						
							| 
									
										
										
										
											2021-05-19 20:47:41 +02:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         for (const themeInfo of themeFiles) { | 
					
						
							|  |  |  |             let themeFile = themeInfo.parsed | 
					
						
							|  |  |  |             const themePath = themeInfo.path | 
					
						
							| 
									
										
										
										
											2022-01-16 01:59:06 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-02-04 01:05:35 +01:00
										 |  |  |             new PrevalidateTheme().convertStrict(themeFile, themePath) | 
					
						
							|  |  |  |             themeFile = new PrepareTheme(convertState).convertStrict(themeFile, themePath) | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             new ValidateThemeAndLayers(knownImagePaths, themePath, true) | 
					
						
							| 
									
										
										
										
											2022-02-04 01:05:35 +01:00
										 |  |  |                 .convertStrict(themeFile, themePath) | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |             this.writeTheme(themeFile) | 
					
						
							|  |  |  |             fixed.set(themeFile.id, themeFile) | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         this.writeSmallOverview(themeFiles.map(tf => { | 
					
						
							|  |  |  |             const t = tf.parsed; | 
					
						
							|  |  |  |             return { | 
					
						
							|  |  |  |                 ...t, | 
					
						
							|  |  |  |                 hideFromOverview: t.hideFromOverview ?? false, | 
					
						
							|  |  |  |                 shortDescription: t.shortDescription ?? new Translation(t.description).FirstSentence().translations | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  |             } | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |         })); | 
					
						
							|  |  |  |         return fixed; | 
					
						
							| 
									
										
										
										
											2021-10-31 02:08:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-21 18:35:31 +01:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-04-10 14:25:06 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-04-23 13:56:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-19 02:13:50 +02:00
										 |  |  | new LayerOverviewUtils().main(process.argv) |