mod doc_comment;
pub use self::doc_comment::DocComment;
use core::fmt::Write as _;
use alloc::collections::BTreeSet;
use crate as genco;
use crate::fmt;
use crate::quote_in;
use crate::tokens::{quoted, ItemStr};
const SEP: &str = ".";
const DART_CORE: &str = "dart:core";
pub type Tokens = crate::Tokens<Dart>;
impl genco::lang::LangSupportsEval for Dart {}
impl_lang! {
pub Dart {
type Config = Config;
type Format = Format;
type Item = Import;
fn string_eval_literal(
out: &mut fmt::Formatter<'_>,
_config: &Self::Config,
_format: &Self::Format,
literal: &str,
) -> fmt::Result {
write!(out, "${literal}")?;
Ok(())
}
fn start_string_eval(
out: &mut fmt::Formatter<'_>,
_config: &Self::Config,
_format: &Self::Format,
) -> fmt::Result {
out.write_str("${")?;
Ok(())
}
fn end_string_eval(
out: &mut fmt::Formatter<'_>,
_config: &Self::Config,
_format: &Self::Format,
) -> fmt::Result {
out.write_char('}')?;
Ok(())
}
fn write_quoted(out: &mut fmt::Formatter<'_>, input: &str) -> fmt::Result {
for c in input.chars() {
match c {
'\u{0008}' => out.write_str("\\b")?,
'\u{0012}' => out.write_str("\\f")?,
'\n' => out.write_str("\\n")?,
'\r' => out.write_str("\\r")?,
'\t' => out.write_str("\\t")?,
'\u{0011}' => out.write_str("\\v")?,
'"' => out.write_str("\\\"")?,
'\\' => out.write_str("\\\\")?,
'$' => out.write_str("\\$")?,
c if !c.is_control() => out.write_char(c)?,
c if (c as u32) < 0x100 => {
write!(out, "\\x{:02x}", c as u32)?;
}
c => {
for c in c.encode_utf16(&mut [0u16; 2]) {
write!(out, "\\u{c:04x}")?;
}
}
};
}
Ok(())
}
fn format_file(
tokens: &Tokens,
out: &mut fmt::Formatter<'_>,
config: &Self::Config,
) -> fmt::Result {
let mut imports: Tokens = Tokens::new();
Self::imports(&mut imports, tokens, config);
let format = Format::default();
imports.format(out, config, &format)?;
tokens.format(out, config, &format)?;
Ok(())
}
}
Import(Import) {
fn format(&self, out: &mut fmt::Formatter<'_>, _: &Config, _: &Format) -> fmt::Result {
if let Some(alias) = &self.alias {
out.write_str(alias.as_ref())?;
out.write_str(SEP)?;
}
out.write_str(&self.name)?;
Ok(())
}
}
}
#[derive(Debug, Default)]
pub struct Format {}
#[derive(Debug, Default)]
pub struct Config {}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Import {
path: ItemStr,
name: ItemStr,
alias: Option<ItemStr>,
}
impl Import {
pub fn with_alias(self, alias: impl Into<ItemStr>) -> Import {
Self {
alias: Some(alias.into()),
..self
}
}
}
impl Dart {
fn imports(out: &mut Tokens, input: &Tokens, _: &Config) {
let mut modules = BTreeSet::new();
for import in input.iter_lang() {
if &*import.path == DART_CORE {
continue;
}
modules.insert((import.path.clone(), import.alias.clone()));
}
if modules.is_empty() {
return;
}
for (name, alias) in modules {
if let Some(alias) = alias {
quote_in!(*out => import $(quoted(name)) as $alias;);
} else {
quote_in!(*out => import $(quoted(name)););
}
out.push();
}
out.line();
}
}
pub fn import<P, N>(path: P, name: N) -> Import
where
P: Into<ItemStr>,
N: Into<ItemStr>,
{
Import {
path: path.into(),
alias: None,
name: name.into(),
}
}
pub fn doc_comment<T>(comment: T) -> DocComment<T>
where
T: IntoIterator,
T::Item: Into<ItemStr>,
{
DocComment(comment)
}