1
0
Fork 0
mirror of https://github.com/laravel-ls/uri synced 2026-06-18 11:00:02 +02:00

uri: fix URI json tag and add {,Un}MarshalJSON methods

This commit is contained in:
Koichi Shiraishi 2019-06-05 08:41:34 +09:00
parent a62f200b52
commit 90a5178f88
No known key found for this signature in database
GPG key ID: A71DFD3B4DA7A79B

231
uri.go
View file

@ -5,13 +5,25 @@
package uri
import (
"bytes"
"encoding/json"
"fmt"
"net/url"
"path/filepath"
"golang.org/x/xerrors"
)
// FileScheme schema of filesystem path.
const FileScheme = "file"
const (
// FileScheme schema of filesystem path.
FileScheme = "file"
// HTTPScheme schema of http.
HTTPScheme = "http"
// HTTPSScheme schema of https.
HTTPSScheme = "https"
)
// URI Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986.
//
@ -29,10 +41,10 @@ const FileScheme = "file"
type URI struct {
// Authority is the 'www.msft.com' part of 'http://www.msft.com/some/path?query#fragment'.
// The part between the first double slashes and the next slash.
Authority string `json:"authority,omitempty"`
Authority string `json:"authority"`
// Fragment is the 'fragment' part of 'http://www.msft.com/some/path?query#fragment'.
Fragment string `json:"fragment,omitempty"`
Fragment string `json:"fragment"`
// FsPath returns a string representing the corresponding file system path of this URI.
//
@ -56,18 +68,212 @@ type URI struct {
// namely the server name, would be missing.
//
// Therefore `URI#fsPath` exists - it's sugar to ease working with URIs that represent files on disk (`file` scheme).
FsPath string `json:"fsPath,omitempty"`
FsPath string `json:"fsPath"`
// Path is the '/some/path' part of 'http://www.msft.com/some/path?query#fragment'.
Path string `json:"path,omitempty"`
Path string `json:"path"`
// Query is the 'query' part of 'http://www.msft.com/some/path?query#fragment'.
Query string `json:"query,omitempty"`
Query string `json:"query"`
// Scheme is the 'http' part of 'http://www.msft.com/some/path?query#fragment'.
//
// The part before the first colon.
Scheme string `json:"scheme,omitempty"`
Scheme string `json:"scheme"`
}
// MarshalJSON implements json.Marshaler.
func (u *URI) MarshalJSON() ([]byte, error) {
buf := bytes.NewBuffer(make([]byte, 0))
buf.WriteString("{")
comma := false
// "Authority" field is required
// only required object types supported for marshal checking (for now)
// Marshal the "authority" field
if comma {
buf.WriteString(",")
}
buf.WriteString("\"authority\": ")
if tmp, err := json.Marshal(u.Authority); err != nil {
return nil, err
} else {
buf.Write(tmp)
}
comma = true
// "Fragment" field is required
// only required object types supported for marshal checking (for now)
// Marshal the "fragment" field
if comma {
buf.WriteString(",")
}
buf.WriteString("\"fragment\": ")
if tmp, err := json.Marshal(u.Fragment); err != nil {
return nil, err
} else {
buf.Write(tmp)
}
comma = true
// "FsPath" field is required
// only required object types supported for marshal checking (for now)
// Marshal the "fsPath" field
if comma {
buf.WriteString(",")
}
buf.WriteString("\"fsPath\": ")
if tmp, err := json.Marshal(u.FsPath); err != nil {
return nil, err
} else {
buf.Write(tmp)
}
comma = true
// "Path" field is required
// only required object types supported for marshal checking (for now)
// Marshal the "path" field
if comma {
buf.WriteString(",")
}
buf.WriteString("\"path\": ")
if tmp, err := json.Marshal(u.Path); err != nil {
return nil, err
} else {
buf.Write(tmp)
}
comma = true
// "Query" field is required
// only required object types supported for marshal checking (for now)
// Marshal the "query" field
if comma {
buf.WriteString(",")
}
buf.WriteString("\"query\": ")
if tmp, err := json.Marshal(u.Query); err != nil {
return nil, err
} else {
buf.Write(tmp)
}
comma = true
// "Scheme" field is required
// only required object types supported for marshal checking (for now)
// Marshal the "scheme" field
if comma {
buf.WriteString(",")
}
buf.WriteString("\"scheme\": ")
if tmp, err := json.Marshal(u.Scheme); err != nil {
return nil, err
} else {
buf.Write(tmp)
}
comma = true
buf.WriteString("}")
rv := buf.Bytes()
return rv, nil
}
// UnmarshalJSON implements json.Unmarshaler.
func (u *URI) UnmarshalJSON(b []byte) error {
var authorityReceived bool
var fragmentReceived bool
var fsPathReceived bool
var pathReceived bool
var queryReceived bool
var schemeReceived bool
var jm map[string]json.RawMessage
if err := json.Unmarshal(b, &jm); err != nil {
return err
}
// parse all the defined properties
for k, v := range jm {
switch k {
case "authority":
if err := json.Unmarshal([]byte(v), &u.Authority); err != nil {
return err
}
authorityReceived = true
case "fragment":
if err := json.Unmarshal([]byte(v), &u.Fragment); err != nil {
return err
}
fragmentReceived = true
case "fsPath":
if err := json.Unmarshal([]byte(v), &u.FsPath); err != nil {
return err
}
fsPathReceived = true
case "path":
if err := json.Unmarshal([]byte(v), &u.Path); err != nil {
return err
}
pathReceived = true
case "query":
if err := json.Unmarshal([]byte(v), &u.Query); err != nil {
return err
}
queryReceived = true
case "scheme":
if err := json.Unmarshal([]byte(v), &u.Scheme); err != nil {
return err
}
schemeReceived = true
default:
return fmt.Errorf("additional property not allowed: \"" + k + "\"")
}
}
// check if authority (a required property) was received
if !authorityReceived {
return xerrors.New("\"authority\" is required but was not present")
}
// check if fragment (a required property) was received
if !fragmentReceived {
return xerrors.New("\"fragment\" is required but was not present")
}
// check if fsPath (a required property) was received
if !fsPathReceived {
return xerrors.New("\"fsPath\" is required but was not present")
}
// check if path (a required property) was received
if !pathReceived {
return xerrors.New("\"path\" is required but was not present")
}
// check if query (a required property) was received
if !queryReceived {
return xerrors.New("\"query\" is required but was not present")
}
// check if scheme (a required property) was received
if !schemeReceived {
return xerrors.New("\"scheme\" is required but was not present")
}
return nil
}
// String implements fmt.Stringer.
@ -80,7 +286,7 @@ func (u *URI) String() string {
}
return uri.String()
case "http", "https":
case HTTPScheme, HTTPSScheme:
uri := &url.URL{
Scheme: u.Scheme,
Host: u.Authority,
@ -95,13 +301,6 @@ func (u *URI) String() string {
}
}
// State represents a URI State.
type State struct {
*URI
Mid float64 `json:"$mid,omitempty"`
External string `json:"external,omitempty"`
}
// Parse parses and creates a new URI from uri.
func Parse(s string) *URI {
u, err := url.Parse(s)