<commit_before>package client

import (
	"fmt"
	"strings"

	"github.com/hashicorp/go-version"
	hcl "github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"
	"github.com/hashicorp/hcl/v2/json"
	"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
)

// Attribute is an intermediate representation of hcl.Attribute.
type Attribute struct {
	Name      string
	Expr      []byte
	ExprRange hcl.Range
	Range     hcl.Range
	NameRange hcl.Range
}

func decodeAttribute(attribute *Attribute) (*hcl.Attribute, hcl.Diagnostics) {
	expr, diags := parseExpression(attribute.Expr, attribute.ExprRange.Filename, attribute.ExprRange.Start)
	if diags.HasErrors() {
		return nil, diags
	}

	return &hcl.Attribute{
		Name:      attribute.Name,
		Expr:      expr,
		Range:     attribute.Range,
		NameRange: attribute.NameRange,
	}, nil
}

// Block is an intermediate representation of hcl.Block.
type Block struct {
	Type      string
	Labels    []string
	Body      []byte
	BodyRange hcl.Range

	DefRange    hcl.Range
	TypeRange   hcl.Range
	LabelRanges []hcl.Range
}

func decodeBlock(block *Block) (*hcl.Block, hcl.Diagnostics) {
	file, diags := parseConfig(block.Body, block.BodyRange.Filename, block.BodyRange.Start)
	if diags.HasErrors() {
		return nil, diags
	}

	return &hcl.Block{
		Type:        block.Type,
		Labels:      block.Labels,
		Body:        file.Body,
		DefRange:    block.DefRange,
		TypeRange:   block.TypeRange,
		LabelRanges: block.LabelRanges,
	}, nil
}

func parseExpression(src []byte, filename string, start hcl.Pos) (hcl.Expression, hcl.Diagnostics) {
	if strings.HasSuffix(filename, ".tf") {
		return hclsyntax.ParseExpression(src, filename, start)
	}

	if strings.HasSuffix(filename, ".tf.json") {
		return json.ParseExpressionWithStartPos(src, filename, start)
	}

	panic(fmt.Sprintf("Unexpected file: %s", filename))
}
<commit_msg>tflint: Add workaround for parsing heredoc expressions (#93)<commit_after>package client

import (
	"fmt"
	"strings"

	"github.com/hashicorp/go-version"
	hcl "github.com/hashicorp/hcl/v2"
	"github.com/hashicorp/hcl/v2/hclsyntax"
	"github.com/hashicorp/hcl/v2/json"
	"github.com/terraform-linters/tflint-plugin-sdk/terraform/configs"
)

// Attribute is an intermediate representation of hcl.Attribute.
type Attribute struct {
	Name      string
	Expr      []byte
	ExprRange hcl.Range
	Range     hcl.Range
	NameRange hcl.Range
}

func decodeAttribute(attribute *Attribute) (*hcl.Attribute, hcl.Diagnostics) {
	expr, diags := parseExpression(attribute.Expr, attribute.ExprRange.Filename, attribute.ExprRange.Start)
	if diags.HasErrors() {
		return nil, diags
	}

	return &hcl.Attribute{
		Name:      attribute.Name,
		Expr:      expr,
		Range:     attribute.Range,
		NameRange: attribute.NameRange,
	}, nil
}

// Block is an intermediate representation of hcl.Block.
type Block struct {
	Type      string
	Labels    []string
	Body      []byte
	BodyRange hcl.Range

	DefRange    hcl.Range
	TypeRange   hcl.Range
	LabelRanges []hcl.Range
}

func decodeBlock(block *Block) (*hcl.Block, hcl.Diagnostics) {
	file, diags := parseConfig(block.Body, block.BodyRange.Filename, block.BodyRange.Start)
	if diags.HasErrors() {
		return nil, diags
	}

	return &hcl.Block{
		Type:        block.Type,
		Labels:      block.Labels,
		Body:        file.Body,
		DefRange:    block.DefRange,
		TypeRange:   block.TypeRange,
		LabelRanges: block.LabelRanges,
	}, nil
}

func parseExpression(src []byte, filename string, start hcl.Pos) (hcl.Expression, hcl.Diagnostics) {
	if strings.HasSuffix(filename, ".tf") {
		// HACK: Always add a newline to avoid heredoc parse errors.
		// @see https://github.com/hashicorp/hcl/issues/441
		src = []byte(string(src) + "\n")
		return hclsyntax.ParseExpression(src, filename, start)
	}

	if strings.HasSuffix(filename, ".tf.json") {
		return json.ParseExpressionWithStartPos(src, filename, start)
	}

	panic(fmt.Sprintf("Unexpected file: %s", filename))
}

{'fraction_non_alphanumeric': 0.12033511043412033, 'fraction_numerical': 0.0027925869510027927, 'mean_word_length': 3.8048780487804876, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7213846', 'n_tokens_mistral': 1411, 'n_tokens_neox': 1364, 'n_words': 298}