Skip to content

Commit

Permalink
feat: check for assets, refactor, error indexes (#17)
Browse files Browse the repository at this point in the history
* refactor flint package

* refactor builtins to share value check logic + asset validator

* add asset rule

* update readme
  • Loading branch information
hay-kot committed Jan 8, 2023
1 parent 55d382b commit 3b352c4
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 287 deletions.
22 changes: 21 additions & 1 deletion README.md
Expand Up @@ -45,8 +45,8 @@ This library is still experimental.
- Date Format
- Field Length
- Disallowed Fields
- Asset Existence
- <s>Field types</s> (coming soon!)
- <s>Asset Existence</s> (coming soon!)

## Installation

Expand Down Expand Up @@ -205,6 +205,26 @@ Supported types are `string` and `[]string`
- "tags"
```

##### `assets`

Checks to see if the filepath defined in the field exists in a relative path to the sources defined in the assets section. This is useful for checking to see if an image exists in a directory.

Supported types are `string` and `[]string`

```yaml
FM008:
level: error
description: "assets required"
assets:
sources:
- "content/"
- "static/"
- "public/"
fields:
- image
- images
```

#### Content

The content is an array of objects that define the content to be linted and the rules to apply to it. You can use a robust glob pattern to define the paths to be linted. See [doublestar](https://github.com/bmatcuk/doublestar) for more details on supported patterns
Expand Down
37 changes: 37 additions & 0 deletions flint/builtins/builtins.go
Expand Up @@ -17,3 +17,40 @@ func New(id, level, desc string) BuiltIns {
Description: desc,
}
}

// valueCheckerFactory is a helper function that creates a Checker for a given field. It
// uses the given function to check the value of the field.
func (b BuiltIns) valueCheckerFactory(fields []string, f func(v string) bool) Checker {
return func(fm *frontmatter.FrontMatter) error {
errors := newValueErrors(b.ID, b.Level, b.Description)

for _, field := range fields {
v, ok := fm.Get(field)
if !ok {
continue
}

check := func(v string, i int) {
if f(v) {
return
}

line, y := fm.KeyCords(field)
errors.Errors = append(errors.Errors, newValueError(line, y, field, i))
}

switch v := v.(type) {
case string:
check(v, -1)
case []any:
mapAnyToStr(v, check)
}
}

if len(errors.Errors) > 0 {
return errors
}

return nil
}
}
55 changes: 0 additions & 55 deletions flint/builtins/enum.go

This file was deleted.

27 changes: 26 additions & 1 deletion flint/builtins/errors.go
@@ -1,6 +1,9 @@
package builtins

import "errors"
import (
"errors"
"fmt"
)

type ValueError struct {
Line string
Expand All @@ -27,6 +30,28 @@ func (m *ValueErrors) Error() string {
return "match failed"
}

// newValueError constructs a ValueError type, if a i >= 0 then the field
// is assumed to be an array and the index is appended to the field name.
//
// Example:
//
// v := newValueError(1, 2, "foo", 3)
// fmt.Println(v.Line)
// // Output: 1:2
// fmt.Println(v.Field)
// // Output: foo[3]
func newValueError(line, y int, field string, i int) ValueError {
fieldStr := field
if i >= 0 {
fieldStr = fmt.Sprintf("%s[%d]", fieldStr, i)
}

return ValueError{
Line: fmtKeyCords(y, line),
Field: fieldStr,
}
}

type FieldError = ValueError

type FieldErrors struct {
Expand Down
13 changes: 0 additions & 13 deletions flint/builtins/extractors.go

This file was deleted.

24 changes: 24 additions & 0 deletions flint/builtins/funcs.go
@@ -0,0 +1,24 @@
package builtins

import "fmt"

// mapAnyToStr maps any slice to string slice and calls f for each string.
// values that don't pass a type assertion to string are ignored.
func mapAnyToStr(vv []any, f func(s string, i int)) {
for i, v := range vv {
s, ok := v.(string)
if !ok {
continue
}

f(s, i)
}
}

func fmtKeyCords(x, y int) string {
if x == -1 {
return "0:0"
}

return fmt.Sprintf("%d:%d", x, y)
}
49 changes: 0 additions & 49 deletions flint/builtins/length.go

This file was deleted.

58 changes: 0 additions & 58 deletions flint/builtins/match.go

This file was deleted.

52 changes: 52 additions & 0 deletions flint/builtins/validators.go
@@ -0,0 +1,52 @@
package builtins

import (
"os"
"path/filepath"
"regexp"

"github.com/hay-kot/flint/pkgs/set"
)

func (b BuiltIns) AssetsFunc(fields []string, dirs []string) Checker {
return b.valueCheckerFactory(fields, func(v string) bool {
for _, dir := range dirs {
path := filepath.Join(dir, v)
if _, err := os.Stat(path); err == nil {
return true
}
}

return false
})
}

func (b BuiltIns) EnumFunc(values []string, fields []string) Checker {
valuesSet := set.New(values...)

return b.valueCheckerFactory(fields, func(v string) bool {
return valuesSet.Contains(v)
})
}

func (b BuiltIns) MatchFunc(patterns []string, fields []string) Checker {
compiled := make([]*regexp.Regexp, 0, len(patterns))
for _, r := range patterns {
compiled = append(compiled, regexp.MustCompile(r))
}

return b.valueCheckerFactory(fields, func(v string) bool {
for _, r := range compiled {
if r.MatchString(v) {
return true
}
}
return false
})
}

func (b BuiltIns) LengthFunc(min, max int, fields []string) Checker {
return b.valueCheckerFactory(fields, func(v string) bool {
return len(v) >= min && len(v) <= max
})
}

0 comments on commit 3b352c4

Please sign in to comment.