2023-07-17 22:04:35 +02:00
import { AllKnownLayouts } from "../src/Customizations/AllKnownLayouts"
import Locale from "../src/UI/i18n/Locale"
import { Translation } from "../src/UI/i18n/Translation"
2021-05-05 11:30:44 +02:00
import { readFileSync , writeFileSync } from "fs"
2024-10-17 04:06:03 +02:00
import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig"
2023-07-17 22:04:35 +02:00
import LayerConfig from "../src/Models/ThemeConfig/LayerConfig"
import { Utils } from "../src/Utils"
2021-04-19 18:17:26 +02:00
2021-05-04 17:46:45 +02:00
/ * *
* Generates all the files in "Docs/TagInfo" . These are picked up by the taginfo project , showing a link to the mapcomplete theme if the key is used
* /
2021-04-19 18:17:26 +02:00
const outputDirectory = "Docs/TagInfo"
2021-09-09 00:05:51 +02:00
function generateTagOverview (
kv : { k : string ; v : string } ,
description : string
) : {
2021-06-24 14:02:18 +02:00
key : string
description : string
value? : string
} {
2021-04-20 11:54:45 +02:00
const overview = {
// OSM tag key (required)
key : kv.k ,
2021-06-24 14:02:18 +02:00
description : description ,
2021-09-09 00:05:51 +02:00
value : undefined ,
2021-04-20 11:54:45 +02:00
}
if ( kv . v !== undefined ) {
// OSM tag value (optional, if not supplied it means "all values")
2021-06-24 14:02:18 +02:00
overview . value = kv . v
2021-04-20 11:54:45 +02:00
}
return overview
}
2024-10-17 04:06:03 +02:00
function generateLayerUsage ( layer : LayerConfig , layout : ThemeConfig ) : any [ ] {
2021-09-09 00:05:51 +02:00
if ( layer . name === undefined ) {
2021-07-28 00:12:14 +02:00
return [ ] // Probably a duplicate or irrelevant layer
}
2021-09-09 00:05:51 +02:00
2021-04-19 18:17:26 +02:00
const usedTags = layer . source . osmTags . asChange ( { } )
2021-09-09 00:05:51 +02:00
const result : {
2021-06-24 14:02:18 +02:00
key : string
description : string
value? : string
} [ ] = [ ]
2021-04-19 18:17:26 +02:00
for ( const kv of usedTags ) {
2021-04-20 11:54:45 +02:00
const description =
"The MapComplete theme " +
layout . title . txt +
" has a layer " +
layer . name . txt +
" showing features with this tag"
result . push ( generateTagOverview ( kv , description ) )
}
for ( const tr of layer . tagRenderings ) {
2022-12-23 17:42:53 +01:00
let condition = tr . condition ? . asHumanString ( false , false , { } ) ? ? ""
if ( condition !== "" ) {
condition = ` (This is only shown if ${ condition } ) `
}
2021-05-04 17:46:45 +02:00
{
2021-07-03 22:00:36 +02:00
const usesImageCarousel = ( tr . render ? . txt ? . indexOf ( "image_carousel" ) ? ? - 2 ) > 0
const usesImageUpload = ( tr . render ? . txt ? . indexOf ( "image_upload" ) ? ? - 2 ) > 0
2021-05-04 17:46:45 +02:00
if ( usesImageCarousel || usesImageUpload ) {
2024-10-29 18:45:13 +01:00
const descrNoUpload = ` The layer ' ${ layer . name . txt } shows images based on the keys image, image:0, image:1,..., panoramax, panoramax:0, panoramx:1, ... , wikidata, wikipedia, wikimedia_commons and mapillary `
const descrUpload = ` The layer ' ${ layer . name . txt } allows to upload images and adds them under the 'panoramax'-tag (and panoramax:0, panoramax:1, ... for multiple images). Furthermore, this layer shows images based on the keys panoramax, image, wikidata, wikipedia, wikimedia_commons and mapillary `
2022-09-08 21:40:48 +02:00
2022-12-23 17:42:53 +01:00
const descr = ( usesImageUpload ? descrUpload : descrNoUpload ) + condition
2021-05-04 17:46:45 +02:00
result . push ( generateTagOverview ( { k : "image" , v : undefined } , descr ) )
2024-10-29 18:45:13 +01:00
result . push ( generateTagOverview ( { k : "panoramax" , v : undefined } , descr ) )
2021-05-04 17:46:45 +02:00
result . push ( generateTagOverview ( { k : "mapillary" , v : undefined } , descr ) )
result . push ( generateTagOverview ( { k : "wikidata" , v : undefined } , descr ) )
result . push ( generateTagOverview ( { k : "wikipedia" , v : undefined } , descr ) )
}
}
2021-04-20 11:54:45 +02:00
const q = tr . question ? . txt
const key = tr . freeform ? . key
if ( key != undefined ) {
2021-04-21 18:51:12 +02:00
let descr = ` Layer ' ${ layer . name . txt } ' `
2021-04-20 11:54:45 +02:00
if ( q == undefined ) {
descr += " shows values with"
} else {
descr += " shows and asks freeform values for"
}
2023-08-23 18:33:30 +02:00
descr += ` key ' ${ key } ' (in the mapcomplete.org theme ' ${ layout . title . txt } ') `
2022-12-23 17:42:53 +01:00
result . push ( generateTagOverview ( { k : key , v : undefined } , descr + condition ) )
2021-04-20 11:54:45 +02:00
}
const mappings = tr . mappings ? ? [ ]
for ( const mapping of mappings ) {
2021-04-21 18:51:12 +02:00
let descr = "Layer '" + layer . name . txt + "'"
2021-04-20 11:54:45 +02:00
descr +=
" shows " +
mapping . if . asHumanString ( false , false , { } ) +
" with a fixed text, namely '" +
mapping . then . txt +
"'"
if (
q != undefined &&
mapping . hideInAnswer != true // != true will also match if a
) {
2021-04-21 18:51:12 +02:00
descr += " and allows to pick this as a default answer"
2021-04-20 11:54:45 +02:00
}
2023-08-23 18:33:30 +02:00
descr += ` (in the mapcomplete.org theme ' ${ layout . title . txt } ') `
2021-04-20 11:54:45 +02:00
for ( const kv of mapping . if . asChange ( { } ) ) {
let d = descr
2021-05-04 17:46:45 +02:00
if ( q != undefined && kv . v == "" ) {
2021-04-20 11:54:45 +02:00
d = ` ${ descr } Picking this answer will delete the key ${ kv . k } . `
}
2022-12-23 17:42:53 +01:00
result . push ( generateTagOverview ( kv , d + condition ) )
2021-04-20 11:54:45 +02:00
}
2021-04-19 18:17:26 +02:00
}
}
2021-09-09 00:05:51 +02:00
2021-06-24 14:02:18 +02:00
return result . filter ( ( result ) = > ! result . key . startsWith ( "_" ) )
2021-04-19 18:17:26 +02:00
}
/ * *
* Generates the JSON - object representing the theme for inclusion on taginfo
* @param layout
* /
2024-10-17 04:06:03 +02:00
function generateTagInfoEntry ( layout : ThemeConfig ) : any {
2021-04-19 18:17:26 +02:00
const usedTags = [ ]
for ( const layer of layout . layers ) {
2023-03-25 02:48:24 +01:00
if ( layer . source === null ) {
2022-03-12 16:30:43 +01:00
continue
}
if ( layer . source . geojsonSource !== undefined && layer . source . isOsmCacheLayer !== true ) {
continue
}
2021-04-19 18:17:26 +02:00
usedTags . push ( . . . generateLayerUsage ( layer , layout ) )
}
2022-09-08 21:40:48 +02:00
2022-03-12 16:35:27 +01:00
if ( usedTags . length == 0 ) {
return undefined
}
2021-04-19 18:17:26 +02:00
let icon = layout . icon
if ( icon . startsWith ( "./" ) ) {
icon = icon . substring ( 2 )
}
const themeInfo = {
// data format version, currently always 1, will get updated if there are incompatible changes to the format (required)
data_format : 1 ,
2022-03-12 16:30:43 +01:00
// timestamp when project file was updated is not given as it pollutes the github history
2021-04-19 18:17:26 +02:00
project : {
name : "MapComplete " + layout . title . txt , // name of the project (required)
description : layout.shortDescription.txt , // short description of the project (required)
2023-08-23 18:33:30 +02:00
project_url : "https://mapcomplete.org/" + layout . id , // home page of the project with general information (required)
2021-04-19 18:17:26 +02:00
doc_url : "https://github.com/pietervdvn/MapComplete/tree/master/assets/themes/" , // documentation of the project and especially the tags used (optional)
2023-08-23 18:33:30 +02:00
icon_url : "https://mapcomplete.org/" + icon , // project logo, should work in 16x16 pixels on white and light gray backgrounds (optional)
2022-08-24 14:48:33 +02:00
contact_name : "Pieter Vander Vennet" , // contact name, needed for taginfo maintainer (required)
2021-04-19 18:17:26 +02:00
contact_email : "pietervdvn@posteo.net" , // contact email, needed for taginfo maintainer (required)
} ,
tags : usedTags ,
}
const filename = "mapcomplete_" + layout . id
console . log ( "Writing info about " + layout . id )
2021-09-09 00:30:48 +02:00
writeFileSync ( ` ${ outputDirectory } / ${ filename } .json ` , JSON . stringify ( themeInfo , null , 2 ) )
2021-04-19 18:17:26 +02:00
return filename
}
2021-05-07 12:39:37 +02:00
// Write the URLS to the taginfo repository. Might fail if the repository is not checked ou
2022-03-12 16:35:27 +01:00
function generateProjectsOverview ( files : string [ ] ) {
2021-05-07 12:39:37 +02:00
try {
const tagInfoList = "../taginfo-projects/project_list.txt"
2023-01-15 23:28:02 +01:00
let projectList = readFileSync ( tagInfoList , { encoding : "utf8" } )
2021-05-07 12:39:37 +02:00
. split ( "\n" )
. filter ( ( entry ) = > entry . indexOf ( "mapcomplete_" ) < 0 )
2022-03-12 16:42:14 +01:00
. concat (
files . map (
( f ) = >
` ${ f } https://raw.githubusercontent.com/pietervdvn/MapComplete/develop/Docs/TagInfo/ ${ f } .json `
2022-09-08 21:40:48 +02:00
)
)
2021-05-07 12:39:37 +02:00
. sort ( )
. filter ( ( entry ) = > entry != "" )
console . log ( "Writing taginfo project filelist" )
writeFileSync ( tagInfoList , projectList . join ( "\n" ) + "\n" )
} catch ( e ) {
console . warn (
"Could not write the taginfo-projects list - the repository is probably not checked out. Are you creating a fork? Ignore this message then."
)
}
}
2022-03-12 16:35:27 +01:00
function main() {
2021-04-19 18:17:26 +02:00
console . log ( "Creating taginfo project files" )
2021-05-07 12:39:37 +02:00
2021-04-19 18:17:26 +02:00
Locale . language . setData ( "en" )
Translation . forcedLanguage = "en"
2022-03-12 16:35:27 +01:00
const files = [ ]
2022-09-08 21:40:48 +02:00
2023-03-02 05:20:53 +01:00
for ( const layout of AllKnownLayouts . allKnownLayouts . values ( ) ) {
2022-03-12 16:35:27 +01:00
if ( layout . hideFromOverview ) {
continue
}
2024-11-07 11:19:15 +01:00
if ( layout . id === "personal" ) {
2024-11-01 14:08:06 +01:00
continue
}
2022-03-12 16:35:27 +01:00
files . push ( generateTagInfoEntry ( layout ) )
2021-04-19 18:17:26 +02:00
}
2022-03-12 16:35:27 +01:00
generateProjectsOverview ( Utils . NoNull ( files ) )
2021-04-19 18:17:26 +02:00
}
2022-03-12 16:35:27 +01:00
main ( )