update whole structure : each syntax feature implements now the 'internal/transform/Transformer' interface ; to apply all transforms on the same input text, use a 'internal/transform/Registry' that dispatches errors | update all transformers' code to the new structure | still pass tests
This commit is contained in:
parent
e553670836
commit
7ee7710e74
33
clifmt.go
33
clifmt.go
|
@ -3,8 +3,12 @@ package clifmt
|
|||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/go/clifmt/internal/color"
|
||||
colorTransform "git.xdrm.io/go/clifmt/internal/transform/color"
|
||||
mdTransform "git.xdrm.io/go/clifmt/internal/transform/markdown"
|
||||
tbold "git.xdrm.io/go/clifmt/internal/syntax/bold"
|
||||
tcolor "git.xdrm.io/go/clifmt/internal/syntax/color"
|
||||
thyperlink "git.xdrm.io/go/clifmt/internal/syntax/hyperlink"
|
||||
titalic "git.xdrm.io/go/clifmt/internal/syntax/italic"
|
||||
tunderline "git.xdrm.io/go/clifmt/internal/syntax/underline"
|
||||
"git.xdrm.io/go/clifmt/internal/transform"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
@ -28,26 +32,27 @@ func Sprintf(format string, a ...interface{}) (string, error) {
|
|||
formatted = strings.Replace(formatted, "\\_", underscoreToken, -1)
|
||||
formatted = strings.Replace(formatted, "\\[", squareBracketToken, -1)
|
||||
|
||||
// 3. Colorize
|
||||
colorized, err := colorTransform.Transform(formatted, theme)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 3. create transformation registry
|
||||
reg := transform.Registry{Transformers: make([]transform.Transformer, 0, 10)}
|
||||
reg.Transformers = append(reg.Transformers, tcolor.Export)
|
||||
reg.Transformers = append(reg.Transformers, tbold.Export)
|
||||
reg.Transformers = append(reg.Transformers, titalic.Export)
|
||||
reg.Transformers = append(reg.Transformers, tunderline.Export)
|
||||
reg.Transformers = append(reg.Transformers, thyperlink.Export)
|
||||
|
||||
// 4. Markdown format
|
||||
markdown, err := mdTransform.Transform(colorized)
|
||||
transformed, err := reg.Transform(formatted)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 5. Restore token-protected characters
|
||||
markdown = strings.Replace(markdown, dollarToken, "$", -1)
|
||||
markdown = strings.Replace(markdown, asteriskToken, "*", -1)
|
||||
markdown = strings.Replace(markdown, underscoreToken, "_", -1)
|
||||
markdown = strings.Replace(markdown, squareBracketToken, "[", -1)
|
||||
transformed = strings.Replace(transformed, dollarToken, "$", -1)
|
||||
transformed = strings.Replace(transformed, asteriskToken, "*", -1)
|
||||
transformed = strings.Replace(transformed, underscoreToken, "_", -1)
|
||||
transformed = strings.Replace(transformed, squareBracketToken, "[", -1)
|
||||
|
||||
// 6. return final output
|
||||
return markdown, nil
|
||||
return transformed, nil
|
||||
}
|
||||
|
||||
// Printf prints a terminal-colorized output following the coloring format
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package bold
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type export string
|
||||
|
||||
var Export = export("bold")
|
||||
|
||||
func (syn export) Regex() *regexp.Regexp {
|
||||
return regexp.MustCompile(`(?m)\*\*((?:[^\*]+\*?)+)\*\*`)
|
||||
}
|
||||
|
||||
func (syn export) Transform(args ...string) (string, error) {
|
||||
// no arg, empty -> ignore
|
||||
if len(args) < 1 || len(args[0]) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\x1b[1m%s\x1b[22m", strings.Replace(args[0], "\x1b[0m", "\x1b[0m\x1b[1m", -1)), nil
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/go/clifmt/internal/color"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var theme = color.DefaultTheme()
|
||||
|
||||
type export string
|
||||
|
||||
var Export = export("color")
|
||||
|
||||
func (syn export) Regex() *regexp.Regexp {
|
||||
return regexp.MustCompile(`(?m)\${([^$]+)}\(((?:[a-z]+|#(?:[0-9a-f]{3}|[0-9a-f]{6})))?(?:\:((?:[a-z]+|#(?:[0-9a-f]{3}|[0-9a-f]{6}))))?\)`)
|
||||
}
|
||||
|
||||
func (syn export) Transform(args ...string) (string, error) {
|
||||
// no arg, no color -> error
|
||||
if len(args) < 3 {
|
||||
return "", fmt.Errorf("invalid format")
|
||||
}
|
||||
|
||||
// extract colors
|
||||
var (
|
||||
fg *color.T = nil
|
||||
bg *color.T = nil
|
||||
)
|
||||
|
||||
if len(args[1]) > 0 {
|
||||
tmp, err := color.Parse(theme, args[1])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fg = &tmp
|
||||
}
|
||||
if len(args[2]) > 0 {
|
||||
tmp, err := color.Parse(theme, args[2])
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bg = &tmp
|
||||
}
|
||||
|
||||
return colorize(args[0], fg, bg), nil
|
||||
|
||||
}
|
||||
|
||||
// colorize returns the terminal-formatted @text colorized with the @fg and @bg colors
|
||||
func colorize(t string, fg *color.T, bg *color.T) string {
|
||||
// no coloring
|
||||
if fg == nil && bg == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
// only foreground
|
||||
if bg == nil {
|
||||
return fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", fg.Red(), fg.Green(), fg.Blue(), t)
|
||||
}
|
||||
// only background
|
||||
if fg == nil {
|
||||
return fmt.Sprintf("\x1b[48;2;%d;%d;%dm%s\x1b[0m", bg.Red(), bg.Green(), bg.Blue(), t)
|
||||
}
|
||||
|
||||
// both colors
|
||||
return fmt.Sprintf("\x1b[38;2;%d;%d;%d;48;2;%d;%d;%dm%s\x1b[0m", fg.Red(), fg.Green(), fg.Blue(), bg.Red(), bg.Green(), bg.Blue(), t)
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package hyperlink
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type export string
|
||||
|
||||
var Export = export("hyperlink")
|
||||
|
||||
func (syn export) Regex() *regexp.Regexp {
|
||||
return regexp.MustCompile(`(?m)\[([^\[]+)\]\(([^\)]+)\)`)
|
||||
}
|
||||
|
||||
func (syn export) Transform(args ...string) (string, error) {
|
||||
// no arg, empty -> ignore
|
||||
if len(args) < 2 || len(args[0]) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\", args[1], args[0]), nil
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package italic
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type export string
|
||||
|
||||
var Export = export("italic")
|
||||
|
||||
func (syn export) Regex() *regexp.Regexp {
|
||||
return regexp.MustCompile(`(?m)\*([^\*]+)\*`)
|
||||
}
|
||||
|
||||
func (syn export) Transform(args ...string) (string, error) {
|
||||
// no arg, empty -> ignore
|
||||
if len(args) < 1 || len(args[0]) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\x1b[3m%s\x1b[23m", strings.Replace(args[0], "\x1b[0m", "\x1b[0m\x1b[3m", -1)), nil
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package underline
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type export string
|
||||
|
||||
var Export = export("underline")
|
||||
|
||||
func (syn export) Regex() *regexp.Regexp {
|
||||
return regexp.MustCompile(`(?m)_([^_]+)_`)
|
||||
}
|
||||
|
||||
func (syn export) Transform(args ...string) (string, error) {
|
||||
// no arg, empty -> ignore
|
||||
if len(args) < 1 || len(args[0]) < 1 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return fmt.Sprintf("\x1b[4m%s\x1b[24m", strings.Replace(args[0], "\x1b[0m", "\x1b[0m\x1b[4m", -1)), nil
|
||||
}
|
|
@ -1,92 +0,0 @@
|
|||
package color
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.xdrm.io/go/clifmt/internal/color"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// extractor helps extract features from the coloring format defined as follows :
|
||||
//
|
||||
// - [Color] -> [a-z] # named color
|
||||
// - [Color] -> #[0-9a-f]{3} # hexa color (shortcode)
|
||||
// - [Color] -> #[0-9a-f]{6} # hexa color (full-sized)
|
||||
// - [Text] -> ANY
|
||||
// - [Format] -> ${Text}(Color:Color) # foreground, background colors
|
||||
// - [Format] -> ${Text}(Color) # foreground color only
|
||||
// - [Format] -> ${Text}(:Color) # background color only
|
||||
var extractor = regexp.MustCompile(`(?m)\${([^$]+)}\(((?:[a-z]+|#(?:[0-9a-f]{3}|[0-9a-f]{6})))?(?:\:((?:[a-z]+|#(?:[0-9a-f]{3}|[0-9a-f]{6}))))?\)`)
|
||||
|
||||
// colorize returns the terminal-formatted @text colorized with the @fg and @bg colors
|
||||
func colorize(t string, fg *color.T, bg *color.T) string {
|
||||
// no coloring
|
||||
if fg == nil && bg == nil {
|
||||
return t
|
||||
}
|
||||
|
||||
// only foreground
|
||||
if bg == nil {
|
||||
return fmt.Sprintf("\x1b[38;2;%d;%d;%dm%s\x1b[0m", fg.Red(), fg.Green(), fg.Blue(), t)
|
||||
}
|
||||
// only background
|
||||
if fg == nil {
|
||||
return fmt.Sprintf("\x1b[48;2;%d;%d;%dm%s\x1b[0m", bg.Red(), bg.Green(), bg.Blue(), t)
|
||||
}
|
||||
|
||||
// both colors
|
||||
return fmt.Sprintf("\x1b[38;2;%d;%d;%d;48;2;%d;%d;%dm%s\x1b[0m", fg.Red(), fg.Green(), fg.Blue(), bg.Red(), bg.Green(), bg.Blue(), t)
|
||||
}
|
||||
|
||||
// Transform the @input text colorized according to the @extractor format
|
||||
func Transform(input string, theme color.Theme) (string, error) {
|
||||
output := ""
|
||||
cursor := int(0)
|
||||
|
||||
// 1. Replace for each match
|
||||
for _, match := range extractor.FindAllStringSubmatchIndex(input, -1) {
|
||||
|
||||
// (1) add gap between input start OR previous match
|
||||
output += input[cursor:match[0]]
|
||||
cursor = match[1]
|
||||
|
||||
// (2) extract features
|
||||
var (
|
||||
text = ""
|
||||
sFg = ""
|
||||
sBg = ""
|
||||
fg *color.T = nil
|
||||
bg *color.T = nil
|
||||
)
|
||||
|
||||
if match[3]-match[2] > 0 {
|
||||
text = input[match[2]:match[3]]
|
||||
}
|
||||
if match[5]-match[4] > 0 {
|
||||
sFg = input[match[4]:match[5]]
|
||||
fgv, err := color.Parse(theme, sFg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fg = &fgv
|
||||
}
|
||||
if match[7]-match[6] > 0 {
|
||||
sBg = input[match[6]:match[7]]
|
||||
bgv, err := color.Parse(theme, sBg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bg = &bgv
|
||||
}
|
||||
|
||||
// (3) replace text with colorized text
|
||||
output += colorize(text, fg, bg)
|
||||
}
|
||||
|
||||
// 2. Add end of input
|
||||
if cursor < len(input) {
|
||||
output += input[cursor:]
|
||||
}
|
||||
|
||||
// 3. print final output
|
||||
return output, nil
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package transform
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type TransformerError struct {
|
||||
// Transformer that returned the error
|
||||
Transformer Transformer
|
||||
|
||||
// Err is the actual error
|
||||
Err error
|
||||
|
||||
// Input is the input string to be transformed
|
||||
Input string
|
||||
}
|
||||
|
||||
func (err *TransformerError) Error() string {
|
||||
return fmt.Sprintf("Transformer <%T> failed on input '%s': %s",
|
||||
err.Transformer,
|
||||
err.Input,
|
||||
err.Err)
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package markdown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var boldRe = regexp.MustCompile(`(?m)\*\*((?:[^\*]+\*?)+)\*\*`)
|
||||
|
||||
// boldify returns the terminal-formatted bold text @t
|
||||
func boldify(t string) string {
|
||||
return fmt.Sprintf("\x1b[1m%s\x1b[22m", strings.Replace(t, "\x1b[0m", "\x1b[0m\x1b[1m", -1))
|
||||
}
|
||||
|
||||
// boldTransform the @input text using markdown-like syntax :
|
||||
// - "normal **bold** normal"
|
||||
func boldTransform(input string) (string, error) {
|
||||
output := ""
|
||||
cursor := int(0)
|
||||
|
||||
// 1. Replace for each match
|
||||
for _, match := range boldRe.FindAllStringSubmatchIndex(input, -1) {
|
||||
|
||||
// (1) add gap between input start OR previous match
|
||||
output += input[cursor:match[0]]
|
||||
cursor = match[1]
|
||||
|
||||
// (2) extract features
|
||||
text := ""
|
||||
|
||||
if match[3]-match[2] > 0 {
|
||||
text = input[match[2]:match[3]]
|
||||
}
|
||||
|
||||
// (3) replace text with bold text
|
||||
output += boldify(text)
|
||||
}
|
||||
|
||||
// 2. Add end of input
|
||||
if cursor < len(input) {
|
||||
output += input[cursor:]
|
||||
}
|
||||
|
||||
// 3. print final output
|
||||
return output, nil
|
||||
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package markdown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var hyperlinkRe = regexp.MustCompile(`(?m)\[([^\[]+)\]\(([^\)]+)\)`)
|
||||
|
||||
// linkify returns the terminal-formatted hyperlink for @url with the text : @label
|
||||
func linkify(url, label string) string {
|
||||
return fmt.Sprintf("\x1b]8;;%s\x1b\\%s\x1b]8;;\x1b\\", url, label)
|
||||
}
|
||||
|
||||
// hyperlinkTransform the @input text using markdown-like syntax :
|
||||
// - "normal [link label](link url) normal"
|
||||
func hyperlinkTransform(input string) (string, error) {
|
||||
output := ""
|
||||
cursor := int(0)
|
||||
|
||||
// 1. Replace for each match
|
||||
for _, match := range hyperlinkRe.FindAllStringSubmatchIndex(input, -1) {
|
||||
|
||||
// (1) add gap between input start OR previous match
|
||||
output += input[cursor:match[0]]
|
||||
cursor = match[1]
|
||||
|
||||
// (2) extract features
|
||||
var label, url string
|
||||
|
||||
if match[3]-match[2] > 0 {
|
||||
label = input[match[2]:match[3]]
|
||||
}
|
||||
if match[5]-match[4] > 0 {
|
||||
url = input[match[4]:match[5]]
|
||||
}
|
||||
|
||||
// (3) replace with hyperlink
|
||||
output += linkify(url, label)
|
||||
}
|
||||
|
||||
// 2. Add end of input
|
||||
if cursor < len(input) {
|
||||
output += input[cursor:]
|
||||
}
|
||||
|
||||
// 3. print final output
|
||||
return output, nil
|
||||
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package markdown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var italicRe = regexp.MustCompile(`(?m)\*([^\*]+)\*`)
|
||||
|
||||
// italic returns the terminal-formatted italic text @t
|
||||
func italic(t string) string {
|
||||
return fmt.Sprintf("\x1b[3m%s\x1b[23m", strings.Replace(t, "\x1b[0m", "\x1b[0m\x1b[3m", -1))
|
||||
}
|
||||
|
||||
// italicTransform the @input text using markdown-like syntax :
|
||||
// - "normal *italic* normal"
|
||||
func italicTransform(input string) (string, error) {
|
||||
output := ""
|
||||
cursor := int(0)
|
||||
|
||||
// 1. Replace for each match
|
||||
for _, match := range italicRe.FindAllStringSubmatchIndex(input, -1) {
|
||||
|
||||
// (1) add gap between input start OR previous match
|
||||
output += input[cursor:match[0]]
|
||||
cursor = match[1]
|
||||
|
||||
// (2) extract features
|
||||
text := ""
|
||||
|
||||
if match[3]-match[2] > 0 {
|
||||
text = input[match[2]:match[3]]
|
||||
}
|
||||
|
||||
// (3) replace text with bold text
|
||||
output += italic(text)
|
||||
}
|
||||
|
||||
// 2. Add end of input
|
||||
if cursor < len(input) {
|
||||
output += input[cursor:]
|
||||
}
|
||||
|
||||
// 3. print final output
|
||||
return output, nil
|
||||
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package markdown
|
||||
|
||||
func Transform(input string) (string, error) {
|
||||
|
||||
// 1. bold
|
||||
bold, err := boldTransform(input)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 2. italic
|
||||
italic, err := italicTransform(bold)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 3. underline
|
||||
underline, err := underlineTransform(italic)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 4. hyperlink
|
||||
hyperlinked, err := hyperlinkTransform(underline)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return hyperlinked, nil
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
package markdown
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var underlineRe = regexp.MustCompile(`(?m)_([^_]+)_`)
|
||||
|
||||
// underline returns the terminal-formatted underline text @t
|
||||
func underline(t string) string {
|
||||
return fmt.Sprintf("\x1b[4m%s\x1b[24m", strings.Replace(t, "\x1b[0m", "\x1b[0m\x1b[4m", -1))
|
||||
}
|
||||
|
||||
// underlineTransform the @input text using markdown-like syntax :
|
||||
// - "normal _underline_ normal"
|
||||
func underlineTransform(input string) (string, error) {
|
||||
output := ""
|
||||
cursor := int(0)
|
||||
|
||||
// 1. Replace for each match
|
||||
for _, match := range underlineRe.FindAllStringSubmatchIndex(input, -1) {
|
||||
|
||||
// (1) add gap between input start OR previous match
|
||||
output += input[cursor:match[0]]
|
||||
cursor = match[1]
|
||||
|
||||
// (2) extract features
|
||||
text := ""
|
||||
|
||||
if match[3]-match[2] > 0 {
|
||||
text = input[match[2]:match[3]]
|
||||
}
|
||||
|
||||
// (3) replace text with bold text
|
||||
output += underline(text)
|
||||
}
|
||||
|
||||
// 2. Add end of input
|
||||
if cursor < len(input) {
|
||||
output += input[cursor:]
|
||||
}
|
||||
|
||||
// 3. print final output
|
||||
return output, nil
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
package transform
|
||||
|
||||
// Registry is used to apply a stack of transformations
|
||||
// over an input string
|
||||
type Registry struct {
|
||||
// cursor is the current transformer
|
||||
cursor uint
|
||||
// Transformers represents the transformer stack
|
||||
// ; each one will be executed in ascending order
|
||||
Transformers []Transformer
|
||||
}
|
||||
|
||||
// Transform executes each transformer of the stack in ascending order feeding
|
||||
// each one with the output of its predecessor (@input for the first). Note that if one returns an error
|
||||
// the process stops here and the error is directly returned.
|
||||
func (r *Registry) Transform(input string) (string, error) {
|
||||
in := input
|
||||
|
||||
// execute each transformer by order
|
||||
for _, t := range r.Transformers {
|
||||
|
||||
// 1. execute ; dispatch error on failure
|
||||
out, err := execute(t, in)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// 2. replace next input with current output
|
||||
in = out
|
||||
}
|
||||
|
||||
return in, nil
|
||||
}
|
||||
|
||||
// execute 1 given transformer @t with its @input string and returns the output,
|
||||
// and the error if one.
|
||||
func execute(t Transformer, input string) (string, error) {
|
||||
var (
|
||||
output string
|
||||
cursor int
|
||||
)
|
||||
|
||||
// apply transformatione for each match
|
||||
for _, match := range t.Regex().FindAllStringSubmatchIndex(input, -1) {
|
||||
|
||||
// (1) append gap between input start OR previous match
|
||||
output += input[cursor:match[0]]
|
||||
cursor = match[1]
|
||||
|
||||
// (2) build transformation arguments
|
||||
args := make([]string, 0, len(match)/2+1)
|
||||
for i, l := 2, len(match); i < l; i += 2 {
|
||||
// match exists (not both -1, nor negative length)
|
||||
if match[i+1]-match[i] > 0 {
|
||||
args = append(args, input[match[i]:match[i+1]])
|
||||
continue
|
||||
}
|
||||
args = append(args, "")
|
||||
}
|
||||
|
||||
// (3) execute transformation
|
||||
transformed, err := t.Transform(args...)
|
||||
if err != nil {
|
||||
return "", &TransformerError{t, err, input[match[0]:match[1]]}
|
||||
}
|
||||
|
||||
// (4) apply transformation
|
||||
output += transformed
|
||||
|
||||
}
|
||||
|
||||
// Add end of input (if not covered by matches)
|
||||
if cursor < len(input) {
|
||||
output += input[cursor:]
|
||||
}
|
||||
|
||||
// return final output
|
||||
return output, nil
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package transform
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type Transformer interface {
|
||||
// Regex returns the regex matching text to replace
|
||||
Regex() *regexp.Regexp
|
||||
|
||||
// Transform is called to replace a match by its transformation
|
||||
// ; it takes as arguments the matched string chunks from the Regex()
|
||||
Transform(...string) (string, error)
|
||||
}
|
Loading…
Reference in New Issue