forked from MapComplete/MapComplete
		
	
		
			
	
	
		
			111 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
		
		
			
		
	
	
			111 lines
		
	
	
	
		
			4.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
|  | import {SpecialVisualization} from "../../UI/SpecialVisualizations"; | ||
|  | import {SubstitutedTranslation} from "../../UI/SubstitutedTranslation"; | ||
|  | import TagRenderingConfig from "./TagRenderingConfig"; | ||
|  | import {ExtraFuncParams, ExtraFunctions} from "../../Logic/ExtraFunctions"; | ||
|  | import LayerConfig from "./LayerConfig"; | ||
|  | 
 | ||
|  | 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 = { | ||
|  |                 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 | ||
|  |     } | ||
|  | } |