Skip to content
Merged
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
2 changes: 1 addition & 1 deletion DEVIATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
aspiration — see ARCHITECTURE.md §2. Every intentional difference belongs here, with its reason.
An undocumented divergence in a port is a bug report waiting to happen.

**Ported against:** upstream `cucumber/gherkin` `main` as of 2026-07-31 (80 languages).
**Ported against:** upstream `cucumber/gherkin` `main` as of 2026-08-19 (80 languages).

## Architectural

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,7 @@ private fun gherkinDialectsChunk2(): Map<String, GherkinDialect> = mapOf(
name = "Texas",
nativeName = "Texas",
featureKeywords = listOf("This ain’t my first rodeo", "All gussied up"),
ruleKeywords = listOf("Rule "),
ruleKeywords = listOf("Rule"),
backgroundKeywords = listOf("Lemme tell y'all a story"),
scenarioKeywords = listOf("All hat and no cattle"),
scenarioOutlineKeywords = listOf("Serious as a snake bite", "Busy as a hound in flea season"),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// GENERATED FILE — DO NOT EDIT BY HAND.
//
// Regenerate with: python3 tools/update-expression-corpus.py
// Source: https://github.com/cucumber/cucumber-expressions @ 6dbb4888abadf5d3e113f18b00e4887507ce6ca9
// Source: https://github.com/cucumber/cucumber-expressions @ 7e7c482cbeb79a72580049c747aa23392b6fc20a
// 16 tokenizer, 28 parser, 8 transformation, 65 matching, 3 regex

package io.github.menjoo.cucumberkmp.core.expression
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// GENERATED FILE — DO NOT EDIT BY HAND.
//
// Regenerate with: python3 tools/update-gherkin-corpus.py
// Source: https://github.com/cucumber/gherkin @ bce691b4d3ec06d3b9ce83bf6c264ec11f108540
// Source: https://github.com/cucumber/gherkin @ 39d5a71caaa2b6e90042a043525c8e6cd8a7be09
// 50 parseable features, 12 failing features.
//
// Embedded as Kotlin rather than test resources because Native and Wasm cannot
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// GENERATED FILE — DO NOT EDIT BY HAND.
//
// Regenerate with: python3 tools/update-tag-expression-corpus.py
// Source: https://github.com/cucumber/tag-expressions @ 3046b904a97b088855029abf5b0f2c935024d4c6
// Source: https://github.com/cucumber/tag-expressions @ 80196942f4e16407f25a481097e954fcbe06e7fa
// 23 parsing, 26 evaluation, 15 error cases.

package io.github.menjoo.cucumberkmp.core.tag
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion tools/gherkin-languages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@
"name": "Texas",
"native": "Texas",
"rule": [
"Rule "
"Rule"
],
"scenario": [
"All hat and no cattle"
Expand Down
38 changes: 30 additions & 8 deletions tools/update-expression-corpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,35 @@ def render(families: dict, ref: str) -> str:
return "\n".join(out)


def clone_and_pin(ref: str, destination: pathlib.Path) -> str:
"""Clone upstream at `ref` and return the last commit that touched `testdata/`.

Pinning `HEAD` instead would re-pin on every unrelated upstream commit, and the drift
check (.github/workflows/upstream-drift.yml) would then report news every week the
fixtures had not moved. The clone is blobless rather than shallow because a shallow
one cannot answer a path-scoped log; trees are cheap and blobs arrive on checkout.
"""
subprocess.run(
["git", "clone", "--filter=blob:none", "--branch", ref, "-q", REPO, str(destination)],
check=True,
)
log = subprocess.run(
["git", "-C", str(destination), "log", "-1", "--format=%H", "--", "testdata"],
check=True,
capture_output=True,
text=True,
).stdout.strip()
if log:
return log
# No commit touches testdata/ -- upstream moved it, so fall back to naming the checkout.
return subprocess.run(
["git", "-C", str(destination), "rev-parse", "HEAD"],
check=True,
capture_output=True,
text=True,
).stdout.strip()


def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--ref", default="main")
Expand All @@ -183,14 +212,7 @@ def main() -> int:
workdir = pathlib.Path(tempfile.mkdtemp(prefix="expression-corpus-"))
try:
checkout = workdir / "cucumber-expressions"
subprocess.run(
["git", "clone", "--depth", "1", "--branch", args.ref, "-q", REPO, str(checkout)],
check=True,
)
ref = subprocess.run(
["git", "-C", str(checkout), "rev-parse", "HEAD"],
check=True, capture_output=True, text=True,
).stdout.strip()
ref = clone_and_pin(args.ref, checkout)

testdata = checkout / "testdata"
families: dict[str, list[dict]] = {}
Expand Down
40 changes: 30 additions & 10 deletions tools/update-gherkin-corpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,35 @@ def render(good: list[tuple[str, str, str]], bad: list[tuple[str, str, list[str]
return "\n".join(out)


def clone_and_pin(ref: str, destination: pathlib.Path) -> str:
"""Clone upstream at `ref` and return the last commit that touched `testdata/`.

Pinning `HEAD` instead would re-pin on every unrelated upstream commit, and the drift
check (.github/workflows/upstream-drift.yml) would then report news every week the
fixtures had not moved. The clone is blobless rather than shallow because a shallow
one cannot answer a path-scoped log; trees are cheap and blobs arrive on checkout.
"""
subprocess.run(
["git", "clone", "--filter=blob:none", "--branch", ref, "-q", REPO, str(destination)],
check=True,
)
log = subprocess.run(
["git", "-C", str(destination), "log", "-1", "--format=%H", "--", "testdata"],
check=True,
capture_output=True,
text=True,
).stdout.strip()
if log:
return log
# No commit touches testdata/ -- upstream moved it, so fall back to naming the checkout.
return subprocess.run(
["git", "-C", str(destination), "rev-parse", "HEAD"],
check=True,
capture_output=True,
text=True,
).stdout.strip()


# --------------------------------------------------------------------------- main


Expand All @@ -324,17 +353,8 @@ def main() -> int:

workdir = pathlib.Path(tempfile.mkdtemp(prefix="gherkin-corpus-"))
try:
subprocess.run(
["git", "clone", "--depth", "1", "--branch", args.ref, "-q", REPO, str(workdir / "gherkin")],
check=True,
)
checkout = workdir / "gherkin"
ref = subprocess.run(
["git", "-C", str(checkout), "rev-parse", "HEAD"],
check=True,
capture_output=True,
text=True,
).stdout.strip()
ref = clone_and_pin(args.ref, checkout)

good: list[tuple[str, str, str, str]] = []
for feature_path in sorted((checkout / "testdata" / "good").glob("*.feature")):
Expand Down
38 changes: 30 additions & 8 deletions tools/update-tag-expression-corpus.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,35 @@ def render(parsing, evaluations, errors, ref: str) -> str:
return "\n".join(out)


def clone_and_pin(ref: str, destination: pathlib.Path) -> str:
"""Clone upstream at `ref` and return the last commit that touched `testdata/`.

Pinning `HEAD` instead would re-pin on every unrelated upstream commit, and the drift
check (.github/workflows/upstream-drift.yml) would then report news every week the
fixtures had not moved. The clone is blobless rather than shallow because a shallow
one cannot answer a path-scoped log; trees are cheap and blobs arrive on checkout.
"""
subprocess.run(
["git", "clone", "--filter=blob:none", "--branch", ref, "-q", REPO, str(destination)],
check=True,
)
log = subprocess.run(
["git", "-C", str(destination), "log", "-1", "--format=%H", "--", "testdata"],
check=True,
capture_output=True,
text=True,
).stdout.strip()
if log:
return log
# No commit touches testdata/ -- upstream moved it, so fall back to naming the checkout.
return subprocess.run(
["git", "-C", str(destination), "rev-parse", "HEAD"],
check=True,
capture_output=True,
text=True,
).stdout.strip()


def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--ref", default="main")
Expand All @@ -116,14 +145,7 @@ def main() -> int:
workdir = pathlib.Path(tempfile.mkdtemp(prefix="tag-expression-corpus-"))
try:
checkout = workdir / "tag-expressions"
subprocess.run(
["git", "clone", "--depth", "1", "--branch", args.ref, "-q", REPO, str(checkout)],
check=True,
)
ref = subprocess.run(
["git", "-C", str(checkout), "rev-parse", "HEAD"],
check=True, capture_output=True, text=True,
).stdout.strip()
ref = clone_and_pin(args.ref, checkout)

testdata = checkout / "testdata"
parsing = yaml.safe_load((testdata / "parsing.yml").read_text(encoding="utf-8"))
Expand Down
Loading