forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			316 lines
		
	
	
		
			No EOL
		
	
	
		
			9.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			316 lines
		
	
	
		
			No EOL
		
	
	
		
			9.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| /***
 | |
|  * Parses presets from the iD repository and extracts some usefull tags from them
 | |
|  */
 | |
| import ScriptUtils from "./ScriptUtils";
 | |
| import {existsSync, readFileSync, writeFileSync} from "fs";
 | |
| import * as known_languages from "../assets/language_native.json"
 | |
| import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
 | |
| import {
 | |
|     MappingConfigJson,
 | |
| 
 | |
|     QuestionableTagRenderingConfigJson
 | |
| } from "../Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson";
 | |
| import SmallLicense from "../Models/smallLicense";
 | |
| 
 | |
| interface IconThief {
 | |
|     steal(iconName: string): boolean
 | |
| }
 | |
| 
 | |
| interface IdPresetJson {
 | |
|     icon: string,
 | |
|     geometry: ("point" | "line" | "area")[]
 | |
|     /**
 | |
|      * Extra search terms
 | |
|      */
 | |
|     terms: string []
 | |
|     tags: Record<string, string>
 | |
|     name: string,
 | |
|     searchable?: boolean,
 | |
| }
 | |
| 
 | |
| class IdPreset implements IdPresetJson {
 | |
|     private _preset: IdPresetJson;
 | |
| 
 | |
|     constructor(preset: IdPresetJson) {
 | |
|         this._preset = preset;
 | |
|     }
 | |
| 
 | |
|     public get searchable(): boolean {
 | |
|         return this._preset.searchable
 | |
|     }
 | |
| 
 | |
|     public get name() {
 | |
|         return this._preset.name
 | |
|     }
 | |
| 
 | |
|     public get terms() {
 | |
|         return this._preset.terms
 | |
|     }
 | |
| 
 | |
|     public get tags() {
 | |
|         return this._preset.tags
 | |
|     }
 | |
| 
 | |
|     public get geometry() {
 | |
|         return this._preset.geometry
 | |
|     }
 | |
| 
 | |
|     public get icon(): string {
 | |
|         return this._preset.icon
 | |
|     }
 | |
| 
 | |
|     static fromFile(file: string): IdPreset {
 | |
|         return new IdPreset(JSON.parse(readFileSync(file, 'utf8')))
 | |
|     }
 | |
| 
 | |
|     public parseTags(): string | { and: string[] } {
 | |
|         const preset = this._preset;
 | |
|         const tagKeys = Object.keys(preset.tags)
 | |
|         if (tagKeys.length === 1) {
 | |
|             return tagKeys[0] + "=" + preset.tags[tagKeys[0]]
 | |
|         } else {
 | |
|             return {
 | |
|                 and: tagKeys.map(key => key + "=" + preset.tags[key])
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| class MakiThief implements IconThief {
 | |
|     public readonly _prefix: string;
 | |
|     private readonly _directory: string;
 | |
|     private readonly _license: SmallLicense;
 | |
|     private readonly _targetDir: string;
 | |
| 
 | |
|     constructor(directory: string, targetDir: string,
 | |
|                 license: SmallLicense,
 | |
|                 prefix: string = "maki-") {
 | |
|         this._license = license;
 | |
|         this._directory = directory;
 | |
|         this._targetDir = targetDir;
 | |
|         this._prefix = prefix;
 | |
|     }
 | |
| 
 | |
|     public steal(iconName: string): boolean {
 | |
|         const target = this._targetDir + iconName + ".svg"
 | |
|         if (existsSync(target)) {
 | |
|             return true
 | |
|         }
 | |
|         try {
 | |
| 
 | |
|             const file = readFileSync(this._directory + iconName + ".svg", "utf8")
 | |
|             writeFileSync(target, file, 'utf8')
 | |
| 
 | |
|             writeFileSync(target + ".license_info.json",
 | |
|                 JSON.stringify(
 | |
|                     {...this._license, path: this._prefix + iconName + ".svg"}), 'utf8')
 | |
|             console.log("Successfully stolen " + iconName)
 | |
|             return true
 | |
|         } catch (e) {
 | |
|             console.log("Could not steal " + iconName + " due to " + e.message)
 | |
|             return false
 | |
|         }
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| class AggregateIconThief implements IconThief {
 | |
|     private readonly makiThiefs: MakiThief[];
 | |
| 
 | |
|     constructor(makiThiefs: MakiThief[]) {
 | |
|         this.makiThiefs = makiThiefs;
 | |
|     }
 | |
| 
 | |
| 
 | |
|     public steal(iconName: string): boolean {
 | |
|         for (const makiThief1 of this.makiThiefs) {
 | |
|             if (iconName.startsWith(makiThief1._prefix)) {
 | |
|                 return makiThief1.steal(iconName.substr(makiThief1._prefix.length))
 | |
|             }
 | |
|         }
 | |
|         return false
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| class IdThief {
 | |
|     private readonly _idPresetsRepository: string;
 | |
| 
 | |
|     private readonly _tranlationFiles: Record<string, object> = {}
 | |
|     private readonly _knownLanguages: string[]
 | |
|     private readonly _iconThief: IconThief;
 | |
| 
 | |
|     public constructor(idPresetsRepository: string, iconThief: IconThief) {
 | |
|         this._idPresetsRepository = idPresetsRepository;
 | |
|         this._iconThief = iconThief;
 | |
|         const knownById = ScriptUtils.readDirRecSync(`${this._idPresetsRepository}/dist/translations/`)
 | |
|             .map(pth => pth.substring(pth.lastIndexOf('/') + 1, pth.length - '.json'.length))
 | |
|             .filter(lng => !lng.endsWith('.min'));
 | |
|         const missing = Object.keys(known_languages).filter(lng => knownById.indexOf(lng.replace('-', '_')) < 0)
 | |
|         this._knownLanguages = knownById.filter(lng => known_languages[lng] !== undefined)
 | |
|         console.log("Id knows following languages:", this._knownLanguages.join(", "), "missing:", missing)
 | |
|     }
 | |
| 
 | |
|     public getTranslation(language: string, ...path: string[]): string {
 | |
|         let obj = this.loadTranslationFile(language)[language]
 | |
|         for (const p of path) {
 | |
|             obj = obj[p]
 | |
|             if (obj === undefined) {
 | |
|                 return undefined;
 | |
|             }
 | |
|         }
 | |
|         return obj
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Creates a mapRendering-mapping for the 'shop' theme
 | |
|      */
 | |
|     public readShopIcons(): { if: string | { and: string[] }, then: string }[] {
 | |
| 
 | |
|         const dir = this._idPresetsRepository + "/data/presets/shop"
 | |
| 
 | |
|         const mappings:
 | |
|             {
 | |
|                 if: string | { and: string[] },
 | |
|                 then: string
 | |
|             }[] = []
 | |
|         const files = ScriptUtils.readDirRecSync(dir, 1);
 | |
|         for (const file of files) {
 | |
|             const preset = IdPreset.fromFile(file);
 | |
| 
 | |
|             if (!this._iconThief.steal(preset.icon)) {
 | |
|                 continue
 | |
|             }
 | |
| 
 | |
|             const mapping = {
 | |
|                 if: preset.parseTags(),
 | |
|                 then: "circle:white;./assets/layers/id_presets/" + preset.icon + ".svg"
 | |
|             }
 | |
|             mappings.push(mapping)
 | |
| 
 | |
|         }
 | |
| 
 | |
|         return mappings
 | |
|     }
 | |
| 
 | |
| 
 | |
|     /**
 | |
|      * Creates a tagRenderingConfigJson for the 'shop' theme
 | |
|      */
 | |
|     public readShopPresets(): MappingConfigJson[] {
 | |
| 
 | |
|         const dir = this._idPresetsRepository + "/data/presets/shop"
 | |
| 
 | |
|         const mappings: MappingConfigJson[] = []
 | |
|         const files = ScriptUtils.readDirRecSync(dir, 1);
 | |
|         for (const file of files) {
 | |
|             const name = file.substring(file.lastIndexOf('/') + 1, file.length - '.json'.length)
 | |
|             const preset = IdPreset.fromFile(file)
 | |
| 
 | |
|             if (preset.searchable === false) {
 | |
|                 continue
 | |
|             }
 | |
| 
 | |
|             console.log(`     ${name} (shop=${preset.tags["shop"]}), ${preset.icon}`)
 | |
| 
 | |
|             const thenClause: Record<string, string> = {
 | |
|                 en: preset.name
 | |
|             }
 | |
|             const terms: Record<string, string[]> = {
 | |
|                 en: preset.terms
 | |
|             }
 | |
|             for (const lng of this._knownLanguages) {
 | |
|                 const lngMc = lng.replace('-', '_')
 | |
|                 const tr = this.getTranslation(lng, "presets", "presets", "shop/" + name, "name")
 | |
|                 if (tr !== undefined) {
 | |
|                     thenClause[lngMc] = tr
 | |
|                 }
 | |
| 
 | |
|                 const termsTr = this.getTranslation(lng, "presets", "presets", "shop/" + name, "terms")
 | |
|                 if (termsTr !== undefined) {
 | |
|                     terms[lngMc] = termsTr.split(",")
 | |
|                 }
 | |
| 
 | |
|             }
 | |
| 
 | |
|             let tag = preset.parseTags();
 | |
|             const mapping : MappingConfigJson= {
 | |
|                 if: tag,
 | |
|                 then: thenClause,
 | |
|                 searchTerms: terms
 | |
|             }
 | |
|             if (preset.tags["shop"] == "yes") {
 | |
|                 mapping["hideInAnswer"] = true
 | |
|                 mapping.if["en"] = "Unspecified shop"
 | |
|             }
 | |
| 
 | |
|             if (this._iconThief.steal(preset.icon)) {
 | |
|                 mapping["icon"] = {
 | |
|                     path: "./assets/layers/id_presets/" + preset.icon + ".svg",
 | |
|                     class: "medium"
 | |
|                 }
 | |
|             } else {
 | |
|                 console.log(preset.icon + " could not be stolen :(")
 | |
|             }
 | |
| 
 | |
|             mappings.push(mapping)
 | |
| 
 | |
|         }
 | |
| 
 | |
|         return mappings
 | |
|     }
 | |
| 
 | |
|     private loadTranslationFile(language: string): object {
 | |
|         const cached = this._tranlationFiles[language]
 | |
|         if (cached) {
 | |
|             return cached
 | |
|         }
 | |
|         return this._tranlationFiles[language] = JSON.parse(readFileSync(`${this._idPresetsRepository}/dist/translations/${language}.json`, 'utf8'))
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| const targetDir = "./assets/layers/id_presets/"
 | |
| 
 | |
| const makiThief = new MakiThief('../maki/icons/', targetDir + "maki-", {
 | |
|     authors: ['Maki icon set'],
 | |
|     license: 'CC0',
 | |
|     path: null,
 | |
|     sources: ["https://github.com/mapbox/maki"]
 | |
| }, 'maki-');
 | |
| 
 | |
| 
 | |
| const temakiThief = new MakiThief('../temaki/icons/', targetDir + "temaki-", {
 | |
|     authors: ['Temaki icon set'],
 | |
|     license: 'CC0',
 | |
|     path: null,
 | |
|     sources: ["https://github.com/ideditor/temaki"]
 | |
| }, 'temaki-');
 | |
| const fasThief = new MakiThief('../Font-Awesome/svgs/solid/', targetDir + "fas-", {
 | |
|     authors: ['Font-Awesome icon set'],
 | |
|     license: 'CC-BY 4.0',
 | |
|     path: null,
 | |
|     sources: ["https://github.com/FortAwesome/Font-Awesome"]
 | |
| }, 'fas-');
 | |
| const iconThief = new AggregateIconThief(
 | |
|     [makiThief, temakiThief, fasThief]
 | |
| )
 | |
| 
 | |
| const thief = new IdThief("../id-tagging-schema/", iconThief)
 | |
| 
 | |
| const shopLayerPath = targetDir + "id_presets.json"
 | |
| const idPresets = <LayerConfigJson>JSON.parse(readFileSync(shopLayerPath, 'utf8'))
 | |
| idPresets.tagRenderings = [
 | |
|     {
 | |
|         id: "shop_types",
 | |
|         mappings: thief.readShopPresets()
 | |
|     },
 | |
|     {
 | |
|         id: "shop_rendering",
 | |
|         mappings: thief.readShopIcons()
 | |
|     }
 | |
| ]
 | |
| 
 | |
| writeFileSync(shopLayerPath, JSON.stringify(idPresets, null, "  "), 'utf8') |