initial commit
commit
7d22424cf1
@ -0,0 +1,4 @@
|
||||
|
||||
*.local*
|
||||
bin/
|
||||
dist/
|
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/alecthomas/repr"
|
||||
"github.com/aziis98/cabret/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Printf("Rendering current project")
|
||||
|
||||
site, err := config.ParseCabretfile("./Cabretfile.yaml")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
repr.Println(site)
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Operation is an enum of various operations
|
||||
type Operation struct {
|
||||
Layout string `yaml:"layout,omitempty"`
|
||||
Target string `yaml:"target,omitempty"`
|
||||
Plugin string `yaml:"plugin,omitempty"`
|
||||
}
|
||||
|
||||
type EntryPoint struct {
|
||||
Source string `yaml:"source"`
|
||||
Pipeline []Operation `yaml:"pipeline"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Output string `yaml:"output,omitempty"`
|
||||
}
|
||||
|
||||
// Site has some configuration for the
|
||||
type Site struct {
|
||||
Config Config `yaml:"config,omitempty"`
|
||||
EntryPoints []EntryPoint `yaml:"entry-points"`
|
||||
}
|
||||
|
||||
func ParseCabretfile(file string) (*Site, error) {
|
||||
f, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
site := new(Site)
|
||||
if err := yaml.NewDecoder(f).Decode(&site); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return site, nil
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
site:
|
||||
entry-points:
|
||||
- source: index.html
|
||||
pipeline:
|
||||
- layout: layouts/base
|
||||
- target: dist/index.html
|
||||
- source: 'posts/{post-name}.md'
|
||||
pipeline:
|
||||
- plugin: markdown
|
||||
- layout: layouts/base
|
||||
- layout: layouts/post.html
|
||||
- target: 'dist/posts/{post-name}/index.html'
|
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>{{ .Metadata.Title }}</title>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: First Post
|
||||
description: Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
publish_date: 2022-12-22 11:00
|
||||
---
|
||||
|
||||
# First Post
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Beatae ratione eos saepe veritatis, temporibus nemo vero rerum earum voluptatibus minus voluptatem neque consequatur necessitatibus, error magnam deserunt! Ad, accusantium excepturi?
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Beatae ratione eos saepe veritatis, temporibus nemo vero rerum earum voluptatibus minus voluptatem neque consequatur necessitatibus, error magnam deserunt! Ad, accusantium excepturi?
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Second Post
|
||||
description: Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
publish_date: 2022-12-22 11:00
|
||||
---
|
||||
|
||||
# Second Post
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Beatae ratione eos saepe veritatis, temporibus nemo vero rerum earum voluptatibus minus voluptatem neque consequatur necessitatibus, error magnam deserunt! Ad, accusantium excepturi?
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Beatae ratione eos saepe veritatis, temporibus nemo vero rerum earum voluptatibus minus voluptatem neque consequatur necessitatibus, error magnam deserunt! Ad, accusantium excepturi?
|
@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Third Post
|
||||
description: Lorem ipsum dolor sit amet consectetur adipisicing elit.
|
||||
publish_date: 2022-12-22 11:00
|
||||
---
|
||||
|
||||
# Third Post
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Beatae ratione eos saepe veritatis, temporibus nemo vero rerum earum voluptatibus minus voluptatem neque consequatur necessitatibus, error magnam deserunt! Ad, accusantium excepturi?
|
||||
|
||||
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Beatae ratione eos saepe veritatis, temporibus nemo vero rerum earum voluptatibus minus voluptatem neque consequatur necessitatibus, error magnam deserunt! Ad, accusantium excepturi?
|
@ -0,0 +1,13 @@
|
||||
module github.com/aziis98/cabret
|
||||
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 // indirect
|
||||
github.com/alecthomas/repr v0.1.1 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/yuin/goldmark v1.5.3 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo=
|
||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
|
||||
github.com/alecthomas/repr v0.1.1 h1:87P60cSmareLAxMc4Hro0r2RBY4ROm0dYwkJNpS4pPs=
|
||||
github.com/alecthomas/repr v0.1.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/yuin/goldmark v1.5.3 h1:3HUJmBFbQW9fhQOzMgseU134xfi6hU+mjWywx5Ty+/M=
|
||||
github.com/yuin/goldmark v1.5.3/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
@ -0,0 +1,111 @@
|
||||
package path
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/participle/v2"
|
||||
"github.com/alecthomas/participle/v2/lexer"
|
||||
)
|
||||
|
||||
type PathPart interface {
|
||||
regex() string
|
||||
}
|
||||
|
||||
type PathSlash struct {
|
||||
Value string `"/"`
|
||||
}
|
||||
|
||||
func (p PathSlash) regex() string {
|
||||
return "/"
|
||||
}
|
||||
|
||||
type PathShortPattern struct {
|
||||
Name string `"{" @Ident "}"`
|
||||
}
|
||||
|
||||
func (p PathShortPattern) regex() string {
|
||||
return fmt.Sprintf("(?P<%s>[^/]+?)", p.Name)
|
||||
}
|
||||
|
||||
type PathLongPattern struct {
|
||||
Name string `"{{" @Ident "}}"`
|
||||
}
|
||||
|
||||
func (p PathLongPattern) regex() string {
|
||||
return fmt.Sprintf("(?P<%s>.+?)", p.Name)
|
||||
}
|
||||
|
||||
type PathString struct {
|
||||
Value string `@Ident`
|
||||
}
|
||||
|
||||
func (p PathString) regex() string {
|
||||
return regexp.QuoteMeta(p.Value)
|
||||
}
|
||||
|
||||
type PathPattern struct {
|
||||
Parts []PathPart `@@+`
|
||||
}
|
||||
|
||||
func (pp PathPattern) regex() string {
|
||||
sb := &strings.Builder{}
|
||||
|
||||
for _, p := range pp.Parts {
|
||||
sb.WriteString(p.regex())
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (pp PathPattern) Match(s string) (bool, map[string]string, error) {
|
||||
r, err := regexp.Compile("^" + pp.regex() + "$")
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
ms := r.FindStringSubmatch(s)
|
||||
if ms == nil {
|
||||
return false, nil, nil
|
||||
}
|
||||
|
||||
ctx := map[string]string{}
|
||||
for i, name := range r.SubexpNames() {
|
||||
ctx[name] = ms[i]
|
||||
}
|
||||
|
||||
return true, ctx, nil
|
||||
}
|
||||
|
||||
var parser = participle.MustBuild[PathPattern](
|
||||
participle.Union[PathPart](
|
||||
&PathSlash{},
|
||||
&PathLongPattern{},
|
||||
&PathShortPattern{},
|
||||
&PathString{},
|
||||
),
|
||||
participle.Lexer(
|
||||
lexer.MustSimple([]lexer.SimpleRule{
|
||||
{Name: "Slash", Pattern: `/`},
|
||||
{Name: "PatternLongOpen", Pattern: `{{`},
|
||||
{Name: "PatternLongClose", Pattern: `}}`},
|
||||
{Name: "PatternShortOpen", Pattern: `{`},
|
||||
{Name: "PatternShortClose", Pattern: `}`},
|
||||
{Name: "Ident", Pattern: `[^/{}]+`},
|
||||
}),
|
||||
),
|
||||
)
|
||||
|
||||
func ParsePattern(path string) (*PathPattern, error) {
|
||||
return parser.ParseString("", path)
|
||||
}
|
||||
|
||||
func MustParsePattern(path string) *PathPattern {
|
||||
p, err := ParsePattern(path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package path_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/aziis98/cabret/path"
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func Test1(t *testing.T) {
|
||||
p, err := path.ParsePattern("/foo/bar")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, p, &path.PathPattern{
|
||||
Parts: []path.PathPart{
|
||||
&path.PathSlash{}, &path.PathString{"foo"}, &path.PathSlash{}, &path.PathString{"bar"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func Test2(t *testing.T) {
|
||||
p, err := path.ParsePattern("posts/{name}.md")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, p, &path.PathPattern{
|
||||
Parts: []path.PathPart{
|
||||
&path.PathString{"posts"}, &path.PathSlash{}, &path.PathShortPattern{"name"}, &path.PathString{".md"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func Test3(t *testing.T) {
|
||||
p, err := path.ParsePattern("posts/{{path}}/{name}.md")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, p, &path.PathPattern{
|
||||
Parts: []path.PathPart{
|
||||
&path.PathString{"posts"},
|
||||
&path.PathSlash{},
|
||||
&path.PathLongPattern{"path"},
|
||||
&path.PathSlash{},
|
||||
&path.PathShortPattern{"name"},
|
||||
&path.PathString{".md"},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func Test4(t *testing.T) {
|
||||
p, err := path.ParsePattern("foo{{path}}/{name}.md")
|
||||
|
||||
assert.NilError(t, err)
|
||||
assert.DeepEqual(t, p, &path.PathPattern{
|
||||
Parts: []path.PathPart{
|
||||
&path.PathString{"foo"},
|
||||
&path.PathLongPattern{"path"},
|
||||
&path.PathSlash{},
|
||||
&path.PathShortPattern{"name"},
|
||||
&path.PathString{".md"},
|
||||
},
|
||||
})
|
||||
|
||||
t.Run("match", func(t *testing.T) {
|
||||
m, ctx, err := p.Match("foo-1/bar/baz/post-1.md")
|
||||
|
||||
assert.NilError(t, err, nil)
|
||||
assert.Equal(t, m, true)
|
||||
assert.DeepEqual(t, ctx, map[string]string{
|
||||
"": "foo-1/bar/baz/post-1.md",
|
||||
"name": "post-1",
|
||||
"path": "-1/bar/baz",
|
||||
})
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue