ADR-0024 Phase E: replay end-to-end
Migrate `replay <path>` to the walker. Shape is Choice(StringLit, BarePath); the StringLit branch handles the quoted form (with the existing `''` escape), and BarePath handles the unquoted form. Per ADR-0024's path-bearing UX change (already shipped for import / export in Phase A), bare `replay` paths terminate at the first whitespace byte. Paths with spaces require the quoted form. The legacy `try_parse_replay_with_bare_path` source-slice helper in dsl/parser.rs is removed; the chumsky-side replay branch in command_parser stays declared but unreachable until Phase F sweeps the chumsky path. Tests: - 7 new walker-specific tests for replay: bare relative path, bare absolute path, quoted with whitespace, quoted with escaped quote, case-insensitive keyword, missing-path error, empty-quoted-path parses to empty (runtime layer rejects). - Total: 844 passed, 0 failed, 1 ignored (was 838 / 1). - cargo clippy --all-targets -- -D warnings clean.
This commit is contained in:
@@ -490,6 +490,36 @@ fn build_delete(path: &MatchedPath) -> Result<Command, ValidationError> {
|
||||
Ok(Command::Delete { table, filter })
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// replay — `replay <bare-path>` | `replay '<path>'`
|
||||
// =================================================================
|
||||
//
|
||||
// Phase E (ADR-0024 §migration). The chumsky-side
|
||||
// `try_parse_replay_with_bare_path` source-slice helper is
|
||||
// retired here: walker BarePath consumes the unquoted form
|
||||
// (terminating at whitespace per the path-bearing UX change),
|
||||
// and StringLit consumes the quoted form. Paths with spaces
|
||||
// must use the quoted form — same UX that `import` / `export`
|
||||
// adopted in Phase A.
|
||||
|
||||
const REPLAY_PATH_CHOICES: &[Node] = &[Node::StringLit, Node::BarePath];
|
||||
const REPLAY_PATH: Node = Node::Choice(REPLAY_PATH_CHOICES);
|
||||
|
||||
fn build_replay(path: &MatchedPath) -> Result<Command, ValidationError> {
|
||||
let payload = path
|
||||
.items
|
||||
.iter()
|
||||
.find_map(|i| match &i.kind {
|
||||
MatchedKind::StringLit | MatchedKind::BarePath => Some(i.text.clone()),
|
||||
_ => None,
|
||||
})
|
||||
.ok_or_else(|| ValidationError {
|
||||
message_key: "parse.error_wrapper",
|
||||
args: vec![("detail", "missing path".to_string())],
|
||||
})?;
|
||||
Ok(Command::Replay { path: payload })
|
||||
}
|
||||
|
||||
// =================================================================
|
||||
// CommandNodes
|
||||
// =================================================================
|
||||
@@ -529,3 +559,12 @@ pub static DELETE: CommandNode = CommandNode {
|
||||
usage_id: Some("parse.usage.delete"),
|
||||
hint_mode: None,
|
||||
};
|
||||
|
||||
pub static REPLAY: CommandNode = CommandNode {
|
||||
entry: Word::keyword("replay"),
|
||||
shape: REPLAY_PATH,
|
||||
ast_builder: build_replay,
|
||||
help_id: Some("data.replay"),
|
||||
usage_id: Some("parse.usage.replay"),
|
||||
hint_mode: None,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user