-
Notifications
You must be signed in to change notification settings - Fork 385
/
memfile.go
83 lines (75 loc) · 2.16 KB
/
memfile.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package std
import (
"fmt"
"regexp"
"strings"
"github.com/gnolang/gno/tm2/pkg/errors"
)
type MemFile struct {
Name string
Body string
}
// NOTE: in the future, a MemPackage may represent
// updates/additional-files for an existing package.
type MemPackage struct {
Name string
Path string
Files []*MemFile
}
func (mempkg *MemPackage) GetFile(name string) *MemFile {
for _, memFile := range mempkg.Files {
if memFile.Name == name {
return memFile
}
}
return nil
}
const (
reDomainPart = `gno\.land`
rePathPart = `[a-z][a-z0-9_]*`
rePkgName = `^[a-z][a-z0-9_]*$`
rePkgPath = reDomainPart + `/p/` + rePathPart + `(/` + rePathPart + `)*`
reRlmPath = reDomainPart + `/r/` + rePathPart + `(/` + rePathPart + `)*`
rePkgOrRlmPath = `^(` + rePkgPath + `|` + reRlmPath + `)$`
reFileName = `^[a-zA-Z0-9_]*\.[a-z0-9_\.]*$`
)
// path must not contain any dots after the first domain component.
// file names must contain dots.
// NOTE: this is to prevent conflicts with nested paths.
func (mempkg *MemPackage) Validate() error {
ok, _ := regexp.MatchString(rePkgName, mempkg.Name)
if !ok {
return errors.New(fmt.Sprintf("invalid package name %q", mempkg.Name))
}
ok, _ = regexp.MatchString(rePkgOrRlmPath, mempkg.Path)
if !ok {
return errors.New(fmt.Sprintf("invalid package/realm path %q", mempkg.Path))
}
fnames := map[string]struct{}{}
for _, memfile := range mempkg.Files {
ok, _ := regexp.MatchString(reFileName, memfile.Name)
if !ok {
return errors.New(fmt.Sprintf("invalid file name %q", memfile.Name))
}
if _, exists := fnames[memfile.Name]; exists {
return errors.New(fmt.Sprintf("duplicate file name %q", memfile.Name))
}
fnames[memfile.Name] = struct{}{}
}
return nil
}
// Splits a path into the dirpath and filename.
func SplitFilepath(filepath string) (dirpath string, filename string) {
parts := strings.Split(filepath, "/")
if len(parts) == 1 {
return parts[0], ""
}
last := parts[len(parts)-1]
if strings.Contains(last, ".") {
return strings.Join(parts[:len(parts)-1], "/"), last
} else if last == "" {
return strings.Join(parts[:len(parts)-1], "/"), ""
} else {
return strings.Join(parts, "/"), ""
}
}