forked from MapComplete/MapComplete
		
	
		
			
				
	
	
		
			116 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			116 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
import { SubstitutedTranslation } from "../../UI/SubstitutedTranslation"
 | 
						|
import TagRenderingConfig from "./TagRenderingConfig"
 | 
						|
import { ExtraFuncParams, ExtraFunctions } from "../../Logic/ExtraFunctions"
 | 
						|
import LayerConfig from "./LayerConfig"
 | 
						|
import { SpecialVisualization } from "../../UI/SpecialVisualization"
 | 
						|
 | 
						|
export default class DependencyCalculator {
 | 
						|
    public static GetTagRenderingDependencies(tr: TagRenderingConfig): string[] {
 | 
						|
        if (tr === undefined) {
 | 
						|
            throw "Got undefined tag rendering in getTagRenderingDependencies"
 | 
						|
        }
 | 
						|
        const deps: string[] = []
 | 
						|
 | 
						|
        // All translated snippets
 | 
						|
        const parts: string[] = [].concat(...tr.EnumerateTranslations().map((tr) => tr.AllValues()))
 | 
						|
 | 
						|
        for (const part of parts) {
 | 
						|
            const specialVizs: { func: SpecialVisualization; args: string[] }[] =
 | 
						|
                SubstitutedTranslation.ExtractSpecialComponents(part)
 | 
						|
                    .map((o) => o.special)
 | 
						|
                    .filter((o) => o?.func?.getLayerDependencies !== undefined)
 | 
						|
            for (const specialViz of specialVizs) {
 | 
						|
                deps.push(...specialViz.func.getLayerDependencies(specialViz.args))
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return deps
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Returns a set of all other layer-ids that this layer needs to function.
 | 
						|
     * E.g. if this layers does snap to another layer in the preset, this other layer id will be mentioned
 | 
						|
     */
 | 
						|
    public static getLayerDependencies(
 | 
						|
        layer: LayerConfig
 | 
						|
    ): { neededLayer: string; reason: string; context?: string; neededBy: string }[] {
 | 
						|
        const deps: { neededLayer: string; reason: string; context?: string; neededBy: string }[] =
 | 
						|
            []
 | 
						|
 | 
						|
        for (let i = 0; layer.presets !== undefined && i < layer.presets.length; i++) {
 | 
						|
            const preset = layer.presets[i]
 | 
						|
            preset.preciseInput?.snapToLayers?.forEach((id) => {
 | 
						|
                deps.push({
 | 
						|
                    neededLayer: id,
 | 
						|
                    reason: "a preset snaps to this layer",
 | 
						|
                    context: "presets[" + i + "]",
 | 
						|
                    neededBy: layer.id,
 | 
						|
                })
 | 
						|
            })
 | 
						|
        }
 | 
						|
 | 
						|
        for (const tr of layer.AllTagRenderings()) {
 | 
						|
            for (const dep of DependencyCalculator.GetTagRenderingDependencies(tr)) {
 | 
						|
                deps.push({
 | 
						|
                    neededLayer: dep,
 | 
						|
                    reason: "a tagrendering needs this layer",
 | 
						|
                    context: tr.id,
 | 
						|
                    neededBy: layer.id,
 | 
						|
                })
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (layer.calculatedTags?.length > 0) {
 | 
						|
            const obj = {
 | 
						|
                type: "Feature",
 | 
						|
                geometry: {
 | 
						|
                    type: "Point",
 | 
						|
                    coordinates: [0, 0],
 | 
						|
                },
 | 
						|
                properties: {
 | 
						|
                    id: "node/1",
 | 
						|
                },
 | 
						|
            }
 | 
						|
            let currentKey = undefined
 | 
						|
            let currentLine = undefined
 | 
						|
            const params: ExtraFuncParams = {
 | 
						|
                getFeatureById: (_) => undefined,
 | 
						|
                getFeaturesWithin: (layerId, _) => {
 | 
						|
                    if (layerId === "*") {
 | 
						|
                        // This is a wildcard
 | 
						|
                        return []
 | 
						|
                    }
 | 
						|
 | 
						|
                    // The important line: steal the dependencies!
 | 
						|
                    deps.push({
 | 
						|
                        neededLayer: layerId,
 | 
						|
                        reason: "a calculated tag loads features from this layer",
 | 
						|
                        context:
 | 
						|
                            "calculatedTag[" +
 | 
						|
                            currentLine +
 | 
						|
                            "] which calculates the value for " +
 | 
						|
                            currentKey,
 | 
						|
                        neededBy: layer.id,
 | 
						|
                    })
 | 
						|
 | 
						|
                    return []
 | 
						|
                },
 | 
						|
                memberships: undefined,
 | 
						|
            }
 | 
						|
            // Init the extra patched functions...
 | 
						|
            ExtraFunctions.FullPatchFeature(params, obj)
 | 
						|
            // ... Run the calculated tag code, which will trigger the getFeaturesWithin above...
 | 
						|
            for (let i = 0; i < layer.calculatedTags.length; i++) {
 | 
						|
                const [key, code] = layer.calculatedTags[i]
 | 
						|
                currentLine = i // Leak the state...
 | 
						|
                currentKey = key
 | 
						|
                try {
 | 
						|
                    const func = new Function("feat", "return " + code + ";")
 | 
						|
                    const result = func(obj)
 | 
						|
                    obj.properties[key] = JSON.stringify(result)
 | 
						|
                } catch (e) {}
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return deps
 | 
						|
    }
 | 
						|
}
 |