cucumber/parser/
mod.rs

1// Copyright (c) 2018-2024  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::{Display, Error};
20use futures::Stream;
21
22use crate::feature::ExpandExamplesError;
23
24#[doc(inline)]
25pub use self::basic::Basic;
26
27/// Source of parsed [`Feature`]s.
28///
29/// [`Feature`]: gherkin::Feature
30pub trait Parser<I> {
31    /// CLI options of this [`Parser`]. In case no options should be introduced,
32    /// just use [`cli::Empty`].
33    ///
34    /// All CLI options from [`Parser`], [`Runner`] and [`Writer`] will be
35    /// merged together, so overlapping arguments will cause a runtime panic.
36    ///
37    /// [`cli::Empty`]: crate::cli::Empty
38    /// [`Runner`]: crate::Runner
39    /// [`Writer`]: crate::Writer
40    type Cli: clap::Args;
41
42    /// Output [`Stream`] of parsed [`Feature`]s.
43    ///
44    /// [`Feature`]: gherkin::Feature
45    type Output: Stream<Item = Result<gherkin::Feature>> + 'static;
46
47    /// Parses the given `input` into a [`Stream`] of [`Feature`]s.
48    ///
49    /// [`Feature`]: gherkin::Feature
50    fn parse(self, input: I, cli: Self::Cli) -> Self::Output;
51}
52
53/// Result of parsing [Gherkin] files.
54///
55/// [Gherkin]: https://cucumber.io/docs/gherkin/reference
56#[allow(clippy::absolute_paths)] // intentional
57pub type Result<T> = std::result::Result<T, Error>;
58
59/// [`Parser`] error.
60#[derive(Clone, Debug, Display, Error)]
61pub enum Error {
62    /// Failed to parse a [`Feature`].
63    ///
64    /// [`Feature`]: gherkin::Feature
65    #[display(fmt = "Failed to parse feature: {}", _0)]
66    Parsing(Arc<gherkin::ParseFileError>),
67
68    /// Failed to expand [`Examples`]
69    ///
70    /// [`Examples`]: gherkin::Examples
71    #[display(fmt = "Failed to expand examples: {}", _0)]
72    ExampleExpansion(Arc<ExpandExamplesError>),
73}
74
75impl From<gherkin::ParseFileError> for Error {
76    fn from(e: gherkin::ParseFileError) -> Self {
77        Self::Parsing(Arc::new(e))
78    }
79}
80
81impl From<ExpandExamplesError> for Error {
82    fn from(e: ExpandExamplesError) -> Self {
83        Self::ExampleExpansion(Arc::new(e))
84    }
85}