Skip to content

Commit 719e92d

Browse files
committed
add exports_default parameter
1 parent 51651c9 commit 719e92d

File tree

7 files changed

+65
-28
lines changed

7 files changed

+65
-28
lines changed

docs/source/examples/cytoscape.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33

44
react_cytoscapejs = idom.web.module_from_template(
55
# we need to use this template because react-cytoscapejs uses a default export
6-
"react-default",
6+
"react",
77
"react-cytoscapejs",
8+
exports_default=True,
89
fallback="⌛",
910
)
1011
Cytoscape = idom.web.export(react_cytoscapejs, "default")

src/client/package-lock.json

Lines changed: 0 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/idom/web/module.py

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ def module_from_template(
8383
package: str,
8484
cdn: str = "https://esm.sh",
8585
fallback: Optional[Any] = None,
86+
exports_default: bool = False,
8687
resolve_exports: bool = IDOM_DEBUG_MODE.current,
8788
resolve_exports_depth: int = 5,
8889
unmount_before_update: bool = False,
@@ -114,6 +115,8 @@ def module_from_template(
114115
Where the package should be loaded from. The CDN must distribute ESM modules
115116
fallback:
116117
What to temporarilly display while the module is being loaded.
118+
exports_default:
119+
Whether the module has a default export.
117120
resolve_imports:
118121
Whether to try and find all the named exports of this module.
119122
resolve_exports_depth:
@@ -132,7 +135,12 @@ def module_from_template(
132135
# downstream code assumes no trailing slash
133136
cdn = cdn.rstrip("/")
134137

135-
template_file_name = f"{template}{module_name_suffix(package_name)}"
138+
template_file_name = (
139+
template
140+
+ (".default" if exports_default else "")
141+
+ module_name_suffix(package_name)
142+
)
143+
136144
template_file = Path(__file__).parent / "templates" / template_file_name
137145
if not template_file.exists():
138146
raise ValueError(f"No template for {template_file_name!r} exists")
@@ -144,16 +152,19 @@ def module_from_template(
144152
_resolve_template(template_file, {"$PACKAGE": package, "$CDN": cdn})
145153
)
146154

155+
if resolve_exports:
156+
export_names = resolve_module_exports_from_file(
157+
target_file, resolve_exports_depth
158+
)
159+
else:
160+
export_names = None
161+
147162
return WebModule(
148163
source="from-template/" + package_name + module_name_suffix(package_name),
149164
source_type=NAME_SOURCE,
150165
default_fallback=fallback,
151166
file=target_file,
152-
export_names=(
153-
resolve_module_exports_from_url(f"{cdn}/{package}", resolve_exports_depth)
154-
if resolve_exports
155-
else None
156-
),
167+
export_names=export_names,
157168
unmount_before_update=unmount_before_update,
158169
)
159170

src/idom/web/templates/react-default.js renamed to src/idom/web/templates/react.default.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
export { default } from "$CDN/$PACKAGE";
33

44
// insert the normal react template
5-
$TEMPLATE:react.js
5+
$react.js

src/idom/web/utils.py

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,41 @@ def module_name_suffix(name: str) -> str:
1818
return PurePosixPath(tail or head).suffix or ".js"
1919

2020

21-
def resolve_module_exports_from_file(file: Path, max_depth: int) -> Set[str]:
21+
def resolve_module_exports_from_file(
22+
file: Path,
23+
max_depth: int,
24+
is_re_export: bool = False,
25+
) -> Set[str]:
2226
if max_depth == 0:
2327
logger.warning(f"Did not resolve all exports for {file} - max depth reached")
2428
return set()
2529
elif not file.exists():
2630
logger.warning(f"Did not resolve exports for unknown file {file}")
2731
return set()
2832

29-
export_names, references = resolve_module_exports_from_source(file.read_text())
33+
export_names, references = resolve_module_exports_from_source(
34+
file.read_text(), exclude_default=is_re_export
35+
)
3036

3137
for ref in references:
3238
if urlparse(ref).scheme: # is an absolute URL
33-
export_names.update(resolve_module_exports_from_url(ref, max_depth - 1))
39+
export_names.update(
40+
resolve_module_exports_from_url(ref, max_depth - 1, is_re_export=True)
41+
)
3442
else:
3543
path = file.parent.joinpath(*ref.split("/"))
36-
export_names.update(resolve_module_exports_from_file(path, max_depth - 1))
44+
export_names.update(
45+
resolve_module_exports_from_file(path, max_depth - 1, is_re_export=True)
46+
)
3747

3848
return export_names
3949

4050

41-
def resolve_module_exports_from_url(url: str, max_depth: int) -> Set[str]:
51+
def resolve_module_exports_from_url(
52+
url: str,
53+
max_depth: int,
54+
is_re_export: bool = False,
55+
) -> Set[str]:
4256
if max_depth == 0:
4357
logger.warning(f"Did not resolve all exports for {url} - max depth reached")
4458
return set()
@@ -50,16 +64,22 @@ def resolve_module_exports_from_url(url: str, max_depth: int) -> Set[str]:
5064
logger.warning("Did not resolve exports for url " + url + reason)
5165
return set()
5266

53-
export_names, references = resolve_module_exports_from_source(text)
67+
export_names, references = resolve_module_exports_from_source(
68+
text, exclude_default=is_re_export
69+
)
5470

5571
for ref in references:
5672
url = _resolve_relative_url(url, ref)
57-
export_names.update(resolve_module_exports_from_url(url, max_depth - 1))
73+
export_names.update(
74+
resolve_module_exports_from_url(url, max_depth - 1, is_re_export=True)
75+
)
5876

5977
return export_names
6078

6179

62-
def resolve_module_exports_from_source(content: str) -> Tuple[Set[str], Set[str]]:
80+
def resolve_module_exports_from_source(
81+
content: str, exclude_default: bool
82+
) -> Tuple[Set[str], Set[str]]:
6383
names: Set[str] = set()
6484
references: Set[str] = set()
6585

@@ -69,7 +89,9 @@ def resolve_module_exports_from_source(content: str) -> Tuple[Set[str], Set[str]
6989
# Exporting functions and classes
7090
names.update(_JS_FUNC_OR_CLS_EXPORT_PATTERN.findall(content))
7191

92+
print(content)
7293
for export in _JS_GENERAL_EXPORT_PATTERN.findall(content):
94+
print(export)
7395
export = export.rstrip(";").strip()
7496
# Exporting individual features
7597
if export.startswith("let "):
@@ -100,7 +122,14 @@ def resolve_module_exports_from_source(content: str) -> Tuple[Set[str], Set[str]
100122
)
101123
elif not (export.startswith("function ") or export.startswith("class ")):
102124
logger.warning(f"Unknown export type {export!r}")
103-
return {n.strip() for n in names}, {r.strip() for r in references}
125+
126+
names = {n.strip() for n in names}
127+
references = {r.strip() for r in references}
128+
129+
if exclude_default and "default" in names:
130+
names.remove("default")
131+
132+
return names, references
104133

105134

106135
def _resolve_relative_url(base_url: str, rel_url: str) -> str:
@@ -126,5 +155,5 @@ def _resolve_relative_url(base_url: str, rel_url: str) -> str:
126155
r";?\s*export\s+(?:function|class)\s+([a-zA-Z_$][0-9a-zA-Z_$]*)"
127156
)
128157
_JS_GENERAL_EXPORT_PATTERN = re.compile(
129-
r";?\s*export(?=\s+|{)(.*?)(?:;|$)", re.MULTILINE
158+
r"(?:^|;)\s*export(?=\s+|{)(.*?)(?=;|$)", re.MULTILINE
130159
)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
export {one as One};
22
// use ../ just to check that it works
33
export * from "../export-resolution/two.js";
4+
// this default should not be exported by the * re-export in index.js
5+
export default 0;

tests/test_web/test_utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,15 @@ def test_resolve_module_exports_from_url_log_on_bad_response(caplog):
127127
],
128128
)
129129
def test_resolve_module_default_exports_from_source(text):
130-
names, references = resolve_module_exports_from_source(text)
130+
names, references = resolve_module_exports_from_source(text, exclude_default=False)
131131
assert names == {"default"} and not references
132132

133133

134134
def test_resolve_module_exports_from_source():
135135
fixture_file = JS_FIXTURES_DIR / "exports-syntax.js"
136-
names, references = resolve_module_exports_from_source(fixture_file.read_text())
136+
names, references = resolve_module_exports_from_source(
137+
fixture_file.read_text(), exclude_default=False
138+
)
137139
assert (
138140
names
139141
== (

0 commit comments

Comments
 (0)