- Add complete domain layer: Note, Vault, WikiLink, Tag, Frontmatter, Graph entities - Implement repository interfaces for data access abstraction - Create comprehensive configuration system with YAML and env support - Add CLI entry point with signal handling and graceful shutdown - Fix mermaid diagram syntax in design.md (array notation) - Add CLAUDE.md for development guidance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
79 lines
1.1 KiB
Go
79 lines
1.1 KiB
Go
package domain
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
type Tag struct {
|
|
name string
|
|
}
|
|
|
|
func NewTag(name string) (*Tag, error) {
|
|
if name == "" {
|
|
return nil, fmt.Errorf("tag name cannot be empty")
|
|
}
|
|
|
|
if !strings.HasPrefix(name, "#") {
|
|
name = "#" + name
|
|
}
|
|
|
|
if !isValidTagName(name) {
|
|
return nil, ErrInvalidTag
|
|
}
|
|
|
|
return &Tag{name: name}, nil
|
|
}
|
|
|
|
func (t *Tag) Name() string {
|
|
return t.name
|
|
}
|
|
|
|
func (t *Tag) Parent() *Tag {
|
|
if !t.IsNested() {
|
|
return nil
|
|
}
|
|
|
|
lastSlash := strings.LastIndex(t.name, "/")
|
|
if lastSlash == -1 {
|
|
return nil
|
|
}
|
|
|
|
parentName := t.name[:lastSlash]
|
|
parent, _ := NewTag(parentName)
|
|
return parent
|
|
}
|
|
|
|
func (t *Tag) IsNested() bool {
|
|
return strings.Contains(t.name, "/")
|
|
}
|
|
|
|
func (t *Tag) String() string {
|
|
return t.name
|
|
}
|
|
|
|
func isValidTagName(name string) bool {
|
|
if !strings.HasPrefix(name, "#") {
|
|
return false
|
|
}
|
|
|
|
if len(name) <= 1 {
|
|
return false
|
|
}
|
|
|
|
tagContent := name[1:]
|
|
|
|
if strings.Contains(tagContent, " ") {
|
|
return false
|
|
}
|
|
|
|
if strings.HasPrefix(tagContent, "/") || strings.HasSuffix(tagContent, "/") {
|
|
return false
|
|
}
|
|
|
|
if strings.Contains(tagContent, "//") {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
} |