chore: automated housekeeping...

This commit is contained in:
Pieter Vander Vennet 2025-10-11 14:03:42 +02:00
parent d3b6c090f3
commit 332f960f86
57 changed files with 2884 additions and 1972 deletions

View file

@ -46,8 +46,7 @@ class ToSlideshowJson {
}
public convert() {
const lines = readFileSync(this._source, "utf8")
.split("\n")
const lines = readFileSync(this._source, "utf8").split("\n")
const sections: string[][] = []
let currentSection: string[] = []
@ -159,10 +158,10 @@ export class GenerateDocs extends Script {
this.generateEliDocs()
this.generateBuiltinUnits()
this.writeMarkdownFile("./Docs/Studio/SpecialInputElements.md", Validators.HelpText(), [
"src/UI/InputElement/Validators.ts"
"src/UI/InputElement/Validators.ts",
])
this.writeMarkdownFile("./Docs/Studio/Tags_format.md", TagUtils.generateDocs(), [
"src/Logic/Tags/TagUtils.ts"
"src/Logic/Tags/TagUtils.ts",
])
this.writeMarkdownFile(
@ -170,7 +169,7 @@ export class GenerateDocs extends Script {
SpecialVisualizations.HelpMessage(),
["src/UI/SpecialVisualizations.ts"],
{
tocMaxDepth: 3
tocMaxDepth: 3,
}
)
this.writeMarkdownFile(
@ -181,7 +180,6 @@ export class GenerateDocs extends Script {
)
}
// For dev
{
this.generateQueryParameterDocs()
@ -208,13 +206,12 @@ export class GenerateDocs extends Script {
ScriptUtils.erasableLog("Written docs for theme", theme.id)
})
this.generateOverviewsForAllSingleLayer("./Docs/nl/Layers", "nl")
}
this.writeMarkdownFile("./Docs/ChangesetMeta.md", Changes.getDocs(), [
"src/Logic/Osm/Changes.ts",
"src/Logic/Osm/ChangesetHandler.ts"
"src/Logic/Osm/ChangesetHandler.ts",
])
new WikiPageGenerator().generate()
@ -224,9 +221,11 @@ export class GenerateDocs extends Script {
this.generateSidebar("nl")
this.generatedPaths.push(".gitignore")
writeFileSync("./Docs/.gitignore", this.generatedPaths
.map(p => p.replace("./Docs/", ""))
.join("\n"), "utf-8")
writeFileSync(
"./Docs/.gitignore",
this.generatedPaths.map((p) => p.replace("./Docs/", "")).join("\n"),
"utf-8"
)
console.log("Generated docs")
}
@ -238,7 +237,7 @@ export class GenerateDocs extends Script {
options?: {
noTableOfContents?: boolean
tocMaxDepth?: number
lang?: string,
lang?: string
noWarn?: boolean
}
): void {
@ -269,25 +268,31 @@ export class GenerateDocs extends Script {
md += "\n"
}
const warnAutomated = options?.noWarn ? "" :
"[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)\n\n"
const warnAutomated = options?.noWarn
? ""
: "[//]: # (WARNING: this file is automatically generated. Please find the sources at the bottom and edit those sources)\n\n"
const sources = autogenSource
.map(
(s) =>
`[${s}](https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/${s})`
)
.join(", ")
const sources = autogenSource.map(
(s) => `[${s}](https://source.mapcomplete.org/MapComplete/MapComplete/src/branch/develop/${s})`).join(", ")
const generatedFrom = new TypedTranslation<{ sources; date }>({
en: "This document is autogenerated from {sources} on {date}",
nl: "Dit document werd gegenereerd op basis van {sources} op {date}",
})
.Subs({ sources, date: new Date().toDateString() })
.textFor(lang)
const generatedFrom =
new TypedTranslation<{ sources, date }>({
en: "This document is autogenerated from {sources} on {date}",
nl: "Dit document werd gegenereerd op basis van {sources} op {date}"
}).Subs({ sources, date: new Date().toDateString() }).textFor(lang)
writeFileSync(filename, warnAutomated + md + (options?.noWarn ? "" : "\n\n" + generatedFrom + "\n"))
writeFileSync(
filename,
warnAutomated + md + (options?.noWarn ? "" : "\n\n" + generatedFrom + "\n")
)
this.generatedPaths.push(filename)
}
private generateEliDocs() {
const eli = AvailableRasterLayers.editorLayerIndex()
this.writeMarkdownFile(
@ -295,8 +300,8 @@ export class GenerateDocs extends Script {
[
"# Layers in the Editor Layer Index",
"This table gives a summary of ids, names and other metainformation of background imagery that is available in MapComplete and that can be used as (default) map background." +
"These are sourced from [the Editor Layer Index](https://github.com/osmlab/editor-layer-index)", +
"\n[See the online, interactive map here](https://osmlab.github.io/editor-layer-index/)",
"These are sourced from [the Editor Layer Index](https://github.com/osmlab/editor-layer-index)",
+"\n[See the online, interactive map here](https://osmlab.github.io/editor-layer-index/)",
MarkdownUtils.table(
["id", "name", "category", "Best", "attribution"],
eli.map((f) => [
@ -305,10 +310,10 @@ export class GenerateDocs extends Script {
f.properties.category,
f.properties.best ? "⭐" : "",
f.properties.attribution?.html ?? f.properties.attribution?.text,
]),
])
),
].join("\n\n"),
["./public/assets/data/editor-layer-index.json"],
["./public/assets/data/editor-layer-index.json"]
)
}
@ -367,7 +372,10 @@ export class GenerateDocs extends Script {
* Generates documentation for the all the individual layers.
* Inline layers are included (if the theme is public)
*/
private generateOverviewsForAllSingleLayer(targetDirectory: string = "./Docs/Layers", lang: string = "en"): void {
private generateOverviewsForAllSingleLayer(
targetDirectory: string = "./Docs/Layers",
lang: string = "en"
): void {
const allLayers: LayerConfig[] = Array.from(AllSharedLayers.sharedLayers.values()).filter(
(layer) => layer["source"] !== null
)
@ -434,19 +442,23 @@ export class GenerateDocs extends Script {
mkdirSync(targetDirectory)
}
allLayers.forEach((layer) => {
const element = layer.generateDocumentation({
usedInThemes: themesPerLayer.get(layer.id),
layerIsNeededBy: layerIsNeededBy,
dependencies: DependencyCalculator.getLayerDependencies(layer),
lang
}).replaceAll("./Docs/Layers", targetDirectory)
const element = layer
.generateDocumentation({
usedInThemes: themesPerLayer.get(layer.id),
layerIsNeededBy: layerIsNeededBy,
dependencies: DependencyCalculator.getLayerDependencies(layer),
lang,
})
.replaceAll("./Docs/Layers", targetDirectory)
const inlineSource = inlineLayers.get(layer.id)
ScriptUtils.erasableLog("Exporting layer documentation for", layer.id)
let source: string = `assets/layers/${layer.id}/${layer.id}.json`
if (inlineSource !== undefined) {
source = `assets/themes/${inlineSource}/${inlineSource}.json`
}
this.writeMarkdownFile(targetDirectory + "/" + layer.id + ".md", element, [source], { lang })
this.writeMarkdownFile(targetDirectory + "/" + layer.id + ".md", element, [source], {
lang,
})
})
}
@ -491,17 +503,24 @@ export class GenerateDocs extends Script {
}
const docs: string[] = [
"# Which tagrendering is used where?", "",
"This document details where a tagRendering from one layer is reused in another layer, either by directly using it or by using a `{\"builtin\": id, \"override\": ...}` syntax",
"# Which tagrendering is used where?",
"",
'This document details where a tagRendering from one layer is reused in another layer, either by directly using it or by using a `{"builtin": id, "override": ...}` syntax',
"Having this overview supports e.g. refactoring efforts",
"## Existing builtin tagrenderings", ""]
"## Existing builtin tagrenderings",
"",
]
for (const [builtin, usedByLayers] of Array.from(layersUsingBuiltin.entries())) {
docs.push(`### ${builtin}\n`)
docs.push(usedByLayers.length + " usages")
docs.push(`${usedByLayers.map((item) => ` - [${item}](./Docs/Layers/${item}.md)`).join("\n")}`)
docs.push(
`${usedByLayers.map((item) => ` - [${item}](./Docs/Layers/${item}.md)`).join("\n")}`
)
}
this.writeMarkdownFile("./Docs/Studio/TagRendering_reuse_overview.md", docs.join("\n"), ["assets/layers/*.json"])
this.writeMarkdownFile("./Docs/Studio/TagRendering_reuse_overview.md", docs.join("\n"), [
"assets/layers/*.json",
])
}
private generateQueryParameterDocs() {
@ -537,7 +556,7 @@ export class GenerateDocs extends Script {
])
}
private generateForTheme(theme: ThemeConfig, options?: { path?: string, lang?: string }): void {
private generateForTheme(theme: ThemeConfig, options?: { path?: string; lang?: string }): void {
const allLayers = AllSharedLayers.sharedLayers
const layersToShow = theme.layers.filter(
(l) => l.id !== "favourite" && Constants.added_by_default.indexOf(<any>l.id) < 0
@ -563,38 +582,59 @@ export class GenerateDocs extends Script {
if (allLayers.has(l.id)) {
return `[${l.id}](../Layers/${l.id}.md)`
}
return `[${l.id} (${l.name?.textFor(lang)})](#${l.id.trim().replace(/ /g, "-")})`
return `[${l.id} (${l.name?.textFor(lang)})](#${l.id
.trim()
.replace(/ /g, "-")})`
})
),
new Translation(
{
en: "This theme is available in the following languages:",
nl: "Deze kaart is beschikbaar in de volgende talen:",
},
).textFor(lang),
MarkdownUtils.list(theme.language.filter((ln) => ln !== "_context").map(ln => {
if (language_translations[ln]) {
return ln + " (" + new Translation(language_translations[ln]).textFor(lang) + ")"
} else {
return ln
}
},
)),
new Translation({
en: "This theme is available in the following languages:",
nl: "Deze kaart is beschikbaar in de volgende talen:",
}).textFor(lang),
MarkdownUtils.list(
theme.language
.filter((ln) => ln !== "_context")
.map((ln) => {
if (language_translations[ln]) {
return (
ln +
" (" +
new Translation(language_translations[ln]).textFor(lang) +
")"
)
} else {
return ln
}
})
),
]
if (layersToInline.length > 0) {
el.push(MarkdownUtils.title(1, new Translation({
en: "Layers defined in this theme configuration file",
nl: "Lagen gedefinieerd in dit kaartthema-bestand",
})).textFor(lang))
el.push(MarkdownUtils.list(layersToInline.map(l => `[${l.name?.textFor(lang) ?? ""} (\`${l.id}\`)](#${l.id})`)))
el.push(new Translation({
en: "These layers can not be reused in different themes.",
nl: "Deze lagen kunnen niet in andere kaartthemas hergebruikt worden",
}).textFor(lang))
el.push(
...layersToInline.map((l) => l.generateDocumentation({ usedInThemes: null, lang })),
MarkdownUtils.title(
1,
new Translation({
en: "Layers defined in this theme configuration file",
nl: "Lagen gedefinieerd in dit kaartthema-bestand",
})
).textFor(lang)
)
el.push(
MarkdownUtils.list(
layersToInline.map(
(l) => `[${l.name?.textFor(lang) ?? ""} (\`${l.id}\`)](#${l.id})`
)
)
)
el.push(
new Translation({
en: "These layers can not be reused in different themes.",
nl: "Deze lagen kunnen niet in andere kaartthemas hergebruikt worden",
}).textFor(lang)
)
el.push(
...layersToInline.map((l) => l.generateDocumentation({ usedInThemes: null, lang }))
)
}
@ -606,7 +646,7 @@ export class GenerateDocs extends Script {
path + "/" + theme.id + ".md",
el.join("\n"),
[`assets/themes/${theme.id}/${theme.id}.json`],
{ noTableOfContents: true, lang },
{ noTableOfContents: true, lang }
)
}
@ -742,14 +782,16 @@ export class GenerateDocs extends Script {
*/
private generateSidebar(subdirectory = ""): string[] {
const tr = Translations.t.app.back.textFor(subdirectory)
const sidebar: string[] = [
`<a href='https://mapcomplete.org' class='back-to-mc'>${tr}</a>`
]
const sidebar: string[] = [`<a href='https://mapcomplete.org' class='back-to-mc'>${tr}</a>`]
const allFiles = ScriptUtils.readDirRecSync("./Docs/" + subdirectory)
.filter(path => path.endsWith(".md"))
.filter(path => !path.startsWith("_"))
.filter(path => !path.startsWith("./Docs/nl/") || (path.startsWith("./Docs/" + subdirectory) && subdirectory !== ""))
.map(path => path.substring("./Docs/".length + subdirectory.length + 1))
.filter((path) => path.endsWith(".md"))
.filter((path) => !path.startsWith("_"))
.filter(
(path) =>
!path.startsWith("./Docs/nl/") ||
(path.startsWith("./Docs/" + subdirectory) && subdirectory !== "")
)
.map((path) => path.substring("./Docs/".length + subdirectory.length + 1))
const perDirectory = new Map<string, string[]>()
function addFile(dir: string, path: string) {
@ -779,13 +821,15 @@ export class GenerateDocs extends Script {
const directories: [string, Translation | string][] = [
["", ""],
["Layers", new Translation({ en: "Overview of layers", nl: "Overzicht van de lagen" })],
["Themes", new Translation({ en: "Overview of map themes", nl: "Overzicht van de themas" })],
[
"Themes",
new Translation({ en: "Overview of map themes", nl: "Overzicht van de themas" }),
],
["UserTests", "Usability tests with users"],
["Studio", "For theme builders"],
["Dev", "For developers"],
]
for (const [dir, title] of directories) {
if (title === null) {
continue
@ -830,10 +874,9 @@ export class GenerateDocs extends Script {
}
private generateNormalLayerOverview(type: "Layers" | "Themes", subdir = "") {
const layerinfo: [string, string, string][] = []
const source: ReadonlyMap<string, LayerConfig> | AllKnownLayoutsLazy
= type === "Layers" ? AllSharedLayers.sharedLayers : AllKnownLayouts.allKnownLayouts
const source: ReadonlyMap<string, LayerConfig> | AllKnownLayoutsLazy =
type === "Layers" ? AllSharedLayers.sharedLayers : AllKnownLayouts.allKnownLayouts
const keys = Array.from(source.keys())
keys.sort()
@ -841,7 +884,7 @@ export class GenerateDocs extends Script {
const layer = source.get(id)
let name: Translation
if (type === "Layers") {
const layer_ = (<LayerConfig>layer)
const layer_ = <LayerConfig>layer
if (!layer_.isNormal()) {
continue
}
@ -849,36 +892,41 @@ export class GenerateDocs extends Script {
} else {
name = (<ThemeConfig>layer).title
}
layerinfo.push([`[${id}](./${type}/${id})`, name.textFor(subdir), (layer["shortDescription"] ?? layer.description)?.textFor(subdir)])
layerinfo.push([
`[${id}](./${type}/${id})`,
name.textFor(subdir),
(layer["shortDescription"] ?? layer.description)?.textFor(subdir),
])
}
const titles = {
"Layers": new Translation({ en: "Layers", nl: "Lagen" }),
"Themes": new Translation({ en: "Themes", nl: "Kaartthema's" })
Layers: new Translation({ en: "Layers", nl: "Lagen" }),
Themes: new Translation({ en: "Themes", nl: "Kaartthema's" }),
}
const intro: Record<string, TypedTranslation<{ version }>> = {
"Layers": new TypedTranslation<{ version }>({
Layers: new TypedTranslation<{ version }>({
en: "The following layers are available in MapComplete {version}:",
nl: "De volgende lagen zijn beschikbaar in MapComplete {version}:"
nl: "De volgende lagen zijn beschikbaar in MapComplete {version}:",
}),
"Themes": new TypedTranslation<{ version }>({
Themes: new TypedTranslation<{ version }>({
en: "The following themes are available in MapComplete {version}:",
nl: "De volgende kaartthemas zijn beschikbaar in MapComplete {version}:"
})
nl: "De volgende kaartthemas zijn beschikbaar in MapComplete {version}:",
}),
}
const doc = ["# " + titles[type].textFor(subdir),
intro[type].Subs({ version: Constants.vNumber }).textFor(subdir)
, MarkdownUtils.table(
["id", "name", "description"],
layerinfo)
const doc = [
"# " + titles[type].textFor(subdir),
intro[type].Subs({ version: Constants.vNumber }).textFor(subdir),
MarkdownUtils.table(["id", "name", "description"], layerinfo),
]
const path = `./Docs/${subdir}/${type}`
if (!existsSync(path)) {
mkdirSync(path)
}
this.writeMarkdownFile(`${path}/README.md`, doc.join("\n\n"), [`./assets/${type.toLowerCase()}/*.json`])
this.writeMarkdownFile(`${path}/README.md`, doc.join("\n\n"), [
`./assets/${type.toLowerCase()}/*.json`,
])
}
/**
@ -893,8 +941,7 @@ export class GenerateDocs extends Script {
continue
}
if (!AllSharedLayers.sharedLayers.has(id)) {
throw ("Privileged layer definition not found: " + id)
throw "Privileged layer definition not found: " + id
}
}
@ -933,7 +980,8 @@ export class GenerateDocs extends Script {
}
const el = [
"# Special and priviliged layers", "",
"# Special and priviliged layers",
"",
"MapComplete has a few data layers available which have special properties through builtin-hooks.",
"They perform various tasks, such as showing the GPS-location and track on the screen or help in special elements such as the 'cut way'-element.",
"As a theme builder, you can influence the behaviour of those layers by overriding them in your .json file",
@ -942,14 +990,15 @@ export class GenerateDocs extends Script {
),
...Lists.noNull(
Constants.priviliged_layers.map((id) => AllSharedLayers.sharedLayers.get(id))
).map((l) =>
l.generateDocumentation({
usedInThemes: themesPerLayer.get(l.id),
layerIsNeededBy: layerIsNeededBy,
dependencies: DependencyCalculator.getLayerDependencies(l),
addedByDefault: Constants.added_by_default.indexOf(<any>l.id) >= 0,
canBeIncluded: Constants.no_include.indexOf(<any>l.id) < 0,
}) + "\n"
).map(
(l) =>
l.generateDocumentation({
usedInThemes: themesPerLayer.get(l.id),
layerIsNeededBy: layerIsNeededBy,
dependencies: DependencyCalculator.getLayerDependencies(l),
addedByDefault: Constants.added_by_default.indexOf(<any>l.id) >= 0,
canBeIncluded: Constants.no_include.indexOf(<any>l.id) < 0,
}) + "\n"
),
].join("\n")
this.writeMarkdownFile("./Docs/Studio/SpecialLayers.md", el, [