1from typing import Any, Dict, Optional 2 3from draftjs_exporter.constants import BLOCK_TYPES, ENTITY_TYPES, INLINE_STYLES 4from draftjs_exporter.error import ConfigException 5from draftjs_exporter.types import ConfigMap, Props, RenderableType 6 7# Internal equivalent of a ConfigMap. 8OptionsMap = Dict[str, "Options"] 9 10 11class Options(object): 12 """ 13 Facilitates querying configuration from a config map. 14 """ 15 16 __slots__ = ("type", "element", "props", "wrapper", "wrapper_props") 17 18 def __init__( 19 self, 20 type_: str, 21 element: RenderableType, 22 props: Optional[Props] = None, 23 wrapper: RenderableType = None, 24 wrapper_props: Optional[Props] = None, 25 ) -> None: 26 self.type = type_ 27 self.element = element 28 self.props = props if props else {} 29 self.wrapper = wrapper 30 self.wrapper_props = wrapper_props 31 32 def __str__(self) -> str: 33 return f"<Options {self.type} {self.element} {self.props} {self.wrapper} {self.wrapper_props}>" 34 35 def __repr__(self) -> str: 36 return str(self) 37 38 def __eq__(self, other: Any) -> bool: 39 """ 40 Equality used in test code only, not to be relied on for the exporter. 41 """ 42 return str(self) == str(other) 43 44 def __ne__(self, other: Any) -> bool: 45 return not self == other 46 47 def __hash__(self) -> int: 48 return hash(str(self)) 49 50 @staticmethod 51 def create(kind_map: ConfigMap, type_: str, fallback_key: str) -> "Options": 52 """ 53 Create an Options object from any mapping. 54 """ 55 if type_ not in kind_map: 56 if fallback_key not in kind_map: 57 raise ConfigException( 58 f'"{type_}" is not in the config and has no fallback' 59 ) 60 61 config = kind_map[fallback_key] 62 else: 63 config = kind_map[type_] 64 65 if isinstance(config, dict): 66 if "element" not in config: 67 raise ConfigException(f'"{type_}" does not define an element') 68 69 opts = Options(type_, **config) 70 else: 71 opts = Options(type_, config) 72 73 return opts 74 75 @staticmethod 76 def map(kind_map: ConfigMap, fallback_key: str) -> OptionsMap: 77 options = {} 78 for type_ in kind_map: 79 options[type_] = Options.create(kind_map, type_, fallback_key) 80 81 return options 82 83 @staticmethod 84 def map_blocks(block_map: ConfigMap) -> OptionsMap: 85 return Options.map(block_map, BLOCK_TYPES.FALLBACK) 86 87 @staticmethod 88 def map_styles(style_map: ConfigMap) -> OptionsMap: 89 return Options.map(style_map, INLINE_STYLES.FALLBACK) 90 91 @staticmethod 92 def map_entities(entity_map: ConfigMap) -> OptionsMap: 93 return Options.map(entity_map, ENTITY_TYPES.FALLBACK) 94 95 @staticmethod 96 def get(options: OptionsMap, type_: str, fallback_key: str) -> "Options": 97 try: 98 return options[type_] 99 except KeyError: 100 try: 101 return options[fallback_key] 102 except KeyError: 103 raise ConfigException( 104 f'"{type_}" is not in the config and has no fallback' 105 ) 106