sequence.py 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598
  1. """Collection of string classes and utilities."""
  2. from __future__ import annotations
  3. import dataclasses
  4. import functools
  5. import inspect
  6. import json
  7. import re
  8. import typing
  9. from typing import (
  10. TYPE_CHECKING,
  11. Any,
  12. Callable,
  13. ClassVar,
  14. List,
  15. Sequence,
  16. Set,
  17. Tuple,
  18. Type,
  19. Union,
  20. cast,
  21. )
  22. from typing_extensions import TypeAliasType, TypeVar
  23. from reflex import constants
  24. from reflex.constants.base import REFLEX_VAR_OPENING_TAG
  25. from reflex.constants.colors import Color
  26. from reflex.utils.exceptions import UntypedVarError, VarTypeError
  27. from reflex.utils.types import GenericType, get_origin
  28. from reflex.vars.base import (
  29. CachedVarOperation,
  30. CustomVarOperationReturn,
  31. LiteralVar,
  32. ReflexCallable,
  33. Var,
  34. VarData,
  35. VarWithDefault,
  36. _global_vars,
  37. cached_property_no_lock,
  38. figure_out_type,
  39. get_python_literal,
  40. get_unique_variable_name,
  41. nary_type_computer,
  42. passthrough_unary_type_computer,
  43. unionize,
  44. unwrap_reflex_callalbe,
  45. var_operation,
  46. var_operation_return,
  47. )
  48. from .number import (
  49. _AT_SLICE_IMPORT,
  50. _AT_SLICE_OR_INDEX,
  51. _IS_TRUE_IMPORT,
  52. _RANGE_IMPORT,
  53. LiteralNumberVar,
  54. NumberVar,
  55. raise_unsupported_operand_types,
  56. ternary_operation,
  57. )
  58. if TYPE_CHECKING:
  59. from .function import FunctionVar
  60. STRING_TYPE = TypeVar("STRING_TYPE", default=str)
  61. ARRAY_VAR_TYPE = TypeVar("ARRAY_VAR_TYPE", bound=Union[Set, Tuple, Sequence])
  62. OTHER_ARRAY_VAR_TYPE = TypeVar(
  63. "OTHER_ARRAY_VAR_TYPE", bound=Union[Set, Tuple, Sequence]
  64. )
  65. INNER_ARRAY_VAR = TypeVar("INNER_ARRAY_VAR", covariant=True)
  66. ANOTHER_ARRAY_VAR = TypeVar("ANOTHER_ARRAY_VAR", covariant=True)
  67. KEY_TYPE = TypeVar("KEY_TYPE")
  68. VALUE_TYPE = TypeVar("VALUE_TYPE")
  69. @var_operation
  70. def string_lt_operation(lhs: Var[str], rhs: Var[str]):
  71. """Check if a string is less than another string.
  72. Args:
  73. lhs: The left-hand side string.
  74. rhs: The right-hand side string.
  75. Returns:
  76. The string less than operation.
  77. """
  78. return var_operation_return(js_expression=f"({lhs} < {rhs})", var_type=bool)
  79. @var_operation
  80. def string_gt_operation(lhs: Var[str], rhs: Var[str]):
  81. """Check if a string is greater than another string.
  82. Args:
  83. lhs: The left-hand side string.
  84. rhs: The right-hand side string.
  85. Returns:
  86. The string greater than operation.
  87. """
  88. return var_operation_return(js_expression=f"({lhs} > {rhs})", var_type=bool)
  89. @var_operation
  90. def string_le_operation(lhs: Var[str], rhs: Var[str]):
  91. """Check if a string is less than or equal to another string.
  92. Args:
  93. lhs: The left-hand side string.
  94. rhs: The right-hand side string.
  95. Returns:
  96. The string less than or equal operation.
  97. """
  98. return var_operation_return(js_expression=f"({lhs} <= {rhs})", var_type=bool)
  99. @var_operation
  100. def string_ge_operation(lhs: Var[str], rhs: Var[str]):
  101. """Check if a string is greater than or equal to another string.
  102. Args:
  103. lhs: The left-hand side string.
  104. rhs: The right-hand side string.
  105. Returns:
  106. The string greater than or equal operation.
  107. """
  108. return var_operation_return(js_expression=f"({lhs} >= {rhs})", var_type=bool)
  109. @var_operation
  110. def string_lower_operation(string: Var[str]):
  111. """Convert a string to lowercase.
  112. Args:
  113. string: The string to convert.
  114. Returns:
  115. The lowercase string.
  116. """
  117. return var_operation_return(
  118. js_expression=f"String.prototype.toLowerCase.apply({string})",
  119. var_type=str,
  120. _raw_js_function="String.prototype.toLowerCase.apply",
  121. )
  122. @var_operation
  123. def string_upper_operation(string: Var[str]):
  124. """Convert a string to uppercase.
  125. Args:
  126. string: The string to convert.
  127. Returns:
  128. The uppercase string.
  129. """
  130. return var_operation_return(
  131. js_expression=f"String.prototype.toUpperCase.apply({string})",
  132. var_type=str,
  133. _raw_js_function="String.prototype.toUpperCase.apply",
  134. )
  135. @var_operation
  136. def string_strip_operation(string: Var[str]):
  137. """Strip a string.
  138. Args:
  139. string: The string to strip.
  140. Returns:
  141. The stripped string.
  142. """
  143. return var_operation_return(
  144. js_expression=f"String.prototype.trim.apply({string})",
  145. var_type=str,
  146. _raw_js_function="String.prototype.trim.apply",
  147. )
  148. @var_operation
  149. def string_contains_field_operation(
  150. haystack: Var[str],
  151. needle: Var[str],
  152. ):
  153. """Check if a string contains another string.
  154. Args:
  155. haystack: The haystack.
  156. needle: The needle.
  157. Returns:
  158. The string contains operation.
  159. """
  160. return var_operation_return(
  161. js_expression=f"{haystack}.includes({needle})",
  162. var_type=bool,
  163. var_data=VarData(
  164. imports=_IS_TRUE_IMPORT,
  165. ),
  166. )
  167. @var_operation
  168. def string_contains_operation(haystack: Var[str], needle: Var[str]):
  169. """Check if a string contains another string.
  170. Args:
  171. haystack: The haystack.
  172. needle: The needle.
  173. Returns:
  174. The string contains operation.
  175. """
  176. return var_operation_return(
  177. js_expression=f"{haystack}.includes({needle})", var_type=bool
  178. )
  179. @var_operation
  180. def string_starts_with_operation(full_string: Var[str], prefix: Var[str]):
  181. """Check if a string starts with a prefix.
  182. Args:
  183. full_string: The full string.
  184. prefix: The prefix.
  185. Returns:
  186. Whether the string starts with the prefix.
  187. """
  188. return var_operation_return(
  189. js_expression=f"{full_string}.startsWith({prefix})", var_type=bool
  190. )
  191. @var_operation
  192. def string_ends_with_operation(full_string: Var[str], suffix: Var[str]):
  193. """Check if a string ends with a suffix.
  194. Args:
  195. full_string: The full string.
  196. suffix: The suffix.
  197. Returns:
  198. Whether the string ends with the suffix.
  199. """
  200. return var_operation_return(
  201. js_expression=f"{full_string}.endsWith({suffix})", var_type=bool
  202. )
  203. @var_operation
  204. def string_item_operation(string: Var[str], index: Var[int]):
  205. """Get an item from a string.
  206. Args:
  207. string: The string.
  208. index: The index of the item.
  209. Returns:
  210. The item from the string.
  211. """
  212. return var_operation_return(js_expression=f"{string}.at({index})", var_type=str)
  213. @var_operation
  214. def string_slice_operation(
  215. string: Var[str], slice: Var[slice]
  216. ) -> CustomVarOperationReturn[str]:
  217. """Get a slice from a string.
  218. Args:
  219. string: The string.
  220. slice: The slice.
  221. Returns:
  222. The sliced string.
  223. """
  224. return var_operation_return(
  225. js_expression=f'atSlice({string}.split(""), {slice}).join("")',
  226. type_computer=nary_type_computer(
  227. ReflexCallable[[List[str], slice], str],
  228. ReflexCallable[[slice], str],
  229. computer=lambda args: str,
  230. ),
  231. var_data=VarData(
  232. imports=_AT_SLICE_IMPORT,
  233. ),
  234. )
  235. @var_operation
  236. def string_index_or_slice_operation(
  237. string: Var[str], index_or_slice: Var[Union[int, slice]]
  238. ) -> CustomVarOperationReturn[Union[str, Sequence[str]]]:
  239. """Get an item or slice from a string.
  240. Args:
  241. string: The string.
  242. index_or_slice: The index or slice.
  243. Returns:
  244. The item or slice from the string.
  245. """
  246. return var_operation_return(
  247. js_expression=f"Array.prototype.join.apply(atSliceOrIndex({string}, {index_or_slice}), [''])",
  248. _raw_js_function="atSliceOrIndex",
  249. type_computer=nary_type_computer(
  250. ReflexCallable[[List[str], Union[int, slice]], str],
  251. ReflexCallable[[Union[int, slice]], str],
  252. computer=lambda args: str,
  253. ),
  254. var_data=VarData(
  255. imports=_AT_SLICE_OR_INDEX,
  256. ),
  257. )
  258. @var_operation
  259. def string_replace_operation(
  260. string: Var[str], search_value: Var[str], new_value: Var[str]
  261. ):
  262. """Replace a string with a value.
  263. Args:
  264. string: The string.
  265. search_value: The string to search.
  266. new_value: The value to be replaced with.
  267. Returns:
  268. The string replace operation.
  269. """
  270. return var_operation_return(
  271. js_expression=f"{string}.replaceAll({search_value}, {new_value})",
  272. var_type=str,
  273. )
  274. @var_operation
  275. def array_pluck_operation(
  276. array: Var[Sequence[Any]],
  277. field: Var[str],
  278. ) -> CustomVarOperationReturn[Sequence[Any]]:
  279. """Pluck a field from an array of objects.
  280. Args:
  281. array: The array to pluck from.
  282. field: The field to pluck from the objects in the array.
  283. Returns:
  284. The reversed array.
  285. """
  286. return var_operation_return(
  287. js_expression=f"Array.prototype.map.apply({array}, [e=>e?.[{field}]])",
  288. var_type=List[Any],
  289. )
  290. @var_operation
  291. def array_join_operation(
  292. array: Var[Sequence[Any]], sep: VarWithDefault[str] = VarWithDefault("")
  293. ):
  294. """Join the elements of an array.
  295. Args:
  296. array: The array.
  297. sep: The separator.
  298. Returns:
  299. The joined elements.
  300. """
  301. return var_operation_return(
  302. js_expression=f"Array.prototype.join.apply({array},[{sep}])", var_type=str
  303. )
  304. @var_operation
  305. def array_reverse_operation(
  306. array: Var[Sequence[INNER_ARRAY_VAR]],
  307. ) -> CustomVarOperationReturn[Sequence[INNER_ARRAY_VAR]]:
  308. """Reverse an array.
  309. Args:
  310. array: The array to reverse.
  311. Returns:
  312. The reversed array.
  313. """
  314. return var_operation_return(
  315. js_expression=f"{array}.slice().reverse()",
  316. type_computer=passthrough_unary_type_computer(ReflexCallable[[List], List]),
  317. )
  318. @var_operation
  319. def array_lt_operation(lhs: Var[ARRAY_VAR_TYPE], rhs: Var[ARRAY_VAR_TYPE]):
  320. """Check if an array is less than another array.
  321. Args:
  322. lhs: The left-hand side array.
  323. rhs: The right-hand side array.
  324. Returns:
  325. The array less than operation.
  326. """
  327. return var_operation_return(js_expression=f"{lhs} < {rhs}", var_type=bool)
  328. @var_operation
  329. def array_gt_operation(lhs: Var[ARRAY_VAR_TYPE], rhs: Var[ARRAY_VAR_TYPE]):
  330. """Check if an array is greater than another array.
  331. Args:
  332. lhs: The left-hand side array.
  333. rhs: The right-hand side array.
  334. Returns:
  335. The array greater than operation.
  336. """
  337. return var_operation_return(js_expression=f"{lhs} > {rhs}", var_type=bool)
  338. @var_operation
  339. def array_le_operation(lhs: Var[ARRAY_VAR_TYPE], rhs: Var[ARRAY_VAR_TYPE]):
  340. """Check if an array is less than or equal to another array.
  341. Args:
  342. lhs: The left-hand side array.
  343. rhs: The right-hand side array.
  344. Returns:
  345. The array less than or equal operation.
  346. """
  347. return var_operation_return(js_expression=f"{lhs} <= {rhs}", var_type=bool)
  348. @var_operation
  349. def array_ge_operation(lhs: Var[ARRAY_VAR_TYPE], rhs: Var[ARRAY_VAR_TYPE]):
  350. """Check if an array is greater than or equal to another array.
  351. Args:
  352. lhs: The left-hand side array.
  353. rhs: The right-hand side array.
  354. Returns:
  355. The array greater than or equal operation.
  356. """
  357. return var_operation_return(js_expression=f"{lhs} >= {rhs}", var_type=bool)
  358. @var_operation
  359. def array_length_operation(array: Var[ARRAY_VAR_TYPE]):
  360. """Get the length of an array.
  361. Args:
  362. array: The array.
  363. Returns:
  364. The length of the array.
  365. """
  366. return var_operation_return(
  367. js_expression=f"{array}.length",
  368. var_type=int,
  369. )
  370. @var_operation
  371. def string_split_operation(
  372. string: Var[STRING_TYPE], sep: VarWithDefault[STRING_TYPE] = VarWithDefault("")
  373. ):
  374. """Split a string.
  375. Args:
  376. string: The string to split.
  377. sep: The separator.
  378. Returns:
  379. The split string.
  380. """
  381. return var_operation_return(
  382. js_expression=f"isTrue({sep}) ? {string}.split({sep}) : [...{string}]",
  383. var_type=Sequence[str],
  384. var_data=VarData(imports=_IS_TRUE_IMPORT),
  385. )
  386. def _element_type(array: Var, index: Var) -> Any:
  387. array_args = typing.get_args(array._var_type)
  388. if (
  389. array_args
  390. and isinstance(index, LiteralNumberVar)
  391. and is_tuple_type(array._var_type)
  392. ):
  393. index_value = int(index._var_value)
  394. return array_args[index_value % len(array_args)]
  395. return unionize(*(array_arg for array_arg in array_args if array_arg is not ...))
  396. @var_operation
  397. def array_item_or_slice_operation(
  398. array: Var[Sequence[INNER_ARRAY_VAR]],
  399. index_or_slice: Var[Union[int, slice]],
  400. ) -> CustomVarOperationReturn[Union[INNER_ARRAY_VAR, Sequence[INNER_ARRAY_VAR]]]:
  401. """Get an item or slice from an array.
  402. Args:
  403. array: The array.
  404. index_or_slice: The index or slice.
  405. Returns:
  406. The item or slice from the array.
  407. """
  408. return var_operation_return(
  409. js_expression=f"atSliceOrIndex({array}, {index_or_slice})",
  410. _raw_js_function="atSliceOrIndex",
  411. type_computer=nary_type_computer(
  412. ReflexCallable[[Sequence, Union[int, slice]], Any],
  413. ReflexCallable[[Union[int, slice]], Any],
  414. computer=lambda args: (
  415. args[0]._var_type
  416. if args[1]._var_type is slice
  417. else (_element_type(args[0], args[1]))
  418. ),
  419. ),
  420. var_data=VarData(
  421. imports=_AT_SLICE_OR_INDEX,
  422. ),
  423. )
  424. @var_operation
  425. def array_slice_operation(
  426. array: Var[Sequence[INNER_ARRAY_VAR]],
  427. slice: Var[slice],
  428. ) -> CustomVarOperationReturn[Sequence[INNER_ARRAY_VAR]]:
  429. """Get a slice from an array.
  430. Args:
  431. array: The array.
  432. slice: The slice.
  433. Returns:
  434. The item or slice from the array.
  435. """
  436. return var_operation_return(
  437. js_expression=f"atSlice({array}, {slice})",
  438. type_computer=nary_type_computer(
  439. ReflexCallable[[List, slice], Any],
  440. ReflexCallable[[slice], Any],
  441. computer=lambda args: args[0]._var_type,
  442. ),
  443. var_data=VarData(
  444. imports=_AT_SLICE_IMPORT,
  445. ),
  446. )
  447. @var_operation
  448. def array_item_operation(
  449. array: Var[Sequence[INNER_ARRAY_VAR]], index: Var[int]
  450. ) -> CustomVarOperationReturn[INNER_ARRAY_VAR]:
  451. """Get an item from an array.
  452. Args:
  453. array: The array.
  454. index: The index of the item.
  455. Returns:
  456. The item from the array.
  457. """
  458. def type_computer(*args):
  459. if len(args) == 0:
  460. return (
  461. ReflexCallable[[List[Any], int], Any],
  462. functools.partial(type_computer, *args),
  463. )
  464. array = args[0]
  465. array_args = typing.get_args(array._var_type)
  466. if len(args) == 1:
  467. return (
  468. ReflexCallable[[int], unionize(*array_args)],
  469. functools.partial(type_computer, *args),
  470. )
  471. index = args[1]
  472. if (
  473. array_args
  474. and isinstance(index, LiteralNumberVar)
  475. and is_tuple_type(array._var_type)
  476. ):
  477. index_value = int(index._var_value)
  478. element_type = array_args[index_value % len(array_args)]
  479. else:
  480. element_type = unionize(*array_args)
  481. return (ReflexCallable[[], element_type], None)
  482. return var_operation_return(
  483. js_expression=f"{array}.at({index})",
  484. type_computer=type_computer,
  485. )
  486. @var_operation
  487. def array_range_operation(
  488. e1: Var[int],
  489. e2: VarWithDefault[int | None] = VarWithDefault(None),
  490. step: VarWithDefault[int] = VarWithDefault(1),
  491. ) -> CustomVarOperationReturn[Sequence[int]]:
  492. """Create a range of numbers.
  493. Args:
  494. e1: The end of the range if e2 is not provided, otherwise the start of the range.
  495. e2: The end of the range.
  496. step: The step of the range.
  497. Returns:
  498. The range of numbers.
  499. """
  500. return var_operation_return(
  501. js_expression=f"[...range({e1}, {e2}, {step})]",
  502. var_type=List[int],
  503. var_data=VarData(
  504. imports=_RANGE_IMPORT,
  505. ),
  506. )
  507. @var_operation
  508. def array_contains_field_operation(
  509. haystack: Var[ARRAY_VAR_TYPE],
  510. needle: Var[Any],
  511. field: VarWithDefault[str] = VarWithDefault(""),
  512. ):
  513. """Check if an array contains an element.
  514. Args:
  515. haystack: The array to check.
  516. needle: The element to check for.
  517. field: The field to check.
  518. Returns:
  519. The array contains operation.
  520. """
  521. return var_operation_return(
  522. js_expression=f"isTrue({field}) ? {haystack}.some(obj => obj[{field}] === {needle}) : {haystack}.some(obj => obj === {needle})",
  523. var_type=bool,
  524. var_data=VarData(
  525. imports=_IS_TRUE_IMPORT,
  526. ),
  527. )
  528. @var_operation
  529. def array_contains_operation(haystack: Var[ARRAY_VAR_TYPE], needle: Var):
  530. """Check if an array contains an element.
  531. Args:
  532. haystack: The array to check.
  533. needle: The element to check for.
  534. Returns:
  535. The array contains operation.
  536. """
  537. return var_operation_return(
  538. js_expression=f"{haystack}.includes({needle})",
  539. var_type=bool,
  540. )
  541. @var_operation
  542. def repeat_array_operation(
  543. array: Var[Sequence[INNER_ARRAY_VAR]], count: Var[int]
  544. ) -> CustomVarOperationReturn[Sequence[INNER_ARRAY_VAR]]:
  545. """Repeat an array a number of times.
  546. Args:
  547. array: The array to repeat.
  548. count: The number of times to repeat the array.
  549. Returns:
  550. The repeated array.
  551. """
  552. def type_computer(*args: Var):
  553. if not args:
  554. return (
  555. ReflexCallable[[List[Any], int], List[Any]],
  556. type_computer,
  557. )
  558. if len(args) == 1:
  559. return (
  560. ReflexCallable[[int], args[0]._var_type],
  561. functools.partial(type_computer, *args),
  562. )
  563. return (ReflexCallable[[], args[0]._var_type], None)
  564. return var_operation_return(
  565. js_expression=f"Array.from({{ length: {count} }}).flatMap(() => {array})",
  566. type_computer=type_computer,
  567. )
  568. @var_operation
  569. def repeat_string_operation(
  570. string: Var[str], count: Var[int]
  571. ) -> CustomVarOperationReturn[str]:
  572. """Repeat a string a number of times.
  573. Args:
  574. string: The string to repeat.
  575. count: The number of times to repeat the string.
  576. Returns:
  577. The repeated string.
  578. """
  579. return var_operation_return(
  580. js_expression=f"{string}.repeat({count})",
  581. var_type=str,
  582. )
  583. if TYPE_CHECKING:
  584. pass
  585. @var_operation
  586. def map_array_operation(
  587. array: Var[Sequence[INNER_ARRAY_VAR]],
  588. function: Var[
  589. ReflexCallable[[INNER_ARRAY_VAR, int], ANOTHER_ARRAY_VAR]
  590. | ReflexCallable[[INNER_ARRAY_VAR], ANOTHER_ARRAY_VAR]
  591. | ReflexCallable[[], ANOTHER_ARRAY_VAR]
  592. ],
  593. ) -> CustomVarOperationReturn[Sequence[ANOTHER_ARRAY_VAR]]:
  594. """Map a function over an array.
  595. Args:
  596. array: The array.
  597. function: The function to map.
  598. Returns:
  599. The mapped array.
  600. """
  601. def type_computer(*args: Var):
  602. if not args:
  603. return (
  604. ReflexCallable[[List[Any], ReflexCallable], List[Any]],
  605. type_computer,
  606. )
  607. if len(args) == 1:
  608. return (
  609. ReflexCallable[[ReflexCallable], List[Any]],
  610. functools.partial(type_computer, *args),
  611. )
  612. return (ReflexCallable[[], List[args[0]._var_type]], None)
  613. return var_operation_return(
  614. js_expression=f"Array.prototype.map.apply({array}, [{function}])",
  615. type_computer=nary_type_computer(
  616. ReflexCallable[[List[Any], ReflexCallable], List[Any]],
  617. ReflexCallable[[ReflexCallable], List[Any]],
  618. computer=lambda args: List[unwrap_reflex_callalbe(args[1]._var_type)[1]],
  619. ),
  620. )
  621. @var_operation
  622. def array_concat_operation(
  623. lhs: Var[Sequence[INNER_ARRAY_VAR]], rhs: Var[Sequence[ANOTHER_ARRAY_VAR]]
  624. ) -> CustomVarOperationReturn[Sequence[INNER_ARRAY_VAR | ANOTHER_ARRAY_VAR]]:
  625. """Concatenate two arrays.
  626. Args:
  627. lhs: The left-hand side array.
  628. rhs: The right-hand side array.
  629. Returns:
  630. The concatenated array.
  631. """
  632. return var_operation_return(
  633. js_expression=f"[...{lhs}, ...{rhs}]",
  634. type_computer=nary_type_computer(
  635. ReflexCallable[[List[Any], List[Any]], List[Any]],
  636. ReflexCallable[[List[Any]], List[Any]],
  637. computer=lambda args: unionize(args[0]._var_type, args[1]._var_type),
  638. ),
  639. )
  640. @var_operation
  641. def string_concat_operation(
  642. lhs: Var[str], rhs: Var[str]
  643. ) -> CustomVarOperationReturn[str]:
  644. """Concatenate two strings.
  645. Args:
  646. lhs: The left-hand side string.
  647. rhs: The right-hand side string.
  648. Returns:
  649. The concatenated string.
  650. """
  651. return var_operation_return(
  652. js_expression=f"{lhs} + {rhs}",
  653. var_type=str,
  654. )
  655. @var_operation
  656. def reverse_string_concat_operation(
  657. lhs: Var[str], rhs: Var[str]
  658. ) -> CustomVarOperationReturn[str]:
  659. """Concatenate two strings in reverse order.
  660. Args:
  661. lhs: The left-hand side string.
  662. rhs: The right-hand side string.
  663. Returns:
  664. The concatenated string.
  665. """
  666. return var_operation_return(
  667. js_expression=f"{rhs} + {lhs}",
  668. var_type=str,
  669. )
  670. class SliceVar(Var[slice], python_types=slice):
  671. """Base class for immutable slice vars."""
  672. @dataclasses.dataclass(
  673. eq=False,
  674. frozen=True,
  675. slots=True,
  676. )
  677. class LiteralSliceVar(CachedVarOperation, LiteralVar, SliceVar):
  678. """Base class for immutable literal slice vars."""
  679. _var_value: slice = dataclasses.field(default_factory=lambda: slice(None))
  680. @cached_property_no_lock
  681. def _cached_var_name(self) -> str:
  682. """The name of the var.
  683. Returns:
  684. The name of the var.
  685. """
  686. return f"[{LiteralVar.create(self._var_value.start)!s}, {LiteralVar.create(self._var_value.stop)!s}, {LiteralVar.create(self._var_value.step)!s}]"
  687. @cached_property_no_lock
  688. def _cached_get_all_var_data(self) -> VarData | None:
  689. """Get all the VarData asVarDatae Var.
  690. Returns:
  691. The VarData associated with the Var.
  692. """
  693. return VarData.merge(
  694. *[
  695. var._get_all_var_data()
  696. for var in [
  697. self._var_value.start,
  698. self._var_value.stop,
  699. self._var_value.step,
  700. ]
  701. if isinstance(var, Var)
  702. ],
  703. self._var_data,
  704. )
  705. @classmethod
  706. def create(
  707. cls,
  708. value: slice,
  709. _var_type: Type[slice] | None = None,
  710. _var_data: VarData | None = None,
  711. ) -> SliceVar:
  712. """Create a var from a slice value.
  713. Args:
  714. value: The value to create the var from.
  715. _var_type: The type of the var.
  716. _var_data: Additional hooks and imports associated with the Var.
  717. Returns:
  718. The var.
  719. """
  720. return cls(
  721. _js_expr="",
  722. _var_type=slice if _var_type is None else _var_type,
  723. _var_data=_var_data,
  724. _var_value=value,
  725. )
  726. def __hash__(self) -> int:
  727. """Get the hash of the var.
  728. Returns:
  729. The hash of the var.
  730. """
  731. return hash(
  732. (
  733. self.__class__.__name__,
  734. self._var_value.start,
  735. self._var_value.stop,
  736. self._var_value.step,
  737. )
  738. )
  739. def json(self) -> str:
  740. """Get the JSON representation of the var.
  741. Returns:
  742. The JSON representation of the var.
  743. """
  744. return json.dumps(
  745. [self._var_value.start, self._var_value.stop, self._var_value.step]
  746. )
  747. class ArrayVar(Var[ARRAY_VAR_TYPE], python_types=(Sequence, set)):
  748. """Base class for immutable array vars."""
  749. join = array_join_operation
  750. reverse = array_reverse_operation
  751. __add__ = array_concat_operation
  752. __getitem__ = array_item_or_slice_operation
  753. at = array_item_operation
  754. slice = array_slice_operation
  755. length = array_length_operation
  756. range: ClassVar[
  757. FunctionVar[
  758. ReflexCallable[
  759. [int, VarWithDefault[int | None], VarWithDefault[int]], Sequence[int]
  760. ]
  761. ]
  762. ] = array_range_operation
  763. contains = array_contains_field_operation
  764. pluck = array_pluck_operation
  765. __rmul__ = __mul__ = repeat_array_operation
  766. __lt__ = array_lt_operation
  767. __gt__ = array_gt_operation
  768. __le__ = array_le_operation
  769. __ge__ = array_ge_operation
  770. def foreach(
  771. self: ArrayVar[Sequence[INNER_ARRAY_VAR]],
  772. fn: Callable[[Var[INNER_ARRAY_VAR], NumberVar[int]], ANOTHER_ARRAY_VAR]
  773. | Callable[[Var[INNER_ARRAY_VAR]], ANOTHER_ARRAY_VAR]
  774. | Callable[[], ANOTHER_ARRAY_VAR],
  775. ) -> ArrayVar[Sequence[ANOTHER_ARRAY_VAR]]:
  776. """Apply a function to each element of the array.
  777. Args:
  778. fn: The function to apply.
  779. Returns:
  780. The array after applying the function.
  781. Raises:
  782. VarTypeError: If the function takes more than one argument.
  783. TypeError: If the function is a ComponentState.
  784. """
  785. from reflex.state import ComponentState
  786. from .function import ArgsFunctionOperation
  787. if not callable(fn):
  788. raise_unsupported_operand_types("foreach", (type(self), type(fn)))
  789. # get the number of arguments of the function
  790. required_num_args = len(
  791. [
  792. p
  793. for p in inspect.signature(fn).parameters.values()
  794. if p.default == p.empty
  795. ]
  796. )
  797. if required_num_args > 2:
  798. raise VarTypeError(
  799. "The function passed to foreach should take at most two arguments."
  800. )
  801. num_args = len(inspect.signature(fn).parameters)
  802. if (
  803. hasattr(fn, "__qualname__")
  804. and fn.__qualname__ == ComponentState.create.__qualname__
  805. ):
  806. raise TypeError(
  807. "Using a ComponentState as `render_fn` inside `rx.foreach` is not supported yet."
  808. )
  809. def invoke_fn(*args):
  810. try:
  811. return fn(*args)
  812. except UntypedVarError as e:
  813. raise UntypedVarError(
  814. f"Could not foreach over var `{self!s}` without a type annotation. "
  815. "See https://reflex.dev/docs/library/dynamic-rendering/foreach/"
  816. ) from e
  817. if num_args == 0:
  818. fn_result = invoke_fn()
  819. return_value = Var.create(fn_result)
  820. simple_function_var: FunctionVar[ReflexCallable[[], ANOTHER_ARRAY_VAR]] = (
  821. ArgsFunctionOperation.create(
  822. (),
  823. return_value,
  824. _var_type=ReflexCallable[[], return_value._var_type],
  825. )
  826. )
  827. return map_array_operation(self, simple_function_var).guess_type()
  828. # generic number var
  829. number_var = Var("").to(NumberVar, int)
  830. first_arg_type = self.__getitem__(number_var)._var_type
  831. arg_name = get_unique_variable_name()
  832. # get first argument type
  833. first_arg = cast(
  834. Var[Any],
  835. Var(
  836. _js_expr=arg_name,
  837. _var_type=first_arg_type,
  838. ).guess_type(),
  839. )
  840. if required_num_args < 2:
  841. fn_result = invoke_fn(first_arg)
  842. return_value = Var.create(fn_result)
  843. function_var = cast(
  844. Var[ReflexCallable[[INNER_ARRAY_VAR], ANOTHER_ARRAY_VAR]],
  845. ArgsFunctionOperation.create(
  846. (arg_name,),
  847. return_value,
  848. _var_type=ReflexCallable[[first_arg_type], return_value._var_type],
  849. ),
  850. )
  851. return map_array_operation.call(self, function_var).guess_type()
  852. second_arg = cast(
  853. NumberVar[int],
  854. Var(
  855. _js_expr=get_unique_variable_name(),
  856. _var_type=int,
  857. ).guess_type(),
  858. )
  859. fn_result = invoke_fn(first_arg, second_arg)
  860. return_value = Var.create(fn_result)
  861. function_var = cast(
  862. Var[ReflexCallable[[INNER_ARRAY_VAR, int], ANOTHER_ARRAY_VAR]],
  863. ArgsFunctionOperation.create(
  864. (arg_name, second_arg._js_expr),
  865. return_value,
  866. _var_type=ReflexCallable[[first_arg_type, int], return_value._var_type],
  867. ),
  868. )
  869. return map_array_operation.call(self, function_var).guess_type()
  870. LIST_ELEMENT = TypeVar("LIST_ELEMENT", covariant=True)
  871. ARRAY_VAR_OF_LIST_ELEMENT = TypeAliasType(
  872. "ARRAY_VAR_OF_LIST_ELEMENT",
  873. Union[
  874. ArrayVar[Sequence[LIST_ELEMENT]],
  875. ArrayVar[Set[LIST_ELEMENT]],
  876. ],
  877. type_params=(LIST_ELEMENT,),
  878. )
  879. @dataclasses.dataclass(
  880. eq=False,
  881. frozen=True,
  882. slots=True,
  883. )
  884. class LiteralArrayVar(CachedVarOperation, LiteralVar, ArrayVar[ARRAY_VAR_TYPE]):
  885. """Base class for immutable literal array vars."""
  886. _var_value: Union[
  887. Sequence[Union[Var, Any]],
  888. Set[Union[Var, Any]],
  889. ] = dataclasses.field(default_factory=list)
  890. @cached_property_no_lock
  891. def _cached_var_name(self) -> str:
  892. """The name of the var.
  893. Returns:
  894. The name of the var.
  895. """
  896. return (
  897. "["
  898. + ", ".join(
  899. [str(LiteralVar.create(element)) for element in self._var_value]
  900. )
  901. + "]"
  902. )
  903. @cached_property_no_lock
  904. def _cached_get_all_var_data(self) -> VarData | None:
  905. """Get all the VarData associated with the Var.
  906. Returns:
  907. The VarData associated with the Var.
  908. """
  909. return VarData.merge(
  910. *[
  911. LiteralVar.create(element)._get_all_var_data()
  912. for element in self._var_value
  913. ],
  914. self._var_data,
  915. )
  916. def __hash__(self) -> int:
  917. """Get the hash of the var.
  918. Returns:
  919. The hash of the var.
  920. """
  921. return hash((self.__class__.__name__, self._js_expr))
  922. def json(self) -> str:
  923. """Get the JSON representation of the var.
  924. Returns:
  925. The JSON representation of the var.
  926. Raises:
  927. TypeError: If the array elements are not of type LiteralVar.
  928. """
  929. elements = []
  930. for element in self._var_value:
  931. element_var = LiteralVar.create(element)
  932. if not isinstance(element_var, LiteralVar):
  933. raise TypeError(
  934. f"Array elements must be of type LiteralVar, not {type(element_var)}"
  935. )
  936. elements.append(element_var.json())
  937. return "[" + ", ".join(elements) + "]"
  938. @classmethod
  939. def create(
  940. cls,
  941. value: OTHER_ARRAY_VAR_TYPE,
  942. _var_type: Type[OTHER_ARRAY_VAR_TYPE] | None = None,
  943. _var_data: VarData | None = None,
  944. ) -> LiteralArrayVar[OTHER_ARRAY_VAR_TYPE]:
  945. """Create a var from a string value.
  946. Args:
  947. value: The value to create the var from.
  948. _var_type: The type of the var.
  949. _var_data: Additional hooks and imports associated with the Var.
  950. Returns:
  951. The var.
  952. """
  953. return LiteralArrayVar(
  954. _js_expr="",
  955. _var_type=figure_out_type(value) if _var_type is None else _var_type,
  956. _var_data=_var_data,
  957. _var_value=value,
  958. )
  959. class StringVar(Var[STRING_TYPE], python_types=str):
  960. """Base class for immutable string vars."""
  961. __add__ = string_concat_operation
  962. __radd__ = reverse_string_concat_operation
  963. __getitem__ = string_index_or_slice_operation
  964. at = string_item_operation
  965. slice = string_slice_operation
  966. lower = string_lower_operation
  967. upper = string_upper_operation
  968. strip = string_strip_operation
  969. contains = string_contains_field_operation
  970. split = string_split_operation
  971. length = split.chain(array_length_operation)
  972. reversed = split.chain(array_reverse_operation).chain(array_join_operation)
  973. startswith = string_starts_with_operation
  974. __rmul__ = __mul__ = repeat_string_operation
  975. __lt__ = string_lt_operation
  976. __gt__ = string_gt_operation
  977. __le__ = string_le_operation
  978. __ge__ = string_ge_operation
  979. # Compile regex for finding reflex var tags.
  980. _decode_var_pattern_re = (
  981. rf"{constants.REFLEX_VAR_OPENING_TAG}(.*?){constants.REFLEX_VAR_CLOSING_TAG}"
  982. )
  983. _decode_var_pattern = re.compile(_decode_var_pattern_re, flags=re.DOTALL)
  984. @dataclasses.dataclass(
  985. eq=False,
  986. frozen=True,
  987. slots=True,
  988. )
  989. class LiteralStringVar(LiteralVar, StringVar[str]):
  990. """Base class for immutable literal string vars."""
  991. _var_value: str = dataclasses.field(default="")
  992. @classmethod
  993. def create(
  994. cls,
  995. value: str,
  996. _var_type: GenericType | None = None,
  997. _var_data: VarData | None = None,
  998. ) -> StringVar:
  999. """Create a var from a string value.
  1000. Args:
  1001. value: The value to create the var from.
  1002. _var_type: The type of the var.
  1003. _var_data: Additional hooks and imports associated with the Var.
  1004. Returns:
  1005. The var.
  1006. """
  1007. # Determine var type in case the value is inherited from str.
  1008. _var_type = _var_type or type(value) or str
  1009. if REFLEX_VAR_OPENING_TAG in value:
  1010. strings_and_vals: list[Var | str] = []
  1011. offset = 0
  1012. # Find all tags
  1013. while m := _decode_var_pattern.search(value):
  1014. start, end = m.span()
  1015. strings_and_vals.append(value[:start])
  1016. serialized_data = m.group(1)
  1017. if serialized_data.isnumeric() or (
  1018. serialized_data[0] == "-" and serialized_data[1:].isnumeric()
  1019. ):
  1020. # This is a global immutable var.
  1021. var = _global_vars[int(serialized_data)]
  1022. strings_and_vals.append(var)
  1023. value = value[(end + len(var._js_expr)) :]
  1024. offset += end - start
  1025. strings_and_vals.append(value)
  1026. filtered_strings_and_vals = [
  1027. s for s in strings_and_vals if isinstance(s, Var) or s
  1028. ]
  1029. if len(filtered_strings_and_vals) == 1:
  1030. only_string = filtered_strings_and_vals[0]
  1031. if isinstance(only_string, str):
  1032. return LiteralVar.create(only_string).to(StringVar, _var_type)
  1033. else:
  1034. return only_string.to(StringVar, only_string._var_type)
  1035. if len(
  1036. literal_strings := [
  1037. s
  1038. for s in filtered_strings_and_vals
  1039. if isinstance(s, (str, LiteralStringVar))
  1040. ]
  1041. ) == len(filtered_strings_and_vals):
  1042. return LiteralStringVar.create(
  1043. "".join(
  1044. s._var_value if isinstance(s, LiteralStringVar) else s
  1045. for s in literal_strings
  1046. ),
  1047. _var_type=_var_type,
  1048. _var_data=VarData.merge(
  1049. _var_data,
  1050. *(
  1051. s._get_all_var_data()
  1052. for s in filtered_strings_and_vals
  1053. if isinstance(s, Var)
  1054. ),
  1055. ),
  1056. )
  1057. concat_result = ConcatVarOperation.create(
  1058. *filtered_strings_and_vals,
  1059. _var_data=_var_data,
  1060. )
  1061. return (
  1062. concat_result
  1063. if _var_type is str
  1064. else concat_result.to(StringVar, _var_type)
  1065. )
  1066. return LiteralStringVar(
  1067. _js_expr=json.dumps(value),
  1068. _var_type=_var_type,
  1069. _var_data=_var_data,
  1070. _var_value=value,
  1071. )
  1072. def __hash__(self) -> int:
  1073. """Get the hash of the var.
  1074. Returns:
  1075. The hash of the var.
  1076. """
  1077. return hash((self.__class__.__name__, self._var_value))
  1078. def json(self) -> str:
  1079. """Get the JSON representation of the var.
  1080. Returns:
  1081. The JSON representation of the var.
  1082. """
  1083. return json.dumps(self._var_value)
  1084. @dataclasses.dataclass(
  1085. eq=False,
  1086. frozen=True,
  1087. slots=True,
  1088. )
  1089. class ConcatVarOperation(CachedVarOperation, StringVar[str]):
  1090. """Representing a concatenation of literal string vars."""
  1091. _var_value: Tuple[Var, ...] = dataclasses.field(default_factory=tuple)
  1092. @cached_property_no_lock
  1093. def _cached_var_name(self) -> str:
  1094. """The name of the var.
  1095. Returns:
  1096. The name of the var.
  1097. """
  1098. list_of_strs: List[Union[str, Var]] = []
  1099. last_string = ""
  1100. for var in self._var_value:
  1101. if isinstance(var, LiteralStringVar):
  1102. last_string += var._var_value
  1103. else:
  1104. if last_string:
  1105. list_of_strs.append(last_string)
  1106. last_string = ""
  1107. list_of_strs.append(var)
  1108. if last_string:
  1109. list_of_strs.append(last_string)
  1110. list_of_strs_filtered = [
  1111. str(LiteralVar.create(s)) for s in list_of_strs if isinstance(s, Var) or s
  1112. ]
  1113. if len(list_of_strs_filtered) == 1:
  1114. return list_of_strs_filtered[0]
  1115. return "(" + "+".join(list_of_strs_filtered) + ")"
  1116. @cached_property_no_lock
  1117. def _cached_get_all_var_data(self) -> VarData | None:
  1118. """Get all the VarData asVarDatae Var.
  1119. Returns:
  1120. The VarData associated with the Var.
  1121. """
  1122. return VarData.merge(
  1123. *[
  1124. var._get_all_var_data()
  1125. for var in self._var_value
  1126. if isinstance(var, Var)
  1127. ],
  1128. self._var_data,
  1129. )
  1130. @classmethod
  1131. def create(
  1132. cls,
  1133. *value: Var | str,
  1134. _var_data: VarData | None = None,
  1135. ) -> ConcatVarOperation:
  1136. """Create a var from a string value.
  1137. Args:
  1138. value: The values to concatenate.
  1139. _var_data: Additional hooks and imports associated with the Var.
  1140. Returns:
  1141. The var.
  1142. """
  1143. return cls(
  1144. _js_expr="",
  1145. _var_type=str,
  1146. _var_data=_var_data,
  1147. _var_value=tuple(map(LiteralVar.create, value)),
  1148. )
  1149. def is_tuple_type(t: GenericType) -> bool:
  1150. """Check if a type is a tuple type.
  1151. Args:
  1152. t: The type to check.
  1153. Returns:
  1154. Whether the type is a tuple type.
  1155. """
  1156. if inspect.isclass(t):
  1157. return issubclass(t, tuple)
  1158. return get_origin(t) is tuple
  1159. class ColorVar(StringVar[Color], python_types=Color):
  1160. """Base class for immutable color vars."""
  1161. @dataclasses.dataclass(
  1162. eq=False,
  1163. frozen=True,
  1164. slots=True,
  1165. )
  1166. class LiteralColorVar(CachedVarOperation, LiteralVar, ColorVar):
  1167. """Base class for immutable literal color vars."""
  1168. _var_value: Color = dataclasses.field(default_factory=lambda: Color(color="black"))
  1169. @classmethod
  1170. def create(
  1171. cls,
  1172. value: Color,
  1173. _var_type: Type[Color] | None = None,
  1174. _var_data: VarData | None = None,
  1175. ) -> ColorVar:
  1176. """Create a var from a string value.
  1177. Args:
  1178. value: The value to create the var from.
  1179. _var_type: The type of the var.
  1180. _var_data: Additional hooks and imports associated with the Var.
  1181. Returns:
  1182. The var.
  1183. """
  1184. return cls(
  1185. _js_expr="",
  1186. _var_type=_var_type or Color,
  1187. _var_data=_var_data,
  1188. _var_value=value,
  1189. )
  1190. def __hash__(self) -> int:
  1191. """Get the hash of the var.
  1192. Returns:
  1193. The hash of the var.
  1194. """
  1195. return hash(
  1196. (
  1197. self.__class__.__name__,
  1198. self._var_value.color,
  1199. self._var_value.alpha,
  1200. self._var_value.shade,
  1201. )
  1202. )
  1203. @cached_property_no_lock
  1204. def _cached_var_name(self) -> str:
  1205. """The name of the var.
  1206. Returns:
  1207. The name of the var.
  1208. """
  1209. alpha = cast(Union[Var[bool], bool], self._var_value.alpha)
  1210. alpha = (
  1211. ternary_operation(
  1212. alpha,
  1213. LiteralStringVar.create("a"),
  1214. LiteralStringVar.create(""),
  1215. )
  1216. if isinstance(alpha, Var)
  1217. else LiteralStringVar.create("a" if alpha else "")
  1218. )
  1219. shade = self._var_value.shade
  1220. shade = (
  1221. shade.to_string(use_json=False)
  1222. if isinstance(shade, Var)
  1223. else LiteralStringVar.create(str(shade))
  1224. )
  1225. return str(
  1226. ConcatVarOperation.create(
  1227. LiteralStringVar.create("var(--"),
  1228. self._var_value.color,
  1229. LiteralStringVar.create("-"),
  1230. alpha,
  1231. shade,
  1232. LiteralStringVar.create(")"),
  1233. )
  1234. )
  1235. @cached_property_no_lock
  1236. def _cached_get_all_var_data(self) -> VarData | None:
  1237. """Get all the var data.
  1238. Returns:
  1239. The var data.
  1240. """
  1241. return VarData.merge(
  1242. *[
  1243. LiteralVar.create(var)._get_all_var_data()
  1244. for var in (
  1245. self._var_value.color,
  1246. self._var_value.alpha,
  1247. self._var_value.shade,
  1248. )
  1249. ],
  1250. self._var_data,
  1251. )
  1252. def json(self) -> str:
  1253. """Get the JSON representation of the var.
  1254. Returns:
  1255. The JSON representation of the var.
  1256. Raises:
  1257. TypeError: If the color is not a valid color.
  1258. """
  1259. color, alpha, shade = map(
  1260. get_python_literal,
  1261. (self._var_value.color, self._var_value.alpha, self._var_value.shade),
  1262. )
  1263. if color is None or alpha is None or shade is None:
  1264. raise TypeError("Cannot serialize color that contains non-literal vars.")
  1265. if (
  1266. not isinstance(color, str)
  1267. or not isinstance(alpha, bool)
  1268. or not isinstance(shade, int)
  1269. ):
  1270. raise TypeError("Color is not a valid color.")
  1271. return f"var(--{color}-{'a' if alpha else ''}{shade})"