<commit_before>/*
Package minify is a minifier written in Go that has built-in HTML, CSS and JS minifiers.

Usage example:

	package main

	import (
		"fmt"
		"os"
		"os/exec"

		"github.com/tdewolff/minify"
		"github.com/tdewolff/minify/html"
		"github.com/tdewolff/minify/css"
		"github.com/tdewolff/minify/js"
	)

	// Minifies HTML from stdin to stdout.
	// Note that reading the file into a buffer first and writing to a buffer would be faster.
	func main() {
		m := minify.New()
		m.AddFunc("text/html", html.Minify)
		m.AddFunc("text/css", css.Minify)
		m.AddFunc("text/javascript", js.Minify)
		// Or use an external tool:
		// m.AddCmd("text/javascript", exec.Command("java", "-jar", "build/compiler.jar"))

		if err := m.Minify("text/html", os.Stdout, os.Stdin); err != nil {
			fmt.Println("minify.Minify:", err)
		}
	}

*/
package minify // import "github.com/tdewolff/minify"

import (
	"errors"
	"io"
	"os/exec"
	"regexp"

	"github.com/tdewolff/buffer"
)

// ErrNotExist is returned when no minifier exists for a given mediatype.
var ErrNotExist = errors.New("minify function does not exist for mediatype")

////////////////////////////////////////////////////////////////

// Func is the function interface for minifiers.
// The Minifier parameter is used for embedded resources, such as JS within HTML.
// The mediatype string is for wildcard minifiers so they know what they minify and for parameter passing (charset for example).
type Func func(m Minifier, mediatype string, w io.Writer, r io.Reader) error

// Minifier is the interface which all minifier functions accept as first parameter.
// It's used to extract parameter values of the mediatype and to recursively call other minifier functions.
type Minifier interface {
	Minify(mediatype string, w io.Writer, r io.Reader) error
}

func cmdFunc(origCmd *exec.Cmd) func(_ Minifier, _ string, w io.Writer, r io.Reader) error {
	return func(_ Minifier, _ string, w io.Writer, r io.Reader) error {
		cmd := &exec.Cmd{}
		*cmd = *origCmd // concurrency safe
		cmd.Stdout = w
		cmd.Stdin = r
		return cmd.Run()
	}
}

////////////////////////////////////////////////////////////////

type regexpFunc struct {
	re *regexp.Regexp
	Func
}

// Minify holds a map of mediatype => function to allow recursive minifier calls of the minifier functions.
type Minify struct {
	literal map[string]Func
	regexp  []regexpFunc
}

// New returns a new Minify. It is the same as doing `Minify{}`.
func New() *Minify {
	return &Minify{
		map[string]Func{},
		[]regexpFunc{},
	}
}

// AddFunc adds a minify function to the mediatype => function map (unsafe for concurrent use).
// It allows one to implement a custom minifier for a specific mediatype.
func (m *Minify) AddFunc(mediatype string, minifyFunc Func) {
	m.literal[mediatype] = minifyFunc
}

// AddFuncRegexp adds a minify function to the mediatype => function map (unsafe for concurrent use).
// It allows one to implement a custom minifier for a specific mediatype regular expression.
func (m *Minify) AddFuncRegexp(mediatype *regexp.Regexp, minifyFunc Func) {
	m.regexp = append(m.regexp, regexpFunc{mediatype, minifyFunc})
}

// AddCmd adds a minify function to the mediatype => function map (unsafe for concurrent use) that executes a command to process the minification.
// It allows the use of external tools like ClosureCompiler, UglifyCSS, etc. for a specific mediatype.
// Be aware that running external tools will slow down minification a lot!<commit_msg>Commentary changes<commit_after>// Package minify is a minifier written in Go that can attach minification functions to MIME types. Several minifiers are provided in subpackages.
package minify // import "github.com/tdewolff/minify"

import (
	"errors"
	"io"
	"os/exec"
	"regexp"

	"github.com/tdewolff/buffer"
)

// ErrNotExist is returned when no minifier exists for a given mediatype.
var ErrNotExist = errors.New("minify function does not exist for mediatype")

////////////////////////////////////////////////////////////////

// Func is the function interface for minifiers.
// The Minifier parameter is used for embedded resources, such as JS within HTML.
// The mediatype string is for wildcard minifiers so they know what they minify and for parameter passing (charset for example).
type Func func(m Minifier, mediatype string, w io.Writer, r io.Reader) error

// Minifier is the interface which all minifier functions accept as first parameter.
// It's used to extract parameter values of the mediatype and to recursively call other minifier functions.
type Minifier interface {
	Minify(mediatype string, w io.Writer, r io.Reader) error
}

////////////////////////////////////////////////////////////////

type regexpFunc struct {
	re *regexp.Regexp
	Func
}

func cmdFunc(origCmd *exec.Cmd) func(_ Minifier, _ string, w io.Writer, r io.Reader) error {
	return func(_ Minifier, _ string, w io.Writer, r io.Reader) error {
		cmd := &exec.Cmd{}
		*cmd = *origCmd // concurrency safety
		cmd.Stdout = w
		cmd.Stdin = r
		return cmd.Run()
	}
}

////////////////////////////////////////////////////////////////

// Minify holds a map of mediatype => function to allow recursive minifier calls of the minifier functions.
type Minify struct {
	literal map[string]Func
	regexp  []regexpFunc
}

// New returns a new Minify. It is the same as doing `Minify{}`.
func New() *Minify {
	return &Minify{
		map[string]Func{},
		[]regexpFunc{},
	}
}

// AddFunc adds a minify function to the mediatype => function map (unsafe for concurrent use).
// It allows one to implement a custom minifier for a specific mediatype.
func (m *Minify) AddFunc(mediatype string, minifyFunc Func) {
	m.literal[mediatype] = minifyFunc
}

// AddFuncRegexp adds a minify function to the mediatype => function map (unsafe for concurrent use).
// It allows one to implement a custom minifier for a specific mediatype regular expression.
func (m *Minify) AddFuncRegexp(mediatype *regexp.Regexp, minifyFunc Func) {
	m.regexp = append(m.regexp, regexpFunc{mediatype, minifyFunc})
}

// AddCmd adds a minify function to the mediatype => function map (unsafe for concurrent use) that executes a command to process the minification.
// It allows the use of external tools like ClosureCompiler, UglifyCSS, etc. for a specific mediatype.
// Be aware that running external tools will slow down minification a lot!
{'fraction_non_alphanumeric': 0.13986454559773193, 'fraction_numerical': 0.0, 'mean_word_length': 3.150326797385621, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, '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': '6755895', 'n_tokens_mistral': 1951, 'n_tokens_neox': 1890, 'n_words': 747}