Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions scripts/snippets/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,9 @@ class SnippetAttributeIssue:
rule: SnippetAttributeRule
span: Span
message: str


@dataclass(frozen=True)
class SnippetConditionContext:
snippet: SnippetTag
condition: IfVersionCondition | None
36 changes: 36 additions & 0 deletions scripts/snippets/semantics.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
from __future__ import annotations

from .model import (
ElseTag,
IfVersionCondition,
IfVersionTag,
ImmutableSourceReference,
LocalSourceReference,
PullRequestSnippetSource,
PullRequestSourceReference,
SnippetAttributeIssue,
SnippetAttributeRule,
SnippetConditionContext,
SnippetSourceAttributeIssue,
SnippetSourceAttributeRule,
SnippetSourceAttributeValidation,
Expand Down Expand Up @@ -136,3 +140,35 @@ def validate_snippet_basic_attributes(
)
)
return tuple(issues)


def map_snippet_condition_contexts(
snippets: tuple[SnippetTag, ...],
conditional_tags: tuple[IfVersionTag | ElseTag, ...],
conditions: tuple[IfVersionCondition, ...],
) -> tuple[SnippetConditionContext, ...]:
"""Associate snippets with their innermost enclosing IfVersion condition."""

conditions_by_start = {
condition.span.start: condition for condition in conditions
}
events = sorted(
(*snippets, *conditional_tags), key=lambda event: event.span.start
)
stack: list[IfVersionCondition | None] = []
contexts: list[SnippetConditionContext] = []
for event in events:
if isinstance(event, IfVersionTag):
if event.closing:
if stack:
stack.pop()
else:
stack.append(conditions_by_start.get(event.span.start))
elif isinstance(event, SnippetTag):
contexts.append(
SnippetConditionContext(
snippet=event,
condition=stack[-1] if stack else None,
)
)
return tuple(contexts)
75 changes: 75 additions & 0 deletions tests/test_snippet_condition_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from __future__ import annotations

from scripts.snippets.model import IfVersionCondition, IfVersionTag
from scripts.snippets.references import parse_github_repository_url
from scripts.snippets.semantics import map_snippet_condition_contexts
from scripts.snippets.syntax import (
parse_if_version_tags,
parse_snippet_tags,
)


def conditions(text: str) -> tuple[IfVersionCondition, ...]:
result: list[IfVersionCondition] = []
for tag in parse_if_version_tags(text):
if not isinstance(tag, IfVersionTag) or tag.closing:
continue
repository_value = tag.attribute("repository")
candidate = tag.attribute("containsPullRequest")
assert isinstance(repository_value, str)
repository = parse_github_repository_url(repository_value)
assert repository is not None
assert isinstance(candidate, int)
result.append(
IfVersionCondition(
repository=repository,
contains_pull_request=candidate,
span=tag.span,
)
)
return tuple(result)


def contexts(text: str):
return map_snippet_condition_contexts(
parse_snippet_tags(text),
parse_if_version_tags(text),
conditions(text),
)


def test_maps_unconditional_snippet_to_no_condition() -> None:
result = contexts('<Snippet source="ref" language="yaml" />')

assert len(result) == 1
assert result[0].condition is None


def test_maps_both_branches_to_enclosing_condition() -> None:
result = contexts(
"""<IfVersion repository="https://github.com/example/outer" containsPullRequest={12}>
<Snippet source="new" language="yaml" />
<Else>
<Snippet source="old" language="yaml" />
</Else>
</IfVersion>"""
)

assert [context.condition.contains_pull_request for context in result] == [
12,
12,
]


def test_maps_nested_snippet_to_innermost_condition() -> None:
result = contexts(
"""<IfVersion repository="https://github.com/example/outer" containsPullRequest={12}>
<IfVersion repository="https://github.com/example/inner" containsPullRequest={34}>
<Snippet source="nested" language="yaml" />
</IfVersion>
</IfVersion>"""
)

assert result[0].condition is not None
assert result[0].condition.repository == "example/inner"
assert result[0].condition.contains_pull_request == 34