Repository: terraform-docs/terraform-docs (go)

Issue:
Using heredoc with CRLF encoding breaks markdown output
<!-- Please note, this template is for bugs report, not feature requests -->
<!-- For more information, see the Contributing Guidelines at -->
<!-- https://github.com/terraform-docs/terraform-docs/tree/master/CONTRIBUTING.md -->

**Describe the bug**

Using multi-line strings (heredoc) with Windows line encoding (CRLF) breaks markdown output.

**To Reproduce**

Steps to reproduce the behavior:

1. Create `main.tf` and save it with Windows line encoding (CRLF)

```hcl
variable "myvar" {
    type = string
    description = <<-EOT
    The quick brown fox jumps
    over the lazy dog
    EOT
}
```

2. `terraform-docs --no-outputs --no-requirements --no-providers md .`


```
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
<br>over the lazy dog | `string` | n/a | yes |
```

**Expected behavior**

The markdown output should contain the full description

```
## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| myvar | The quick brown fox jumps<br>over the lazy dog | `string` | n/a | yes |
```

**Version information:**

- terraform-docs version: `v0.0.0- v0.9.1 darwin/amd64 BuildDate: 2020-04-02T23:00:25+0100`
- OS: `MacOS`

**Additional context**

Saving the `main.tf` file with UNIX line encoding (LF) creates the desired markdown.


Pull request:
Normalize variables with CRLF line ending in heredoc
### Prerequisites

Put an `x` into the box(es) that apply:

- [x] This pull request fixes a bug.
- [ ] This pull request adds a feature.
- [ ] This pull request enhances existing functionality.
- [ ] This pull request introduces breaking change.

For more information, see the [Contributing Guide](https://github.com/terraform-docs/terraform-docs/tree/master/CONTRIBUTING.md).

### Description

This PR normalizes input variables which has CRLF as line ending in multi-line heredoc style description. It will convert them internally to LF early on and continue parsing and rendering them as usual.

### Issues Resolved

Fixes #305 

### Checklist

Put an `x` into all boxes that apply:

- [ ] I have read the [Contributing Guidelines](https://github.com/terraform-docs/terraform-docs/tree/master/CONTRIBUTING.md).

#### Tests

- [x] I have added tests to cover my changes.
- [ ] All tests pass when I run `make test`.

#### Documentation

- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.

#### Code Style

- [ ] My code follows the code style of this project.


Patch:
diff --git a/.editorconfig b/.editorconfig
index 8cb8f1f..aec6e8b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -30,5 +30,8 @@ indent_size = 2
 [*.tf]
 trim_trailing_whitespace = false
 
+[**/inputs-crlf/variables.tf]
+end_of_line = crlf
+
 [Makefile]
 indent_style = tab
diff --git a/internal/module/module.go b/internal/module/module.go
index 8b317c5..b81bfbe 100644
--- a/internal/module/module.go
+++ b/internal/module/module.go
@@ -139,7 +139,8 @@ func loadInputs(tfmodule *tfconfig.Module) ([]*tfconf.Input, []*tfconf.Input, []
 	var optional = make([]*tfconf.Input, 0, len(tfmodule.Variables))
 
 	for _, input := range tfmodule.Variables {
-		inputDescription := input.Description
+		// convert CRLF to LF early on (https://github.com/terraform-docs/terraform-docs/issues/305)
+		inputDescription := strings.Replace(input.Description, "\r\n", "\n", -1)
 		if inputDescription == "" {
 			inputDescription = loadComments(input.Pos.Filename, input.Pos.Line)
 		}


Test patch:
diff --git a/internal/module/module_test.go b/internal/module/module_test.go
index 5d1e534..5d39b99 100644
--- a/internal/module/module_test.go
+++ b/internal/module/module_test.go
@@ -340,6 +340,35 @@ func TestLoadInputs(t *testing.T) {
 	}
 }
 
+func TestLoadInputsLineEnding(t *testing.T) {
+	tests := []struct {
+		name     string
+		path     string
+		expected string
+	}{
+		{
+			name:     "load module inputs from file with lf line ending",
+			path:     "inputs-lf",
+			expected: "The quick brown fox jumps\nover the lazy dog\n",
+		},
+		{
+			name:     "load module inputs from file with crlf line ending",
+			path:     "inputs-crlf",
+			expected: "The quick brown fox jumps\nover the lazy dog\n",
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			assert := assert.New(t)
+			module, _ := loadModule(filepath.Join("testdata", tt.path))
+			inputs, _, _ := loadInputs(module)
+
+			assert.Equal(1, len(inputs))
+			assert.Equal(tt.expected, string(inputs[0].Description))
+		})
+	}
+}
+
 func TestLoadOutputs(t *testing.T) {
 	type expected struct {
 		outputs int
diff --git a/internal/module/testdata/inputs-crlf/variables.tf b/internal/module/testdata/inputs-crlf/variables.tf
new file mode 100644
index 0000000..2333cc8
--- /dev/null
+++ b/internal/module/testdata/inputs-crlf/variables.tf
@@ -0,0 +1,7 @@
+variable "multi-line-lf" {
+  type = string
+  description = <<-EOT
+  The quick brown fox jumps
+  over the lazy dog
+  EOT
+}
diff --git a/internal/module/testdata/inputs-lf/variables.tf b/internal/module/testdata/inputs-lf/variables.tf
new file mode 100644
index 0000000..b2cbf52
--- /dev/null
+++ b/internal/module/testdata/inputs-lf/variables.tf
@@ -0,0 +1,7 @@
+variable "multi-line-crlf" {
+  type = string
+  description = <<-EOT
+  The quick brown fox jumps
+  over the lazy dog
+  EOT
+}