Reduce Syntax highlighter footprint (#2037)

This commit is contained in:
Elijah Ahianyo 2023-11-13 20:47:55 +00:00 committed by GitHub
parent 39cc1b2f12
commit ea22452b27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1928 additions and 1074 deletions

View File

@ -3,8 +3,25 @@
{% block export %}
{% for component in components %}
export const {{component.name}} = memo(({ {{-component.props|join(", ")-}} }) => (
{{utils.render(component.render)}}
))
export const {{component.name}} = memo(({ {{-component.props|join(", ")-}} }) => {
{% if component.name == "CodeBlock" and "language" in component.props %}
if (language) {
(async () => {
try {
const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${language}`);
SyntaxHighlighter.registerLanguage(language, module.default);
} catch (error) {
console.error(`Error importing language module for ${language}:`, error);
}
})();
}
{% endif %}
return(
{{utils.render(component.render)}}
)
})
{% endfor %}
{% endblock %}

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,8 @@
from .badge import Badge
from .code import Code, CodeBlock
from .code import LiteralCodeBlockTheme as LiteralCodeBlockTheme
from .code import LiteralCodeLanguage as LiteralCodeLanguage
from .dataeditor import DataEditor, DataEditorTheme
from .datatable import DataTable
from .divider import Divider

View File

@ -1,19 +1,349 @@
"""A code component."""
from typing import Dict, Optional, Union
from typing import Dict, Literal, Optional, Union
from reflex.components.component import Component
from reflex.components.forms import Button
from reflex.components.layout import Box
from reflex.components.libs.chakra import ChakraComponent, LiteralTheme
from reflex.components.libs.chakra import (
ChakraComponent,
)
from reflex.components.media import Icon
from reflex.event import set_clipboard
from reflex.style import Style
from reflex.utils import imports
from reflex.utils import format, imports
from reflex.vars import ImportVar, Var
# Path to the prism styles.
PRISM_STYLES_PATH: str = "/styles/code/prism"
LiteralCodeBlockTheme = Literal[
"a11y-dark",
"atom-dark",
"cb",
"coldark-cold",
"coldark-dark",
"coy",
"coy-without-shadows",
"darcula",
"dark",
"dracula",
"duotone-dark",
"duotone-earth",
"duotone-forest",
"duotone-light",
"duotone-sea",
"duotone-space",
"funky",
"ghcolors",
"gruvbox-dark",
"gruvbox-light",
"holi-theme",
"hopscotch",
"light", # not present in react-syntax-highlighter styles
"lucario",
"material-dark",
"material-light",
"material-oceanic",
"night-owl",
"nord",
"okaidia",
"one-dark",
"one-light",
"pojoaque",
"prism",
"shades-of-purple",
"solarized-dark-atom",
"solarizedlight",
"synthwave84",
"tomorrow",
"twilight",
"vs",
"vs-dark",
"vsc-dark-plus",
"xonokai",
"z-touch",
]
LiteralCodeLanguage = Literal[
"abap",
"abnf",
"actionscript",
"ada",
"agda",
"al",
"antlr4",
"apacheconf",
"apex",
"apl",
"applescript",
"aql",
"arduino",
"arff",
"asciidoc",
"asm6502",
"asmatmel",
"aspnet",
"autohotkey",
"autoit",
"avisynth",
"avro-idl",
"bash",
"basic",
"batch",
"bbcode",
"bicep",
"birb",
"bison",
"bnf",
"brainfuck",
"brightscript",
"bro",
"bsl",
"c",
"cfscript",
"chaiscript",
"cil",
"clike",
"clojure",
"cmake",
"cobol",
"coffeescript",
"concurnas",
"coq",
"core",
"cpp",
"crystal",
"csharp",
"cshtml",
"csp",
"css",
"css-extras",
"csv",
"cypher",
"d",
"dart",
"dataweave",
"dax",
"dhall",
"diff",
"django",
"dns-zone-file",
"docker",
"dot",
"ebnf",
"editorconfig",
"eiffel",
"ejs",
"elixir",
"elm",
"erb",
"erlang",
"etlua",
"excel-formula",
"factor",
"false",
"firestore-security-rules",
"flow",
"fortran",
"fsharp",
"ftl",
"gap",
"gcode",
"gdscript",
"gedcom",
"gherkin",
"git",
"glsl",
"gml",
"gn",
"go",
"go-module",
"graphql",
"groovy",
"haml",
"handlebars",
"haskell",
"haxe",
"hcl",
"hlsl",
"hoon",
"hpkp",
"hsts",
"http",
"ichigojam",
"icon",
"icu-message-format",
"idris",
"iecst",
"ignore",
"index",
"inform7",
"ini",
"io",
"j",
"java",
"javadoc",
"javadoclike",
"javascript",
"javastacktrace",
"jexl",
"jolie",
"jq",
"js-extras",
"js-templates",
"jsdoc",
"json",
"json5",
"jsonp",
"jsstacktrace",
"jsx",
"julia",
"keepalived",
"keyman",
"kotlin",
"kumir",
"kusto",
"latex",
"latte",
"less",
"lilypond",
"liquid",
"lisp",
"livescript",
"llvm",
"log",
"lolcode",
"lua",
"magma",
"makefile",
"markdown",
"markup",
"markup-templating",
"matlab",
"maxscript",
"mel",
"mermaid",
"mizar",
"mongodb",
"monkey",
"moonscript",
"n1ql",
"n4js",
"nand2tetris-hdl",
"naniscript",
"nasm",
"neon",
"nevod",
"nginx",
"nim",
"nix",
"nsis",
"objectivec",
"ocaml",
"opencl",
"openqasm",
"oz",
"parigp",
"parser",
"pascal",
"pascaligo",
"pcaxis",
"peoplecode",
"perl",
"php",
"php-extras",
"phpdoc",
"plsql",
"powerquery",
"powershell",
"processing",
"prolog",
"promql",
"properties",
"protobuf",
"psl",
"pug",
"puppet",
"pure",
"purebasic",
"purescript",
"python",
"q",
"qml",
"qore",
"qsharp",
"r",
"racket",
"reason",
"regex",
"rego",
"renpy",
"rest",
"rip",
"roboconf",
"robotframework",
"ruby",
"rust",
"sas",
"sass",
"scala",
"scheme",
"scss",
"shell-session",
"smali",
"smalltalk",
"smarty",
"sml",
"solidity",
"solution-file",
"soy",
"sparql",
"splunk-spl",
"sqf",
"sql",
"squirrel",
"stan",
"stylus",
"swift",
"systemd",
"t4-cs",
"t4-templating",
"t4-vb",
"tap",
"tcl",
"textile",
"toml",
"tremor",
"tsx",
"tt2",
"turtle",
"twig",
"typescript",
"typoscript",
"unrealscript",
"uorazor",
"uri",
"v",
"vala",
"vbnet",
"velocity",
"verilog",
"vhdl",
"vim",
"visual-basic",
"warpscript",
"wasm",
"web-idl",
"wiki",
"wolfram",
"wren",
"xeora",
"xml-doc",
"xojo",
"xquery",
"yaml",
"yang",
"zig",
]
class CodeBlock(Component):
@ -21,13 +351,15 @@ class CodeBlock(Component):
library = "react-syntax-highlighter@15.5.0"
tag = "Prism"
tag = "PrismAsyncLight"
alias = "SyntaxHighlighter"
# The theme to use ("light" or "dark").
theme: Var[LiteralTheme]
theme: Var[LiteralCodeBlockTheme] = "one-light" # type: ignore
# The language to use.
language: Var[str]
language: Var[LiteralCodeLanguage] = "python" # type: ignore
# If this is enabled line numbers will be shown next to the code block.
show_line_numbers: Var[bool]
@ -46,13 +378,43 @@ class CodeBlock(Component):
def _get_imports(self) -> imports.ImportDict:
merged_imports = super()._get_imports()
if self.theme is not None:
merged_imports = imports.merge_imports(
merged_imports,
{
f"react-syntax-highlighter/dist/cjs/styles/prism/{self.theme._var_name}": {
ImportVar(
tag=format.to_camel_case(self.theme._var_name),
is_default=True,
install=False,
)
}
},
)
if (
self.language is not None
and self.language._var_name in LiteralCodeLanguage.__args__ # type: ignore
):
merged_imports = imports.merge_imports(
merged_imports,
{PRISM_STYLES_PATH: {ImportVar(tag=self.theme._var_name)}},
{
f"react-syntax-highlighter/dist/cjs/languages/prism/{self.language._var_name}": {
ImportVar(
tag=format.to_camel_case(self.language._var_name),
is_default=True,
install=False,
)
}
},
)
return merged_imports
def _get_custom_code(self) -> Optional[str]:
if (
self.language is not None
and self.language._var_name in LiteralCodeLanguage.__args__ # type: ignore
):
return f"{self.alias}.registerLanguage('{self.language._var_name}', {format.to_camel_case(self.language._var_name)})"
@classmethod
def create(
cls,
@ -75,6 +437,17 @@ class CodeBlock(Component):
# This component handles style in a special prop.
custom_style = props.pop("custom_style", {})
# react-syntax-highlighter doesnt have an explicit "light" or "dark" theme so we use one-light and one-dark
# themes respectively to ensure code compatibility.
if "theme" in props:
props["theme"] = (
"one-light"
if props["theme"] == "light"
else "one-dark"
if props["theme"] == "dark"
else props["theme"]
)
if can_copy:
code = children[0]
copy_button = ( # type: ignore
@ -112,10 +485,11 @@ class CodeBlock(Component):
def _render(self):
out = super()._render()
if self.theme is not None:
out.add_props(
style=Var.create(self.theme._var_name, _var_is_local=False)
).remove_props("theme")
out.add_props(
style=Var.create(
format.to_camel_case(self.theme._var_name), _var_is_local=False
)
).remove_props("theme")
return out

File diff suppressed because it is too large Load Diff

View File

@ -122,6 +122,8 @@ LiteralColorScheme = Literal[
LiteralVariant = Literal["solid", "subtle", "outline"]
LiteralDividerVariant = Literal["solid", "dashed"]
LiteralTheme = Literal["light", "dark"]
LiteralTagColorScheme = Literal[
"gray",
"red",

View File

@ -1,14 +1,330 @@
"""Stub file for chakra.py"""
"""Stub file for reflex/components/libs/chakra.py"""
# ------------------- DO NOT EDIT ----------------------
# This file was generated by `scripts/pyi_generator.py`!
# ------------------------------------------------------
from typing import Literal, Optional, Union, overload
from reflex.components.component import Component
from typing import Optional, Literal, Any, overload, List, Union, Dict
from reflex.vars import Var, BaseVar, ComputedVar
from reflex.event import EventHandler, EventChain, EventSpec
from reflex.event import EventChain, EventHandler, EventSpec
from reflex.style import Style
from typing import List, Literal
from reflex.components.component import Component
from reflex.utils import imports
from reflex.vars import ImportVar, Var
class ChakraComponent(Component):
...
@overload
@classmethod
def create( # type: ignore
cls,
*children,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, str]] = None,
on_blur: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_context_menu: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_double_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_focus: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_scroll: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
**props
) -> "ChakraComponent":
"""Create the component.
Args:
*children: The children of the component.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The props of the component.
Returns:
The component.
Raises:
TypeError: If an invalid child is passed.
"""
...
class Global(Component):
...
@overload
@classmethod
def create( # type: ignore
cls,
*children,
styles: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, str]] = None,
on_blur: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_context_menu: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_double_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_focus: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_scroll: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
**props
) -> "Global":
"""Create the component.
Args:
*children: The children of the component.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The props of the component.
Returns:
The component.
Raises:
TypeError: If an invalid child is passed.
"""
...
class ChakraProvider(ChakraComponent):
@overload
@classmethod
def create( # type: ignore
cls,
*children,
theme: Optional[Union[Var[str], str]] = None,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, str]] = None,
on_blur: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_context_menu: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_double_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_focus: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_scroll: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
**props
) -> "ChakraProvider":
"""Create a new ChakraProvider component.
Returns:
A new ChakraProvider component.
"""
...
class ChakraColorModeProvider(Component):
...
@overload
@classmethod
def create( # type: ignore
cls,
*children,
style: Optional[Style] = None,
key: Optional[Any] = None,
id: Optional[Any] = None,
class_name: Optional[Any] = None,
autofocus: Optional[bool] = None,
custom_attrs: Optional[Dict[str, str]] = None,
on_blur: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_context_menu: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_double_click: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_focus: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_down: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_enter: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_leave: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_move: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_out: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_over: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_mouse_up: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_scroll: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
on_unmount: Optional[
Union[EventHandler, EventSpec, List, function, BaseVar]
] = None,
**props
) -> "ChakraColorModeProvider":
"""Create the component.
Args:
*children: The children of the component.
style: The style of the component.
key: A unique key for the component.
id: The id for the component.
class_name: The class name for the component.
autofocus: Whether the component should take the focus once the page is loaded
custom_attrs: custom attribute
**props: The props of the component.
Returns:
The component.
Raises:
TypeError: If an invalid child is passed.
"""
...
LiteralColorScheme = Literal[
"none",
"gray",
"red",
"orange",
@ -32,6 +348,7 @@ LiteralColorScheme = Literal[
LiteralVariant = Literal["solid", "subtle", "outline"]
LiteralDividerVariant = Literal["solid", "dashed"]
LiteralTheme = Literal["light", "dark"]
LiteralTagColorScheme = Literal[
"gray",
"red",
@ -94,8 +411,8 @@ LiteralCardVariant = Literal["outline", "filled", "elevated", "unstyled"]
LiteralStackDirection = Literal["row", "column"]
LiteralImageLoading = Literal["eager", "lazy"]
LiteralTagSize = Literal["sm", "md", "lg"]
LiteralSpinnerSize = Literal[Literal[LiteralTagSize], "xs"]
LiteralAvatarSize = Literal[Literal[LiteralTagSize], "xs", "2xl", "full", "2xs"]
LiteralSpinnerSize = Literal[Literal[LiteralTagSize], "xs", "xl"]
LiteralAvatarSize = Literal[Literal[LiteralTagSize], "xl", "xs", "2xl", "full", "2xs"]
LiteralButtonSize = Literal["sm", "md", "lg", "xs"]
# Applies to AlertDialog and Modal
LiteralAlertDialogSize = Literal[
@ -108,21 +425,3 @@ LiteralMenuOption = Literal["checkbox", "radio"]
LiteralPopOverTrigger = Literal["click", "hover"]
LiteralHeadingSize = Literal["lg", "md", "sm", "xs", "xl", "2xl", "3xl", "4xl"]
class ChakraComponent(Component):
@overload
@classmethod
def create(cls, *children, on_blur: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_context_menu: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_double_click: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_focus: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_down: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_enter: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_leave: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_move: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_out: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_over: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_mouse_up: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_scroll: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, on_unmount: Optional[Union[EventHandler, EventSpec, List, function, BaseVar]] = None, **props) -> "ChakraComponent": # type: ignore
"""Create the component.
Args:
*children: The children of the component.
**props: The props of the component.
Returns:
The component.
Raises:
TypeError: If an invalid child is passed.
"""
...

View File

@ -240,6 +240,16 @@ class Markdown(Component):
] = f"""{{({{inline, className, {_CHILDREN._var_name}, {_PROPS._var_name}}}) => {{
const match = (className || '').match(/language-(?<lang>.*)/);
const language = match ? match[1] : '';
if (language) {{
(async () => {{
try {{
const module = await import(`react-syntax-highlighter/dist/cjs/languages/prism/${{language}}`);
SyntaxHighlighter.registerLanguage(language, module.default);
}} catch (error) {{
console.error(`Error importing language module for ${{language}}:`, error);
}}
}})();
}}
return inline ? (
{self.format_component("code")}
) : (

View File

@ -137,14 +137,9 @@ def to_camel_case(text: str) -> str:
Returns:
The camel case string.
"""
if "_" not in text:
return text
camel = "".join(
word.capitalize() if i > 0 else word.lower()
for i, word in enumerate(text.lstrip("_").split("_"))
)
prefix = "_" if text.startswith("_") else ""
return prefix + camel
words = re.split("[_-]", text)
# Capitalize the first letter of each word except the first one
return words[0] + "".join(x.capitalize() for x in words[1:])
def to_title_case(text: str) -> str:

View File

@ -0,0 +1,31 @@
import pytest
from reflex.components.datadisplay.code import CodeBlock
@pytest.mark.parametrize(
"theme, expected", [("light", "one-light"), ("dark", "one-dark")]
)
def test_code_light_dark_theme(theme, expected):
code_block = CodeBlock.create(theme=theme)
assert code_block.theme._var_name == expected # type: ignore
def generate_custom_code(language, expected_case):
return f"SyntaxHighlighter.registerLanguage('{language}', {expected_case})"
@pytest.mark.parametrize(
"language, expected_case",
[
("python", "python"),
("firestore-security-rules", "firestoreSecurityRules"),
("typescript", "typescript"),
],
)
def test_get_custom_code(language, expected_case):
code_block = CodeBlock.create(language=language)
assert code_block._get_custom_code() == generate_custom_code(
language, expected_case
)

View File

@ -139,6 +139,9 @@ def test_to_snake_case(input: str, output: str):
("Hello", "Hello"),
("snake_case", "snakeCase"),
("snake_case_two", "snakeCaseTwo"),
("kebab-case", "kebabCase"),
("kebab-case-two", "kebabCaseTwo"),
("snake_kebab-case", "snakeKebabCase"),
],
)
def test_to_camel_case(input: str, output: str):