fix: add involves edge from task to agent:nomos at creation
Some checks failed
ci / build-test (push) Has been cancelled
ci / docker-build (push) Has been cancelled
ci / web (push) Has been cancelled
Desktop App / Build Linux (amd64) (push) Has been cancelled
Desktop App / Attach to Release (push) Has been cancelled

Plus sync vendor directory for Docker build compatibility.
This commit is contained in:
2026-08-11 22:03:12 +02:00
parent 7d6a3320d4
commit febc153b7f
3384 changed files with 945212 additions and 2 deletions

25
vendor/github.com/yosida95/uritemplate/v3/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,25 @@
Copyright (C) 2016, Kohei YOSHIDA <https://yosida95.com/>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

46
vendor/github.com/yosida95/uritemplate/v3/README.rst generated vendored Normal file
View File

@@ -0,0 +1,46 @@
uritemplate
===========
`uritemplate`_ is a Go implementation of `URI Template`_ [RFC6570] with
full functionality of URI Template Level 4.
uritemplate can also generate a regexp that matches expansion of the
URI Template from a URI Template.
Getting Started
---------------
Installation
~~~~~~~~~~~~
.. code-block:: sh
$ go get -u github.com/yosida95/uritemplate/v3
Documentation
~~~~~~~~~~~~~
The documentation is available on GoDoc_.
Examples
--------
See `examples on GoDoc`_.
License
-------
`uritemplate`_ is distributed under the BSD 3-Clause license.
PLEASE READ ./LICENSE carefully and follow its clauses to use this software.
Author
------
yosida95_
.. _`URI Template`: https://tools.ietf.org/html/rfc6570
.. _Godoc: https://godoc.org/github.com/yosida95/uritemplate
.. _`examples on GoDoc`: https://godoc.org/github.com/yosida95/uritemplate#pkg-examples
.. _yosida95: https://yosida95.com/
.. _uritemplate: https://github.com/yosida95/uritemplate

224
vendor/github.com/yosida95/uritemplate/v3/compile.go generated vendored Normal file
View File

@@ -0,0 +1,224 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"fmt"
"unicode/utf8"
)
type compiler struct {
prog *prog
}
func (c *compiler) init() {
c.prog = &prog{}
}
func (c *compiler) op(opcode progOpcode) uint32 {
i := len(c.prog.op)
c.prog.op = append(c.prog.op, progOp{code: opcode})
return uint32(i)
}
func (c *compiler) opWithRune(opcode progOpcode, r rune) uint32 {
addr := c.op(opcode)
(&c.prog.op[addr]).r = r
return addr
}
func (c *compiler) opWithRuneClass(opcode progOpcode, rc runeClass) uint32 {
addr := c.op(opcode)
(&c.prog.op[addr]).rc = rc
return addr
}
func (c *compiler) opWithAddr(opcode progOpcode, absaddr uint32) uint32 {
addr := c.op(opcode)
(&c.prog.op[addr]).i = absaddr
return addr
}
func (c *compiler) opWithAddrDelta(opcode progOpcode, delta uint32) uint32 {
return c.opWithAddr(opcode, uint32(len(c.prog.op))+delta)
}
func (c *compiler) opWithName(opcode progOpcode, name string) uint32 {
addr := c.op(opcode)
(&c.prog.op[addr]).name = name
return addr
}
func (c *compiler) compileString(str string) {
for i := 0; i < len(str); {
// NOTE(yosida95): It is confirmed at parse time that literals
// consist of only valid-UTF8 runes.
r, size := utf8.DecodeRuneInString(str[i:])
c.opWithRune(opRune, r)
i += size
}
}
func (c *compiler) compileRuneClass(rc runeClass, maxlen int) {
for i := 0; i < maxlen; i++ {
if i > 0 {
c.opWithAddrDelta(opSplit, 7)
}
c.opWithAddrDelta(opSplit, 3) // raw rune or pct-encoded
c.opWithRuneClass(opRuneClass, rc) // raw rune
c.opWithAddrDelta(opJmp, 4) //
c.opWithRune(opRune, '%') // pct-encoded
c.opWithRuneClass(opRuneClass, runeClassPctE) //
c.opWithRuneClass(opRuneClass, runeClassPctE) //
}
}
func (c *compiler) compileRuneClassInfinite(rc runeClass) {
start := c.opWithAddrDelta(opSplit, 3) // raw rune or pct-encoded
c.opWithRuneClass(opRuneClass, rc) // raw rune
c.opWithAddrDelta(opJmp, 4) //
c.opWithRune(opRune, '%') // pct-encoded
c.opWithRuneClass(opRuneClass, runeClassPctE) //
c.opWithRuneClass(opRuneClass, runeClassPctE) //
c.opWithAddrDelta(opSplit, 2) // loop
c.opWithAddr(opJmp, start) //
}
func (c *compiler) compileVarspecValue(spec varspec, expr *expression) {
var specname string
if spec.maxlen > 0 {
specname = fmt.Sprintf("%s:%d", spec.name, spec.maxlen)
} else {
specname = spec.name
}
c.prog.numCap++
c.opWithName(opCapStart, specname)
split := c.op(opSplit)
if spec.maxlen > 0 {
c.compileRuneClass(expr.allow, spec.maxlen)
} else {
c.compileRuneClassInfinite(expr.allow)
}
capEnd := c.opWithName(opCapEnd, specname)
c.prog.op[split].i = capEnd
}
func (c *compiler) compileVarspec(spec varspec, expr *expression) {
switch {
case expr.named && spec.explode:
split1 := c.op(opSplit)
noop := c.op(opNoop)
c.compileString(spec.name)
split2 := c.op(opSplit)
c.opWithRune(opRune, '=')
c.compileVarspecValue(spec, expr)
split3 := c.op(opSplit)
c.compileString(expr.sep)
c.opWithAddr(opJmp, noop)
c.prog.op[split2].i = uint32(len(c.prog.op))
c.compileString(expr.ifemp)
c.opWithAddr(opJmp, split3)
c.prog.op[split1].i = uint32(len(c.prog.op))
c.prog.op[split3].i = uint32(len(c.prog.op))
case expr.named && !spec.explode:
c.compileString(spec.name)
split2 := c.op(opSplit)
c.opWithRune(opRune, '=')
split3 := c.op(opSplit)
split4 := c.op(opSplit)
c.compileVarspecValue(spec, expr)
split5 := c.op(opSplit)
c.prog.op[split4].i = split5
c.compileString(",")
c.opWithAddr(opJmp, split4)
c.prog.op[split3].i = uint32(len(c.prog.op))
c.compileString(",")
jmp1 := c.op(opJmp)
c.prog.op[split2].i = uint32(len(c.prog.op))
c.compileString(expr.ifemp)
c.prog.op[split5].i = uint32(len(c.prog.op))
c.prog.op[jmp1].i = uint32(len(c.prog.op))
case !expr.named:
start := uint32(len(c.prog.op))
c.compileVarspecValue(spec, expr)
split1 := c.op(opSplit)
jmp := c.op(opJmp)
c.prog.op[split1].i = uint32(len(c.prog.op))
if spec.explode {
c.compileString(expr.sep)
} else {
c.opWithRune(opRune, ',')
}
c.opWithAddr(opJmp, start)
c.prog.op[jmp].i = uint32(len(c.prog.op))
}
}
func (c *compiler) compileExpression(expr *expression) {
if len(expr.vars) < 1 {
return
}
split1 := c.op(opSplit)
c.compileString(expr.first)
for i, size := 0, len(expr.vars); i < size; i++ {
spec := expr.vars[i]
split2 := c.op(opSplit)
if i > 0 {
split3 := c.op(opSplit)
c.compileString(expr.sep)
c.prog.op[split3].i = uint32(len(c.prog.op))
}
c.compileVarspec(spec, expr)
c.prog.op[split2].i = uint32(len(c.prog.op))
}
c.prog.op[split1].i = uint32(len(c.prog.op))
}
func (c *compiler) compileLiterals(lt literals) {
c.compileString(string(lt))
}
func (c *compiler) compile(tmpl *Template) {
c.op(opLineBegin)
for i := range tmpl.exprs {
expr := tmpl.exprs[i]
switch expr := expr.(type) {
default:
panic("unhandled expression")
case *expression:
c.compileExpression(expr)
case literals:
c.compileLiterals(expr)
}
}
c.op(opLineEnd)
c.op(opEnd)
}

53
vendor/github.com/yosida95/uritemplate/v3/equals.go generated vendored Normal file
View File

@@ -0,0 +1,53 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
type CompareFlags uint8
const (
CompareVarname CompareFlags = 1 << iota
)
// Equals reports whether or not two URI Templates t1 and t2 are equivalent.
func Equals(t1 *Template, t2 *Template, flags CompareFlags) bool {
if len(t1.exprs) != len(t2.exprs) {
return false
}
for i := 0; i < len(t1.exprs); i++ {
switch t1 := t1.exprs[i].(type) {
case literals:
t2, ok := t2.exprs[i].(literals)
if !ok {
return false
}
if t1 != t2 {
return false
}
case *expression:
t2, ok := t2.exprs[i].(*expression)
if !ok {
return false
}
if t1.op != t2.op || len(t1.vars) != len(t2.vars) {
return false
}
for n := 0; n < len(t1.vars); n++ {
v1 := t1.vars[n]
v2 := t2.vars[n]
if flags&CompareVarname == CompareVarname && v1.name != v2.name {
return false
}
if v1.maxlen != v2.maxlen || v1.explode != v2.explode {
return false
}
}
default:
panic("unhandled case")
}
}
return true
}

16
vendor/github.com/yosida95/uritemplate/v3/error.go generated vendored Normal file
View File

@@ -0,0 +1,16 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"fmt"
)
func errorf(pos int, format string, a ...interface{}) error {
msg := fmt.Sprintf(format, a...)
return fmt.Errorf("uritemplate:%d:%s", pos, msg)
}

190
vendor/github.com/yosida95/uritemplate/v3/escape.go generated vendored Normal file
View File

@@ -0,0 +1,190 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"strings"
"unicode"
"unicode/utf8"
)
var (
hex = []byte("0123456789ABCDEF")
// reserved = gen-delims / sub-delims
// gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
// sub-delims = "!" / "$" / "&" / "" / "(" / ")"
// / "*" / "+" / "," / ";" / "="
rangeReserved = &unicode.RangeTable{
R16: []unicode.Range16{
{Lo: 0x21, Hi: 0x21, Stride: 1}, // '!'
{Lo: 0x23, Hi: 0x24, Stride: 1}, // '#' - '$'
{Lo: 0x26, Hi: 0x2C, Stride: 1}, // '&' - ','
{Lo: 0x2F, Hi: 0x2F, Stride: 1}, // '/'
{Lo: 0x3A, Hi: 0x3B, Stride: 1}, // ':' - ';'
{Lo: 0x3D, Hi: 0x3D, Stride: 1}, // '='
{Lo: 0x3F, Hi: 0x40, Stride: 1}, // '?' - '@'
{Lo: 0x5B, Hi: 0x5B, Stride: 1}, // '['
{Lo: 0x5D, Hi: 0x5D, Stride: 1}, // ']'
},
LatinOffset: 9,
}
reReserved = `\x21\x23\x24\x26-\x2c\x2f\x3a\x3b\x3d\x3f\x40\x5b\x5d`
// ALPHA = %x41-5A / %x61-7A
// DIGIT = %x30-39
// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
rangeUnreserved = &unicode.RangeTable{
R16: []unicode.Range16{
{Lo: 0x2D, Hi: 0x2E, Stride: 1}, // '-' - '.'
{Lo: 0x30, Hi: 0x39, Stride: 1}, // '0' - '9'
{Lo: 0x41, Hi: 0x5A, Stride: 1}, // 'A' - 'Z'
{Lo: 0x5F, Hi: 0x5F, Stride: 1}, // '_'
{Lo: 0x61, Hi: 0x7A, Stride: 1}, // 'a' - 'z'
{Lo: 0x7E, Hi: 0x7E, Stride: 1}, // '~'
},
}
reUnreserved = `\x2d\x2e\x30-\x39\x41-\x5a\x5f\x61-\x7a\x7e`
)
type runeClass uint8
const (
runeClassU runeClass = 1 << iota
runeClassR
runeClassPctE
runeClassLast
runeClassUR = runeClassU | runeClassR
)
var runeClassNames = []string{
"U",
"R",
"pct-encoded",
}
func (rc runeClass) String() string {
ret := make([]string, 0, len(runeClassNames))
for i, j := 0, runeClass(1); j < runeClassLast; j <<= 1 {
if rc&j == j {
ret = append(ret, runeClassNames[i])
}
i++
}
return strings.Join(ret, "+")
}
func pctEncode(w *strings.Builder, r rune) {
if s := r >> 24 & 0xff; s > 0 {
w.Write([]byte{'%', hex[s/16], hex[s%16]})
}
if s := r >> 16 & 0xff; s > 0 {
w.Write([]byte{'%', hex[s/16], hex[s%16]})
}
if s := r >> 8 & 0xff; s > 0 {
w.Write([]byte{'%', hex[s/16], hex[s%16]})
}
if s := r & 0xff; s > 0 {
w.Write([]byte{'%', hex[s/16], hex[s%16]})
}
}
func unhex(c byte) byte {
switch {
case '0' <= c && c <= '9':
return c - '0'
case 'a' <= c && c <= 'f':
return c - 'a' + 10
case 'A' <= c && c <= 'F':
return c - 'A' + 10
}
return 0
}
func ishex(c byte) bool {
switch {
case '0' <= c && c <= '9':
return true
case 'a' <= c && c <= 'f':
return true
case 'A' <= c && c <= 'F':
return true
default:
return false
}
}
func pctDecode(s string) string {
size := len(s)
for i := 0; i < len(s); {
switch s[i] {
case '%':
size -= 2
i += 3
default:
i++
}
}
if size == len(s) {
return s
}
buf := make([]byte, size)
j := 0
for i := 0; i < len(s); {
switch c := s[i]; c {
case '%':
buf[j] = unhex(s[i+1])<<4 | unhex(s[i+2])
i += 3
j++
default:
buf[j] = c
i++
j++
}
}
return string(buf)
}
type escapeFunc func(*strings.Builder, string) error
func escapeLiteral(w *strings.Builder, v string) error {
w.WriteString(v)
return nil
}
func escapeExceptU(w *strings.Builder, v string) error {
for i := 0; i < len(v); {
r, size := utf8.DecodeRuneInString(v[i:])
if r == utf8.RuneError {
return errorf(i, "invalid encoding")
}
if unicode.Is(rangeUnreserved, r) {
w.WriteRune(r)
} else {
pctEncode(w, r)
}
i += size
}
return nil
}
func escapeExceptUR(w *strings.Builder, v string) error {
for i := 0; i < len(v); {
r, size := utf8.DecodeRuneInString(v[i:])
if r == utf8.RuneError {
return errorf(i, "invalid encoding")
}
// TODO(yosida95): is pct-encoded triplets allowed here?
if unicode.In(r, rangeUnreserved, rangeReserved) {
w.WriteRune(r)
} else {
pctEncode(w, r)
}
i += size
}
return nil
}

173
vendor/github.com/yosida95/uritemplate/v3/expression.go generated vendored Normal file
View File

@@ -0,0 +1,173 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"regexp"
"strconv"
"strings"
)
type template interface {
expand(*strings.Builder, Values) error
regexp(*strings.Builder)
}
type literals string
func (l literals) expand(b *strings.Builder, _ Values) error {
b.WriteString(string(l))
return nil
}
func (l literals) regexp(b *strings.Builder) {
b.WriteString("(?:")
b.WriteString(regexp.QuoteMeta(string(l)))
b.WriteByte(')')
}
type varspec struct {
name string
maxlen int
explode bool
}
type expression struct {
vars []varspec
op parseOp
first string
sep string
named bool
ifemp string
escape escapeFunc
allow runeClass
}
func (e *expression) init() {
switch e.op {
case parseOpSimple:
e.sep = ","
e.escape = escapeExceptU
e.allow = runeClassU
case parseOpPlus:
e.sep = ","
e.escape = escapeExceptUR
e.allow = runeClassUR
case parseOpCrosshatch:
e.first = "#"
e.sep = ","
e.escape = escapeExceptUR
e.allow = runeClassUR
case parseOpDot:
e.first = "."
e.sep = "."
e.escape = escapeExceptU
e.allow = runeClassU
case parseOpSlash:
e.first = "/"
e.sep = "/"
e.escape = escapeExceptU
e.allow = runeClassU
case parseOpSemicolon:
e.first = ";"
e.sep = ";"
e.named = true
e.escape = escapeExceptU
e.allow = runeClassU
case parseOpQuestion:
e.first = "?"
e.sep = "&"
e.named = true
e.ifemp = "="
e.escape = escapeExceptU
e.allow = runeClassU
case parseOpAmpersand:
e.first = "&"
e.sep = "&"
e.named = true
e.ifemp = "="
e.escape = escapeExceptU
e.allow = runeClassU
}
}
func (e *expression) expand(w *strings.Builder, values Values) error {
first := true
for _, varspec := range e.vars {
value := values.Get(varspec.name)
if !value.Valid() {
continue
}
if first {
w.WriteString(e.first)
first = false
} else {
w.WriteString(e.sep)
}
if err := value.expand(w, varspec, e); err != nil {
return err
}
}
return nil
}
func (e *expression) regexp(b *strings.Builder) {
if e.first != "" {
b.WriteString("(?:") // $1
b.WriteString(regexp.QuoteMeta(e.first))
}
b.WriteByte('(') // $2
runeClassToRegexp(b, e.allow, e.named || e.vars[0].explode)
if len(e.vars) > 1 || e.vars[0].explode {
max := len(e.vars) - 1
for i := 0; i < len(e.vars); i++ {
if e.vars[i].explode {
max = -1
break
}
}
b.WriteString("(?:") // $3
b.WriteString(regexp.QuoteMeta(e.sep))
runeClassToRegexp(b, e.allow, e.named || max < 0)
b.WriteByte(')') // $3
if max > 0 {
b.WriteString("{0,")
b.WriteString(strconv.Itoa(max))
b.WriteByte('}')
} else {
b.WriteByte('*')
}
}
b.WriteByte(')') // $2
if e.first != "" {
b.WriteByte(')') // $1
}
b.WriteByte('?')
}
func runeClassToRegexp(b *strings.Builder, class runeClass, named bool) {
b.WriteString("(?:(?:[")
if class&runeClassR == 0 {
b.WriteString(`\x2c`)
if named {
b.WriteString(`\x3d`)
}
}
if class&runeClassU == runeClassU {
b.WriteString(reUnreserved)
}
if class&runeClassR == runeClassR {
b.WriteString(reReserved)
}
b.WriteString("]")
b.WriteString("|%[[:xdigit:]][[:xdigit:]]")
b.WriteString(")*)")
}

23
vendor/github.com/yosida95/uritemplate/v3/machine.go generated vendored Normal file
View File

@@ -0,0 +1,23 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
// threadList implements https://research.swtch.com/sparse.
type threadList struct {
dense []threadEntry
sparse []uint32
}
type threadEntry struct {
pc uint32
t *thread
}
type thread struct {
op *progOp
cap map[string][]int
}

213
vendor/github.com/yosida95/uritemplate/v3/match.go generated vendored Normal file
View File

@@ -0,0 +1,213 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"bytes"
"unicode"
"unicode/utf8"
)
type matcher struct {
prog *prog
list1 threadList
list2 threadList
matched bool
cap map[string][]int
input string
}
func (m *matcher) at(pos int) (rune, int, bool) {
if l := len(m.input); pos < l {
c := m.input[pos]
if c < utf8.RuneSelf {
return rune(c), 1, pos+1 < l
}
r, size := utf8.DecodeRuneInString(m.input[pos:])
return r, size, pos+size < l
}
return -1, 0, false
}
func (m *matcher) add(list *threadList, pc uint32, pos int, next bool, cap map[string][]int) {
if i := list.sparse[pc]; i < uint32(len(list.dense)) && list.dense[i].pc == pc {
return
}
n := len(list.dense)
list.dense = list.dense[:n+1]
list.sparse[pc] = uint32(n)
e := &list.dense[n]
e.pc = pc
e.t = nil
op := &m.prog.op[pc]
switch op.code {
default:
panic("unhandled opcode")
case opRune, opRuneClass, opEnd:
e.t = &thread{
op: &m.prog.op[pc],
cap: make(map[string][]int, len(m.cap)),
}
for k, v := range cap {
e.t.cap[k] = make([]int, len(v))
copy(e.t.cap[k], v)
}
case opLineBegin:
if pos == 0 {
m.add(list, pc+1, pos, next, cap)
}
case opLineEnd:
if !next {
m.add(list, pc+1, pos, next, cap)
}
case opCapStart, opCapEnd:
ocap := make(map[string][]int, len(m.cap))
for k, v := range cap {
ocap[k] = make([]int, len(v))
copy(ocap[k], v)
}
ocap[op.name] = append(ocap[op.name], pos)
m.add(list, pc+1, pos, next, ocap)
case opSplit:
m.add(list, pc+1, pos, next, cap)
m.add(list, op.i, pos, next, cap)
case opJmp:
m.add(list, op.i, pos, next, cap)
case opJmpIfNotDefined:
m.add(list, pc+1, pos, next, cap)
m.add(list, op.i, pos, next, cap)
case opJmpIfNotFirst:
m.add(list, pc+1, pos, next, cap)
m.add(list, op.i, pos, next, cap)
case opJmpIfNotEmpty:
m.add(list, op.i, pos, next, cap)
m.add(list, pc+1, pos, next, cap)
case opNoop:
m.add(list, pc+1, pos, next, cap)
}
}
func (m *matcher) step(clist *threadList, nlist *threadList, r rune, pos int, nextPos int, next bool) {
debug.Printf("===== %q =====", string(r))
for i := 0; i < len(clist.dense); i++ {
e := clist.dense[i]
if debug {
var buf bytes.Buffer
dumpProg(&buf, m.prog, e.pc)
debug.Printf("\n%s", buf.String())
}
if e.t == nil {
continue
}
t := e.t
op := t.op
switch op.code {
default:
panic("unhandled opcode")
case opRune:
if op.r == r {
m.add(nlist, e.pc+1, nextPos, next, t.cap)
}
case opRuneClass:
ret := false
if !ret && op.rc&runeClassU == runeClassU {
ret = ret || unicode.Is(rangeUnreserved, r)
}
if !ret && op.rc&runeClassR == runeClassR {
ret = ret || unicode.Is(rangeReserved, r)
}
if !ret && op.rc&runeClassPctE == runeClassPctE {
ret = ret || unicode.Is(unicode.ASCII_Hex_Digit, r)
}
if ret {
m.add(nlist, e.pc+1, nextPos, next, t.cap)
}
case opEnd:
m.matched = true
for k, v := range t.cap {
m.cap[k] = make([]int, len(v))
copy(m.cap[k], v)
}
clist.dense = clist.dense[:0]
}
}
clist.dense = clist.dense[:0]
}
func (m *matcher) match() bool {
pos := 0
clist, nlist := &m.list1, &m.list2
for {
if len(clist.dense) == 0 && m.matched {
break
}
r, width, next := m.at(pos)
if !m.matched {
m.add(clist, 0, pos, next, m.cap)
}
m.step(clist, nlist, r, pos, pos+width, next)
if width < 1 {
break
}
pos += width
clist, nlist = nlist, clist
}
return m.matched
}
func (tmpl *Template) Match(expansion string) Values {
tmpl.mu.Lock()
if tmpl.prog == nil {
c := compiler{}
c.init()
c.compile(tmpl)
tmpl.prog = c.prog
}
prog := tmpl.prog
tmpl.mu.Unlock()
n := len(prog.op)
m := matcher{
prog: prog,
list1: threadList{
dense: make([]threadEntry, 0, n),
sparse: make([]uint32, n),
},
list2: threadList{
dense: make([]threadEntry, 0, n),
sparse: make([]uint32, n),
},
cap: make(map[string][]int, prog.numCap),
input: expansion,
}
if !m.match() {
return nil
}
match := make(Values, len(m.cap))
for name, indices := range m.cap {
v := Value{V: make([]string, len(indices)/2)}
for i := range v.V {
v.V[i] = pctDecode(expansion[indices[2*i]:indices[2*i+1]])
}
if len(v.V) == 1 {
v.T = ValueTypeString
} else {
v.T = ValueTypeList
}
match[name] = v
}
return match
}

277
vendor/github.com/yosida95/uritemplate/v3/parse.go generated vendored Normal file
View File

@@ -0,0 +1,277 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"fmt"
"unicode"
"unicode/utf8"
)
type parseOp int
const (
parseOpSimple parseOp = iota
parseOpPlus
parseOpCrosshatch
parseOpDot
parseOpSlash
parseOpSemicolon
parseOpQuestion
parseOpAmpersand
)
var (
rangeVarchar = &unicode.RangeTable{
R16: []unicode.Range16{
{Lo: 0x0030, Hi: 0x0039, Stride: 1}, // '0' - '9'
{Lo: 0x0041, Hi: 0x005A, Stride: 1}, // 'A' - 'Z'
{Lo: 0x005F, Hi: 0x005F, Stride: 1}, // '_'
{Lo: 0x0061, Hi: 0x007A, Stride: 1}, // 'a' - 'z'
},
LatinOffset: 4,
}
rangeLiterals = &unicode.RangeTable{
R16: []unicode.Range16{
{Lo: 0x0021, Hi: 0x0021, Stride: 1}, // '!'
{Lo: 0x0023, Hi: 0x0024, Stride: 1}, // '#' - '$'
{Lo: 0x0026, Hi: 0x003B, Stride: 1}, // '&' ''' '(' - ';'. '''/27 used to be excluded but an errata is in the review process https://www.rfc-editor.org/errata/eid6937
{Lo: 0x003D, Hi: 0x003D, Stride: 1}, // '='
{Lo: 0x003F, Hi: 0x005B, Stride: 1}, // '?' - '['
{Lo: 0x005D, Hi: 0x005D, Stride: 1}, // ']'
{Lo: 0x005F, Hi: 0x005F, Stride: 1}, // '_'
{Lo: 0x0061, Hi: 0x007A, Stride: 1}, // 'a' - 'z'
{Lo: 0x007E, Hi: 0x007E, Stride: 1}, // '~'
{Lo: 0x00A0, Hi: 0xD7FF, Stride: 1}, // ucschar
{Lo: 0xE000, Hi: 0xF8FF, Stride: 1}, // iprivate
{Lo: 0xF900, Hi: 0xFDCF, Stride: 1}, // ucschar
{Lo: 0xFDF0, Hi: 0xFFEF, Stride: 1}, // ucschar
},
R32: []unicode.Range32{
{Lo: 0x00010000, Hi: 0x0001FFFD, Stride: 1}, // ucschar
{Lo: 0x00020000, Hi: 0x0002FFFD, Stride: 1}, // ucschar
{Lo: 0x00030000, Hi: 0x0003FFFD, Stride: 1}, // ucschar
{Lo: 0x00040000, Hi: 0x0004FFFD, Stride: 1}, // ucschar
{Lo: 0x00050000, Hi: 0x0005FFFD, Stride: 1}, // ucschar
{Lo: 0x00060000, Hi: 0x0006FFFD, Stride: 1}, // ucschar
{Lo: 0x00070000, Hi: 0x0007FFFD, Stride: 1}, // ucschar
{Lo: 0x00080000, Hi: 0x0008FFFD, Stride: 1}, // ucschar
{Lo: 0x00090000, Hi: 0x0009FFFD, Stride: 1}, // ucschar
{Lo: 0x000A0000, Hi: 0x000AFFFD, Stride: 1}, // ucschar
{Lo: 0x000B0000, Hi: 0x000BFFFD, Stride: 1}, // ucschar
{Lo: 0x000C0000, Hi: 0x000CFFFD, Stride: 1}, // ucschar
{Lo: 0x000D0000, Hi: 0x000DFFFD, Stride: 1}, // ucschar
{Lo: 0x000E1000, Hi: 0x000EFFFD, Stride: 1}, // ucschar
{Lo: 0x000F0000, Hi: 0x000FFFFD, Stride: 1}, // iprivate
{Lo: 0x00100000, Hi: 0x0010FFFD, Stride: 1}, // iprivate
},
LatinOffset: 10,
}
)
type parser struct {
r string
start int
stop int
state parseState
}
func (p *parser) errorf(i rune, format string, a ...interface{}) error {
return fmt.Errorf("%s: %s%s", fmt.Sprintf(format, a...), p.r[0:p.stop], string(i))
}
func (p *parser) rune() (rune, int) {
r, size := utf8.DecodeRuneInString(p.r[p.stop:])
if r != utf8.RuneError {
p.stop += size
}
return r, size
}
func (p *parser) unread(r rune) {
p.stop -= utf8.RuneLen(r)
}
type parseState int
const (
parseStateDefault = parseState(iota)
parseStateOperator
parseStateVarList
parseStateVarName
parseStatePrefix
)
func (p *parser) setState(state parseState) {
p.state = state
p.start = p.stop
}
func (p *parser) parseURITemplate() (*Template, error) {
tmpl := Template{
raw: p.r,
exprs: []template{},
}
var exp *expression
for {
r, size := p.rune()
if r == utf8.RuneError {
if size == 0 {
if p.state != parseStateDefault {
return nil, p.errorf('_', "incomplete expression")
}
if p.start < p.stop {
tmpl.exprs = append(tmpl.exprs, literals(p.r[p.start:p.stop]))
}
return &tmpl, nil
}
return nil, p.errorf('_', "invalid UTF-8 sequence")
}
switch p.state {
case parseStateDefault:
switch r {
case '{':
if stop := p.stop - size; stop > p.start {
tmpl.exprs = append(tmpl.exprs, literals(p.r[p.start:stop]))
}
exp = &expression{}
tmpl.exprs = append(tmpl.exprs, exp)
p.setState(parseStateOperator)
case '%':
p.unread(r)
if err := p.consumeTriplet(); err != nil {
return nil, err
}
default:
if !unicode.Is(rangeLiterals, r) {
p.unread(r)
return nil, p.errorf('_', "unacceptable character (hint: use %%XX encoding)")
}
}
case parseStateOperator:
switch r {
default:
p.unread(r)
exp.op = parseOpSimple
case '+':
exp.op = parseOpPlus
case '#':
exp.op = parseOpCrosshatch
case '.':
exp.op = parseOpDot
case '/':
exp.op = parseOpSlash
case ';':
exp.op = parseOpSemicolon
case '?':
exp.op = parseOpQuestion
case '&':
exp.op = parseOpAmpersand
case '=', ',', '!', '@', '|': // op-reserved
return nil, p.errorf('|', "unimplemented operator (op-reserved)")
}
p.setState(parseStateVarName)
case parseStateVarList:
switch r {
case ',':
p.setState(parseStateVarName)
case '}':
exp.init()
p.setState(parseStateDefault)
default:
p.unread(r)
return nil, p.errorf('_', "unrecognized value modifier")
}
case parseStateVarName:
switch r {
case ':', '*':
name := p.r[p.start : p.stop-size]
if !isValidVarname(name) {
return nil, p.errorf('|', "unacceptable variable name")
}
explode := r == '*'
exp.vars = append(exp.vars, varspec{
name: name,
explode: explode,
})
if explode {
p.setState(parseStateVarList)
} else {
p.setState(parseStatePrefix)
}
case ',', '}':
p.unread(r)
name := p.r[p.start:p.stop]
if !isValidVarname(name) {
return nil, p.errorf('|', "unacceptable variable name")
}
exp.vars = append(exp.vars, varspec{
name: name,
})
p.setState(parseStateVarList)
case '%':
p.unread(r)
if err := p.consumeTriplet(); err != nil {
return nil, err
}
case '.':
if dot := p.stop - size; dot == p.start || p.r[dot-1] == '.' {
return nil, p.errorf('|', "unacceptable variable name")
}
default:
if !unicode.Is(rangeVarchar, r) {
p.unread(r)
return nil, p.errorf('_', "unacceptable variable name")
}
}
case parseStatePrefix:
spec := &(exp.vars[len(exp.vars)-1])
switch {
case '0' <= r && r <= '9':
spec.maxlen *= 10
spec.maxlen += int(r - '0')
if spec.maxlen == 0 || spec.maxlen > 9999 {
return nil, p.errorf('|', "max-length must be (0, 9999]")
}
default:
p.unread(r)
if spec.maxlen == 0 {
return nil, p.errorf('_', "max-length must be (0, 9999]")
}
p.setState(parseStateVarList)
}
default:
p.unread(r)
panic(p.errorf('_', "unhandled parseState(%d)", p.state))
}
}
}
func isValidVarname(name string) bool {
if l := len(name); l == 0 || name[0] == '.' || name[l-1] == '.' {
return false
}
for i := 1; i < len(name)-1; i++ {
switch c := name[i]; c {
case '.':
if name[i-1] == '.' {
return false
}
}
}
return true
}
func (p *parser) consumeTriplet() error {
if len(p.r)-p.stop < 3 || p.r[p.stop] != '%' || !ishex(p.r[p.stop+1]) || !ishex(p.r[p.stop+2]) {
return p.errorf('_', "incomplete pct-encodeed")
}
p.stop += 3
return nil
}

130
vendor/github.com/yosida95/uritemplate/v3/prog.go generated vendored Normal file
View File

@@ -0,0 +1,130 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"bytes"
"strconv"
)
type progOpcode uint16
const (
// match
opRune progOpcode = iota
opRuneClass
opLineBegin
opLineEnd
// capture
opCapStart
opCapEnd
// stack
opSplit
opJmp
opJmpIfNotDefined
opJmpIfNotEmpty
opJmpIfNotFirst
// result
opEnd
// fake
opNoop
opcodeMax
)
var opcodeNames = []string{
// match
"opRune",
"opRuneClass",
"opLineBegin",
"opLineEnd",
// capture
"opCapStart",
"opCapEnd",
// stack
"opSplit",
"opJmp",
"opJmpIfNotDefined",
"opJmpIfNotEmpty",
"opJmpIfNotFirst",
// result
"opEnd",
}
func (code progOpcode) String() string {
if code >= opcodeMax {
return ""
}
return opcodeNames[code]
}
type progOp struct {
code progOpcode
r rune
rc runeClass
i uint32
name string
}
func dumpProgOp(b *bytes.Buffer, op *progOp) {
b.WriteString(op.code.String())
switch op.code {
case opRune:
b.WriteString("(")
b.WriteString(strconv.QuoteToASCII(string(op.r)))
b.WriteString(")")
case opRuneClass:
b.WriteString("(")
b.WriteString(op.rc.String())
b.WriteString(")")
case opCapStart, opCapEnd:
b.WriteString("(")
b.WriteString(strconv.QuoteToASCII(op.name))
b.WriteString(")")
case opSplit:
b.WriteString(" -> ")
b.WriteString(strconv.FormatInt(int64(op.i), 10))
case opJmp, opJmpIfNotFirst:
b.WriteString(" -> ")
b.WriteString(strconv.FormatInt(int64(op.i), 10))
case opJmpIfNotDefined, opJmpIfNotEmpty:
b.WriteString("(")
b.WriteString(strconv.QuoteToASCII(op.name))
b.WriteString(")")
b.WriteString(" -> ")
b.WriteString(strconv.FormatInt(int64(op.i), 10))
}
}
type prog struct {
op []progOp
numCap int
}
func dumpProg(b *bytes.Buffer, prog *prog, pc uint32) {
for i := range prog.op {
op := prog.op[i]
pos := strconv.Itoa(i)
if uint32(i) == pc {
pos = "*" + pos
}
b.WriteString(" "[len(pos):])
b.WriteString(pos)
b.WriteByte('\t')
dumpProgOp(b, &op)
b.WriteByte('\n')
}
}
func (p *prog) String() string {
b := bytes.Buffer{}
dumpProg(&b, p, 0)
return b.String()
}

View File

@@ -0,0 +1,116 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import (
"log"
"regexp"
"strings"
"sync"
)
var (
debug = debugT(false)
)
type debugT bool
func (t debugT) Printf(format string, v ...interface{}) {
if t {
log.Printf(format, v...)
}
}
// Template represents a URI Template.
type Template struct {
raw string
exprs []template
// protects the rest of fields
mu sync.Mutex
varnames []string
re *regexp.Regexp
prog *prog
}
// New parses and constructs a new Template instance based on the template.
// New returns an error if the template cannot be recognized.
func New(template string) (*Template, error) {
return (&parser{r: template}).parseURITemplate()
}
// MustNew panics if the template cannot be recognized.
func MustNew(template string) *Template {
ret, err := New(template)
if err != nil {
panic(err)
}
return ret
}
// Raw returns a raw URI template passed to New in string.
func (t *Template) Raw() string {
return t.raw
}
// Varnames returns variable names used in the template.
func (t *Template) Varnames() []string {
t.mu.Lock()
defer t.mu.Unlock()
if t.varnames != nil {
return t.varnames
}
reg := map[string]struct{}{}
t.varnames = []string{}
for i := range t.exprs {
expr, ok := t.exprs[i].(*expression)
if !ok {
continue
}
for _, spec := range expr.vars {
if _, ok := reg[spec.name]; ok {
continue
}
reg[spec.name] = struct{}{}
t.varnames = append(t.varnames, spec.name)
}
}
return t.varnames
}
// Expand returns a URI reference corresponding to the template expanded using the passed variables.
func (t *Template) Expand(vars Values) (string, error) {
var w strings.Builder
for i := range t.exprs {
expr := t.exprs[i]
if err := expr.expand(&w, vars); err != nil {
return w.String(), err
}
}
return w.String(), nil
}
// Regexp converts the template to regexp and returns compiled *regexp.Regexp.
func (t *Template) Regexp() *regexp.Regexp {
t.mu.Lock()
defer t.mu.Unlock()
if t.re != nil {
return t.re
}
var b strings.Builder
b.WriteByte('^')
for _, expr := range t.exprs {
expr.regexp(&b)
}
b.WriteByte('$')
t.re = regexp.MustCompile(b.String())
return t.re
}

216
vendor/github.com/yosida95/uritemplate/v3/value.go generated vendored Normal file
View File

@@ -0,0 +1,216 @@
// Copyright (C) 2016 Kohei YOSHIDA. All rights reserved.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of The BSD 3-Clause License
// that can be found in the LICENSE file.
package uritemplate
import "strings"
// A varname containing pct-encoded characters is not the same variable as
// a varname with those same characters decoded.
//
// -- https://tools.ietf.org/html/rfc6570#section-2.3
type Values map[string]Value
func (v Values) Set(name string, value Value) {
v[name] = value
}
func (v Values) Get(name string) Value {
if v == nil {
return Value{}
}
return v[name]
}
type ValueType uint8
const (
ValueTypeString = iota
ValueTypeList
ValueTypeKV
valueTypeLast
)
var valueTypeNames = []string{
"String",
"List",
"KV",
}
func (vt ValueType) String() string {
if vt < valueTypeLast {
return valueTypeNames[vt]
}
return ""
}
type Value struct {
T ValueType
V []string
}
func (v Value) String() string {
if v.Valid() && v.T == ValueTypeString {
return v.V[0]
}
return ""
}
func (v Value) List() []string {
if v.Valid() && v.T == ValueTypeList {
return v.V
}
return nil
}
func (v Value) KV() []string {
if v.Valid() && v.T == ValueTypeKV {
return v.V
}
return nil
}
func (v Value) Valid() bool {
switch v.T {
default:
return false
case ValueTypeString:
return len(v.V) > 0
case ValueTypeList:
return len(v.V) > 0
case ValueTypeKV:
return len(v.V) > 0 && len(v.V)%2 == 0
}
}
func (v Value) expand(w *strings.Builder, spec varspec, exp *expression) error {
switch v.T {
case ValueTypeString:
val := v.V[0]
var maxlen int
if max := len(val); spec.maxlen < 1 || spec.maxlen > max {
maxlen = max
} else {
maxlen = spec.maxlen
}
if exp.named {
w.WriteString(spec.name)
if val == "" {
w.WriteString(exp.ifemp)
return nil
}
w.WriteByte('=')
}
return exp.escape(w, val[:maxlen])
case ValueTypeList:
var sep string
if spec.explode {
sep = exp.sep
} else {
sep = ","
}
var pre string
var preifemp string
if spec.explode && exp.named {
pre = spec.name + "="
preifemp = spec.name + exp.ifemp
}
if !spec.explode && exp.named {
w.WriteString(spec.name)
w.WriteByte('=')
}
for i := range v.V {
val := v.V[i]
if i > 0 {
w.WriteString(sep)
}
if val == "" {
w.WriteString(preifemp)
continue
}
w.WriteString(pre)
if err := exp.escape(w, val); err != nil {
return err
}
}
case ValueTypeKV:
var sep string
var kvsep string
if spec.explode {
sep = exp.sep
kvsep = "="
} else {
sep = ","
kvsep = ","
}
var ifemp string
var kescape escapeFunc
if spec.explode && exp.named {
ifemp = exp.ifemp
kescape = escapeLiteral
} else {
ifemp = ","
kescape = exp.escape
}
if !spec.explode && exp.named {
w.WriteString(spec.name)
w.WriteByte('=')
}
for i := 0; i < len(v.V); i += 2 {
if i > 0 {
w.WriteString(sep)
}
if err := kescape(w, v.V[i]); err != nil {
return err
}
if v.V[i+1] == "" {
w.WriteString(ifemp)
continue
}
w.WriteString(kvsep)
if err := exp.escape(w, v.V[i+1]); err != nil {
return err
}
}
}
return nil
}
// String returns Value that represents string.
func String(v string) Value {
return Value{
T: ValueTypeString,
V: []string{v},
}
}
// List returns Value that represents list.
func List(v ...string) Value {
return Value{
T: ValueTypeList,
V: v,
}
}
// KV returns Value that represents associative list.
// KV panics if len(kv) is not even.
func KV(kv ...string) Value {
if len(kv)%2 != 0 {
panic("uritemplate.go: count of the kv must be even number")
}
return Value{
T: ValueTypeKV,
V: kv,
}
}