use serde::Deserialize;
#[macro_use]
mod context;
mod formatters;
mod shape;
mod verify_ast;
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum IndentType {
Tabs,
Spaces,
}
impl Default for IndentType {
fn default() -> Self {
IndentType::Tabs
}
}
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum LineEndings {
Unix,
Windows,
}
impl Default for LineEndings {
fn default() -> Self {
LineEndings::Unix
}
}
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum QuoteStyle {
AutoPreferDouble,
AutoPreferSingle,
ForceDouble,
ForceSingle,
}
impl Default for QuoteStyle {
fn default() -> Self {
QuoteStyle::AutoPreferDouble
}
}
#[derive(Debug, Copy, Clone, PartialEq, Deserialize)]
pub enum CallParenType {
Always,
NoSingleString,
NoSingleTable,
None,
}
impl Default for CallParenType {
fn default() -> Self {
CallParenType::Always
}
}
#[derive(Debug, Copy, Clone, Deserialize)]
pub struct Range {
start: Option<usize>,
end: Option<usize>,
}
impl Range {
pub fn from_values(start: Option<usize>, end: Option<usize>) -> Self {
Self { start, end }
}
}
#[derive(Copy, Clone, Debug, Deserialize)]
#[serde(default, deny_unknown_fields)]
pub struct Config {
column_width: usize,
line_endings: LineEndings,
indent_type: IndentType,
indent_width: usize,
quote_style: QuoteStyle,
no_call_parentheses: bool,
call_parentheses: CallParenType,
}
impl Config {
pub fn new() -> Self {
Config::default()
}
pub fn with_column_width(self, column_width: usize) -> Self {
Self {
column_width,
..self
}
}
pub fn with_line_endings(self, line_endings: LineEndings) -> Self {
Self {
line_endings,
..self
}
}
pub fn with_indent_type(self, indent_type: IndentType) -> Self {
Self {
indent_type,
..self
}
}
pub fn with_indent_width(self, indent_width: usize) -> Self {
Self {
indent_width,
..self
}
}
pub fn with_quote_style(self, quote_style: QuoteStyle) -> Self {
Self {
quote_style,
..self
}
}
pub fn with_no_call_parentheses(self, no_call_parentheses: bool) -> Self {
Self {
no_call_parentheses,
..self
}
}
pub fn with_call_parentheses(self, call_parentheses: CallParenType) -> Self {
Self {
call_parentheses,
..self
}
}
}
impl Default for Config {
fn default() -> Self {
Self {
column_width: 120,
line_endings: LineEndings::Unix,
indent_type: IndentType::Tabs,
indent_width: 4,
quote_style: QuoteStyle::default(),
no_call_parentheses: false,
call_parentheses: CallParenType::default(),
}
}
}
#[derive(Debug, Copy, Clone, Deserialize)]
pub enum OutputVerification {
Full,
None,
}
#[derive(Clone, Debug)]
pub enum Error {
ParseError(full_moon::Error),
VerificationAstError(full_moon::Error),
VerificationAstDifference,
}
impl std::fmt::Display for Error {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Error::ParseError(error) => match error {
full_moon::Error::AstError(error) => write!(formatter, "error parsing: {}", error),
full_moon::Error::TokenizerError(error) => write!(formatter, "error parsing: {}", error),
},
Error::VerificationAstError(error) => write!(formatter, "INTERNAL ERROR: Output AST generated a syntax error. Please report this at https://github.com/johnnymorganz/stylua/issues\n{}", error),
Error::VerificationAstDifference => write!(formatter, "INTERNAL WARNING: Output AST may be different to input AST. Code correctness may have changed. Please examine the formatting diff and report any issues at https://github.com/johnnymorganz/stylua/issues"),
}
}
}
impl std::error::Error for Error {}
pub fn format_code(
code: &str,
config: Config,
range: Option<Range>,
verify_output: OutputVerification,
) -> Result<String, Error> {
let input_ast = match full_moon::parse(code) {
Ok(ast) => ast,
Err(error) => {
return Err(Error::ParseError(error));
}
};
let input_ast_for_verification = if let OutputVerification::Full = verify_output {
Some(input_ast.to_owned())
} else {
None
};
let code_formatter = formatters::CodeFormatter::new(config, range);
let ast = code_formatter.format(input_ast);
let output = full_moon::print(&ast);
if let Some(input_ast) = input_ast_for_verification {
let reparsed_output = match full_moon::parse(&output) {
Ok(ast) => ast,
Err(error) => {
return Err(Error::VerificationAstError(error));
}
};
let mut ast_verifier = verify_ast::AstVerifier::new();
if !ast_verifier.compare(input_ast, reparsed_output) {
return Err(Error::VerificationAstDifference);
}
}
Ok(output)
}