forked from MapComplete/MapComplete
Export more meta-information from schema files, add some introspection tools in Utils
This commit is contained in:
parent
244e4c294d
commit
5198f5d310
4 changed files with 300 additions and 29 deletions
0
Models/ThemeConfig/Conversion/FixImages.ts
Normal file
0
Models/ThemeConfig/Conversion/FixImages.ts
Normal file
82
Utils.ts
82
Utils.ts
|
@ -350,6 +350,88 @@ In the case that MapComplete is pointed to the testing grounds, the edit will be
|
||||||
return target;
|
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) {
|
static WalkJson(json: any, f: (v: number | string | boolean | undefined) => any) {
|
||||||
if (json === undefined) {
|
if (json === undefined) {
|
||||||
return f(undefined)
|
return f(undefined)
|
||||||
|
|
176
assets/tagrenderingconfigmeta.json
Normal file
176
assets/tagrenderingconfigmeta.json
Normal file
|
@ -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"
|
||||||
|
}
|
||||||
|
]
|
|
@ -40,16 +40,23 @@ function WalkScheme<T>(
|
||||||
|
|
||||||
fullScheme = fullScheme ?? scheme
|
fullScheme = fullScheme ?? scheme
|
||||||
var t = onEach(scheme)
|
var t = onEach(scheme)
|
||||||
|
if (t !== undefined) {
|
||||||
|
results.push({
|
||||||
|
path: [...path],
|
||||||
|
t
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function walk(v: JsonSchema, pathPart: string) {
|
function walk(v: JsonSchema, pathPart: string) {
|
||||||
if (v === undefined) {
|
if (v === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(registerSchemePath){
|
if (registerSchemePath) {
|
||||||
path.push("" + pathPart)
|
path.push("" + pathPart)
|
||||||
}
|
}
|
||||||
results.push(...WalkScheme(onEach, v, registerSchemePath, fullScheme, path, isHandlingReference))
|
results.push(...WalkScheme(onEach, v, registerSchemePath, fullScheme, path, isHandlingReference))
|
||||||
if(registerSchemePath){
|
if (registerSchemePath) {
|
||||||
path.pop()
|
path.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,21 +65,18 @@ function WalkScheme<T>(
|
||||||
if (scheme === undefined) {
|
if (scheme === undefined) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(registerSchemePath){
|
if (registerSchemePath) {
|
||||||
path.push("" + pathPart)
|
path.push("" + pathPart)
|
||||||
}
|
}
|
||||||
scheme.forEach((v, i) => walk(v, "" + i))
|
scheme.forEach((v, i) => walk(v, "" + i))
|
||||||
if(registerSchemePath){
|
if (registerSchemePath) {
|
||||||
path.pop()
|
path.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t !== undefined) {
|
|
||||||
results.push({
|
|
||||||
path: [...path],
|
{
|
||||||
t
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
walkEach(scheme.enum, "enum")
|
walkEach(scheme.enum, "enum")
|
||||||
walkEach(scheme.anyOf, "anyOf")
|
walkEach(scheme.anyOf, "anyOf")
|
||||||
if (scheme.items !== undefined) {
|
if (scheme.items !== undefined) {
|
||||||
|
@ -84,7 +88,7 @@ function WalkScheme<T>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(registerSchemePath){
|
if (registerSchemePath) {
|
||||||
path.push("properties")
|
path.push("properties")
|
||||||
}
|
}
|
||||||
for (const key in scheme.properties) {
|
for (const key in scheme.properties) {
|
||||||
|
@ -93,7 +97,7 @@ function WalkScheme<T>(
|
||||||
results.push(...WalkScheme(onEach, prop, registerSchemePath, fullScheme, path, isHandlingReference))
|
results.push(...WalkScheme(onEach, prop, registerSchemePath, fullScheme, path, isHandlingReference))
|
||||||
path.pop()
|
path.pop()
|
||||||
}
|
}
|
||||||
if(registerSchemePath){
|
if (registerSchemePath) {
|
||||||
path.pop()
|
path.pop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,6 +105,26 @@ function WalkScheme<T>(
|
||||||
return results
|
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() {
|
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"))
|
||||||
|
@ -122,19 +146,8 @@ function main() {
|
||||||
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"))
|
extractMeta("LayoutConfigJson", "layoutconfigmeta")
|
||||||
const withTypes =WalkScheme((schemePart) => {
|
extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta")
|
||||||
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, " "))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue