userland: add archive tools and pinned GoAWK, esbuild, and QuickJS

This commit is contained in:
2026-11-07 10:56:29 +00:00
parent 7e7e49bfa2
commit d79b2bc2e1
1798 changed files with 562969 additions and 1 deletions
@@ -0,0 +1,55 @@
// Package parseutil contains various utilities for parsing GoAWK source code.
package parseutil
import (
"bytes"
"io"
)
// FileReader serves two purposes:
// 1. read input sources and join them into a single source (slice of bytes)
// 2. track the lines counts of each input source
type FileReader struct {
files []file
source bytes.Buffer
}
type file struct {
path string
lines int
}
// AddFile adds a single source file.
func (fr *FileReader) AddFile(path string, source io.Reader) error {
curLen := fr.source.Len()
_, err := fr.source.ReadFrom(source)
if err != nil {
return err
}
if !bytes.HasSuffix(fr.source.Bytes(), []byte("\n")) {
// Append newline to file in case it doesn't end with one
fr.source.WriteByte('\n')
}
content := fr.source.Bytes()[curLen:]
lines := bytes.Count(content, []byte("\n"))
fr.files = append(fr.files, file{path, lines})
return nil
}
// FileLine resolves an overall line number from the concatenated source code
// to the local line number in that source file (identified by path).
func (fr *FileReader) FileLine(line int) (path string, fileLine int) {
startLine := 1
for _, f := range fr.files {
if line >= startLine && line < startLine+f.lines {
return f.path, line - startLine + 1
}
startLine += f.lines
}
return "", 0
}
// Source returns the concatenated source code from all files added.
func (fr *FileReader) Source() []byte {
return fr.source.Bytes()
}
@@ -0,0 +1,138 @@
package parseutil_test
import (
. "github.com/benhoyt/goawk/internal/parseutil"
"strings"
"testing"
)
type testFile struct{ name, source string }
type test struct {
name string
// input:
files []testFile
line int
// expected:
path string
fileLine int
}
func TestFileReader(t *testing.T) {
fileSetNoNewline := []testFile{
{"file1", `BEGIN {
print f(1)
}`},
{"file2", `function f(x) {
print x
}`},
}
fileSetWithNewline := []testFile{
{"file1", `BEGIN {
print f(1)
}
`},
{"file2", `function f(x) {
print x
}
`},
}
tests := []test{
{
"TestInFirstFile",
fileSetNoNewline,
2,
"file1",
2,
},
{
"TestInSecondFile",
fileSetNoNewline,
5,
"file2",
2,
},
{
"TestInFirstFileWithNewline",
fileSetWithNewline,
2,
"file1",
2,
},
{
"TestInSecondFileWithNewline",
fileSetWithNewline,
5,
"file2",
2,
},
{
"TestOutside",
fileSetNoNewline,
100,
"",
0,
},
{
"TestOutsideNegative",
fileSetNoNewline,
-100,
"",
0,
},
{
"TestNoFiles",
[]testFile{},
1,
"",
0,
},
{
"TestZeroLenFiles",
[]testFile{
{"file1", ""},
},
1,
"file1",
1,
},
{
"TestZeroLenFiles1",
[]testFile{
{"file1", ""},
},
2,
"",
0,
},
}
for _, tst := range tests {
t.Run(tst.name, func(t *testing.T) {
fr := &FileReader{}
for _, file := range tst.files {
if nil != fr.AddFile(file.name, strings.NewReader(file.source)) {
panic("should not happen")
}
}
path, fileLine := fr.FileLine(tst.line)
if path != tst.path {
t.Errorf("expected path: %v, got: %v", tst.path, path)
}
if fileLine != tst.fileLine {
t.Errorf("expected fileLine: %v, got: %v", tst.fileLine, fileLine)
}
// test result source
source := string(fr.Source())
for _, file := range tst.files {
if !strings.Contains(source, file.source) {
t.Errorf("Source() is incorrect")
}
}
})
}
}