<commit_before>package config

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
)

// Config struct which contains an array of banned imports and function calls
type Config struct {
	Imports   []BannedImport   `json:"imports"`
	Functions []BannedFunction `json:"functions"`
}

// BannedImport struct which contains a fully qualified import name,
// message with additional information and a list of exemptions.
type BannedImport struct {
	Name       string      `json:"name"`
	Msg        string      `json:"msg"`
	Exemptions []Exemption `json:"exemptions"`
}

// BannedFunction struct which contains a fully qualified function name,
// message with additional information and a list of exemptions.
type BannedFunction struct {
	Name       string      `json:"name"`
	Msg        string      `json:"msg"`
	Exemptions []Exemption `json:"exemptions"`
}

// Exemption struct which contains a justification and a path to allowed directory.
type Exemption struct {
	Justification string `json:"justification"`
	AllowedDir    string `json:"allowedDir"`
}

// Read reads configs from all files and concatenates them into one object.
func Read(files []string) (*Config, error) {
	imports := make([]BannedImport, 0)
	functions := make([]BannedFunction, 0)

	for _, file := range files {
		config, err := unmarshalCfg(file)
		if err != nil {
			return nil, err
		}

		imports = append(imports, config.Imports...)
		functions = append(functions, config.Functions...)
	}

	return &Config{Imports: imports, Functions: functions}, nil
}

// unmarshalCfg reads contents of one file and converts it to a Config struct.
func unmarshalCfg(file string) (*Config, error) {
	if !fileExists(file) {
		return nil, errors.New("file does not exist or is a directory")
	}

	cfg, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer cfg.Close()

	var config Config<commit_msg>Minor fix.<commit_after>package config

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"os"
)

// Config struct which contains an array of banned imports and function calls
type Config struct {
	Imports   []BannedImport   `json:"imports"`
	Functions []BannedFunction `json:"functions"`
}

// BannedImport struct which contains a fully qualified import name,
// message with additional information and a list of exemptions.
type BannedImport struct {
	Name       string      `json:"name"`
	Msg        string      `json:"msg"`
	Exemptions []Exemption `json:"exemptions"`
}

// BannedFunction struct which contains a fully qualified function name,
// message with additional information and a list of exemptions.
type BannedFunction struct {
	Name       string      `json:"name"`
	Msg        string      `json:"msg"`
	Exemptions []Exemption `json:"exemptions"`
}

// Exemption struct which contains a justification and a path to allowed directory.
type Exemption struct {
	Justification string `json:"justification"`
	AllowedDir    string `json:"allowedDir"`
}

// Read reads configs from all files and concatenates them into one object.
func Read(files []string) (*Config, error) {
	imports := make([]BannedImport, 0)
	functions := make([]BannedFunction, 0)

	for _, file := range files {
		config, err := unmarshalCfg(file)
		if err != nil {
			return nil, err
		}

		imports = append(imports, config.Imports...)
		functions = append(functions, config.Functions...)
	}

	return &Config{Imports: imports, Functions: functions}, nil
}

// unmarshalCfg reads JSON object from a file and converts it to a Config struct.
func unmarshalCfg(file string) (*Config, error) {
	if !fileExists(file) {
		return nil, errors.New("file does not exist or is a directory")
	}

	cfg, err := os.Open(file)
	if err != nil {
		return nil, err
	}
	defer cfg.Close()

	var config Config
{'fraction_non_alphanumeric': 0.10643431635388739, 'fraction_numerical': 0.0010723860589812334, 'mean_word_length': 3.870757180156658, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, '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': '639930', 'n_tokens_mistral': 1128, 'n_tokens_neox': 1071, 'n_words': 403}