From 5198f5d3106ef323a28d394be9e19afb75e3a5f2 Mon Sep 17 00:00:00 2001 From: pietervdvn Date: Wed, 9 Feb 2022 22:34:02 +0100 Subject: [PATCH] Export more meta-information from schema files, add some introspection tools in Utils --- Models/ThemeConfig/Conversion/FixImages.ts | 0 Utils.ts | 82 ++++++++++ assets/tagrenderingconfigmeta.json | 176 +++++++++++++++++++++ scripts/fixSchemas.ts | 71 +++++---- 4 files changed, 300 insertions(+), 29 deletions(-) create mode 100644 Models/ThemeConfig/Conversion/FixImages.ts create mode 100644 assets/tagrenderingconfigmeta.json diff --git a/Models/ThemeConfig/Conversion/FixImages.ts b/Models/ThemeConfig/Conversion/FixImages.ts new file mode 100644 index 000000000..e69de29bb diff --git a/Utils.ts b/Utils.ts index 524b46835..cdf0cb26b 100644 --- a/Utils.ts +++ b/Utils.ts @@ -350,6 +350,88 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be return target; } + + /** + * Walks the specified path into the object till the end. + * + * If a list is encountered, this is tranparently walked recursively on every object. + * + * The leaf objects are replaced by the function + */ + public static WalkPath(path: string[], object: any, replaceLeaf: ((leaf: any) => any)) { + const head = path[0] + if (path.length === 1) { + // We have reached the leaf + const leaf = object[head]; + if (leaf !== undefined) { + if(Array.isArray(leaf)){ + object[head] = leaf.map(replaceLeaf) + }else{ + object[head] = replaceLeaf(leaf) + } + } + return + + } + const sub = object[head] + if (sub === undefined) { + return; + } + if (typeof sub !== "object") { + return; + } + if (Array.isArray(sub)) { + sub.forEach(el => Utils.WalkPath(path.slice(1), el, replaceLeaf)) + return; + } + Utils.WalkPath(path.slice(1), sub, replaceLeaf) + } + + /** + * Walks the specified path into the object till the end. + * If a list is encountered, this is tranparently walked recursively on every object. + * + * The leaf objects are collected in the list + */ + public static CollectPath(path: string[], object: any, collectedList = []): any[] { + if (object === undefined || object === null) { + return collectedList; + } + const head = path[0] + if (path.length === 1) { + // We have reached the leaf + const leaf = object[head]; + if (leaf === undefined || leaf === null) { + return collectedList + } + if (Array.isArray(leaf)) { + collectedList.push(...leaf) + } else { + collectedList.push(leaf) + } + return collectedList + } + const sub = object[head] + if (sub === undefined || sub === null) { + return collectedList; + } + + if (Array.isArray(sub)) { + sub.forEach(el => Utils.CollectPath(path.slice(1), el, collectedList)) + return collectedList; + } + if (typeof sub !== "object") { + return collectedList; + } + return Utils.CollectPath(path.slice(1), sub, collectedList) + } + + /** + * Apply a function on every leaf of the JSON; used to rewrite parts of the JSON + * @param json + * @param f + * @constructor + */ static WalkJson(json: any, f: (v: number | string | boolean | undefined) => any) { if (json === undefined) { return f(undefined) diff --git a/assets/tagrenderingconfigmeta.json b/assets/tagrenderingconfigmeta.json new file mode 100644 index 000000000..df0942ef0 --- /dev/null +++ b/assets/tagrenderingconfigmeta.json @@ -0,0 +1,176 @@ +[ + { + "path": [], + "type": "object" + }, + { + "path": [ + "id" + ], + "type": "string" + }, + { + "path": [ + "group" + ], + "type": "string" + }, + { + "path": [ + "labels" + ], + "type": "array" + }, + { + "path": [ + "question" + ], + "typeHint": "rendered" + }, + { + "path": [ + "condition" + ], + "type": [ + { + "$ref": "#/definitions/AndOrTagConfigJson" + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "freeform" + ], + "type": "object" + }, + { + "path": [ + "freeform", + "key" + ], + "type": "string" + }, + { + "path": [ + "freeform", + "type" + ], + "type": "string" + }, + { + "path": [ + "freeform", + "placeholder" + ] + }, + { + "path": [ + "freeform", + "helperArgs" + ], + "type": "array" + }, + { + "path": [ + "freeform", + "addExtraTags" + ], + "type": "array" + }, + { + "path": [ + "freeform", + "inline" + ], + "type": "boolean" + }, + { + "path": [ + "freeform", + "default" + ], + "type": "string" + }, + { + "path": [ + "multiAnswer" + ], + "type": "boolean" + }, + { + "path": [ + "mappings" + ], + "type": "array" + }, + { + "path": [ + "mappings", + "if" + ], + "type": [ + { + "$ref": "#/definitions/AndOrTagConfigJson" + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "mappings", + "then" + ], + "typeHint": "rendered" + }, + { + "path": [ + "mappings", + "icon" + ], + "typeHint": "icon", + "type": "string" + }, + { + "path": [ + "mappings", + "hideInAnswer" + ], + "type": [ + { + "$ref": "#/definitions/AndOrTagConfigJson" + }, + { + "type": [ + "string", + "boolean" + ] + } + ] + }, + { + "path": [ + "mappings", + "ifnot" + ], + "type": [ + { + "$ref": "#/definitions/AndOrTagConfigJson" + }, + { + "type": "string" + } + ] + }, + { + "path": [ + "mappings", + "addExtraTags" + ], + "type": "array" + } +] \ No newline at end of file diff --git a/scripts/fixSchemas.ts b/scripts/fixSchemas.ts index 96ce4ed49..5bf91fcb6 100644 --- a/scripts/fixSchemas.ts +++ b/scripts/fixSchemas.ts @@ -40,16 +40,23 @@ function WalkScheme( fullScheme = fullScheme ?? scheme var t = onEach(scheme) - + if (t !== undefined) { + results.push({ + path: [...path], + t + }) + } + + function walk(v: JsonSchema, pathPart: string) { if (v === undefined) { return } - if(registerSchemePath){ + if (registerSchemePath) { path.push("" + pathPart) } results.push(...WalkScheme(onEach, v, registerSchemePath, fullScheme, path, isHandlingReference)) - if(registerSchemePath){ + if (registerSchemePath) { path.pop() } } @@ -58,21 +65,18 @@ function WalkScheme( if (scheme === undefined) { return } - if(registerSchemePath){ + if (registerSchemePath) { path.push("" + pathPart) } scheme.forEach((v, i) => walk(v, "" + i)) - if(registerSchemePath){ + 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) { @@ -84,23 +88,43 @@ function WalkScheme( } } - if(registerSchemePath){ - path.push("properties") - } + 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() + if (registerSchemePath) { + path.pop() } } return results } +function extractMeta(typename: string, path: string) { + const themeSchema = JSON.parse(readFileSync("./Docs/Schemas/" + typename + ".schema.json", "UTF-8")) + const withTypes = WalkScheme((schemePart) => { + if (schemePart.description === undefined) { + return; + } + const typeHint = schemePart.description.split("\n") + .find(line => line.trim().toLocaleLowerCase().startsWith("type:")) + ?.substr("type:".length)?.trim() + const type = schemePart.type ?? schemePart.anyOf; + return {typeHint, type} + }, themeSchema) + + writeFileSync("./assets/" + path + ".json", JSON.stringify(withTypes.map(({ + path, + t + }) => ({path, ...t})), null, " ")) +} + + function main() { const allSchemas = ScriptUtils.readDirRecSync("./Docs/Schemas").filter(pth => pth.endsWith("JSC.ts")) @@ -122,19 +146,8 @@ function main() { 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, " ")) + extractMeta("LayoutConfigJson", "layoutconfigmeta") + extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta") }