forked from MapComplete/MapComplete
Speed up layer generation script
This commit is contained in:
parent
5bcc617d22
commit
fa83a51df5
5 changed files with 100 additions and 79 deletions
|
@ -308,9 +308,30 @@ export class FirstOf<T, X> extends Conversion<T, X> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Cached<TIn, TOut> extends Conversion<TIn, TOut> {
|
||||||
|
private _step: Conversion<TIn, TOut>
|
||||||
|
private readonly key: string
|
||||||
|
constructor(step: Conversion<TIn, TOut>) {
|
||||||
|
super("Secretly caches the output for the given input", [], "cached")
|
||||||
|
this._step = step
|
||||||
|
this.key = "__super_secret_caching_key_" + step.name
|
||||||
|
}
|
||||||
|
|
||||||
|
convert(json: TIn, context: ConversionContext): TOut {
|
||||||
|
if (json[this.key]) {
|
||||||
|
return json[this.key]
|
||||||
|
}
|
||||||
|
const converted = this._step.convert(json, context)
|
||||||
|
Object.defineProperty(json, this.key, {
|
||||||
|
value: converted,
|
||||||
|
enumerable: false,
|
||||||
|
})
|
||||||
|
return converted
|
||||||
|
}
|
||||||
|
}
|
||||||
export class Fuse<T> extends DesugaringStep<T> {
|
export class Fuse<T> extends DesugaringStep<T> {
|
||||||
private readonly steps: DesugaringStep<T>[]
|
private readonly steps: DesugaringStep<T>[]
|
||||||
|
protected debug = false
|
||||||
constructor(doc: string, ...steps: DesugaringStep<T>[]) {
|
constructor(doc: string, ...steps: DesugaringStep<T>[]) {
|
||||||
super(
|
super(
|
||||||
(doc ?? "") +
|
(doc ?? "") +
|
||||||
|
@ -322,8 +343,15 @@ export class Fuse<T> extends DesugaringStep<T> {
|
||||||
this.steps = Utils.NoNull(steps)
|
this.steps = Utils.NoNull(steps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enableDebugging(): Fuse<T> {
|
||||||
|
this.debug = true
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
convert(json: T, context: ConversionContext): T {
|
convert(json: T, context: ConversionContext): T {
|
||||||
|
const timings = []
|
||||||
for (let i = 0; i < this.steps.length; i++) {
|
for (let i = 0; i < this.steps.length; i++) {
|
||||||
|
const start = new Date()
|
||||||
const step = this.steps[i]
|
const step = this.steps[i]
|
||||||
try {
|
try {
|
||||||
const r = step.convert(json, context.inOperation(step.name))
|
const r = step.convert(json, context.inOperation(step.name))
|
||||||
|
@ -335,6 +363,14 @@ export class Fuse<T> extends DesugaringStep<T> {
|
||||||
console.error("Step " + step.name + " failed due to ", e, e.stack)
|
console.error("Step " + step.name + " failed due to ", e, e.stack)
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
|
if (this.debug) {
|
||||||
|
const stop = new Date()
|
||||||
|
const timeNeededMs = stop.getTime() - start.getTime()
|
||||||
|
timings.push(timeNeededMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.debug) {
|
||||||
|
console.log("Time needed,", timings.join(", "))
|
||||||
}
|
}
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import {
|
import {
|
||||||
|
Cached,
|
||||||
Concat,
|
Concat,
|
||||||
Conversion,
|
Conversion,
|
||||||
ConversionContext,
|
ConversionContext,
|
||||||
|
@ -31,6 +32,7 @@ import { RenderingSpecification } from "../../../UI/SpecialVisualization"
|
||||||
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
||||||
import { ConfigMeta } from "../../../UI/Studio/configMeta"
|
import { ConfigMeta } from "../../../UI/Studio/configMeta"
|
||||||
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
import LineRenderingConfigJson from "../Json/LineRenderingConfigJson"
|
||||||
|
import { j } from "vite-node/types-63205a44"
|
||||||
|
|
||||||
class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
class ExpandFilter extends DesugaringStep<LayerConfigJson> {
|
||||||
private static readonly predefinedFilters = ExpandFilter.load_filters()
|
private static readonly predefinedFilters = ExpandFilter.load_filters()
|
||||||
|
@ -483,14 +485,13 @@ export class AddQuestionBox extends DesugaringStep<LayerConfigJson> {
|
||||||
) {
|
) {
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
json = JSON.parse(JSON.stringify(json))
|
json = { ...json }
|
||||||
const allSpecials: Exclude<RenderingSpecification, string>[] = []
|
json.tagRenderings = [...json.tagRenderings]
|
||||||
.concat(
|
const allSpecials: Exclude<RenderingSpecification, string>[] = <any>(
|
||||||
...json.tagRenderings.map((tr) =>
|
ValidationUtils.getAllSpecialVisualisations(<any>json.tagRenderings).filter(
|
||||||
ValidationUtils.getSpecialVisualsationsWithArgs(<TagRenderingConfigJson>tr)
|
(spec) => typeof spec !== "string"
|
||||||
)
|
|
||||||
)
|
)
|
||||||
.filter((spec) => typeof spec !== "string")
|
)
|
||||||
|
|
||||||
const questionSpecials = allSpecials.filter((sp) => sp.func.funcName === "questions")
|
const questionSpecials = allSpecials.filter((sp) => sp.func.funcName === "questions")
|
||||||
const noLabels = questionSpecials.filter(
|
const noLabels = questionSpecials.filter(
|
||||||
|
@ -579,18 +580,34 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
||||||
if (this._desugaring.tagRenderings === null) {
|
if (this._desugaring.tagRenderings === null) {
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
json = JSON.parse(JSON.stringify(json))
|
if (json.source === "special") {
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
if (!json.title && !json.tagRenderings) {
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
json = { ...json }
|
||||||
|
json.tagRenderings = [...(json.tagRenderings ?? [])]
|
||||||
|
const specialVisualisations = ValidationUtils.getAllSpecialVisualisations(
|
||||||
|
<any>json.tagRenderings
|
||||||
|
)
|
||||||
|
const usedSpecialFunctions = new Set(
|
||||||
|
specialVisualisations.map((sv) =>
|
||||||
|
typeof sv === "string" ? undefined : sv.func.funcName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if (!usedSpecialFunctions.has("minimap")) {
|
||||||
|
json.tagRenderings.push(this._desugaring.tagRenderings.get("minimap"))
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
json.tagRenderings &&
|
|
||||||
this._desugaring.tagRenderings.has("just_created") &&
|
this._desugaring.tagRenderings.has("just_created") &&
|
||||||
!json.tagRenderings.some((tr) => tr === "just_created" || tr["id"] === "just_created")
|
!json.tagRenderings.some((tr) => tr === "just_created" || tr["id"] === "just_created")
|
||||||
) {
|
) {
|
||||||
json.tagRenderings.unshift(this._desugaring.tagRenderings.get("just_created"))
|
json.tagRenderings.unshift(this._desugaring.tagRenderings.get("just_created"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.allowSplit && !ValidationUtils.hasSpecialVisualisation(json, "split_button")) {
|
if (json.allowSplit && !usedSpecialFunctions.has("split_button")) {
|
||||||
json.tagRenderings ??= []
|
|
||||||
json.tagRenderings.push({
|
json.tagRenderings.push({
|
||||||
id: "split-button",
|
id: "split-button",
|
||||||
render: { "*": "{split_button()}" },
|
render: { "*": "{split_button()}" },
|
||||||
|
@ -598,14 +615,13 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
||||||
delete json.allowSplit
|
delete json.allowSplit
|
||||||
}
|
}
|
||||||
|
|
||||||
if (json.allowMove && !ValidationUtils.hasSpecialVisualisation(json, "move_button")) {
|
if (json.allowMove && !usedSpecialFunctions.has("move_button")) {
|
||||||
json.tagRenderings ??= []
|
|
||||||
json.tagRenderings.push({
|
json.tagRenderings.push({
|
||||||
id: "move-button",
|
id: "move-button",
|
||||||
render: { "*": "{move_button()}" },
|
render: { "*": "{move_button()}" },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (json.deletion && !ValidationUtils.hasSpecialVisualisation(json, "delete_button")) {
|
if (json.deletion && !usedSpecialFunctions.has("delete_button")) {
|
||||||
json.tagRenderings.push({
|
json.tagRenderings.push({
|
||||||
id: "delete-button",
|
id: "delete-button",
|
||||||
render: { "*": "{delete_button()}" },
|
render: { "*": "{delete_button()}" },
|
||||||
|
@ -622,7 +638,7 @@ export class AddEditingElements extends DesugaringStep<LayerConfigJson> {
|
||||||
json.tagRenderings.push(this._desugaring.tagRenderings.get("last_edit"))
|
json.tagRenderings.push(this._desugaring.tagRenderings.get("last_edit"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ValidationUtils.hasSpecialVisualisation(json, "all_tags")) {
|
if (!usedSpecialFunctions.has("all_tags")) {
|
||||||
const trc: QuestionableTagRenderingConfigJson = {
|
const trc: QuestionableTagRenderingConfigJson = {
|
||||||
id: "all-tags",
|
id: "all-tags",
|
||||||
render: { "*": "{all_tags()}" },
|
render: { "*": "{all_tags()}" },
|
||||||
|
@ -1141,41 +1157,6 @@ class SetFullNodeDatabase extends DesugaringStep<LayerConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AddMiniMap extends DesugaringStep<LayerConfigJson> {
|
|
||||||
private readonly _state: DesugaringContext
|
|
||||||
|
|
||||||
constructor(state: DesugaringContext) {
|
|
||||||
super(
|
|
||||||
"Adds a default 'minimap'-element to the tagrenderings if none of the elements define such a minimap",
|
|
||||||
["tagRenderings"],
|
|
||||||
"AddMiniMap"
|
|
||||||
)
|
|
||||||
this._state = state
|
|
||||||
}
|
|
||||||
|
|
||||||
convert(layerConfig: LayerConfigJson, context: ConversionContext): LayerConfigJson {
|
|
||||||
if (!layerConfig.tagRenderings || layerConfig.source === "special") {
|
|
||||||
return layerConfig
|
|
||||||
}
|
|
||||||
const state = this._state
|
|
||||||
const hasMinimap = ValidationUtils.hasSpecialVisualisation(layerConfig, "minimap")
|
|
||||||
if (!hasMinimap) {
|
|
||||||
layerConfig = { ...layerConfig }
|
|
||||||
layerConfig.tagRenderings = [...layerConfig.tagRenderings]
|
|
||||||
const minimap = state.tagRenderings.get("minimap")
|
|
||||||
if (minimap === undefined) {
|
|
||||||
if (state.tagRenderings.size > 0) {
|
|
||||||
throw "The 'minimap'-builtin tagrendering is not defined. As such, it cannot be added automatically"
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
layerConfig.tagRenderings.push(minimap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return layerConfig
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
|
class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
|
||||||
private readonly _layer: LayerConfigJson
|
private readonly _layer: LayerConfigJson
|
||||||
private readonly _state: DesugaringContext
|
private readonly _state: DesugaringContext
|
||||||
|
@ -1211,16 +1192,15 @@ class ExpandMarkerRenderings extends DesugaringStep<IconConfigJson> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PrepareLayer extends Fuse<LayerConfigJson> {
|
export class PrepareLayer extends Cached<LayerConfigJson, LayerConfigJson> {
|
||||||
constructor(state: DesugaringContext) {
|
constructor(state: DesugaringContext) {
|
||||||
super(
|
const steps = new Fuse<LayerConfigJson>(
|
||||||
"Fully prepares and expands a layer for the LayerConfig.",
|
"Fully prepares and expands a layer for the LayerConfig.",
|
||||||
new On("tagRenderings", new Each(new RewriteSpecial())),
|
new On("tagRenderings", new Each(new RewriteSpecial())),
|
||||||
new On("tagRenderings", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)),
|
new On("tagRenderings", new Concat(new ExpandRewrite()).andThenF(Utils.Flatten)),
|
||||||
new On("tagRenderings", (layer) => new Concat(new ExpandTagRendering(state, layer))),
|
new On("tagRenderings", (layer) => new Concat(new ExpandTagRendering(state, layer))),
|
||||||
new On("tagRenderings", new Each(new DetectInline())),
|
new On("tagRenderings", new Each(new DetectInline())),
|
||||||
new AddQuestionBox(),
|
new AddQuestionBox(),
|
||||||
new AddMiniMap(state),
|
|
||||||
new AddEditingElements(state),
|
new AddEditingElements(state),
|
||||||
new SetFullNodeDatabase(),
|
new SetFullNodeDatabase(),
|
||||||
new On<
|
new On<
|
||||||
|
@ -1244,5 +1224,6 @@ export class PrepareLayer extends Fuse<LayerConfigJson> {
|
||||||
),
|
),
|
||||||
new ExpandFilter(state)
|
new ExpandFilter(state)
|
||||||
)
|
)
|
||||||
|
super(steps)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,8 +275,7 @@ export class ValidateThemeAndLayers extends Fuse<LayoutConfigJson> {
|
||||||
doesImageExist: DoesImageExist,
|
doesImageExist: DoesImageExist,
|
||||||
path: string,
|
path: string,
|
||||||
isBuiltin: boolean,
|
isBuiltin: boolean,
|
||||||
sharedTagRenderings?: Set<string>,
|
sharedTagRenderings?: Set<string>
|
||||||
msg?: string
|
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
"Validates a theme and the contained layers",
|
"Validates a theme and the contained layers",
|
||||||
|
@ -287,8 +286,7 @@ export class ValidateThemeAndLayers extends Fuse<LayoutConfigJson> {
|
||||||
new Pipe(
|
new Pipe(
|
||||||
new ValidateLayer(undefined, isBuiltin, doesImageExist, false, true),
|
new ValidateLayer(undefined, isBuiltin, doesImageExist, false, true),
|
||||||
new Pure((x) => x.raw)
|
new Pure((x) => x.raw)
|
||||||
),
|
)
|
||||||
msg
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,25 +2,17 @@ import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson"
|
||||||
import { Utils } from "../../../Utils"
|
import { Utils } from "../../../Utils"
|
||||||
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
import SpecialVisualizations from "../../../UI/SpecialVisualizations"
|
||||||
import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization"
|
import { RenderingSpecification, SpecialVisualization } from "../../../UI/SpecialVisualization"
|
||||||
import { LayerConfigJson } from "../Json/LayerConfigJson"
|
import { QuestionableTagRenderingConfigJson } from "../Json/QuestionableTagRenderingConfigJson"
|
||||||
|
|
||||||
export default class ValidationUtils {
|
export default class ValidationUtils {
|
||||||
public static hasSpecialVisualisation(
|
public static getAllSpecialVisualisations(
|
||||||
layer: LayerConfigJson,
|
renderingConfigs: (TagRenderingConfigJson | QuestionableTagRenderingConfigJson)[]
|
||||||
specialVisualisation: string
|
): RenderingSpecification[] {
|
||||||
): boolean {
|
const visualisations: RenderingSpecification[] = []
|
||||||
return (
|
for (const renderConfig of renderingConfigs) {
|
||||||
layer.tagRenderings?.some((tagRendering) => {
|
visualisations.push(...ValidationUtils.getSpecialVisualisationsWithArgs(renderConfig))
|
||||||
if (tagRendering === undefined) {
|
}
|
||||||
return false
|
return visualisations
|
||||||
}
|
|
||||||
|
|
||||||
const spec = ValidationUtils.getSpecialVisualisations(
|
|
||||||
<TagRenderingConfigJson>tagRendering
|
|
||||||
)
|
|
||||||
return spec.some((vis) => vis.funcName === specialVisualisation)
|
|
||||||
}) ?? false
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,14 +22,21 @@ export default class ValidationUtils {
|
||||||
public static getSpecialVisualisations(
|
public static getSpecialVisualisations(
|
||||||
renderingConfig: TagRenderingConfigJson
|
renderingConfig: TagRenderingConfigJson
|
||||||
): SpecialVisualization[] {
|
): SpecialVisualization[] {
|
||||||
return ValidationUtils.getSpecialVisualsationsWithArgs(renderingConfig).map(
|
return ValidationUtils.getSpecialVisualisationsWithArgs(renderingConfig).map(
|
||||||
(spec) => spec["func"]
|
(spec) => spec["func"]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getSpecialVisualsationsWithArgs(
|
public static getSpecialVisualisationsWithArgs(
|
||||||
renderingConfig: TagRenderingConfigJson
|
renderingConfig: TagRenderingConfigJson
|
||||||
): RenderingSpecification[] {
|
): RenderingSpecification[] {
|
||||||
|
if (!renderingConfig) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const cacheName = "__specialVisualisationsWithArgs_cache"
|
||||||
|
if (renderingConfig[cacheName]) {
|
||||||
|
return renderingConfig[cacheName]
|
||||||
|
}
|
||||||
const translations: any[] = Utils.NoNull([
|
const translations: any[] = Utils.NoNull([
|
||||||
renderingConfig.render,
|
renderingConfig.render,
|
||||||
...(renderingConfig.mappings ?? []).map((m) => m.then),
|
...(renderingConfig.mappings ?? []).map((m) => m.then),
|
||||||
|
@ -59,6 +58,15 @@ export default class ValidationUtils {
|
||||||
all.push(...specials)
|
all.push(...specials)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// _Very_ dirty hack
|
||||||
|
Object.defineProperty(renderingConfig, cacheName, {
|
||||||
|
value: all,
|
||||||
|
enumerable: false,
|
||||||
|
configurable: true,
|
||||||
|
writable: true,
|
||||||
|
})
|
||||||
|
|
||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,8 +152,6 @@ describe("PrepareTheme", () => {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
startLat: 0,
|
startLat: 0,
|
||||||
pointRendering: null,
|
|
||||||
lineRendering: null,
|
|
||||||
startLon: 0,
|
startLon: 0,
|
||||||
startZoom: 0,
|
startZoom: 0,
|
||||||
title: "Test theme",
|
title: "Test theme",
|
||||||
|
|
Loading…
Reference in a new issue