cucumber/parser/
mod.rs

1// Copyright (c) 2018-2025  Brendan Molloy <brendan@bbqsrc.net>,
2//                          Ilya Solovyiov <ilya.solovyiov@gmail.com>,
3//                          Kai Ren <tyranron@gmail.com>
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! Tools for parsing [Gherkin] files.
12//!
13//! [Gherkin]: https://cucumber.io/docs/gherkin/reference
14
15pub mod basic;
16
17use std::sync::Arc;
18
19use derive_more::with_trait::{Display, Error as StdError};
20use futures::Stream;
21
22#[doc(inline)]
23pub use self::basic::Basic;
24use crate::feature::ExpandExamplesError;
25
26/// Source of parsed [`Feature`]s.
27///
28/// [`Feature`]: gherkin::Feature
29pub trait Parser<I> {
30    /// CLI options of this [`Parser`]. In case no options should be introduced,
31    /// just use [`cli::Empty`].
32    ///
33    /// All CLI options from [`Parser`], [`Runner`] and [`Writer`] will be
34    /// merged together, so overlapping arguments will cause a runtime panic.
35    ///
36    /// [`cli::Empty`]: crate::cli::Empty
37    /// [`Runner`]: crate::Runner
38    /// [`Writer`]: crate::Writer
39    type Cli: clap::Args;
40
41    /// Output [`Stream`] of parsed [`Feature`]s.
42    ///
43    /// [`Feature`]: gherkin::Feature
44    type Output: Stream<Item = Result<gherkin::Feature>> + 'static;
45
46    /// Parses the given `input` into a [`Stream`] of [`Feature`]s.
47    ///
48    /// [`Feature`]: gherkin::Feature
49    fn parse(self, input: I, cli: Self::Cli) -> Self::Output;
50}
51
52/// Result of parsing [Gherkin] files.
53///
54/// [Gherkin]: https://cucumber.io/docs/gherkin/reference
55#[expect(clippy::absolute_paths, reason = "one liner")]
56pub type Result<T> = std::result::Result<T, Error>;
57
58/// [`Parser`] error.
59#[derive(Clone, Debug, Display, StdError)]
60pub enum Error {
61    /// Failed to parse a [`Feature`].
62    ///
63    /// [`Feature`]: gherkin::Feature
64    #[display("Failed to parse feature: {_0}")]
65    Parsing(Arc<gherkin::ParseFileError>),
66
67    /// Failed to expand [`Examples`]
68    ///
69    /// [`Examples`]: gherkin::Examples
70    #[display("Failed to expand examples: {_0}")]
71    ExampleExpansion(Arc<ExpandExamplesError>),
72}
73
74impl From<gherkin::ParseFileError> for Error {
75    fn from(e: gherkin::ParseFileError) -> Self {
76        Self::Parsing(Arc::new(e))
77    }
78}
79
80impl From<ExpandExamplesError> for Error {
81    fn from(e: ExpandExamplesError) -> Self {
82        Self::ExampleExpansion(Arc::new(e))
83    }
84}