diff --git a/capability/command/command.go b/capability/command/command.go index 3c51416..de4b08b 100644 --- a/capability/command/command.go +++ b/capability/command/command.go @@ -1,54 +1,11 @@ package command import ( - "errors" "fmt" "strings" ) -const ( - separator = "/" -) - -// ErrNew indicates that the wrapped error was encountered while creating -// a new Command. -var ErrNew = errors.New("failed to create Command from elems") - -// ErrParse indicates that the wrapped error was encountered while -// attempting to parse a string as a Command. -var ErrParse = errors.New("failed to parse Command") - -// ErrorJoin indicates that the wrapped error was encountered while -// attempting to join a new segment to a Command. -var ErrJoin = errors.New("failed to join segments to Command") - -// ErrRequiresLeadingSlash is returned when a parsing a string that -// doesn't start with a [leading slash character]. -// -// [leading slash character]: https://github.com/ucan-wg/spec#segment-structure -var ErrRequiresLeadingSlash = parseError("a command requires a leading slash character") - -// ErrDisallowsTrailingSlash is returned when parsing a string that [ends -// with a trailing slash character]. -// -// [ends with a trailing slash character]: https://github.com/ucan-wg/spec#segment-structure -var ErrDisallowsTrailingSlash = parseError("a command must not include a trailing slash") - -// ErrUCANNamespaceReserved is returned to indicate that a Command's -// first segment would contain the [reserved "ucan" namespace]. -// -// [reserved "ucan" namespace]: https://github.com/ucan-wg/spec#ucan-namespace -var ErrUCANNamespaceReserved = errors.New("the UCAN namespace is reserved") - -// ErrRequiresLowercase is returned if a Command contains, or would contain, -// [uppercase unicode characters]. -// -// [uppercase unicode characters]: https://github.com/ucan-wg/spec#segment-structure -var ErrRequiresLowercase = parseError("UCAN path segments must must not contain upper-case characters") - -func parseError(msg string) error { - return fmt.Errorf("%w: %s", ErrParse, msg) -} +const separator = "/" var _ fmt.Stringer = (*Command)(nil) @@ -66,18 +23,8 @@ type Command struct { // New creates a validated command from the provided list of segment // strings. An error is returned if an invalid Command would be // formed -func New(segments ...string) (*Command, error) { - return newCommand(ErrNew, segments...) -} - -func newCommand(err error, segments ...string) (*Command, error) { - if len(segments) > 0 && segments[0] == "ucan" { - return nil, fmt.Errorf("%w: %w", err, ErrUCANNamespaceReserved) - } - - cmd := Command{segments} - - return &cmd, nil +func New(segments ...string) *Command { + return &Command{segments: segments} } // Parse verifies that the provided string contains the required @@ -100,7 +47,16 @@ func Parse(s string) (*Command, error) { // The leading slash will result in the first element from strings.Split // being an empty string which is removed as strings.Join will ignore it. - return newCommand(ErrParse, strings.Split(s, "/")[1:]...) + return &Command{strings.Split(s, "/")[1:]}, nil +} + +// MustParse is the same as Parse, but panic() if the parsing fail. +func MustParse(s string) *Command { + c, err := Parse(s) + if err != nil { + panic(err) + } + return c } // [Top] is the most powerful capability. @@ -111,22 +67,19 @@ func Parse(s string) (*Command, error) { // // [Top]: https://github.com/ucan-wg/spec#-aka-top func Top() *Command { - cmd, _ := New() - - return cmd + return New() } // IsValid returns true if the provided string is a valid UCAN command. func IsValid(s string) bool { _, err := Parse(s) - return err == nil } // Join appends segments to the end of this command using the required // segment separator. -func (c *Command) Join(segments ...string) (*Command, error) { - return newCommand(ErrJoin, append(c.segments, segments...)...) +func (c *Command) Join(segments ...string) *Command { + return &Command{append(c.segments, segments...)} } // Segments returns the ordered segments that comprise the Command as a @@ -138,5 +91,5 @@ func (c *Command) Segments() []string { // String returns the composed representation the command. This is also // the required wire representation (before IPLD encoding occurs.) func (c *Command) String() string { - return "/" + strings.Join([]string(c.segments), "/") + return "/" + strings.Join(c.segments, "/") } diff --git a/capability/command/command_errors.go b/capability/command/command_errors.go new file mode 100644 index 0000000..71bb1f6 --- /dev/null +++ b/capability/command/command_errors.go @@ -0,0 +1,21 @@ +package command + +import "fmt" + +// ErrRequiresLeadingSlash is returned when a parsing a string that +// doesn't start with a [leading slash character]. +// +// [leading slash character]: https://github.com/ucan-wg/spec#segment-structure +var ErrRequiresLeadingSlash = fmt.Errorf("a command requires a leading slash character") + +// ErrDisallowsTrailingSlash is returned when parsing a string that [ends +// with a trailing slash character]. +// +// [ends with a trailing slash character]: https://github.com/ucan-wg/spec#segment-structure +var ErrDisallowsTrailingSlash = fmt.Errorf("a command must not include a trailing slash") + +// ErrRequiresLowercase is returned if a Command contains, or would contain, +// [uppercase unicode characters]. +// +// [uppercase unicode characters]: https://github.com/ucan-wg/spec#segment-structure +var ErrRequiresLowercase = fmt.Errorf("UCAN path segments must must not contain upper-case characters") diff --git a/capability/command/command_test.go b/capability/command/command_test.go index 11ad06a..7c18f42 100644 --- a/capability/command/command_test.go +++ b/capability/command/command_test.go @@ -73,7 +73,6 @@ func TestParseCommand(t *testing.T) { t.Parallel() cmd, err := command.Parse(testcase.inp) - require.ErrorIs(t, err, command.ErrParse) require.ErrorIs(t, err, testcase.err) require.Nil(t, cmd) }) @@ -134,20 +133,6 @@ func invalidTestcases(t *testing.T) []errorTestcase { }, err: command.ErrDisallowsTrailingSlash, }, - { - testcase: testcase{ - name: "only reserved ucan namespace", - inp: "/ucan", - }, - err: command.ErrUCANNamespaceReserved, - }, - { - testcase: testcase{ - name: "reserved ucan namespace prefix", - inp: "/ucan/elem0/elem1/elem2", - }, - err: command.ErrUCANNamespaceReserved, - }, { testcase: testcase{ name: "uppercase character are present",