Add some typehints to the models

This commit is contained in:
pietervdvn 2022-01-31 00:39:54 +01:00
parent 046902a139
commit 3679814664
6 changed files with 343 additions and 7 deletions

View file

@ -141,6 +141,8 @@ export interface LayerConfigJson {
* If not specified, the OsmLink and wikipedia links will be used by default. * If not specified, the OsmLink and wikipedia links will be used by default.
* Use an empty array to hide them. * Use an empty array to hide them.
* Note that "defaults" will insert all the default titleIcons (which are added automatically) * Note that "defaults" will insert all the default titleIcons (which are added automatically)
*
* Type: icon[]
*/ */
titleIcons?: (string | TagRenderingConfigJson)[] | ["defaults"]; titleIcons?: (string | TagRenderingConfigJson)[] | ["defaults"];

View file

@ -32,7 +32,7 @@ export interface LayoutConfigJson {
credits?: string; credits?: string;
/** /**
* Who does maintian this preset? * Who does maintain this preset?
*/ */
maintainer: string; maintainer: string;
@ -74,13 +74,17 @@ export interface LayoutConfigJson {
* The icon representing this theme. * The icon representing this theme.
* Used as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ... * Used as logo in the more-screen and (for official themes) as favicon, webmanifest logo, ...
* Either a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64) * Either a URL or a base64 encoded value (which should include 'data:image/svg+xml;base64)
*
* Type: icon
*/ */
icon: string; icon: string;
/** /**
* Link to a 'social image' which is included as og:image-tag on official themes. * Link to a 'social image' which is included as og:image-tag on official themes.
* Useful to share the theme on social media. * Useful to share the theme on social media.
* See https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information * See https://www.h3xed.com/web-and-internet/how-to-use-og-image-meta-tag-facebook-reddit for more information$
*
* Type: image
*/ */
socialImage?: string; socialImage?: string;

View file

@ -26,7 +26,8 @@ export default interface PointRenderingConfigJson {
* As a result, on could use a generic pin, then overlay it with a specific icon. * As a result, on could use a generic pin, then overlay it with a specific icon.
* To make things even more practical, one can use all SVG's from the folder "assets/svg" and _substitute the color_ in it. * To make things even more practical, one can use all SVG's from the folder "assets/svg" and _substitute the color_ in it.
* E.g. to draw a red pin, use "pin:#f00", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>` * E.g. to draw a red pin, use "pin:#f00", to have a green circle with your icon on top, use `circle:#0f0;<path to my icon.svg>`
*
* Type: icon
*/ */
icon?: string | TagRenderingConfigJson; icon?: string | TagRenderingConfigJson;
@ -36,7 +37,13 @@ export default interface PointRenderingConfigJson {
* *
* Note: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle * Note: strings are interpreted as icons, so layering and substituting is supported. You can use `circle:white;./my_icon.svg` to add a background circle
*/ */
iconBadges?: { if: string | AndOrTagConfigJson, then: string | TagRenderingConfigJson }[] iconBadges?: { if: string | AndOrTagConfigJson,
/**
* Badge to show
* Type: icon
*/
then: string | TagRenderingConfigJson
}[]
/** /**

View file

@ -108,6 +108,7 @@ export interface TagRenderingConfigJson {
then: string | any, then: string | any,
/** /**
* An icon supporting this mapping; typically shown pretty small * An icon supporting this mapping; typically shown pretty small
* Type: icon
*/ */
icon?: string icon?: string
/** /**

View file

@ -2,6 +2,105 @@ import ScriptUtils from "./ScriptUtils";
import {readFileSync, writeFileSync} from "fs"; import {readFileSync, writeFileSync} from "fs";
interface JsonSchema {
description?: string,
type?: string,
properties?: any,
items?: JsonSchema | JsonSchema[],
anyOf: JsonSchema[],
enum: JsonSchema[],
"$ref": string
}
function WalkScheme<T>(
onEach: (schemePart: JsonSchema) => T,
scheme: JsonSchema,
registerSchemePath = false,
fullScheme: JsonSchema & { definitions?: any } = undefined,
path: string[] = [],
isHandlingReference = []
): { path: string[], t: T }[] {
const results: { path: string[], t: T } [] = []
if (scheme === undefined) {
return []
}
if (scheme["$ref"] !== undefined) {
const ref = scheme["$ref"]
const prefix = "#/definitions/"
if (!ref.startsWith(prefix)) {
throw "References is not relative!"
}
const definitionName = ref.substr(prefix.length)
if (isHandlingReference.indexOf(definitionName) >= 0) {
return;
}
const loadedScheme = fullScheme.definitions[definitionName]
return WalkScheme(onEach, loadedScheme, registerSchemePath, fullScheme, path, [...isHandlingReference, definitionName]);
}
fullScheme = fullScheme ?? scheme
var t = onEach(scheme)
function walk(v: JsonSchema, pathPart: string) {
if (v === undefined) {
return
}
if(registerSchemePath){
path.push("" + pathPart)
}
results.push(...WalkScheme(onEach, v, registerSchemePath, fullScheme, path, isHandlingReference))
if(registerSchemePath){
path.pop()
}
}
function walkEach(scheme: JsonSchema[], pathPart: string) {
if (scheme === undefined) {
return
}
if(registerSchemePath){
path.push("" + pathPart)
}
scheme.forEach((v, i) => walk(v, "" + i))
if(registerSchemePath){
path.pop()
}
}
if (t !== undefined) {
results.push({
path: [...path],
t
})
} else {
walkEach(scheme.enum, "enum")
walkEach(scheme.anyOf, "anyOf")
if (scheme.items !== undefined) {
if (scheme.items["forEach"] !== undefined) {
walkEach(<any>scheme.items, "items")
} else {
walk(<any>scheme.items, "items")
}
}
if(registerSchemePath){
path.push("properties")
}
for (const key in scheme.properties) {
const prop = scheme.properties[key]
path.push(key)
results.push(...WalkScheme(onEach, prop, registerSchemePath, fullScheme, path, isHandlingReference))
path.pop()
}
if(registerSchemePath){
path.pop()
}
}
return results
}
function main() { function main() {
const allSchemas = ScriptUtils.readDirRecSync("./Docs/Schemas").filter(pth => pth.endsWith("JSC.ts")) const allSchemas = ScriptUtils.readDirRecSync("./Docs/Schemas").filter(pth => pth.endsWith("JSC.ts"))
@ -20,9 +119,23 @@ function main() {
def["additionalProperties"] = false def["additionalProperties"] = false
} }
} }
writeFileSync(dir + "/" + name + ".schema.json", JSON.stringify(parsed, null, " "), "UTF8") writeFileSync(dir + "/" + name + ".schema.json", JSON.stringify(parsed, null, " "), "UTF8")
} }
const themeSchema = JSON.parse(readFileSync("./Docs/Schemas/LayoutConfigJson.schema.json", "UTF-8"))
const withTypes =WalkScheme((schemePart) => {
if (schemePart.description === undefined) {
return;
}
const type = schemePart.description.split("\n").filter(line => line.trim().toLocaleLowerCase().startsWith("type: "))[0]
if (type === undefined) {
return undefined
}
return {typeHint: type.substr("type: ".length), type: schemePart.type ?? schemePart.anyOf}
}, themeSchema)
// writeFileSync("./assets/layoutconfigmeta.json",JSON.stringify(withTypes.map(({path, t}) => ({path, ...t})), null, " "))
} }
main() main()

View file

@ -4,6 +4,7 @@ import LayoutConfig from "../Models/ThemeConfig/LayoutConfig";
import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson"; import {LayerConfigJson} from "../Models/ThemeConfig/Json/LayerConfigJson";
import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson"; import {TagRenderingConfigJson} from "../Models/ThemeConfig/Json/TagRenderingConfigJson";
import {AddMiniMap} from "../Models/ThemeConfig/Conversion/PrepareTheme"; import {AddMiniMap} from "../Models/ThemeConfig/Conversion/PrepareTheme";
import FixRemoteLinks from "../Models/ThemeConfig/Conversion/FixRemoteLinks";
export default class LegacyThemeLoaderSpec extends T { export default class LegacyThemeLoaderSpec extends T {
@ -142,6 +143,215 @@ export default class LegacyThemeLoaderSpec extends T {
] ]
} }
private static readonly organic_waste_theme = {
"id": "recycling-organic",
"title": {
"nl": "Inzamelpunt organisch alval"
},
"shortDescription": {
"nl": "Inzamelpunt organisch alval"
},
"description": {
"nl": "Op deze kaart vindt u inzamelpunten voor organisch afval. Beheer deze naar goeddunken en vermogen."
},
"language": [
"nl"
],
"maintainer": "",
"icon": "https://upload.wikimedia.org/wikipedia/commons/1/15/Compost_…able_waste_-_biodegradable_waste_-_biological_waste_icon.png",
"version": "0",
"startLat": 0,
"startLon": 0,
"startZoom": 1,
"widenFactor": 0.05,
"socialImage": "",
"layers": [
{
"id": "recycling-organic",
"name": {
"nl": "Inzamelpunt organisch alval"
},
"minzoom": 12,
"title": {
"render": {
"nl": "Inzamelpunt organisch alval"
},
"mappings": [
{
"if": {
"and": [
"name~*"
]
},
"then": {
"nl": "{name}"
}
}
]
},
"allowMove": true,
"deletion": {},
"tagRenderings": [
"images",
{
"freeform": {
"key": "opening_hours",
"type": "opening_hours",
"addExtraTags": []
},
"question": {
"nl": "Wat zijn de openingsuren?"
},
"render": {
"nl": "{opening_hours_table()}"
},
"mappings": [
{
"if": {
"and": [
"opening_hours=\"by appointment\""
]
},
"then": {
"nl": "Op afspraak"
}
}
],
"id": "Composthoekjes-opening_hours"
},
{
"question": {
"nl": "Wat is de website voor meer informatie?"
},
"freeform": {
"key": "website",
"type": "url"
},
"render": {
"nl": "<a href=\"{website}\">{website}</a>"
},
"id": "Composthoekjes-website"
},
{
"question": {
"nl": "Wat is het type inzamelpunt?"
},
"mappings":[
{
"if":"recycling_type=container",
"then":"Container of vat"
},
{
"if":"recycling_type=centre",
"then":"Verwerkingsplaats of containerpark"
},
{
"if":"recycling_type=dump",
"then":"Composthoop"
}
],
"id": "Composthoekjes-type"
},
{
"question": {
"nl": "Wie mag hier organisch afval bezorgen?"
},
"mappings":[
{
"if":"access=yes",
"then":"Publiek toegankelijk"
},
{
"if":"access=no",
"then":"Privaat"
},
{
"if":"access=permessive",
"then":"Mogelijks toegelaten tot nader order"
},
{
"if":"access=",
"then":"Waarschijnlijk publiek toegankelijk",
"hideInAnswer":true
},
{
"if":"access=residents",
"then":"Bewoners van gemeente",
"hideInAnswer":"recycling_type!=centre"
}
],
"id": "Composthoekjes-voor-wie"
},
{
"question": {
"nl": "Wat is de naam van dit compost-inzamelpunt?"
},
"freeform": {
"key": "name",
"addExtraTags": ["noname="]
},
"render": {
"nl": "De naam van dit compost-inzamelpunt is {name}"
},
"mappings":[
{
"if":{"and":["noname=yes","name="]},
"then":"Heeft geen naam"
},
{
"if":"name=",
"then":"Geen naam bekend",
"hideInAnswer":true
}
],
"id": "Composthoekjes-name"
}],
"presets": [
{
"tags": [
"amenity=recycling",
"recycling:organic=yes"
],
"title": {
"nl": "een inzamelpunt voor organisch afval"
}
}
],
"source": {
"osmTags": {
"and": [
"recycling:organic~*"
]
}
},
"mapRendering": [
{
"icon": {
"render": "circle:white;https://upload.wikimedia.org/wikipedia/commons/1/15/Compost_…able_waste_-_biodegradable_waste_-_biological_waste_icon.png"
},
"iconSize": {
"render": "40,40,center"
},
"location": [
"point"
]
},
{
"color": {
"render": "#00f"
},
"width": {
"render": "8"
}
}
]
}
]
}
constructor() { constructor() {
super([ super([
["Walking_node_theme", () => { ["Walking_node_theme", () => {
@ -201,8 +411,7 @@ export default class LegacyThemeLoaderSpec extends T {
render: "Some random value {minimap}" render: "Some random value {minimap}"
}) })
} }]
]
] ]
); );
} }