1919
2020import dataclasses as _dataclasses
2121import typing as _typing
22+ from collections .abc import Mapping as _Mapping
23+ from collections .abc import Sequence as _Sequence
2224from enum import Enum as _Enum
2325
2426import typing_extensions as _typing_extensions
2527
2628import firebase_functions .params as _params
2729import firebase_functions .private .util as _util
2830
31+ ManifestParamBase = _params .Param | _params .SecretParam
32+
33+ ManifestParam = (
34+ _params .BoolParam
35+ | _params .IntParam
36+ | _params ._FloatParam
37+ | _params .ListParam
38+ | _params .SecretParam
39+ | _params .StringParam
40+ )
41+
42+ SpecValue : _typing .TypeAlias = (
43+ str
44+ | int
45+ | float
46+ | bool
47+ | _util .Sentinel
48+ | list ["SpecValue" ]
49+ | dict [str , "SpecValue" ]
50+ | None
51+ )
52+
53+
54+ class _DataclassInstance (_typing .Protocol ):
55+ __dataclass_fields__ : _typing .ClassVar [dict [str , _dataclasses .Field [object ]]]
56+
2957
3058class SecretEnvironmentVariable (_typing .TypedDict ):
3159 key : _typing_extensions .Required [str ]
@@ -180,7 +208,7 @@ class ManifestRequiredApi(_typing.TypedDict):
180208class ManifestStack :
181209 endpoints : dict [str , ManifestEndpoint ]
182210 specVersion : str = "v1alpha1"
183- params : list [ _typing . Any ] | None = _dataclasses .field (default_factory = list [_typing . Any ])
211+ params : _Sequence [ ManifestParamBase ] | None = _dataclasses .field (default_factory = list [ManifestParamBase ])
184212 requiredAPIs : list [ManifestRequiredApi ] = _dataclasses .field (
185213 default_factory = list [ManifestRequiredApi ]
186214 )
@@ -191,7 +219,7 @@ def _param_input_to_spec(
191219 | _params .ResourceInput
192220 | _params .SelectInput
193221 | _params .MultiSelectInput ,
194- ) -> dict [str , _typing . Any ]:
222+ ) -> dict [str , SpecValue ]:
195223 if isinstance (param_input , _params .TextInput ):
196224 return {
197225 "text" : {
@@ -233,8 +261,8 @@ def _param_input_to_spec(
233261 return {}
234262
235263
236- def _param_to_spec (param : _params . Param | _params . SecretParam ) -> dict [str , _typing . Any ]:
237- spec_dict : dict [str , _typing . Any ] = {
264+ def _param_to_spec (param : ManifestParamBase ) -> dict [str , SpecValue ]:
265+ spec_dict : dict [str , SpecValue ] = {
238266 "name" : param .name ,
239267 "label" : param .label ,
240268 "description" : param .description ,
@@ -266,45 +294,51 @@ def _param_to_spec(param: _params.Param | _params.SecretParam) -> dict[str, _typ
266294 return _dict_to_spec (spec_dict )
267295
268296
269- def _object_to_spec (data ) -> object :
297+ def _object_to_spec (data : object ) -> SpecValue :
270298 if isinstance (data , _Enum ):
271299 return data .value
272300 elif isinstance (data , _params .Expression ):
273301 return f"{ data } "
274302 elif _dataclasses .is_dataclass (data ):
275- return _dataclass_to_spec (data )
303+ return _dataclass_to_spec (_typing . cast ( _DataclassInstance , data ) )
276304 elif isinstance (data , list ):
277305 return list (map (_object_to_spec , data ))
278306 elif isinstance (data , dict ):
279307 return _dict_to_spec (data )
280- else :
308+ elif data is None :
309+ return None
310+ elif isinstance (data , _util .Sentinel ):
281311 return data
312+ elif isinstance (data , (str , int , float , bool )):
313+ return data
314+ else :
315+ raise TypeError (f"Unsupported manifest spec value: { type (data )!r} " )
282316
283317
284- def _dict_factory (data : list [tuple [str , _typing . Any ]]) -> dict :
285- out : dict = {}
318+ def _dict_factory (data : list [tuple [str , object ]]) -> dict [ str , SpecValue ] :
319+ out : dict [ str , SpecValue ] = {}
286320 for key , value in data :
287321 if value is not None :
288322 out [key ] = _object_to_spec (value )
289323 return out
290324
291325
292- def _dataclass_to_spec (data ) -> dict :
293- out : dict = {}
326+ def _dataclass_to_spec (data : _DataclassInstance ) -> dict [ str , SpecValue ] :
327+ out : dict [ str , SpecValue ] = {}
294328 for field in _dataclasses .fields (data ):
295329 value = _object_to_spec (getattr (data , field .name ))
296330 if value is not None :
297331 out [field .name ] = value
298332 return out
299333
300334
301- def _dict_to_spec (data : dict ) -> dict :
335+ def _dict_to_spec (data : _Mapping [ str , object ] ) -> dict [ str , SpecValue ] :
302336 return _dict_factory (list (data .items ()))
303337
304338
305- def manifest_to_spec_dict (manifest : ManifestStack ) -> dict :
339+ def manifest_to_spec_dict (manifest : ManifestStack ) -> dict [ str , SpecValue ] :
306340 params = manifest .params
307- out : dict = _dataclass_to_spec (manifest )
341+ out : dict [ str , SpecValue ] = _dataclass_to_spec (manifest )
308342 if params is not None :
309343 out ["params" ] = list (map (_param_to_spec , params ))
310344 return out
0 commit comments