mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-13 15:40:05 +00:00
fix(extract): end a Svelte script block's trailing comment and report read errors
Review follow-ups on #3928: - A `//` comment closing one `<script>` block swallowed a second block on the same line, since masking leaves them on one line. Terminate each block with U+2028 then `;`: the line terminator ends the comment and the `;` ends a statement that had none. Line numbers and byte offsets are unchanged. - An unreadable file returns the `error` key again instead of an empty result, matching the behavior before the masking change.
This commit is contained in:
1 parent
b64806924e
commit
5de47e3df3
2 files changed
+41
-6
No files matched your search
+9
-6
@@ -2387,10 +2387,13 @@ def _svelte_mask_non_script(src: str) -> tuple[str, str | None]:
|
||||
continue
|
||||
start, end = m.start(2), m.end(2)
|
||||
chars[start:end] = src[start:end]
|
||||
# Terminate the region in place of the following `<`, so two scripts on
|
||||
# one line don't run together into a single statement.
|
||||
if end < len(chars) and chars[end] == " ":
|
||||
chars[end] = ";"
|
||||
# Terminate the region in place of the closing `</script`, so two scripts
|
||||
# on one line don't run together. U+2028 is a JS line terminator, so it
|
||||
# ends a trailing `//` comment that would otherwise swallow the next
|
||||
# block; the `;` after it then ends the statement (inside the comment it
|
||||
# would be inert). U+2028 is not a newline, so line numbers hold, and its
|
||||
# 3 UTF-8 bytes replace 3 ASCII ones, so byte offsets do too.
|
||||
chars[end:end + 4] = ["\u2028", ";", "", ""]
|
||||
if lang is None:
|
||||
lang_m = _SCRIPT_LANG_RE.search(m.group(1))
|
||||
if lang_m:
|
||||
@@ -2421,8 +2424,8 @@ def extract_svelte(path: Path) -> dict:
|
||||
"""
|
||||
try:
|
||||
src = path.read_text(encoding="utf-8", errors="replace")
|
||||
except OSError:
|
||||
return {"nodes": [], "edges": []}
|
||||
except OSError as e:
|
||||
return {"nodes": [], "edges": [], "error": str(e)}
|
||||
|
||||
masked, lang = _svelte_mask_non_script(src)
|
||||
config = _JS_CONFIG if lang in ("js", "jsx") else _TS_CONFIG
|
||||
|
||||
@@ -164,6 +164,38 @@ def test_extract_svelte_scripts_on_one_line_do_not_merge(tmp_path):
|
||||
assert "b()" in _labels(result)
|
||||
|
||||
|
||||
def test_extract_svelte_line_comment_does_not_swallow_next_script(tmp_path):
|
||||
"""A `//` comment ending one block must not hide a block on the same line."""
|
||||
component = _write(
|
||||
tmp_path / "src/Commented.svelte",
|
||||
"<script module>// shared</script><script>function b() {}</script>\n"
|
||||
"<script>function c() {}</script>\n",
|
||||
)
|
||||
result = extract_svelte(component)
|
||||
assert result.get("parse_errors") is None
|
||||
labels = _labels(result)
|
||||
assert labels.get("b()") == "L1"
|
||||
assert labels.get("c()") == "L2"
|
||||
|
||||
|
||||
def test_extract_svelte_comment_after_unterminated_statement(tmp_path):
|
||||
"""A statement with no `;` before the `//` comment still ends at the block."""
|
||||
component = _write(
|
||||
tmp_path / "src/Unterminated.svelte",
|
||||
"<script module>const a = 1 // shared</script><script>function b() {}</script>\n",
|
||||
)
|
||||
result = extract_svelte(component)
|
||||
assert result.get("parse_errors") is None
|
||||
assert _labels(result).get("b()") == "L1"
|
||||
|
||||
|
||||
def test_extract_svelte_unreadable_file_reports_error(tmp_path):
|
||||
"""A file that cannot be read is reported, not returned as an empty result."""
|
||||
result = extract_svelte(tmp_path / "missing" / "Gone.svelte")
|
||||
assert result["nodes"] == [] and result["edges"] == []
|
||||
assert "error" in result
|
||||
|
||||
|
||||
def test_extract_svelte_markup_only_component_does_not_crash(tmp_path):
|
||||
"""A `.svelte` file need not have a `<script>` block at all."""
|
||||
component = _write(tmp_path / "src/Plain.svelte", "<h1>no script here</h1>\n")
|
||||
|
||||
Reference in new issue
Block a user