use crate::types::Fix;
use crate::wit_guest::nginx_lint::plugin::config_api;
use crate::wit_guest::nginx_lint::plugin::types as wit_types;
pub struct Config {
handle: config_api::Config,
}
impl Config {
pub fn from_handle(handle: config_api::Config) -> Self {
Self { handle }
}
pub fn all_directives_with_context(&self) -> Vec<DirectiveWithContext> {
self.handle
.all_directives_with_context()
.into_iter()
.map(|ctx| DirectiveWithContext {
directive: Directive::from_handle(ctx.directive),
parent_stack: ctx.parent_stack,
depth: ctx.depth as usize,
})
.collect()
}
pub fn all_directives(&self) -> Vec<Directive> {
self.handle
.all_directives()
.into_iter()
.map(Directive::from_handle)
.collect()
}
pub fn items(&self) -> Vec<ConfigItem> {
self.handle
.items()
.into_iter()
.map(ConfigItem::from_wit)
.collect()
}
pub fn include_context(&self) -> Vec<String> {
self.handle.include_context()
}
pub fn is_included_from(&self, context: &str) -> bool {
self.handle.is_included_from(context)
}
pub fn is_included_from_http(&self) -> bool {
self.handle.is_included_from_http()
}
pub fn is_included_from_http_server(&self) -> bool {
self.handle.is_included_from_http_server()
}
pub fn is_included_from_http_location(&self) -> bool {
self.handle.is_included_from_http_location()
}
pub fn is_included_from_stream(&self) -> bool {
self.handle.is_included_from_stream()
}
pub fn immediate_parent_context(&self) -> Option<String> {
self.handle.immediate_parent_context()
}
}
pub struct Directive {
handle: config_api::Directive,
}
impl Directive {
pub(crate) fn from_handle(handle: config_api::Directive) -> Self {
Self { handle }
}
pub fn name(&self) -> String {
self.handle.name()
}
pub fn args(&self) -> Vec<ArgumentInfo> {
self.handle
.args()
.into_iter()
.map(ArgumentInfo::from_wit)
.collect()
}
pub fn has_block(&self) -> bool {
self.handle.has_block()
}
pub fn block_items(&self) -> Vec<ConfigItem> {
self.handle
.block_items()
.into_iter()
.map(ConfigItem::from_wit)
.collect()
}
pub fn block_is_raw(&self) -> bool {
self.handle.block_is_raw()
}
pub fn start_offset(&self) -> usize {
self.handle.start_offset() as usize
}
pub fn end_offset(&self) -> usize {
self.handle.end_offset() as usize
}
pub fn leading_whitespace(&self) -> String {
self.handle.leading_whitespace()
}
pub fn trailing_whitespace(&self) -> String {
self.handle.trailing_whitespace()
}
pub fn space_before_terminator(&self) -> String {
self.handle.space_before_terminator()
}
}
impl Directive {
pub fn is(&self, name: &str) -> bool {
self.handle.is(name)
}
pub fn first_arg_owned(&self) -> Option<String> {
self.handle.first_arg()
}
pub fn first_arg_is(&self, value: &str) -> bool {
self.handle.first_arg_is(value)
}
pub fn arg_at_owned(&self, index: usize) -> Option<String> {
self.handle.arg_at(index as u32)
}
pub fn last_arg_owned(&self) -> Option<String> {
self.handle.last_arg()
}
pub fn has_arg(&self, value: &str) -> bool {
self.handle.has_arg(value)
}
pub fn arg_count(&self) -> usize {
self.handle.arg_count() as usize
}
pub fn line(&self) -> usize {
self.handle.line() as usize
}
pub fn column(&self) -> usize {
self.handle.column() as usize
}
pub fn full_start_offset(&self) -> usize {
self.start_offset() - self.leading_whitespace().len()
}
pub fn replace_with(&self, new_text: &str) -> Fix {
convert_wit_fix(self.handle.replace_with(new_text))
}
pub fn delete_line(&self) -> Fix {
convert_wit_fix(self.handle.delete_line_fix())
}
pub fn insert_after(&self, new_text: &str) -> Fix {
convert_wit_fix(self.handle.insert_after(new_text))
}
pub fn insert_after_many(&self, lines: &[&str]) -> Fix {
let owned: Vec<String> = lines.iter().map(|s| s.to_string()).collect();
convert_wit_fix(self.handle.insert_after_many(&owned))
}
pub fn insert_before(&self, new_text: &str) -> Fix {
convert_wit_fix(self.handle.insert_before(new_text))
}
pub fn insert_before_many(&self, lines: &[&str]) -> Fix {
let owned: Vec<String> = lines.iter().map(|s| s.to_string()).collect();
convert_wit_fix(self.handle.insert_before_many(&owned))
}
}
pub struct DirectiveWithContext {
pub directive: Directive,
pub parent_stack: Vec<String>,
pub depth: usize,
}
impl DirectiveWithContext {
pub fn parent(&self) -> Option<&str> {
self.parent_stack.last().map(|s| s.as_str())
}
pub fn is_inside(&self, parent_name: &str) -> bool {
self.parent_stack.iter().any(|p| p == parent_name)
}
pub fn parent_is(&self, parent_name: &str) -> bool {
self.parent() == Some(parent_name)
}
pub fn is_at_root(&self) -> bool {
self.parent_stack.is_empty()
}
}
pub enum ConfigItem {
Directive(Directive),
Comment(CommentInfo),
BlankLine(BlankLineInfo),
}
impl ConfigItem {
fn from_wit(item: config_api::ConfigItem) -> Self {
match item {
config_api::ConfigItem::DirectiveItem(d) => {
ConfigItem::Directive(Directive::from_handle(d))
}
config_api::ConfigItem::CommentItem(c) => ConfigItem::Comment(CommentInfo {
text: c.text,
line: c.line as usize,
column: c.column as usize,
leading_whitespace: c.leading_whitespace,
trailing_whitespace: c.trailing_whitespace,
start_offset: c.start_offset as usize,
end_offset: c.end_offset as usize,
}),
config_api::ConfigItem::BlankLineItem(b) => ConfigItem::BlankLine(BlankLineInfo {
line: b.line as usize,
content: b.content,
start_offset: b.start_offset as usize,
}),
}
}
}
pub struct CommentInfo {
pub text: String,
pub line: usize,
pub column: usize,
pub leading_whitespace: String,
pub trailing_whitespace: String,
pub start_offset: usize,
pub end_offset: usize,
}
pub struct BlankLineInfo {
pub line: usize,
pub content: String,
pub start_offset: usize,
}
pub struct ArgumentInfo {
pub value: String,
pub raw: String,
pub arg_type: ArgumentType,
pub line: usize,
pub column: usize,
pub start_offset: usize,
pub end_offset: usize,
}
impl ArgumentInfo {
fn from_wit(arg: config_api::ArgumentInfo) -> Self {
Self {
value: arg.value,
raw: arg.raw,
arg_type: match arg.arg_type {
config_api::ArgumentType::Literal => ArgumentType::Literal,
config_api::ArgumentType::QuotedString => ArgumentType::QuotedString,
config_api::ArgumentType::SingleQuotedString => ArgumentType::SingleQuotedString,
config_api::ArgumentType::Variable => ArgumentType::Variable,
},
line: arg.line as usize,
column: arg.column as usize,
start_offset: arg.start_offset as usize,
end_offset: arg.end_offset as usize,
}
}
pub fn as_str(&self) -> &str {
&self.value
}
pub fn is_variable(&self) -> bool {
matches!(self.arg_type, ArgumentType::Variable)
}
pub fn is_quoted(&self) -> bool {
matches!(self.arg_type, ArgumentType::QuotedString)
}
pub fn is_single_quoted(&self) -> bool {
matches!(self.arg_type, ArgumentType::SingleQuotedString)
}
pub fn is_literal(&self) -> bool {
matches!(self.arg_type, ArgumentType::Literal)
}
}
pub enum ArgumentType {
Literal,
QuotedString,
SingleQuotedString,
Variable,
}
fn convert_wit_fix(fix: wit_types::Fix) -> Fix {
Fix {
line: fix.line as usize,
old_text: fix.old_text,
new_text: fix.new_text,
delete_line: fix.delete_line,
insert_after: fix.insert_after,
start_offset: fix.start_offset.map(|v| v as usize),
end_offset: fix.end_offset.map(|v| v as usize),
}
}