1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190
|
package converter
import (
"context"
"fmt"
"github.com/JohannesKaufmann/dom"
"golang.org/x/net/html"
)
// func GetValue[K string, V any](ctx context.Context, key K) V {
// val, _ := ctx.Value(key).(V)
// return val
// }
// func SetValue[K string, V any](ctx context.Context, key K, val V) context.Context {
// return context.WithValue(ctx, key, val)
// }
type ctxKey string
const (
ctxKeyAssembleAbsoluteURL ctxKey = "AssembleAbsoluteURL"
ctxKeyDomain ctxKey = "Domain"
ctxKeySetState ctxKey = "SetState"
ctxKeyUpdateState ctxKey = "UpdateState"
ctxKeyGetState ctxKey = "GetState"
)
func provideDomain(ctx context.Context, domain string) context.Context {
return context.WithValue(ctx, ctxKeyDomain, domain)
}
func GetDomain(ctx context.Context) string {
domain, ok := ctx.Value(ctxKeyDomain).(string)
if !ok {
fmt.Println("[warning] value ctxKeyDomain is different")
return ""
}
return domain
}
// - - - - - - - - - - - - - - - - - - - - - //
type AssembleAbsoluteURLFunc func(tagName string, rawURL string, domain string) string
func assembleAbsoluteURL(ctx context.Context, tagName string, rawURL string) string {
domain := GetDomain(ctx)
// TODO: since this gets passed down from the converter, it doesn't have to provided from the ctx anymore
fn, ok := ctx.Value(ctxKeyAssembleAbsoluteURL).(AssembleAbsoluteURLFunc)
if !ok {
fmt.Println("[warning] func ctxKeyAssembleAbsoluteURL is different")
return ""
}
return fn(tagName, rawURL, domain)
}
func provideAssembleAbsoluteURL(ctx context.Context, fn AssembleAbsoluteURLFunc) context.Context {
return context.WithValue(ctx, ctxKeyAssembleAbsoluteURL, fn)
}
// - - - - - - - - - - - - - - - - - - - - - //
type SetStateFunc func(key string, val any)
type UpdateStateFunc func(key string, fn func(any) any)
type GetStateFunc func(key string) any
type globalState struct {
data map[string]any
}
func newGlobalState() *globalState {
return &globalState{
data: make(map[string]any),
}
}
func (s *globalState) setState(key string, val any) {
s.data[key] = val
}
func (s *globalState) updateState(key string, fn func(any) any) {
s.data[key] = fn(s.data[key])
}
func (s *globalState) getState(key string) any {
return s.data[key]
}
func (s *globalState) provideGlobalState(ctx context.Context) context.Context {
var setState SetStateFunc = s.setState
var updateState UpdateStateFunc = s.updateState
var getState GetStateFunc = s.getState
ctx = context.WithValue(ctx, ctxKeySetState, setState)
ctx = context.WithValue(ctx, ctxKeyUpdateState, updateState)
ctx = context.WithValue(ctx, ctxKeyGetState, getState)
return ctx
}
func GetState[V any](ctx context.Context, key string) V {
fn := ctx.Value(ctxKeyGetState).(GetStateFunc)
val, _ := fn(key).(V)
return val
}
func SetState[V any](ctx context.Context, key string, val V) {
fn := ctx.Value(ctxKeySetState).(SetStateFunc)
fn(key, val)
}
func UpdateState[V any](ctx context.Context, key string, fn func(V) V) {
updater := ctx.Value(ctxKeyUpdateState).(UpdateStateFunc)
updater(key, func(val any) any {
value, ok := val.(V)
if !ok && val != nil {
// TODO: slog?
fmt.Println("[warning] val is different than V in UpdateState")
}
return fn(value)
})
}
// - - - - - - //
// Context extends the normal context.Context with some additional
// methods useful for the process of converting.
type Context interface {
context.Context
AssembleAbsoluteURL(ctx Context, tagName string, rawURL string) string
GetTagType(tagName string) (tagType, bool)
RenderNodes(ctx Context, w Writer, nodes ...*html.Node)
RenderChildNodes(ctx Context, w Writer, n *html.Node)
EscapeContent(content []byte) []byte
UnEscapeContent(content []byte) []byte
WithValue(key any, val any) Context
}
type converterContext struct {
context.Context
conv *Converter
}
func newConverterContext(ctx context.Context, conv *Converter) Context {
return &converterContext{
Context: ctx,
conv: conv,
}
}
func (c *converterContext) AssembleAbsoluteURL(ctx Context, tagName string, rawURL string) string {
return assembleAbsoluteURL(ctx, tagName, rawURL)
}
func (c *converterContext) RenderNodes(ctx Context, w Writer, nodes ...*html.Node) {
c.conv.handleRenderNodes(ctx, w, nodes...)
}
func (c *converterContext) RenderChildNodes(ctx Context, w Writer, n *html.Node) {
c.conv.handleRenderNodes(ctx, w, dom.AllChildNodes(n)...)
}
func (c *converterContext) GetTagType(tagName string) (tagType, bool) {
return c.conv.getTagType(tagName)
}
func (c *converterContext) EscapeContent(content []byte) []byte {
return c.conv.escapeContent(content)
}
func (c *converterContext) UnEscapeContent(content []byte) []byte {
return c.conv.unEscapeContent(content)
}
func (c *converterContext) WithValue(key any, val any) Context {
return &converterContext{
Context: context.WithValue(c.Context, key, val),
conv: c.conv,
}
}
|