• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

fogfish / iq / 20788108294

07 Jan 2026 04:16PM UTC coverage: 32.132% (-7.1%) from 39.274%
20788108294

push

github

web-flow
(fix) Housekeeping after Claude generated code  (#88)

* release [x.Y.z]
* (fix) define abstraction for composition of computation elements
* (fix) all computation elements, defining runtime abstraction
* (fix) improve AST nodes
* (fix) data exchange using the type rather than any
* (fix) the context, use Event instead of context-based data exchange
* (fix) reporting context
* (fix) emit intermediate results to sink
* (fix) caching of intermediate results
* (fix) consolidate file format codec
* (fix) integration testing
* (fix) update ADRs
* (fix) remove outdated/un-used code
* (fix) simple integration testing via it.sh
* (fix) foreach merge results into target format (json array, plain text)
* (fix) remove jsonify feature
* (fix) /dev/null runs-on target for templates, generate report

264 of 1309 new or added lines in 45 files covered. (20.17%)

114 existing lines in 8 files now uncovered.

1248 of 3884 relevant lines covered (32.13%)

0.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.5
/internal/iosystem/codec/codec.go
1
//
2
// Copyright (C) 2025 - 2026 Dmitry Kolesnikov
3
//
4
// This file may be modified and distributed under the terms
5
// of the MIT license.  See the LICENSE file for details.
6
// https://github.com/fogfish/iq
7
//
8

9
package codec
10

11
import (
12
        "bytes"
13
        "fmt"
14
        "io"
15
        "path/filepath"
16
)
17

18
// Content type constants
19
const (
20
        ContentStream = "application/octet-stream"
21
        ContentJSON   = "application/json"
22
        ContentJSONL  = "application/jsonl"
23
        ContentYAML   = "application/x-yaml"
24
        ContentPNG    = "image/png"
25
        ContentJPG    = "image/jpeg"
26
        ContentText   = "text/plain"
27
        ContentEOF    = "application/x-eof" // Signals end of stream
28
)
29

30
// Codec handles encoding/decoding for a specific content type.
31
type Codec interface {
32
        // ContentType returns the MIME type this codec handles
33
        ContentType() string
34

35
        // Decode reads from io.Reader and converts to Go value
36
        Decode(r io.Reader) (any, error)
37

38
        // Encode converts Go value to bytes and writes to io.Writer
39
        Encode(w io.Writer, data any) error
40

41
        // Extensions returns common file extensions for this type
42
        Extensions() []string
43
}
44

45
// Registry manages codec instances.
46
type Registry struct {
47
        codecs map[string]Codec
48
        extMap map[string]string
49
}
50

51
// Default is the global default registry
52
var Default = NewRegistry()
53

54
// NewRegistry creates a new codec registry
55
func NewRegistry() *Registry {
1✔
56
        r := &Registry{
1✔
57
                codecs: make(map[string]Codec),
1✔
58
                extMap: make(map[string]string),
1✔
59
        }
1✔
60

1✔
61
        // Register built-in codecs
1✔
62
        r.Register(NewJSONCodec(false))
1✔
63
        r.Register(NewYAMLCodec())
1✔
64
        r.Register(NewTextCodec())
1✔
65
        r.Register(NewBinaryCodec())
1✔
66
        r.Register(NewJSONLCodec())
1✔
67
        r.Register(NewImageCodec(ContentPNG))
1✔
68
        r.Register(NewImageCodec(ContentJPG))
1✔
69

1✔
70
        return r
1✔
71
}
1✔
72

73
// Register adds a codec to the registry
74
func (r *Registry) Register(c Codec) {
1✔
75
        contentType := c.ContentType()
1✔
76
        r.codecs[contentType] = c
1✔
77

1✔
78
        for _, ext := range c.Extensions() {
2✔
79
                r.extMap[ext] = contentType
1✔
80
        }
1✔
81
}
82

83
// Get returns codec for content type
84
func (r *Registry) Get(contentType string) (Codec, bool) {
1✔
85
        c, ok := r.codecs[contentType]
1✔
86
        return c, ok
1✔
87
}
1✔
88

89
// GetByExtension returns codec for file extension
NEW
90
func (r *Registry) GetByExtension(ext string) (Codec, bool) {
×
NEW
91
        contentType, ok := r.extMap[ext]
×
NEW
92
        if !ok {
×
NEW
93
                return nil, false
×
NEW
94
        }
×
NEW
95
        return r.Get(contentType)
×
96
}
97

98
// Decode decodes a document using appropriate codec
99
func (r *Registry) Decode(doc io.Reader, contentType string) (any, error) {
1✔
100
        codec, ok := r.Get(contentType)
1✔
101
        if !ok {
1✔
NEW
102
                codec = r.codecs[ContentStream]
×
NEW
103
                if codec == nil {
×
NEW
104
                        return nil, fmt.Errorf("no codec found for content type %s", contentType)
×
NEW
105
                }
×
106
        }
107
        return codec.Decode(doc)
1✔
108
}
109

110
// Encode encodes data to a new document
111
func (r *Registry) Encode(data any, contentType string) (io.Reader, error) {
1✔
112
        codec, ok := r.Get(contentType)
1✔
113
        if !ok {
1✔
NEW
114
                switch data.(type) {
×
NEW
115
                case string:
×
NEW
116
                        contentType = ContentText
×
NEW
117
                        codec = r.codecs[contentType]
×
NEW
118
                case []byte:
×
NEW
119
                        contentType = ContentStream
×
NEW
120
                        codec = r.codecs[contentType]
×
NEW
121
                default:
×
NEW
122
                        contentType = ContentJSON
×
NEW
123
                        codec = r.codecs[contentType]
×
124
                }
125
        }
126

127
        if codec == nil {
1✔
NEW
128
                return nil, fmt.Errorf("no codec found for content type %s", contentType)
×
NEW
129
        }
×
130

131
        var buf bytes.Buffer
1✔
132
        if err := codec.Encode(&buf, data); err != nil {
1✔
NEW
133
                return nil, err
×
NEW
134
        }
×
135

136
        return bytes.NewReader(buf.Bytes()), nil
1✔
137
}
138

139
// DetectContentType detects content type from file path
140
func (r *Registry) DetectContentType(path string) string {
1✔
141
        ext := filepath.Ext(path)
1✔
142
        contentType, ok := r.extMap[ext]
1✔
143
        if !ok {
2✔
144
                return ContentStream
1✔
145
        }
1✔
146
        return contentType
1✔
147
}
148

149
// GetExtension returns the preferred file extension for a content type.
150
// Returns empty string if content type is not registered.
151
func (r *Registry) GetExtension(contentType string) string {
1✔
152
        codec, ok := r.Get(contentType)
1✔
153
        if !ok {
2✔
154
                return ""
1✔
155
        }
1✔
156
        
157
        exts := codec.Extensions()
1✔
158
        if len(exts) == 0 {
1✔
NEW
159
                return ""
×
NEW
160
        }
×
161
        
162
        // Return the first (preferred) extension
163
        return exts[0]
1✔
164
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc