Skip to content

Commit

Permalink
feat: initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Oct 9, 2021
1 parent 306cbb0 commit 71484d3
Show file tree
Hide file tree
Showing 25 changed files with 731 additions and 67 deletions.
7 changes: 4 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,10 @@ jobs:
if: matrix.config.kind == 'test_release' && startsWith(github.ref, 'refs/tags/')
run: cargo login ${{ secrets.CRATES_TOKEN }}

- name: Cargo publish
if: matrix.config.kind == 'test_release' && startsWith(github.ref, 'refs/tags/')
run: cargo publish
# enable once the parser is published
# - name: Cargo publish
# if: matrix.config.kind == 'test_release' && startsWith(github.ref, 'refs/tags/')
# run: cargo publish

# GITHUB RELEASE
- name: Pre-release
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "dprint-plugin-dockerfile"
version = "0.0.1"
version = "0.1.0"
authors = ["David Sherret <[email protected]>"]
edition = "2018"
homepage = "https://github.com/dprint/dprint-plugin-dockerfile"
Expand All @@ -25,8 +25,8 @@ wasm = ["serde_json", "dprint-core/wasm"]
tracing = ["dprint-core/tracing"]

[dependencies]
dockerfile-parser = "0.7.1"
dprint-core = { version = "0.44.0", features = ["formatting"] }
dockerfile-parser = { git = "https://github.com/dsherret/dockerfile-parser-rs", branch = "span-for-nodes" }
dprint-core = { version = "0.46.4", features = ["formatting"] }
serde = { version = "1.0.88", features = ["derive"] }
serde_json = { version = "1.0", optional = true }

Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# dprint-plugin-dockerfile

WIP - Future home of a dockerfile formatter.
Dockerfile code formatter plugin for [dprint](https://dprint.dev).

This uses [dockerfile-parser-rs](https://github.com/dsherret/dockerfile-parser-rs) to parse a dockerfile.

See [releases](https://github.com/dprint/dprint-plugin-dockerfile/releases/) for usage.
20 changes: 0 additions & 20 deletions deployment/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,6 @@
"$id": "https://plugins.dprint.dev/schemas/dockerfile-0.0.0.json",
"type": "object",
"definitions": {
"useTabs": {
"description": "Whether to use tabs (true) or spaces (false).",
"type": "boolean",
"default": false,
"oneOf": [{
"const": true,
"description": ""
}, {
"const": false,
"description": ""
}]
},
"newLineKind": {
"description": "The kind of newline to use.",
"type": "string",
Expand Down Expand Up @@ -44,14 +32,6 @@
"default": 120,
"type": "number"
},
"indentWidth": {
"description": "The number of characters for an indent.",
"default": 2,
"type": "number"
},
"useTabs": {
"$ref": "#/definitions/useTabs"
},
"newLineKind": {
"$ref": "#/definitions/newLineKind"
}
Expand Down
31 changes: 6 additions & 25 deletions src/configuration/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl ConfigurationBuilder {
if let Some(global_config) = &self.global_config {
resolve_config(self.config.clone(), global_config).config
} else {
let global_config = resolve_global_config(HashMap::new()).config;
let global_config = resolve_global_config(HashMap::new(), &Default::default()).config;
resolve_config(self.config.clone(), &global_config).config
}
}
Expand All @@ -50,20 +50,6 @@ impl ConfigurationBuilder {
self.insert("lineWidth", (value as i32).into())
}

/// Whether to use tabs (true) or spaces (false).
///
/// Default: `false`
pub fn use_tabs(&mut self, value: bool) -> &mut Self {
self.insert("useTabs", value.into())
}

/// The number of columns for an indent.
///
/// Default: `2`
pub fn indent_width(&mut self, value: u8) -> &mut Self {
self.insert("indentWidth", (value as i32).into())
}

/// The kind of newline to use.
/// Default: `NewLineKind::LineFeed`
pub fn new_line_kind(&mut self, value: NewLineKind) -> &mut Self {
Expand Down Expand Up @@ -91,15 +77,11 @@ mod tests {
#[test]
fn check_all_values_set() {
let mut config = ConfigurationBuilder::new();
config
.new_line_kind(NewLineKind::CarriageReturnLineFeed)
.line_width(90)
.use_tabs(true)
.indent_width(4);
config.new_line_kind(NewLineKind::CarriageReturnLineFeed).line_width(90);

let inner_config = config.get_inner_config();
assert_eq!(inner_config.len(), 4);
let diagnostics = resolve_config(inner_config, &resolve_global_config(HashMap::new()).config).diagnostics;
assert_eq!(inner_config.len(), 2);
let diagnostics = resolve_config(inner_config, &resolve_global_config(HashMap::new(), &Default::default()).config).diagnostics;
assert_eq!(diagnostics.len(), 0);
}

Expand All @@ -109,7 +91,7 @@ mod tests {
global_config.insert(String::from("lineWidth"), 90.into());
global_config.insert(String::from("newLineKind"), "crlf".into());
global_config.insert(String::from("useTabs"), true.into());
let global_config = resolve_global_config(global_config).config;
let global_config = resolve_global_config(global_config, &Default::default()).config;
let mut config_builder = ConfigurationBuilder::new();
let config = config_builder.global_config(global_config).build();
assert_eq!(config.line_width, 90);
Expand All @@ -118,10 +100,9 @@ mod tests {

#[test]
fn use_defaults_when_global_not_set() {
let global_config = resolve_global_config(HashMap::new()).config;
let global_config = resolve_global_config(HashMap::new(), &Default::default()).config;
let mut config_builder = ConfigurationBuilder::new();
let config = config_builder.global_config(global_config).build();
assert_eq!(config.indent_width, 2); // this is different
assert_eq!(config.new_line_kind == NewLineKind::LineFeed, true);
}
}
2 changes: 0 additions & 2 deletions src/configuration/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,5 @@ use serde::{Deserialize, Serialize};
#[serde(rename_all = "camelCase")]
pub struct Configuration {
pub line_width: u32,
pub use_tabs: bool,
pub indent_width: u8,
pub new_line_kind: NewLineKind,
}
13 changes: 3 additions & 10 deletions src/configuration/resolve_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ use dprint_core::configuration::*;
///
/// ```
/// use std::collections::HashMap;
/// use dprint_core::configuration::{resolve_global_config};
/// use dprint_plugin_dockerfile::configuration::{resolve_config};
/// use dprint_core::configuration::resolve_global_config;
/// use dprint_plugin_dockerfile::configuration::resolve_config;
///
/// let config_map = HashMap::new(); // get a collection of key value pairs from somewhere
/// let global_config_result = resolve_global_config(config_map);
/// let global_config_result = resolve_global_config(config_map, &Default::default());
///
/// // check global_config_result.diagnostics here...
///
Expand All @@ -34,13 +34,6 @@ pub fn resolve_config(config: ConfigKeyMap, global_config: &GlobalConfiguration)
global_config.line_width.unwrap_or(DEFAULT_GLOBAL_CONFIGURATION.line_width),
&mut diagnostics,
),
use_tabs: get_value(
&mut config,
"useTabs",
global_config.use_tabs.unwrap_or(DEFAULT_GLOBAL_CONFIGURATION.use_tabs),
&mut diagnostics,
),
indent_width: get_value(&mut config, "indentWidth", global_config.indent_width.unwrap_or(2), &mut diagnostics),
new_line_kind: get_value(
&mut config,
"newLineKind",
Expand Down
34 changes: 31 additions & 3 deletions src/format_text.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
use dockerfile_parser::Dockerfile;
use dprint_core::configuration::resolve_new_line_kind;
use dprint_core::formatting::PrintOptions;
use dprint_core::types::ErrBox;
use std::path::Path;

use crate::configuration::Configuration;
use crate::parser::parse_items;

pub fn format_text(_file_path: &Path, text: &str, _config: &Configuration) -> Result<String, ErrBox> {
// todo :)
Ok(text.to_string())
pub fn format_text(_file_path: &Path, text: &str, config: &Configuration) -> Result<String, ErrBox> {
let node = parse_node(text)?;

Ok(dprint_core::formatting::format(
|| parse_items(&node, text, config),
config_to_print_options(text, config),
))
}

#[cfg(feature = "tracing")]
pub fn trace_file(_file_path: &Path, text: &str, config: &Configuration) -> dprint_core::formatting::TracingResult {
let node = parse_node(text).unwrap();

dprint_core::formatting::trace_printing(|| parse_items(node, text, config), config_to_print_options(text, config))
}

fn parse_node(text: &str) -> Result<Dockerfile, ErrBox> {
Ok(Dockerfile::parse(text)?)
}

fn config_to_print_options(text: &str, config: &Configuration) -> PrintOptions {
PrintOptions {
indent_width: 1,
max_width: config.line_width,
use_tabs: false,
new_line_text: resolve_new_line_kind(text, config.new_line_kind),
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod configuration;
mod format_text;
mod parser;

pub use format_text::format_text;

Expand Down
22 changes: 22 additions & 0 deletions src/parser/context.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::collections::HashSet;

use super::helpers::Node;
use crate::configuration::Configuration;

pub struct Context<'a> {
pub config: &'a Configuration,
pub text: &'a str,
pub handled_comments: HashSet<usize>,
pub current_node: Option<Node<'a>>,
}

impl<'a> Context<'a> {
pub fn new(text: &'a str, config: &'a Configuration) -> Self {
Self {
config,
text,
handled_comments: HashSet::new(),
current_node: None,
}
}
}
119 changes: 119 additions & 0 deletions src/parser/helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use dockerfile_parser::*;

macro_rules! create_node_ref {
($($variant_name:ident($node_name:ident),)*) => {
#[derive(Clone, Copy)]
pub enum Node<'a> {
$(
$variant_name(&'a $node_name),
)*
}

$(
impl<'a> From<&'a $node_name> for Node<'a> {
fn from(instruction: &'a $node_name) -> Node<'a> {
Node::$variant_name(instruction)
}
}
)*
}
}

create_node_ref!(
Arg(ArgInstruction),
Cmd(CmdInstruction),
Copy(CopyInstruction),
CopyFlag(CopyFlag),
From(FromInstruction),
Label(LabelInstruction),
LabelLabel(Label),
Run(RunInstruction),
Entrypoint(EntrypointInstruction),
Env(EnvInstruction),
EnvVar(EnvVar),
Misc(MiscInstruction),
String(SpannedString),
BreakableString(BreakableString),
StringArray(StringArray),
Comment(Comment),
);

impl<'a> Node<'a> {
#[allow(dead_code)]
pub fn span(&self) -> Span {
use Node::*;
match self {
From(node) => node.span,
Arg(node) => node.span,
Label(node) => node.span,
LabelLabel(node) => node.span,
Run(node) => node.span,
Entrypoint(node) => node.span,
Cmd(node) => node.span,
Copy(node) => node.span,
CopyFlag(node) => node.span,
Env(node) => node.span,
EnvVar(node) => node.span,
Misc(node) => node.span,
String(node) => node.span,
BreakableString(node) => node.span,
StringArray(node) => node.span,
Comment(node) => node.span,
}
}
}

pub struct Comment {
pub span: Span,
pub text: String,
}

pub fn parse_comments(text: &str, offset: usize) -> Vec<Comment> {
let mut comments = Vec::new();
let mut char_iterator = text.char_indices();
let mut in_start_comment_context = true;

while let Some((i, c)) = char_iterator.next() {
// leading whitespace is supported but discouraged
if in_start_comment_context && c.is_whitespace() {
continue;
}

if in_start_comment_context && matches!(c, '#') {
let start_index = i;
let mut end_index = i;
while let Some((i, c)) = char_iterator.next() {
if c == '\n' {
break;
}
end_index = i + c.len_utf8();
}
comments.push(Comment {
span: Span::new(offset + start_index, offset + end_index),
text: text[start_index + 1..end_index].to_string(),
});
in_start_comment_context = true;
} else {
in_start_comment_context = false;
}
}

comments
}

impl<'a> From<&'a Instruction> for Node<'a> {
fn from(instruction: &'a Instruction) -> Node<'a> {
use Instruction::*;
match instruction {
From(node) => node.into(),
Arg(node) => node.into(),
Label(node) => node.into(),
Run(node) => node.into(),
Entrypoint(node) => node.into(),
Cmd(node) => node.into(),
Copy(node) => node.into(),
Env(node) => node.into(),
Misc(node) => node.into(),
}
}
}
5 changes: 5 additions & 0 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod context;
mod helpers;
mod parse;

pub use parse::*;
Loading

0 comments on commit 71484d3

Please sign in to comment.