chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2025-03-06 16:21:55 +01:00
parent 8109c13b38
commit 297bb1c498
185 changed files with 2826 additions and 5874 deletions

View file

@ -494,7 +494,7 @@ export class GenerateDocs extends Script {
MarkdownUtils.list(theme.language.filter((ln) => ln !== "_context")),
"# Layers defined in this theme configuration file",
"These layers can not be reused in different themes.",
...layersToInline.map((l) => l.generateDocumentation(null))
...layersToInline.map((l) => l.generateDocumentation(null)),
].join("\n")
this.WriteMarkdownFile(
"./Docs/Themes/" + theme.id + ".md",

View file

@ -9,12 +9,16 @@ import {
DoesImageExist,
PrevalidateTheme,
ValidateLayer,
ValidateThemeEnsemble
ValidateThemeEnsemble,
} from "../src/Models/ThemeConfig/Conversion/Validation"
import { Translation } from "../src/UI/i18n/Translation"
import { PrepareLayer } from "../src/Models/ThemeConfig/Conversion/PrepareLayer"
import { PrepareTheme } from "../src/Models/ThemeConfig/Conversion/PrepareTheme"
import { Conversion, DesugaringContext, DesugaringStep } from "../src/Models/ThemeConfig/Conversion/Conversion"
import {
Conversion,
DesugaringContext,
DesugaringStep,
} from "../src/Models/ThemeConfig/Conversion/Conversion"
import { Utils } from "../src/Utils"
import Script from "./Script"
import { AllSharedLayers } from "../src/Customizations/AllSharedLayers"
@ -283,9 +287,9 @@ class LayerOverviewUtils extends Script {
| LayerConfigJson
| string
| {
builtin
}
)[]
builtin
}
)[]
}[],
sharedLayers: Map<string, LayerConfigJson>
) {
@ -316,8 +320,8 @@ class LayerOverviewUtils extends Script {
keywords,
layers: (<LayerConfigJson[]>theme.layers)
.filter((l) => sharedLayers.has(l.id))
.filter(l => l.minzoom < 17)
.map((l) => l.id)
.filter((l) => l.minzoom < 17)
.map((l) => l.id),
}
perId.set(data.id, data)
}
@ -392,10 +396,10 @@ class LayerOverviewUtils extends Script {
tagRenderings: bootstrapTagRenderings,
tagRenderingOrder: bootstrapTagRenderingsOrder,
sharedLayers: null,
publicLayers: null
publicLayers: null,
},
{
addTagRenderingsToContext: true
addTagRenderingsToContext: true,
}
)
@ -431,7 +435,7 @@ class LayerOverviewUtils extends Script {
"src/assets/SocialImageBanner.svg",
"src/assets/SocialImageRepo.svg",
"src/assets/svg/osm-logo.svg",
"src/assets/templates/*"
"src/assets/templates/*",
]
for (const path of allSvgs) {
if (
@ -456,8 +460,8 @@ class LayerOverviewUtils extends Script {
if (contents.indexOf("<text") > 0) {
console.warn(
"The SVG at " +
path +
" contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path"
path +
" contains a `text`-tag. This is highly discouraged. Every machine viewing your theme has their own font libary, and the font you choose might not be present, resulting in a different font being rendered. Solution: open your .svg in inkscape (or another program), select the text and convert it to a path"
)
errCount++
}
@ -529,7 +533,7 @@ class LayerOverviewUtils extends Script {
JSON.stringify({
layers: Array.from(sharedLayers.values()).filter(
(l) => !(l["#no-index"] === "yes")
)
),
})
)
}
@ -546,11 +550,11 @@ class LayerOverviewUtils extends Script {
// 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
then: th.icon,
}))
const proto: ThemeConfigJson = JSON.parse(
readFileSync("./assets/themes/mapcomplete-changes/mapcomplete-changes.proto.json", {
encoding: "utf8"
encoding: "utf8",
})
)
const protolayer = <LayerConfigJson>(
@ -566,7 +570,7 @@ class LayerOverviewUtils extends Script {
new DetectDuplicateFilters().convertStrict(
{
layers: ScriptUtils.getLayerFiles().map((f) => f.parsed),
themes: ScriptUtils.getThemeFiles().map((f) => f.parsed)
themes: ScriptUtils.getThemeFiles().map((f) => f.parsed),
},
ConversionContext.construct([], [])
)
@ -614,7 +618,7 @@ class LayerOverviewUtils extends Script {
const state: DesugaringContext = {
tagRenderings: LayerOverviewUtils.asDict(sharedTagRenderings),
tagRenderingOrder: sharedTagRenderings.map((tr) => tr.id),
sharedLayers: AllSharedLayers.getSharedLayersConfigs()
sharedLayers: AllSharedLayers.getSharedLayersConfigs(),
}
const sharedLayers = new Map<string, LayerConfigJson>()
const prepLayer = new PrepareLayer(state)
@ -659,12 +663,12 @@ class LayerOverviewUtils extends Script {
console.log(
"Recompiled layers " +
recompiledLayers.join(", ") +
" and skipped " +
skippedLayers.length +
" layers. Detected " +
warningCount +
" warnings"
recompiledLayers.join(", ") +
" and skipped " +
skippedLayers.length +
" layers. Detected " +
warningCount +
" warnings"
)
// We always need the calculated tags of 'usersettings', so we export them separately
this.extractJavascriptCodeForLayer(
@ -686,11 +690,11 @@ class LayerOverviewUtils extends Script {
private extractJavascriptCode(themeFile: ThemeConfigJson) {
const allCode = [
"import {Feature} from 'geojson'",
"import { ExtraFuncType } from \"../../../Logic/ExtraFunctions\";",
"import { Utils } from \"../../../Utils\"",
'import { ExtraFuncType } from "../../../Logic/ExtraFunctions";',
'import { Utils } from "../../../Utils"',
"export class ThemeMetaTagging {",
" public static readonly themeName = " + JSON.stringify(themeFile.id),
""
"",
]
for (const layer of themeFile.layers) {
const l = <LayerConfigJson>layer
@ -699,8 +703,8 @@ class LayerOverviewUtils extends Script {
allCode.push(
" public metaTaggging_for_" +
id +
"(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {"
id +
"(feat: Feature, helperFunctions: Record<ExtraFuncType, (feature: Feature) => Function>) {"
)
allCode.push(" const {" + ExtraFunctions.types.join(", ") + "} = helperFunctions")
for (const line of code) {
@ -711,10 +715,10 @@ class LayerOverviewUtils extends Script {
if (!isStrict) {
allCode.push(
" Utils.AddLazyProperty(feat.properties, '" +
attributeName +
"', () => " +
expression +
" ) "
attributeName +
"', () => " +
expression +
" ) "
)
} else {
attributeName = attributeName.substring(0, attributeName.length - 1).trim()
@ -754,7 +758,7 @@ class LayerOverviewUtils extends Script {
`/** This code is autogenerated - do not edit. Edit ./assets/layers/${l?.id}/${l?.id}.json instead */`,
"export class ThemeMetaTagging {",
" public static readonly themeName = " + JSON.stringify(l.id),
""
"",
]
const code = l.calculatedTags ?? []
@ -769,10 +773,10 @@ class LayerOverviewUtils extends Script {
if (!isStrict) {
allCode.push(
" Utils.AddLazyProperty(feat.properties, '" +
attributeName +
"', () => " +
expression +
" ) "
attributeName +
"', () => " +
expression +
" ) "
)
} else {
attributeName = attributeName.substring(0, attributeName.length - 2).trim()
@ -813,7 +817,7 @@ class LayerOverviewUtils extends Script {
sharedLayers,
tagRenderings: LayerOverviewUtils.asDict(trs),
tagRenderingOrder: trs.map((tr) => tr.id),
publicLayers
publicLayers,
}
const knownTagRenderings = new Set<string>()
convertState.tagRenderings.forEach((_, key) => knownTagRenderings.add(key))
@ -870,7 +874,7 @@ class LayerOverviewUtils extends Script {
)
try {
themeFile = new PrepareTheme(convertState, {
skipDefaultLayers: true
skipDefaultLayers: true,
}).convertStrict(
themeFile,
ConversionContext.construct([themePath], ["PrepareLayer"])
@ -919,7 +923,7 @@ class LayerOverviewUtils extends Script {
const e: string = [
`the icon for theme ${themeFile.id} is too small. Please rescale the icon at ${themeFile.icon}`,
`Even though an SVG is 'infinitely scaleable', the icon should be dimensioned bigger. One of the build steps of the theme does convert the image to a PNG (to serve as PWA-icon) and having a small dimension will cause blurry images.`,
` Width = ${width} height = ${height}; we recommend a size of at least 500px * 500px and to use a square aspect ratio.`
` Width = ${width} height = ${height}; we recommend a size of at least 500px * 500px and to use a square aspect ratio.`,
].join("\n")
err(e)
}
@ -956,7 +960,7 @@ class LayerOverviewUtils extends Script {
hideFromOverview: t.hideFromOverview ?? false,
shortDescription:
t.shortDescription ?? new Translation(t.description).FirstSentence(),
mustHaveLanguage: t.mustHaveLanguage?.length > 0
mustHaveLanguage: t.mustHaveLanguage?.length > 0,
}
}),
sharedLayers
@ -965,10 +969,10 @@ class LayerOverviewUtils extends Script {
console.log(
"Recompiled themes " +
recompiledThemes.join(", ") +
" and skipped " +
skippedThemes.length +
" themes"
recompiledThemes.join(", ") +
" and skipped " +
skippedThemes.length +
" themes"
)
return fixed

View file

@ -107,9 +107,9 @@ class GenerateLayouts extends Script {
if (!layout.icon.endsWith(".svg")) {
console.warn(
"Not creating a social image for " +
layout.id +
" as it is _not_ a .svg: " +
layout.icon
layout.id +
" as it is _not_ a .svg: " +
layout.icon
)
return undefined
}
@ -142,9 +142,9 @@ class GenerateLayouts extends Script {
id: "icon",
transform: `translate(${cx - r},${cy - r}) scale(${
(r * 2) / Number(width)
}) `
}) `,
},
g: [svg]
g: [svg],
}
},
(mightBeTokenToReplace) => {
@ -205,19 +205,19 @@ class GenerateLayouts extends Script {
icons.push({
src: name,
sizes: size + "x" + size,
type: "image/png"
type: "image/png",
})
}
icons.push({
src: path,
sizes: "513x513",
type: "image/svg"
type: "image/svg",
})
} else if (icon.endsWith(".png")) {
icons.push({
src: icon,
sizes: "513x513",
type: "image/png"
type: "image/png",
})
} else {
console.log(icon)
@ -236,11 +236,11 @@ class GenerateLayouts extends Script {
description: ogDescr,
orientation: "portrait-primary, landscape-primary",
icons: icons,
categories: ["map", "navigation"]
categories: ["map", "navigation"],
}
return {
manifest,
whiteIcons
whiteIcons,
}
}
@ -251,7 +251,7 @@ class GenerateLayouts extends Script {
if (lang === "_context") {
continue
}
let display = " style=\"display: none\""
let display = ' style="display: none"'
if (!defaultSet) {
display = ""
defaultSet = true
@ -272,7 +272,7 @@ class GenerateLayouts extends Script {
...eli.features,
bing,
...eli_global.map((properties) => ({ properties })),
...layers_global.layers.map((properties) => ({ properties }))
...layers_global.layers.map((properties) => ({ properties })),
]
for (const feature of rasterLayers) {
const f = <RasterLayerPolygon>feature
@ -293,7 +293,7 @@ class GenerateLayouts extends Script {
url = url.substring("pmtiles://".length)
}
const styleSpec = await Utils.downloadJsonCached(url, 1000 * 120, {
Origin: "https://mapcomplete.org"
Origin: "https://mapcomplete.org",
})
urls.push(...(f.properties["connect-src"] ?? []))
for (const key of Object.keys(styleSpec?.["sources"] ?? {})) {
@ -309,7 +309,7 @@ class GenerateLayouts extends Script {
urls.push(url)
if (urlClipped.endsWith(".json")) {
const tileInfo = await Utils.downloadJsonCached(url, 1000 * 120, {
Origin: "https://mapcomplete.org"
Origin: "https://mapcomplete.org",
})
urls.push(tileInfo["tiles"] ?? [])
}
@ -338,7 +338,7 @@ class GenerateLayouts extends Script {
"https://api.panoramax.xyz",
"https://panoramax.mapcomplete.org",
"https://data.velopark.be",
"https://data.mapcomplete.org"
"https://data.mapcomplete.org",
].concat(...(await this.eliUrls()))
SpecialVisualizations.specialVisualizations.forEach((sv) => {
@ -433,17 +433,15 @@ class GenerateLayouts extends Script {
"script-src": [
"'self'",
"https://gc.zgo.at/count.js",
...(options?.scriptSrcs?.map((s) => "'" + s + "'") ?? [])
...(options?.scriptSrcs?.map((s) => "'" + s + "'") ?? []),
].join(" "),
"connect-src": "'self' " + connectSrc.join(" ")
"connect-src": "'self' " + connectSrc.join(" "),
}
const content = Object.keys(csp)
.map((k) => k + " " + csp[k])
.join(" ; ")
return [
`<meta http-equiv="Content-Security-Policy" content="${content}">`
].join("\n")
return [`<meta http-equiv="Content-Security-Policy" content="${content}">`].join("\n")
}
async createLandingPage(
@ -454,12 +452,12 @@ class GenerateLayouts extends Script {
) {
Locale.language.setData(layout.language[0])
const targetLanguage = layout.language[0]
const ogTitle = Translations.T(layout.title).textFor(targetLanguage).replace(/"/g, "\\\"")
const ogTitle = Translations.T(layout.title).textFor(targetLanguage).replace(/"/g, '\\"')
const ogDescr = Translations.T(
layout.shortDescription ?? "Easily add and edit geodata with OpenStreetMap"
)
.textFor(targetLanguage)
.replace(/"/g, "\\\"")
.replace(/"/g, '\\"')
let ogImage = layout.socialImage
let twitterImage = ogImage
if (ogImage === ThemeConfig.defaultSocialImage && layout.official) {
@ -530,7 +528,7 @@ class GenerateLayouts extends Script {
og,
customCss,
`<link rel="icon" href="${icon}" sizes="any" type="image/svg+xml">`,
...apple_icons
...apple_icons,
].join("\n")
let branchname = await this.getBranchName()
@ -553,7 +551,7 @@ class GenerateLayouts extends Script {
.replace(
/<!-- CSP -->/,
await this.generateCsp(layout, layoutJson, {
scriptSrcs: [this.removeOtherLanguagesHash]
scriptSrcs: [this.removeOtherLanguagesHash],
})
)
.replace(
@ -584,7 +582,7 @@ class GenerateLayouts extends Script {
const imports = [
`import theme from "./public/assets/generated/themes/${theme.id}.json"`,
`import { ThemeMetaTagging } from "./src/assets/generated/metatagging/${theme.id}"`
`import { ThemeMetaTagging } from "./src/assets/generated/metatagging/${theme.id}"`,
]
for (const layerName of Constants.added_by_default) {
imports.push(
@ -631,7 +629,7 @@ class GenerateLayouts extends Script {
"account",
"openstreetmap",
"custom",
"theme"
"theme",
]
const args = process.argv
const theme = args[2]
@ -682,7 +680,7 @@ class GenerateLayouts extends Script {
startLon: 0,
startZoom: 0,
title: { en: "MapComplete" },
description: { en: "A thematic map viewer and editor based on OpenStreetMap" }
description: { en: "A thematic map viewer and editor based on OpenStreetMap" },
}),
alreadyWritten
)

View file

@ -60,7 +60,7 @@ export default class GenerateReviewsAnalysis extends Script {
geojsonFeatures.push({
geometry: {
type: "Point",
coordinates: [lon, lat]
coordinates: [lon, lat],
},
type: "Feature",
properties: {
@ -69,8 +69,8 @@ export default class GenerateReviewsAnalysis extends Script {
opinion: review.opinion,
client: review.metadata.client_id,
nickname: review.metadata.nickname,
affiliated: "" + review.metadata.is_affiliated
}
affiliated: "" + review.metadata.is_affiliated,
},
})
} catch (e) {
console.error(e)
@ -78,8 +78,13 @@ export default class GenerateReviewsAnalysis extends Script {
}
console.log("Total number of reviews", reviews.length)
const aliases = ["mapcomplete.osm.be", "pietervdvn.github.io", "dev.mapcomplete.org", "127.0.0.1:1234", "localhost:1234"]
const aliases = [
"mapcomplete.osm.be",
"pietervdvn.github.io",
"dev.mapcomplete.org",
"127.0.0.1:1234",
"localhost:1234",
]
for (const alias of aliases) {
clientWebsites["mapcomplete.org"] += clientWebsites[alias]
delete clientWebsites[alias]
@ -90,7 +95,7 @@ export default class GenerateReviewsAnalysis extends Script {
this.print("language", languageHist)
const fc: FeatureCollection = {
type: "FeatureCollection",
features: geojsonFeatures
features: geojsonFeatures,
}
const fcmc: FeatureCollection = {
@ -99,7 +104,7 @@ export default class GenerateReviewsAnalysis extends Script {
(f) =>
f.properties.client.indexOf("mapcomplete") >= 0 ||
f.properties.client.indexOf("pietervdvn.github.io") >= 0
)
),
}
if (!fs.existsSync("./reviews-analysis")) {
fs.mkdirSync("./reviews-analysis")
@ -163,10 +168,10 @@ export default class GenerateReviewsAnalysis extends Script {
"rating",
"opinion",
"images",
"metadata"
"metadata",
]
return new Promise<Review[]>((resolve) => {
const parser = parse({ delimiter: "," }, function(err, data) {
const parser = parse({ delimiter: "," }, function (err, data) {
const asJson: Review[] = []
for (let i = 1; i < data.length; i++) {
const line = data[i]

View file

@ -156,7 +156,12 @@ class GenerateStats extends Script {
)
const batchSize = 50
for (let i = 0; i < allBrandNames.length; i += batchSize) {
console.warn("Downloading ", batchSize, "occurence counts, items: ", i + "/" + allBrandNames.length)
console.warn(
"Downloading ",
batchSize,
"occurence counts, items: ",
i + "/" + allBrandNames.length
)
let downloaded = 0
await Promise.all(
Utils.TimesT(batchSize, async (j) => {

View file

@ -155,7 +155,8 @@ function generateTagInfoEntry(layout: ThemeConfig): any {
name: "MapComplete " + layout.title.txt, // name of the project (required)
description: layout.shortDescription.txt, // short description of the project (required)
project_url: "https://mapcomplete.org/" + layout.id, // home page of the project with general information (required)
doc_url: "https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/Themes", // documentation of the project and especially the tags used (optional)
doc_url:
"https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/Docs/Themes", // documentation of the project and especially the tags used (optional)
icon_url: "https://mapcomplete.org/" + icon, // project logo, should work in 16x16 pixels on white and light gray backgrounds (optional)
contact_name: "Pieter Vander Vennet", // contact name, needed for taginfo maintainer (required)
contact_email: "pietervdvn@posteo.net", // contact email, needed for taginfo maintainer (required)