#[cfg(feature = "catalog")]
pub use ferrocat_icu::DiagnosticCode;
#[cfg(not(feature = "catalog"))]
mod code_type {
use std::fmt;
use std::ops::Deref;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(transparent))]
pub struct DiagnosticCode(String);
impl DiagnosticCode {
#[must_use]
pub fn new(code: impl Into<String>) -> Self {
Self(code.into())
}
#[must_use]
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for DiagnosticCode {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(self.as_str())
}
}
impl AsRef<str> for DiagnosticCode {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl Deref for DiagnosticCode {
type Target = str;
fn deref(&self) -> &Self::Target {
self.as_str()
}
}
impl From<&str> for DiagnosticCode {
fn from(code: &str) -> Self {
Self::new(code)
}
}
impl From<String> for DiagnosticCode {
fn from(code: String) -> Self {
Self::new(code)
}
}
impl PartialEq<&str> for DiagnosticCode {
fn eq(&self, other: &&str) -> bool {
self.as_str() == *other
}
}
impl PartialEq<DiagnosticCode> for &str {
fn eq(&self, other: &DiagnosticCode) -> bool {
*self == other.as_str()
}
}
}
#[cfg(not(feature = "catalog"))]
pub use code_type::DiagnosticCode;
pub mod catalog {
pub const MISSING_SOURCE_LOCALE: &str = "catalog.missing_source_locale";
pub const MISSING_LOCALE: &str = "catalog.missing_locale";
pub const OBSOLETE_ENTRY: &str = "catalog.obsolete_entry";
pub const MISSING_TRANSLATION: &str = "catalog.missing_translation";
pub const EMPTY_TRANSLATION: &str = "catalog.empty_translation";
pub const EXTRA_TRANSLATION: &str = "catalog.extra_translation";
pub const DUPLICATE_METADATA: &str = "catalog.duplicate_metadata";
pub const METADATA_UNKNOWN_MESSAGE: &str = "catalog.metadata_unknown_message";
pub const ALL: &[&str] = &[
MISSING_SOURCE_LOCALE,
MISSING_LOCALE,
OBSOLETE_ENTRY,
MISSING_TRANSLATION,
EMPTY_TRANSLATION,
EXTRA_TRANSLATION,
DUPLICATE_METADATA,
METADATA_UNKNOWN_MESSAGE,
];
}
pub mod combine {
pub const CONFLICT_RESOLVED: &str = "combine.conflict_resolved";
pub const ALL: &[&str] = &[CONFLICT_RESOLVED];
}
pub mod compile {
pub const INVALID_ICU_MESSAGE: &str = "compile.invalid_icu_message";
pub const ALL: &[&str] = &[INVALID_ICU_MESSAGE];
}
pub mod parse {
pub const INVALID_PLURAL_FORMS_HEADER: &str = "parse.invalid_plural_forms_header";
pub const ALL: &[&str] = &[INVALID_PLURAL_FORMS_HEADER];
}
pub mod plural {
pub const ASSUMED_VARIABLE: &str = "plural.assumed_variable";
pub const MISSING_PLURAL_FORMS_HEADER: &str = "plural.missing_plural_forms_header";
pub const COMPLETED_PLURAL_FORMS_HEADER: &str = "plural.completed_plural_forms_header";
pub const UNSUPPORTED_GETTEXT_EXPORT: &str = "plural.unsupported_gettext_export";
pub const NPLURALS_LOCALE_MISMATCH: &str = "plural.nplurals_locale_mismatch";
pub const MISSING_PLURAL_EXPRESSION: &str = "plural.missing_plural_expression";
pub const ALL: &[&str] = &[
ASSUMED_VARIABLE,
MISSING_PLURAL_FORMS_HEADER,
COMPLETED_PLURAL_FORMS_HEADER,
UNSUPPORTED_GETTEXT_EXPORT,
NPLURALS_LOCALE_MISMATCH,
MISSING_PLURAL_EXPRESSION,
];
}
pub mod icu {
pub const INVALID_SYNTAX: &str = "icu.invalid_syntax";
pub const UNSUPPORTED_FORMATTER_KIND: &str = "icu.unsupported_formatter_kind";
pub const UNSUPPORTED_FORMATTER_STYLE: &str = "icu.unsupported_formatter_style";
pub const MISSING_ARGUMENT: &str = "icu.missing_argument";
pub const ARGUMENT_KIND_CHANGED: &str = "icu.argument_kind_changed";
pub const EXTRA_ARGUMENT: &str = "icu.extra_argument";
pub const FORMATTER_STYLE_CHANGED: &str = "icu.formatter_style_changed";
pub const MISSING_TAG: &str = "icu.missing_tag";
pub const EXTRA_TAG: &str = "icu.extra_tag";
pub const MISSING_SELECT_SELECTOR: &str = "icu.missing_select_selector";
pub const EXTRA_SELECT_SELECTOR: &str = "icu.extra_select_selector";
pub const PLURAL_OFFSET_CHANGED: &str = "icu.plural_offset_changed";
pub const MISSING_PLURAL_SELECTOR: &str = "icu.missing_plural_selector";
pub const PATTERN_STYLE_DISCOURAGED: &str = "icu.pattern_style_discouraged";
pub const ALL: &[&str] = &[
INVALID_SYNTAX,
UNSUPPORTED_FORMATTER_KIND,
UNSUPPORTED_FORMATTER_STYLE,
MISSING_ARGUMENT,
ARGUMENT_KIND_CHANGED,
EXTRA_ARGUMENT,
FORMATTER_STYLE_CHANGED,
MISSING_TAG,
EXTRA_TAG,
MISSING_SELECT_SELECTOR,
EXTRA_SELECT_SELECTOR,
PLURAL_OFFSET_CHANGED,
MISSING_PLURAL_SELECTOR,
PATTERN_STYLE_DISCOURAGED,
];
}
pub mod metadata {
pub const INVALID_MSGID: &str = "metadata.invalid_msgid";
pub const MISSING_ARGUMENT: &str = "metadata.missing_argument";
pub const EXTRA_ARGUMENT: &str = "metadata.extra_argument";
pub const ARGUMENT_KIND_MISMATCH: &str = "metadata.argument_kind_mismatch";
pub const MISSING_TAG: &str = "metadata.missing_tag";
pub const EXTRA_TAG: &str = "metadata.extra_tag";
pub const MISSING_SELECTOR: &str = "metadata.missing_selector";
pub const EXTRA_SELECTOR: &str = "metadata.extra_selector";
pub const SELECTOR_KIND_MISMATCH: &str = "metadata.selector_kind_mismatch";
pub const MISSING_SELECTOR_CASE: &str = "metadata.missing_selector_case";
pub const EXTRA_SELECTOR_CASE: &str = "metadata.extra_selector_case";
pub const SELECTOR_OFFSET_MISMATCH: &str = "metadata.selector_offset_mismatch";
pub const ALL: &[&str] = &[
INVALID_MSGID,
MISSING_ARGUMENT,
EXTRA_ARGUMENT,
ARGUMENT_KIND_MISMATCH,
MISSING_TAG,
EXTRA_TAG,
MISSING_SELECTOR,
EXTRA_SELECTOR,
SELECTOR_KIND_MISMATCH,
MISSING_SELECTOR_CASE,
EXTRA_SELECTOR_CASE,
SELECTOR_OFFSET_MISMATCH,
];
}
#[cfg(test)]
mod tests {
use super::DiagnosticCode;
#[test]
fn diagnostic_code_preserves_canonical_string_access() {
let code = DiagnosticCode::from(String::from("catalog.missing_translation"));
assert_eq!(code.as_str(), "catalog.missing_translation");
assert_eq!(code.as_ref(), "catalog.missing_translation");
assert_eq!(&*code, "catalog.missing_translation");
assert_eq!(code.to_string(), "catalog.missing_translation");
assert_eq!(code, "catalog.missing_translation");
assert_eq!("catalog.missing_translation", code);
}
#[test]
fn fallback_code_type_matches_ferrocat_icu_definition() {
let fallback = sync_block(include_str!("diagnostic_codes.rs"));
let canonical = sync_block(include_str!("../../ferrocat-icu/src/diagnostic_codes.rs"));
assert_eq!(
fallback, canonical,
"the fallback DiagnosticCode in ferrocat-po drifted from ferrocat-icu; \
apply the change inside both sync(diagnostic-code-type) blocks"
);
}
fn sync_block(source: &str) -> Vec<&str> {
let block: Vec<&str> = source
.lines()
.skip_while(|line| !line.contains("sync(diagnostic-code-type): begin"))
.skip(1)
.take_while(|line| !line.contains("sync(diagnostic-code-type): end"))
.map(str::trim_start)
.collect();
assert!(
!block.is_empty(),
"sync(diagnostic-code-type) markers missing"
);
block
}
}