Skip to content

Commit b620f19

Browse files
committed
feat: initial commit
0 parents  commit b620f19

File tree

167 files changed

+14951
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

167 files changed

+14951
-0
lines changed

.circleci/config.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
version: '2'
2+
jobs:
3+
build:
4+
working_directory: /go/src/github.com/qri-io/jsonschema
5+
docker:
6+
- image: circleci/golang:1.9
7+
environment:
8+
GOLANG_ENV: test
9+
PORT: 3000
10+
environment:
11+
TEST_RESULTS: /tmp/test-results
12+
steps:
13+
- checkout
14+
- run: mkdir -p $TEST_RESULTS
15+
- run: go get github.com/jstemmer/go-junit-report github.com/golang/lint/golint
16+
- run:
17+
name: Install deps
18+
command: >
19+
go get -v -d -u
20+
github.com/jstemmer/go-junit-report
21+
- run:
22+
name: Run Lint Tests
23+
command: golint ./...
24+
- run:
25+
name: Run Tests
26+
command: go test -v -race -coverprofile=coverage.txt -covermode=atomic
27+
- run:
28+
name: Publish coverage info to codecov.io
29+
command: bash <(curl -s https://codecov.io/bash)

.circleci/cover.test.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
echo "" > coverage.txt
5+
go test -v -race -coverprofile=profile.out -covermode=atomic github.com/qri-io/varName
6+
if [ -f profile.out ]; then
7+
cat profile.out >> coverage.txt
8+
rm profile.out
9+
fi

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.DS_Store
2+
coverage.txt

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[![Qri](https://img.shields.io/badge/made%20by-qri-magenta.svg?style=flat-square)](https://qri.io)
2+
[![GoDoc](https://godoc.org/github.com/qri-io/varName?status.svg)](http://godoc.org/github.com/qri-io/varName)
3+
[![License](https://img.shields.io/github/license/qri-io/varName.svg?style=flat-square)](./LICENSE)
4+
[![Codecov](https://img.shields.io/codecov/c/github/qri-io/varName.svg?style=flat-square)](https://codecov.io/gh/qri-io/varName)
5+
[![CI](https://img.shields.io/circleci/project/github/qri-io/varName.svg?style=flat-square)](https://circleci.com/gh/qri-io/varName)
6+
[![Go Report Card](https://goreportcard.com/badge/github.com/qri-io/varName)](https://goreportcard.com/report/github.com/qri-io/varName)
7+
8+
9+
# varName 🐫🍢🐍
10+
11+
Provides utility for converting lengthy titles into condensed but still recognizable variable names
12+

codecov.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
codecov:
2+
ci:
3+
- "ci/circle-ci"
4+
notify:
5+
require_ci_to_pass: no
6+
after_n_builds: 2
7+
coverage:
8+
range: "80...100"
9+
comment: off

keywords.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package jsonschema
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"reflect"
7+
)
8+
9+
// Type specifies one of the six json primitive types.
10+
// The value of this keyword MUST be either a string or an array.
11+
// If it is an array, elements of the array MUST be strings and MUST be unique.
12+
// String values MUST be one of the six primitive types ("null", "boolean", "object", "array", "number", or "string"), or
13+
// "integer" which matches any number with a zero fractional part.
14+
// An instance validates if and only if the instance is in any of the sets listed for this keyword.
15+
type Type []string
16+
17+
// Validate checks to see if input data satisfies the type constraint
18+
func (t Type) Validate(data interface{}) error {
19+
jt := DataType(data)
20+
for _, typestr := range t {
21+
if jt == typestr || jt == "integer" && typestr == "number" {
22+
return nil
23+
}
24+
}
25+
return fmt.Errorf(`expected "%v" to be a %s`, data, jt)
26+
}
27+
28+
// primitiveTypes is a map of strings to check types against
29+
var primitiveTypes = map[string]bool{
30+
"null": true,
31+
"boolean": true,
32+
"object": true,
33+
"array": true,
34+
"number": true,
35+
"string": true,
36+
"integer": true,
37+
}
38+
39+
// UnmarshalJSON implements the json.Unmarshaler interface for Type
40+
func (t *Type) UnmarshalJSON(data []byte) error {
41+
var single string
42+
if err := json.Unmarshal(data, &single); err == nil {
43+
*t = Type{single}
44+
} else {
45+
var set []string
46+
if err := json.Unmarshal(data, &set); err == nil {
47+
*t = Type(set)
48+
} else {
49+
return err
50+
}
51+
}
52+
53+
for _, pr := range *t {
54+
if !primitiveTypes[pr] {
55+
return fmt.Errorf(`"%s" is not a valid type`, pr)
56+
}
57+
}
58+
return nil
59+
}
60+
61+
// MarshalJSON implements the json.Marshaler interface for Type
62+
func (t Type) MarshalJSON() ([]byte, error) {
63+
if len(t) == 1 {
64+
return json.Marshal(t[0])
65+
} else if len(t) > 1 {
66+
return json.Marshal([]string(t))
67+
}
68+
return []byte(`""`), nil
69+
}
70+
71+
// Enum validates successfully against this keyword if its value is equal to one of the
72+
// elements in this keyword's array value.
73+
// Elements in the array SHOULD be unique.
74+
// Elements in the array might be of any value, including null.
75+
type Enum []Const
76+
77+
// String implements the stringer interface for Enum
78+
func (e Enum) String() string {
79+
str := "["
80+
for _, c := range e {
81+
str += ", " + c.String()
82+
}
83+
return str + "]"
84+
}
85+
86+
// Validate implements the Validator interface for Enum
87+
func (e Enum) Validate(data interface{}) error {
88+
for _, v := range e {
89+
if err := v.Validate(data); err == nil {
90+
return nil
91+
}
92+
}
93+
return fmt.Errorf("expected %s to be one of %s", data)
94+
}
95+
96+
// Const MAY be of any type, including null.
97+
// An instance validates successfully against this keyword if its
98+
// value is equal to the value of the keyword.
99+
type Const []byte
100+
101+
// String implements the Stringer interface for Const
102+
func (c Const) String() string {
103+
return string(c)
104+
}
105+
106+
// UnmarshalJSON implements the json.Unmarshaler interface for Const
107+
func (c *Const) UnmarshalJSON(data []byte) error {
108+
*c = data
109+
return nil
110+
}
111+
112+
// Validate implements the validate interface for Const
113+
func (c Const) Validate(data interface{}) error {
114+
var con interface{}
115+
if err := json.Unmarshal(c, &con); err != nil {
116+
return err
117+
}
118+
if !reflect.DeepEqual(con, data) {
119+
return fmt.Errorf(`%s must equal %s`, string(c), data)
120+
}
121+
return nil
122+
}

keywords_arrays.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
package jsonschema
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"reflect"
7+
)
8+
9+
// Items MUST be either a valid JSON Schema or an array of valid JSON Schemas.
10+
// This keyword determines how child instances validate for arrays, and does not directly validate the
11+
// immediate instance itself.
12+
// * If "items" is a schema, validation succeeds if all elements in the array successfully validate
13+
// against that schema.
14+
// * If "items" is an array of schemas, validation succeeds if each element of the instance validates
15+
// against the schema at the same position, if any.
16+
// * Omitting this keyword has the same behavior as an empty schema.
17+
type Items struct {
18+
// need to track weather user specficied a singl object or arry
19+
// b/c it affects additionalItems validation semantics
20+
single bool
21+
Schemas []*Schema
22+
}
23+
24+
// Validate implements the Validator interface for Items
25+
func (it Items) Validate(data interface{}) error {
26+
if arr, ok := data.([]interface{}); ok {
27+
if it.single {
28+
for i, elem := range arr {
29+
if err := it.Schemas[0].Validate(elem); err != nil {
30+
return fmt.Errorf("element %d: %s", i, err.Error())
31+
}
32+
}
33+
} else {
34+
for i, vs := range it.Schemas {
35+
if i < len(arr) {
36+
if err := vs.Validate(arr[i]); err != nil {
37+
return fmt.Errorf("element %d: %s", i, err.Error())
38+
}
39+
}
40+
}
41+
}
42+
}
43+
return nil
44+
}
45+
46+
// UnmarshalJSON implements the json.Unmarshaler interface for Items
47+
func (it *Items) UnmarshalJSON(data []byte) error {
48+
s := &Schema{}
49+
if err := json.Unmarshal(data, s); err == nil {
50+
*it = Items{single: true, Schemas: []*Schema{s}}
51+
return nil
52+
}
53+
ss := []*Schema{}
54+
if err := json.Unmarshal(data, &ss); err != nil {
55+
return err
56+
}
57+
*it = Items{Schemas: ss}
58+
return nil
59+
}
60+
61+
// MarshalJSON implements the json.Marshaler interface for Items
62+
func (it Items) MarshalJSON() ([]byte, error) {
63+
if it.single {
64+
return json.Marshal(it.Schemas[0])
65+
}
66+
return json.Marshal([]*Schema(it.Schemas))
67+
}
68+
69+
// AdditionalItems determines how child instances validate for arrays, and does not directly validate the immediate
70+
// instance itself.
71+
// If "items" is an array of schemas, validation succeeds if every instance element at a position greater than
72+
// the size of "items" validates against "additionalItems".
73+
// Otherwise, "additionalItems" MUST be ignored, as the "items" schema (possibly the default value of an empty schema) is applied to all elements.
74+
// Omitting this keyword has the same behavior as an empty schema.
75+
type AdditionalItems struct {
76+
startIndex int
77+
Schema *Schema
78+
}
79+
80+
// Validate implements the Validator interface for AdditionalItems
81+
func (a *AdditionalItems) Validate(data interface{}) error {
82+
if a.startIndex >= 0 {
83+
if arr, ok := data.([]interface{}); ok {
84+
for i, elem := range arr {
85+
if i < a.startIndex {
86+
continue
87+
}
88+
if err := a.Schema.Validate(elem); err != nil {
89+
return fmt.Errorf("element %d: %s", i, err.Error())
90+
}
91+
}
92+
}
93+
}
94+
return nil
95+
}
96+
97+
// UnmarshalJSON implements the json.Unmarshaler interface for AdditionalItems
98+
func (a *AdditionalItems) UnmarshalJSON(data []byte) error {
99+
sch := &Schema{}
100+
if err := json.Unmarshal(data, sch); err != nil {
101+
return err
102+
}
103+
// begin with -1 as default index to prevent AdditionalItems from evaluating
104+
// unless startIndex is explicitly set
105+
*a = AdditionalItems{startIndex: -1, Schema: sch}
106+
return nil
107+
}
108+
109+
// MaxItems MUST be a non-negative integer.
110+
// An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword.
111+
type MaxItems int
112+
113+
// Validate implements the Validator interface for MaxItems
114+
func (m MaxItems) Validate(data interface{}) error {
115+
if arr, ok := data.([]interface{}); ok {
116+
if len(arr) > int(m) {
117+
return fmt.Errorf("%d array items exceeds %d max", len(arr), m)
118+
}
119+
}
120+
return nil
121+
}
122+
123+
// MinItems MUST be a non-negative integer.
124+
// An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword.
125+
// Omitting this keyword has the same behavior as a value of 0.
126+
type MinItems int
127+
128+
// Validate implements the Validator interface for MinItems
129+
func (m MinItems) Validate(data interface{}) error {
130+
if arr, ok := data.([]interface{}); ok {
131+
if len(arr) < int(m) {
132+
return fmt.Errorf("%d array items below %d minimum", len(arr), m)
133+
}
134+
}
135+
return nil
136+
}
137+
138+
// UniqueItems requires array instance elements be unique
139+
// If this keyword has boolean value false, the instance validates successfully. If it has
140+
// boolean value true, the instance validates successfully if all of its elements are unique.
141+
// Omitting this keyword has the same behavior as a value of false.
142+
type UniqueItems bool
143+
144+
// Validate implements the Validator interface for UniqueItems
145+
func (u *UniqueItems) Validate(data interface{}) error {
146+
if arr, ok := data.([]interface{}); ok {
147+
found := []interface{}{}
148+
for _, elem := range arr {
149+
for _, f := range found {
150+
if reflect.DeepEqual(f, elem) {
151+
return fmt.Errorf("arry must be unique: %v", arr)
152+
}
153+
}
154+
found = append(found, elem)
155+
}
156+
}
157+
return nil
158+
}
159+
160+
// Contains validates that an array instance is valid against "contains" if at
161+
// least one of its elements is valid against the given schema.
162+
type Contains Schema
163+
164+
// Validate implements the Validator interface for Contains
165+
func (c *Contains) Validate(data interface{}) error {
166+
v := Schema(*c)
167+
if arr, ok := data.([]interface{}); ok {
168+
for _, elem := range arr {
169+
if err := v.Validate(elem); err == nil {
170+
return nil
171+
}
172+
}
173+
return fmt.Errorf("expected %v to contain at least one of: %s", data, c)
174+
}
175+
return nil
176+
}
177+
178+
// UnmarshalJSON implements the json.Unmarshaler interface for Contains
179+
func (c *Contains) UnmarshalJSON(data []byte) error {
180+
var sch Schema
181+
if err := json.Unmarshal(data, &sch); err != nil {
182+
return err
183+
}
184+
*c = Contains(sch)
185+
return nil
186+
}

0 commit comments

Comments
 (0)