2022-04-13 00:31:13 +02:00
import { Concat , Conversion , DesugaringContext , DesugaringStep , Each , Fuse , On , Pass , SetDefault } from "./Conversion" ;
2022-01-21 01:57:16 +01:00
import { LayoutConfigJson } from "../Json/LayoutConfigJson" ;
import { PrepareLayer } from "./PrepareLayer" ;
import { LayerConfigJson } from "../Json/LayerConfigJson" ;
import { Utils } from "../../../Utils" ;
import Constants from "../../Constants" ;
import CreateNoteImportLayer from "./CreateNoteImportLayer" ;
import LayerConfig from "../LayerConfig" ;
import { TagRenderingConfigJson } from "../Json/TagRenderingConfigJson" ;
import { SubstitutedTranslation } from "../../../UI/SubstitutedTranslation" ;
import DependencyCalculator from "../DependencyCalculator" ;
2022-04-08 21:53:08 +02:00
import { AddContextToTranslations } from "./AddContextToTranslations" ;
2022-01-21 01:57:16 +01:00
class SubstituteLayer extends Conversion < ( string | LayerConfigJson ) , LayerConfigJson [ ] > {
2022-02-04 01:05:35 +01:00
private readonly _state : DesugaringContext ;
2022-04-13 00:31:13 +02:00
2022-02-04 01:05:35 +01:00
constructor (
state : DesugaringContext ,
) {
2022-04-13 00:31:13 +02:00
super ( "Converts the identifier of a builtin layer into the actual layer, or converts a 'builtin' syntax with override in the fully expanded form" , [ ] , "SubstituteLayer" ) ;
2022-02-04 01:05:35 +01:00
this . _state = state ;
2022-01-21 01:57:16 +01:00
}
2022-04-13 00:31:13 +02:00
2022-02-10 23:16:14 +01:00
convert ( json : string | LayerConfigJson , context : string ) : { result : LayerConfigJson [ ] ; errors : string [ ] , information? : string [ ] } {
2022-01-21 01:57:16 +01:00
const errors = [ ]
2022-02-10 23:16:14 +01:00
const information = [ ]
2022-04-13 00:31:13 +02:00
const state = this . _state
function reportNotFound ( name : string ) {
2022-02-04 00:44:09 +01:00
const knownLayers = Array . from ( state . sharedLayers . keys ( ) )
2022-04-13 00:31:13 +02:00
const withDistance = knownLayers . map ( lname = > [ lname , Utils . levenshteinDistance ( name , lname ) ] )
2022-02-04 00:44:09 +01:00
withDistance . sort ( ( a , b ) = > a [ 1 ] - b [ 1 ] )
const ids = withDistance . map ( n = > n [ 0 ] )
2022-04-13 00:31:13 +02:00
// Known builtin layers are "+.join(",")+"\n For more information, see "
2022-02-04 00:44:09 +01:00
errors . push ( ` ${ context } : The layer with name ${ name } was not found as a builtin layer. Perhaps you meant ${ ids [ 0 ] } , ${ ids [ 1 ] } or ${ ids [ 2 ] } ?
For an overview of all available layers , refer to https : //github.com/pietervdvn/MapComplete/blob/develop/Docs/BuiltinLayers.md`)
}
2022-04-13 00:31:13 +02:00
2022-01-21 01:57:16 +01:00
if ( typeof json === "string" ) {
const found = state . sharedLayers . get ( json )
if ( found === undefined ) {
2022-02-04 00:44:09 +01:00
reportNotFound ( json )
2022-01-21 01:57:16 +01:00
return {
result : null ,
2022-02-04 00:44:09 +01:00
errors ,
2022-01-21 01:57:16 +01:00
}
}
return {
result : [ found ] ,
2022-02-04 01:05:35 +01:00
errors
2022-01-21 01:57:16 +01:00
}
}
if ( json [ "builtin" ] !== undefined ) {
let names = json [ "builtin" ]
if ( typeof names === "string" ) {
names = [ names ]
}
const layers = [ ]
2022-02-08 02:23:38 +01:00
2022-01-21 01:57:16 +01:00
for ( const name of names ) {
const found = Utils . Clone ( state . sharedLayers . get ( name ) )
if ( found === undefined ) {
2022-02-04 00:44:09 +01:00
reportNotFound ( name )
2022-01-21 01:57:16 +01:00
continue
}
if ( json [ "override" ] [ "tagRenderings" ] !== undefined && ( found [ "tagRenderings" ] ? ? [ ] ) . length > 0 ) {
errors . push ( ` At ${ context } : when overriding a layer, an override is not allowed to override into tagRenderings. Use "+tagRenderings" or "tagRenderings+" instead to prepend or append some questions. ` )
}
try {
Utils . Merge ( json [ "override" ] , found ) ;
layers . push ( found )
} catch ( e ) {
errors . push ( ` At ${ context } : could not apply an override due to: ${ e } . \ nThe override is: ${ JSON . stringify ( json [ "override" ] , ) } ` )
}
2022-04-13 00:31:13 +02:00
if ( json [ "hideTagRenderingsWithLabels" ] ) {
2022-02-08 02:23:38 +01:00
const hideLabels : Set < string > = new Set ( json [ "hideTagRenderingsWithLabels" ] )
// These labels caused at least one deletion
2022-04-13 00:31:13 +02:00
const usedLabels : Set < string > = new Set < string > ( ) ;
2022-02-08 02:23:38 +01:00
const filtered = [ ]
for ( const tr of found . tagRenderings ) {
const labels = tr [ "labels" ]
2022-04-13 00:31:13 +02:00
if ( labels !== undefined ) {
2022-02-08 02:23:38 +01:00
const forbiddenLabel = labels . findIndex ( l = > hideLabels . has ( l ) )
2022-04-13 00:31:13 +02:00
if ( forbiddenLabel >= 0 ) {
2022-02-08 02:23:38 +01:00
usedLabels . add ( labels [ forbiddenLabel ] )
2022-04-13 00:31:13 +02:00
information . push ( context + ": Dropping tagRendering " + tr [ "id" ] + " as it has a forbidden label: " + labels [ forbiddenLabel ] )
2022-02-08 02:23:38 +01:00
continue
}
}
2022-04-13 00:31:13 +02:00
if ( hideLabels . has ( tr [ "id" ] ) ) {
2022-02-08 02:23:38 +01:00
usedLabels . add ( tr [ "id" ] )
2022-04-13 00:31:13 +02:00
information . push ( context + ": Dropping tagRendering " + tr [ "id" ] + " as its id is a forbidden label" )
2022-02-08 02:23:38 +01:00
continue
}
2022-04-13 00:31:13 +02:00
if ( hideLabels . has ( tr [ "group" ] ) ) {
2022-02-08 02:23:38 +01:00
usedLabels . add ( tr [ "group" ] )
2022-04-13 00:31:13 +02:00
information . push ( context + ": Dropping tagRendering " + tr [ "id" ] + " as its group `" + tr [ "group" ] + "` is a forbidden label" )
2022-02-08 02:23:38 +01:00
continue
}
filtered . push ( tr )
}
const unused = Array . from ( hideLabels ) . filter ( l = > ! usedLabels . has ( l ) )
2022-04-13 00:31:13 +02:00
if ( unused . length > 0 ) {
errors . push ( "This theme specifies that certain tagrenderings have to be removed based on forbidden layers. One or more of these layers did not match any tagRenderings and caused no deletions: " + unused . join ( ", " ) + "\n This means that this label can be removed or that the original tagRendering that should be deleted does not have this label anymore" )
2022-02-08 02:23:38 +01:00
}
found . tagRenderings = filtered
}
2022-01-21 01:57:16 +01:00
}
return {
result : layers ,
2022-02-08 02:23:38 +01:00
errors ,
2022-02-10 23:16:14 +01:00
information
2022-01-21 01:57:16 +01:00
}
}
return {
result : [ json ] ,
2022-02-04 01:05:35 +01:00
errors
2022-01-21 01:57:16 +01:00
} ;
}
}
class AddDefaultLayers extends DesugaringStep < LayoutConfigJson > {
2022-02-04 01:05:35 +01:00
private _state : DesugaringContext ;
2022-01-21 01:57:16 +01:00
2022-02-04 01:05:35 +01:00
constructor ( state : DesugaringContext ) {
2022-04-13 00:31:13 +02:00
super ( "Adds the default layers, namely: " + Constants . added_by_default . join ( ", " ) , [ "layers" ] , "AddDefaultLayers" ) ;
2022-02-04 01:05:35 +01:00
this . _state = state ;
2022-01-21 01:57:16 +01:00
}
2022-02-04 01:05:35 +01:00
convert ( json : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; errors : string [ ] ; warnings : string [ ] } {
2022-01-21 01:57:16 +01:00
const errors = [ ]
const warnings = [ ]
2022-02-04 01:05:35 +01:00
const state = this . _state
2022-01-21 01:57:16 +01:00
json . layers = [ . . . json . layers ]
2022-01-31 14:34:06 +01:00
const alreadyLoaded = new Set ( json . layers . map ( l = > l [ "id" ] ) )
2022-01-21 01:57:16 +01:00
for ( const layerName of Constants . added_by_default ) {
const v = state . sharedLayers . get ( layerName )
if ( v === undefined ) {
errors . push ( "Default layer " + layerName + " not found" )
2022-03-18 13:04:12 +01:00
continue
2022-01-21 01:57:16 +01:00
}
2022-04-13 00:31:13 +02:00
if ( alreadyLoaded . has ( v . id ) ) {
warnings . push ( "Layout " + context + " already has a layer with name " + v . id + "; skipping inclusion of this builtin layer" )
2022-01-31 14:34:06 +01:00
continue
}
2022-01-21 01:57:16 +01:00
json . layers . push ( v )
}
return {
result : json ,
errors ,
warnings
} ;
}
}
class AddImportLayers extends DesugaringStep < LayoutConfigJson > {
constructor ( ) {
2022-04-13 00:31:13 +02:00
super ( "For every layer in the 'layers'-list, create a new layer which'll import notes. (Note that priviliged layers and layers which have a geojson-source set are ignored)" , [ "layers" ] , "AddImportLayers" ) ;
2022-01-21 01:57:16 +01:00
}
2022-05-06 12:41:24 +02:00
convert ( json : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; errors? : string [ ] , warnings? : string [ ] } {
if ( ! ( json . enableNoteImports ? ? true ) ) {
return {
warnings : [ "Not creating a note import layers for theme " + json . id + " as they are disabled" ] ,
result : json
} ;
}
2022-01-21 01:57:16 +01:00
const errors = [ ]
2022-01-26 21:40:38 +01:00
2022-01-21 01:57:16 +01:00
json = { . . . json }
const allLayers : LayerConfigJson [ ] = < LayerConfigJson [ ] > json . layers ;
json . layers = [ . . . json . layers ]
2022-01-26 21:40:38 +01:00
2022-05-06 12:41:24 +02:00
const creator = new CreateNoteImportLayer ( )
for ( let i1 = 0 ; i1 < allLayers . length ; i1 ++ ) {
const layer = allLayers [ i1 ] ;
if ( Constants . priviliged_layers . indexOf ( layer . id ) >= 0 ) {
// Priviliged layers are skipped
continue
}
2022-01-21 01:57:16 +01:00
2022-05-06 12:41:24 +02:00
if ( layer . source [ "geoJson" ] !== undefined ) {
// Layer which don't get their data from OSM are skipped
continue
}
2022-01-21 01:57:16 +01:00
2022-05-06 12:41:24 +02:00
if ( layer . title === undefined || layer . name === undefined ) {
// Anonymous layers and layers without popup are skipped
continue
}
2022-01-21 01:57:16 +01:00
2022-05-06 12:41:24 +02:00
if ( layer . presets === undefined || layer . presets . length == 0 ) {
// A preset is needed to be able to generate a new point
continue ;
}
2022-01-21 01:57:16 +01:00
2022-05-06 12:41:24 +02:00
try {
2022-01-21 01:57:16 +01:00
2022-05-06 12:41:24 +02:00
const importLayerResult = creator . convert ( layer , context + ".(noteimportlayer)[" + i1 + "]" )
if ( importLayerResult . result !== undefined ) {
json . layers . push ( importLayerResult . result )
2022-01-21 01:57:16 +01:00
}
2022-05-06 12:41:24 +02:00
} catch ( e ) {
errors . push ( "Could not generate an import-layer for " + layer . id + " due to " + e )
2022-01-21 01:57:16 +01:00
}
}
return {
errors ,
result : json
} ;
}
}
2022-01-26 21:12:25 +01:00
2022-01-26 21:21:12 +01:00
export class AddMiniMap extends DesugaringStep < LayerConfigJson > {
2022-02-04 01:05:35 +01:00
private readonly _state : DesugaringContext ;
2022-04-13 00:31:13 +02:00
constructor ( state : DesugaringContext , ) {
super ( "Adds a default 'minimap'-element to the tagrenderings if none of the elements define such a minimap" , [ "tagRenderings" ] , "AddMiniMap" ) ;
2022-02-04 01:05:35 +01:00
this . _state = state ;
2022-01-21 01:57:16 +01:00
}
/ * *
* Returns true if this tag rendering has a minimap in some language .
* Note : this minimap can be hidden by conditions
2022-04-13 00:31:13 +02:00
*
2022-03-23 19:48:06 +01:00
* AddMiniMap . hasMinimap ( { render : "{minimap()}" } ) // => true
* AddMiniMap . hasMinimap ( { render : { en : "{minimap()}" } } ) // => true
* AddMiniMap . hasMinimap ( { render : { en : "{minimap()}" , nl : "{minimap()}" } } ) // => true
* AddMiniMap . hasMinimap ( { render : { en : "{minimap()}" , nl : "No map for the dutch!" } } ) // => true
* AddMiniMap . hasMinimap ( { render : "{minimap()}" } ) // => true
* AddMiniMap . hasMinimap ( { render : "{minimap(18,featurelist)}" } ) // => true
* AddMiniMap . hasMinimap ( { mappings : [ { if : "xyz=abc" , then : "{minimap(18,featurelist)}" } ] } ) // => true
* AddMiniMap . hasMinimap ( { render : "Some random value {key}" } ) // => false
* AddMiniMap . hasMinimap ( { render : "Some random value {minimap}" } ) // => false
2022-01-21 01:57:16 +01:00
* /
2022-01-26 21:21:12 +01:00
static hasMinimap ( renderingConfig : TagRenderingConfigJson ) : boolean {
const translations : any [ ] = Utils . NoNull ( [ renderingConfig . render , . . . ( renderingConfig . mappings ? ? [ ] ) . map ( m = > m . then ) ] ) ;
for ( let translation of translations ) {
2022-01-26 21:40:38 +01:00
if ( typeof translation == "string" ) {
2022-01-26 21:21:12 +01:00
translation = { "*" : translation }
}
2022-01-26 21:40:38 +01:00
2022-01-26 21:21:12 +01:00
for ( const key in translation ) {
if ( ! translation . hasOwnProperty ( key ) ) {
2022-01-21 01:57:16 +01:00
continue
}
2022-05-06 12:41:24 +02:00
2022-01-26 21:21:12 +01:00
const template = translation [ key ]
2022-01-21 01:57:16 +01:00
const parts = SubstitutedTranslation . ExtractSpecialComponents ( template )
const hasMiniMap = parts . filter ( part = > part . special !== undefined ) . some ( special = > special . special . func . funcName === "minimap" )
if ( hasMiniMap ) {
return true ;
}
}
}
return false ;
}
2022-02-10 23:16:14 +01:00
convert ( layerConfig : LayerConfigJson , context : string ) : { result : LayerConfigJson } {
2022-01-21 01:57:16 +01:00
2022-02-04 01:05:35 +01:00
const state = this . _state ;
2022-01-21 01:57:16 +01:00
const hasMinimap = layerConfig . tagRenderings ? . some ( tr = > AddMiniMap . hasMinimap ( < TagRenderingConfigJson > tr ) ) ? ? true
if ( ! hasMinimap ) {
layerConfig = { . . . layerConfig }
layerConfig . tagRenderings = [ . . . layerConfig . tagRenderings ]
2022-01-26 20:47:08 +01:00
layerConfig . tagRenderings . push ( state . tagRenderings . get ( "questions" ) )
2022-01-21 01:57:16 +01:00
layerConfig . tagRenderings . push ( state . tagRenderings . get ( "minimap" ) )
}
return {
result : layerConfig
} ;
}
}
2022-04-13 00:31:13 +02:00
class AddContextToTransltionsInLayout extends DesugaringStep < LayoutConfigJson > {
2022-04-06 17:28:51 +02:00
constructor ( ) {
2022-04-13 00:31:13 +02:00
super ( "Adds context to translations, including the prefix 'themes:json.id'; this is to make sure terms in an 'overrides' or inline layer are linkable too" , [ "_context" ] , "AddContextToTranlationsInLayout" ) ;
2022-04-06 17:28:51 +02:00
}
2022-04-13 00:31:13 +02:00
2022-04-06 17:28:51 +02:00
convert ( json : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; errors? : string [ ] ; warnings? : string [ ] ; information? : string [ ] } {
const conversion = new AddContextToTranslations < LayoutConfigJson > ( "themes:" )
return conversion . convert ( json , json . id ) ;
}
2022-04-13 00:31:13 +02:00
2022-04-06 17:28:51 +02:00
}
2022-01-24 00:59:23 +01:00
class ApplyOverrideAll extends DesugaringStep < LayoutConfigJson > {
constructor ( ) {
2022-04-13 00:31:13 +02:00
super ( "Applies 'overrideAll' onto every 'layer'. The 'overrideAll'-field is removed afterwards" , [ "overrideAll" , "layers" ] , "ApplyOverrideAll" ) ;
2022-01-24 00:59:23 +01:00
}
2022-02-04 01:05:35 +01:00
convert ( json : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; errors : string [ ] ; warnings : string [ ] } {
2022-01-24 00:59:23 +01:00
const overrideAll = json . overrideAll ;
if ( overrideAll === undefined ) {
return { result : json , warnings : [ ] , errors : [ ] }
}
json = { . . . json }
delete json . overrideAll
const newLayers = [ ]
for ( let layer of json . layers ) {
2022-02-24 03:48:28 +01:00
layer = Utils . Clone ( < LayerConfigJson > layer )
2022-01-24 00:59:23 +01:00
Utils . Merge ( overrideAll , layer )
newLayers . push ( layer )
}
json . layers = newLayers
return { result : json , warnings : [ ] , errors : [ ] } ;
}
}
2022-01-21 01:57:16 +01:00
class AddDependencyLayersToTheme extends DesugaringStep < LayoutConfigJson > {
2022-02-04 01:05:35 +01:00
private readonly _state : DesugaringContext ;
2022-04-13 00:31:13 +02:00
constructor ( state : DesugaringContext , ) {
2022-04-23 15:20:54 +02:00
super (
` If a layer has a dependency on another layer, these layers are added automatically on the theme. (For example: defibrillator depends on 'walls_and_buildings' to snap onto. This layer is added automatically)
Note that these layers are added _at the start_ of the layer list , meaning that they will see _every_ feature .
Furthermore , \ ` passAllFeatures \` will be set, so that they won't steal away features from further layers.
Some layers ( e . g . \ ` all_buildings_and_walls \ ' or \ 'streets_with_a_name \ ') are invisible, so by default, \ 'force_load \ ' is set too.
` , ["layers"], "AddDependencyLayersToTheme");
2022-02-04 01:05:35 +01:00
this . _state = state ;
2022-01-21 01:57:16 +01:00
}
2022-04-23 15:20:54 +02:00
private static CalculateDependencies ( alreadyLoaded : LayerConfigJson [ ] , allKnownLayers : Map < string , LayerConfigJson > , themeId : string ) :
{ config : LayerConfigJson , reason : string } [ ] {
const dependenciesToAdd : { config : LayerConfigJson , reason : string } [ ] = [ ]
2022-01-21 01:57:16 +01:00
const loadedLayerIds : Set < string > = new Set < string > ( alreadyLoaded . map ( l = > l . id ) ) ;
// Verify cross-dependencies
let unmetDependencies : { neededLayer : string , neededBy : string , reason : string , context? : string } [ ] = [ ]
do {
const dependencies : { neededLayer : string , reason : string , context? : string , neededBy : string } [ ] = [ ]
for ( const layerConfig of alreadyLoaded ) {
2022-04-13 00:31:13 +02:00
try {
2022-07-18 02:00:32 +02:00
const layerDeps = DependencyCalculator . getLayerDependencies ( new LayerConfig ( layerConfig , themeId + "(dependencies)" ) )
2022-04-06 17:28:51 +02:00
dependencies . push ( . . . layerDeps )
2022-04-13 00:31:13 +02:00
} catch ( e ) {
2022-04-06 17:28:51 +02:00
console . error ( e )
2022-04-13 00:31:13 +02:00
throw "Detecting layer dependencies for " + layerConfig . id + " failed due to " + e
2022-04-06 17:28:51 +02:00
}
2022-01-21 01:57:16 +01:00
}
2022-02-07 01:59:07 +01:00
for ( const dependency of dependencies ) {
2022-04-13 00:31:13 +02:00
if ( loadedLayerIds . has ( dependency . neededLayer ) ) {
2022-02-07 01:59:07 +01:00
// We mark the needed layer as 'mustLoad'
alreadyLoaded . find ( l = > l . id === dependency . neededLayer ) . forceLoad = true
}
}
2022-01-21 01:57:16 +01:00
// During the generate script, builtin layers are verified but not loaded - so we have to add them manually here
2022-04-23 15:20:54 +02:00
// Their existence is checked elsewhere, so this is fine
2022-01-21 01:57:16 +01:00
unmetDependencies = dependencies . filter ( dep = > ! loadedLayerIds . has ( dep . neededLayer ) )
for ( const unmetDependency of unmetDependencies ) {
if ( loadedLayerIds . has ( unmetDependency . neededLayer ) ) {
continue
}
2022-04-23 15:20:54 +02:00
const dep = Utils . Clone ( allKnownLayers . get ( unmetDependency . neededLayer ) )
const reason = "This layer is needed by " + unmetDependency . neededBy + " because " +
unmetDependency . reason + " (at " + unmetDependency . context + ")" ;
2022-01-21 01:57:16 +01:00
if ( dep === undefined ) {
const message =
[ "Loading a dependency failed: layer " + unmetDependency . neededLayer + " is not found, neither as layer of " + themeId + " nor as builtin layer." ,
2022-04-23 15:20:54 +02:00
reason ,
2022-01-21 01:57:16 +01:00
"Loaded layers are: " + alreadyLoaded . map ( l = > l . id ) . join ( "," )
]
throw message . join ( "\n\t" ) ;
}
2022-04-23 15:20:54 +02:00
dep . forceLoad = true ;
dep . passAllFeatures = true ;
dep . description = reason ;
dependenciesToAdd . unshift ( {
config : dep ,
reason
} )
2022-01-21 01:57:16 +01:00
loadedLayerIds . add ( dep . id ) ;
unmetDependencies = unmetDependencies . filter ( d = > d . neededLayer !== unmetDependency . neededLayer )
}
} while ( unmetDependencies . length > 0 )
2022-04-13 00:31:13 +02:00
2022-04-23 15:20:54 +02:00
return dependenciesToAdd
2022-01-21 01:57:16 +01:00
}
2022-02-10 23:16:14 +01:00
convert ( theme : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; information : string [ ] } {
2022-02-04 01:05:35 +01:00
const state = this . _state
2022-01-21 01:57:16 +01:00
const allKnownLayers : Map < string , LayerConfigJson > = state . sharedLayers ;
const knownTagRenderings : Map < string , TagRenderingConfigJson > = state . tagRenderings ;
2022-02-10 23:16:14 +01:00
const information = [ ] ;
2022-01-21 01:57:16 +01:00
const layers : LayerConfigJson [ ] = < LayerConfigJson [ ] > theme . layers ; // Layers should be expanded at this point
knownTagRenderings . forEach ( ( value , key ) = > {
value . id = key ;
} )
const dependencies = AddDependencyLayersToTheme . CalculateDependencies ( layers , allKnownLayers , theme . id ) ;
2022-04-23 15:20:54 +02:00
for ( const dependency of dependencies ) {
}
2022-01-21 01:57:16 +01:00
if ( dependencies . length > 0 ) {
2022-04-23 15:20:54 +02:00
for ( const dependency of dependencies ) {
information . push ( context + ": added " + dependency . config . id + " to the theme. " + dependency . reason )
}
2022-01-21 01:57:16 +01:00
}
2022-04-23 15:20:54 +02:00
layers . unshift ( . . . dependencies . map ( l = > l . config ) ) ;
2022-01-21 01:57:16 +01:00
return {
result : {
. . . theme ,
layers : layers
} ,
2022-02-10 23:16:14 +01:00
information
2022-01-21 01:57:16 +01:00
} ;
}
}
2022-02-14 15:41:14 +01:00
class PreparePersonalTheme extends DesugaringStep < LayoutConfigJson > {
private readonly _state : DesugaringContext ;
2022-04-13 00:31:13 +02:00
2022-02-14 15:41:14 +01:00
constructor ( state : DesugaringContext ) {
2022-04-13 00:31:13 +02:00
super ( "Adds every public layer to the personal theme" , [ "layers" ] , "PreparePersonalTheme" ) ;
2022-02-14 15:41:14 +01:00
this . _state = state ;
}
convert ( json : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; errors? : string [ ] ; warnings? : string [ ] ; information? : string [ ] } {
2022-04-13 00:31:13 +02:00
if ( json . id !== "personal" ) {
2022-02-14 15:41:14 +01:00
return { result : json }
}
2022-06-13 03:13:42 +02:00
// The only thing this _really_ does, is adding the layer-ids into 'layers'
// All other preparations are done by the 'override-all'-block in personal.json
json . layers = Array . from ( this . _state . sharedLayers . keys ( ) )
. filter ( l = > Constants . priviliged_layers . indexOf ( l ) < 0 )
. filter ( l = > this . _state . publicLayers . has ( l ) )
return { result : json , information : [
"The personal theme has " + json . layers . length + " public layers"
] } ;
2022-02-14 15:41:14 +01:00
}
2022-04-13 00:31:13 +02:00
2022-02-14 15:41:14 +01:00
}
2022-01-21 01:57:16 +01:00
2022-04-13 00:31:13 +02:00
class WarnForUnsubstitutedLayersInTheme extends DesugaringStep < LayoutConfigJson > {
2022-03-24 19:59:46 +01:00
constructor ( ) {
2022-04-13 00:31:13 +02:00
super ( "Generates a warning if a theme uses an unsubstituted layer" , [ "layers" ] , "WarnForUnsubstitutedLayersInTheme" ) ;
2022-03-24 19:59:46 +01:00
}
2022-04-13 00:31:13 +02:00
2022-03-24 19:59:46 +01:00
convert ( json : LayoutConfigJson , context : string ) : { result : LayoutConfigJson ; errors? : string [ ] ; warnings? : string [ ] ; information? : string [ ] } {
2022-04-13 00:31:13 +02:00
if ( json . hideFromOverview === true ) {
2022-03-24 19:59:46 +01:00
return { result : json }
}
const warnings = [ ]
for ( const layer of json . layers ) {
2022-04-13 00:31:13 +02:00
if ( typeof layer === "string" ) {
2022-03-24 19:59:46 +01:00
continue
}
2022-04-13 00:31:13 +02:00
if ( layer [ "builtin" ] !== undefined ) {
2022-03-24 19:59:46 +01:00
continue
}
2022-04-13 00:31:13 +02:00
if ( layer [ "source" ] [ "geojson" ] !== undefined ) {
2022-03-24 19:59:46 +01:00
// We turn a blind eye for import layers
continue
}
2022-04-13 00:31:13 +02:00
const wrn = "The theme " + json . id + " has an inline layer: " + layer [ "id" ] + ". This is discouraged."
2022-03-24 19:59:46 +01:00
warnings . push ( wrn )
}
return {
result : json ,
warnings
} ;
}
2022-04-13 00:31:13 +02:00
2022-03-24 19:59:46 +01:00
}
2022-01-21 01:57:16 +01:00
export class PrepareTheme extends Fuse < LayoutConfigJson > {
2022-04-13 00:31:13 +02:00
constructor ( state : DesugaringContext , options ? : {
skipDefaultLayers : false | boolean
} ) {
2022-01-21 01:57:16 +01:00
super (
"Fully prepares and expands a theme" ,
2022-04-22 03:17:40 +02:00
2022-04-06 17:28:51 +02:00
new AddContextToTransltionsInLayout ( ) ,
2022-02-14 15:41:14 +01:00
new PreparePersonalTheme ( state ) ,
2022-03-31 02:54:17 +02:00
new WarnForUnsubstitutedLayersInTheme ( ) ,
2022-04-06 03:06:50 +02:00
new On ( "layers" , new Concat ( new SubstituteLayer ( state ) ) ) ,
2022-01-21 01:57:16 +01:00
new SetDefault ( "socialImage" , "assets/SocialImage.png" , true ) ,
2022-02-18 23:10:27 +01:00
// We expand all tagrenderings first...
2022-04-06 03:06:50 +02:00
new On ( "layers" , new Each ( new PrepareLayer ( state ) ) ) ,
2022-02-18 23:10:27 +01:00
// Then we apply the override all
2022-01-24 00:59:23 +01:00
new ApplyOverrideAll ( ) ,
2022-02-18 23:10:27 +01:00
// And then we prepare all the layers _again_ in case that an override all contained unexpanded tagrenderings!
2022-04-06 03:06:50 +02:00
new On ( "layers" , new Each ( new PrepareLayer ( state ) ) ) ,
2022-04-13 00:31:13 +02:00
options ? . skipDefaultLayers ? new Pass ( "AddDefaultLayers is disabled due to the set flag" ) : new AddDefaultLayers ( state ) ,
2022-02-04 01:05:35 +01:00
new AddDependencyLayersToTheme ( state ) ,
2022-01-21 01:57:16 +01:00
new AddImportLayers ( ) ,
2022-04-06 03:06:50 +02:00
new On ( "layers" , new Each ( new AddMiniMap ( state ) ) )
2022-01-21 01:57:16 +01:00
) ;
}
}