mapcomplete/scripts/fixSchemas.ts

171 lines
5.6 KiB
TypeScript
Raw Normal View History

2022-09-08 21:40:48 +02:00
import ScriptUtils from "./ScriptUtils"
import { readFileSync, writeFileSync } from "fs"
2023-06-16 02:36:11 +02:00
import { JsonSchema } from "../UI/Studio/jsonSchema"
2022-01-31 00:39:54 +01:00
function WalkScheme<T>(
onEach: (schemePart: JsonSchema) => T,
scheme: JsonSchema,
fullScheme: JsonSchema & { definitions?: any } = undefined,
path: string[] = [],
isHandlingReference = [],
required?: string[]
): { path: string[]; required: boolean; t: T }[] {
const results: { path: string[]; required: boolean; t: T }[] = []
2022-01-31 00:39:54 +01:00
if (scheme === undefined) {
return []
}
2022-05-17 01:46:59 +02:00
2022-01-31 00:39:54 +01:00
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) {
2023-03-09 15:15:24 +01:00
return []
2022-01-31 00:39:54 +01:00
}
const loadedScheme = fullScheme.definitions[definitionName]
2022-09-08 21:40:48 +02:00
return WalkScheme(onEach, loadedScheme, fullScheme, path, [
...isHandlingReference,
definitionName,
])
2022-01-31 00:39:54 +01:00
}
fullScheme = fullScheme ?? scheme
2023-06-16 02:36:11 +02:00
let t = onEach(scheme)
if (t !== undefined) {
results.push({
path,
required: required?.indexOf(path.at(-1)) >= 0,
2022-09-08 21:40:48 +02:00
t,
})
}
function walk(v: JsonSchema) {
2022-01-31 00:39:54 +01:00
if (v === undefined) {
return
}
results.push(...WalkScheme(onEach, v, fullScheme, path, isHandlingReference))
2022-01-31 00:39:54 +01:00
}
function walkEach(scheme: JsonSchema[]) {
2022-01-31 00:39:54 +01:00
if (scheme === undefined) {
return
}
2022-05-17 01:46:59 +02:00
2022-09-08 21:40:48 +02:00
scheme.forEach((v) => walk(v))
2022-01-31 00:39:54 +01:00
}
{
walkEach(scheme.enum)
walkEach(scheme.anyOf)
2022-05-17 01:46:59 +02:00
walkEach(scheme.allOf)
if (Array.isArray(scheme.items)) {
walkEach(<any>scheme.items)
} else {
walk(<any>scheme.items)
2022-01-31 00:39:54 +01:00
}
for (const key in scheme.properties) {
const prop = scheme.properties[key]
2022-09-08 21:40:48 +02:00
results.push(
...WalkScheme(
onEach,
prop,
fullScheme,
[...path, key],
isHandlingReference,
scheme.required
)
2022-09-08 21:40:48 +02:00
)
2022-01-31 00:39:54 +01:00
}
}
return results
}
2023-06-16 02:36:11 +02:00
function addMetafields(fieldnames: string[], fullSchema: JsonSchema) {
return WalkScheme((schemePart) => {
if (schemePart.description === undefined) {
2022-09-08 21:40:48 +02:00
return
}
2022-09-08 21:40:48 +02:00
const type = schemePart.items?.anyOf ?? schemePart.type ?? schemePart.anyOf
2023-06-16 02:36:11 +02:00
const hints = {}
let description = schemePart.description.split("\n")
for (const fieldname of fieldnames) {
const hintIndex = description.findIndex((line) =>
line
.trim()
.toLocaleLowerCase()
.startsWith(fieldname + ":")
)
if (hintIndex < 0) {
continue
}
const hintLine = description[hintIndex].substring((fieldname + ":").length).trim()
description.splice(hintIndex, 1)
if (fieldname === "type") {
hints["typehint"] = hintLine
} else {
hints[fieldname] = hintLine
}
}
return { hints, type, description: description.join("\n") }
}, fullSchema)
}
function extractMeta(typename: string, path: string) {
let themeSchema: JsonSchema = JSON.parse(
readFileSync("./Docs/Schemas/" + typename + ".schema.json", { encoding: "utf8" })
)
const metainfo = {
type: "One of the inputValidator types",
group: "A kind of label. Items with the same group name will be placed in the same region",
question: "The question to ask in the tagRenderingConfig",
ifunset:
"Only applicable if _not_ a required item. This will appear in the 'not set'-option as extra description",
inline: "A text, containing `{value}`. This will be used as freeform rendering and will be included into the rendering",
}
const metakeys = Array.from(Object.keys(metainfo))
2023-06-16 02:36:11 +02:00
const hints = addMetafields(metakeys, themeSchema)
const paths = hints.map(({ path, required, t }) => ({ path, required, ...t }))
writeFileSync("./assets/" + path + ".json", JSON.stringify(paths, null, " "))
console.log("Written meta to ./assets/" + path)
}
2021-11-07 17:52:05 +01:00
function main() {
2022-09-08 21:40:48 +02:00
const allSchemas = ScriptUtils.readDirRecSync("./Docs/Schemas").filter((pth) =>
pth.endsWith("JSC.ts")
)
2021-11-07 17:52:05 +01:00
for (const path of allSchemas) {
const dir = path.substring(0, path.lastIndexOf("/"))
const name = path.substring(path.lastIndexOf("/"), path.length - "JSC.ts".length)
2023-01-15 23:28:02 +01:00
let content = readFileSync(path, { encoding: "utf8" })
2021-11-07 17:52:05 +01:00
content = content.substring("export default ".length)
let parsed = JSON.parse(content)
parsed["additionalProperties"] = false
for (const key in parsed.definitions) {
const def = parsed.definitions[key]
if (def.type === "object") {
def["additionalProperties"] = false
}
}
2023-01-29 17:45:48 +01:00
writeFileSync(dir + "/" + name + ".schema.json", JSON.stringify(parsed, null, " "), {
encoding: "utf8",
})
2021-11-07 17:52:05 +01:00
}
2023-06-16 02:36:11 +02:00
extractMeta("LayerConfigJson", "layerconfigmeta")
extractMeta("LayoutConfigJson", "layoutconfigmeta")
extractMeta("TagRenderingConfigJson", "tagrenderingconfigmeta")
extractMeta("QuestionableTagRenderingConfigJson", "questionabletagrenderingconfigmeta")
2021-11-07 17:52:05 +01:00
}
main()