Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
b5 committed Jan 12, 2018
0 parents commit b620f19
Show file tree
Hide file tree
Showing 167 changed files with 14,951 additions and 0 deletions.
29 changes: 29 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
version: '2'
jobs:
build:
working_directory: /go/src/github.com/qri-io/jsonschema
docker:
- image: circleci/golang:1.9
environment:
GOLANG_ENV: test
PORT: 3000
environment:
TEST_RESULTS: /tmp/test-results
steps:
- checkout
- run: mkdir -p $TEST_RESULTS
- run: go get github.com/jstemmer/go-junit-report github.com/golang/lint/golint
- run:
name: Install deps
command: >
go get -v -d -u
github.com/jstemmer/go-junit-report
- run:
name: Run Lint Tests
command: golint ./...
- run:
name: Run Tests
command: go test -v -race -coverprofile=coverage.txt -covermode=atomic
- run:
name: Publish coverage info to codecov.io
command: bash <(curl -s https://codecov.io/bash)
9 changes: 9 additions & 0 deletions .circleci/cover.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

set -e
echo "" > coverage.txt
go test -v -race -coverprofile=profile.out -covermode=atomic github.com/qri-io/varName
if [ -f profile.out ]; then
cat profile.out >> coverage.txt
rm profile.out
fi
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.DS_Store
coverage.txt
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[![Qri](https://img.shields.io/badge/made%20by-qri-magenta.svg?style=flat-square)](https://qri.io)
[![GoDoc](https://godoc.org/github.com/qri-io/varName?status.svg)](http://godoc.org/github.com/qri-io/varName)
[![License](https://img.shields.io/github/license/qri-io/varName.svg?style=flat-square)](./LICENSE)
[![Codecov](https://img.shields.io/codecov/c/github/qri-io/varName.svg?style=flat-square)](https://codecov.io/gh/qri-io/varName)
[![CI](https://img.shields.io/circleci/project/github/qri-io/varName.svg?style=flat-square)](https://circleci.com/gh/qri-io/varName)
[![Go Report Card](https://goreportcard.com/badge/github.com/qri-io/varName)](https://goreportcard.com/report/github.com/qri-io/varName)


# varName 🐫🍢🐍

Provides utility for converting lengthy titles into condensed but still recognizable variable names

9 changes: 9 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
codecov:
ci:
- "ci/circle-ci"
notify:
require_ci_to_pass: no
after_n_builds: 2
coverage:
range: "80...100"
comment: off
122 changes: 122 additions & 0 deletions keywords.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package jsonschema

import (
"encoding/json"
"fmt"
"reflect"
)

// Type specifies one of the six json primitive types.
// The value of this keyword MUST be either a string or an array.
// If it is an array, elements of the array MUST be strings and MUST be unique.
// String values MUST be one of the six primitive types ("null", "boolean", "object", "array", "number", or "string"), or
// "integer" which matches any number with a zero fractional part.
// An instance validates if and only if the instance is in any of the sets listed for this keyword.
type Type []string

// Validate checks to see if input data satisfies the type constraint
func (t Type) Validate(data interface{}) error {
jt := DataType(data)
for _, typestr := range t {
if jt == typestr || jt == "integer" && typestr == "number" {
return nil
}
}
return fmt.Errorf(`expected "%v" to be a %s`, data, jt)
}

// primitiveTypes is a map of strings to check types against
var primitiveTypes = map[string]bool{
"null": true,
"boolean": true,
"object": true,
"array": true,
"number": true,
"string": true,
"integer": true,
}

// UnmarshalJSON implements the json.Unmarshaler interface for Type
func (t *Type) UnmarshalJSON(data []byte) error {
var single string
if err := json.Unmarshal(data, &single); err == nil {
*t = Type{single}
} else {
var set []string
if err := json.Unmarshal(data, &set); err == nil {
*t = Type(set)
} else {
return err
}
}

for _, pr := range *t {
if !primitiveTypes[pr] {
return fmt.Errorf(`"%s" is not a valid type`, pr)
}
}
return nil
}

// MarshalJSON implements the json.Marshaler interface for Type
func (t Type) MarshalJSON() ([]byte, error) {
if len(t) == 1 {
return json.Marshal(t[0])
} else if len(t) > 1 {
return json.Marshal([]string(t))
}
return []byte(`""`), nil
}

// Enum validates successfully against this keyword if its value is equal to one of the
// elements in this keyword's array value.
// Elements in the array SHOULD be unique.
// Elements in the array might be of any value, including null.
type Enum []Const

// String implements the stringer interface for Enum
func (e Enum) String() string {
str := "["
for _, c := range e {
str += ", " + c.String()
}
return str + "]"
}

// Validate implements the Validator interface for Enum
func (e Enum) Validate(data interface{}) error {
for _, v := range e {
if err := v.Validate(data); err == nil {
return nil
}
}
return fmt.Errorf("expected %s to be one of %s", data)
}

// Const MAY be of any type, including null.
// An instance validates successfully against this keyword if its
// value is equal to the value of the keyword.
type Const []byte

// String implements the Stringer interface for Const
func (c Const) String() string {
return string(c)
}

// UnmarshalJSON implements the json.Unmarshaler interface for Const
func (c *Const) UnmarshalJSON(data []byte) error {
*c = data
return nil
}

// Validate implements the validate interface for Const
func (c Const) Validate(data interface{}) error {
var con interface{}
if err := json.Unmarshal(c, &con); err != nil {
return err
}
if !reflect.DeepEqual(con, data) {
return fmt.Errorf(`%s must equal %s`, string(c), data)
}
return nil
}
186 changes: 186 additions & 0 deletions keywords_arrays.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package jsonschema

import (
"encoding/json"
"fmt"
"reflect"
)

// Items MUST be either a valid JSON Schema or an array of valid JSON Schemas.
// This keyword determines how child instances validate for arrays, and does not directly validate the
// immediate instance itself.
// * If "items" is a schema, validation succeeds if all elements in the array successfully validate
// against that schema.
// * If "items" is an array of schemas, validation succeeds if each element of the instance validates
// against the schema at the same position, if any.
// * Omitting this keyword has the same behavior as an empty schema.
type Items struct {
// need to track weather user specficied a singl object or arry
// b/c it affects additionalItems validation semantics
single bool
Schemas []*Schema
}

// Validate implements the Validator interface for Items
func (it Items) Validate(data interface{}) error {
if arr, ok := data.([]interface{}); ok {
if it.single {
for i, elem := range arr {
if err := it.Schemas[0].Validate(elem); err != nil {
return fmt.Errorf("element %d: %s", i, err.Error())
}
}
} else {
for i, vs := range it.Schemas {
if i < len(arr) {
if err := vs.Validate(arr[i]); err != nil {
return fmt.Errorf("element %d: %s", i, err.Error())
}
}
}
}
}
return nil
}

// UnmarshalJSON implements the json.Unmarshaler interface for Items
func (it *Items) UnmarshalJSON(data []byte) error {
s := &Schema{}
if err := json.Unmarshal(data, s); err == nil {
*it = Items{single: true, Schemas: []*Schema{s}}
return nil
}
ss := []*Schema{}
if err := json.Unmarshal(data, &ss); err != nil {
return err
}
*it = Items{Schemas: ss}
return nil
}

// MarshalJSON implements the json.Marshaler interface for Items
func (it Items) MarshalJSON() ([]byte, error) {
if it.single {
return json.Marshal(it.Schemas[0])
}
return json.Marshal([]*Schema(it.Schemas))
}

// AdditionalItems determines how child instances validate for arrays, and does not directly validate the immediate
// instance itself.
// If "items" is an array of schemas, validation succeeds if every instance element at a position greater than
// the size of "items" validates against "additionalItems".
// Otherwise, "additionalItems" MUST be ignored, as the "items" schema (possibly the default value of an empty schema) is applied to all elements.
// Omitting this keyword has the same behavior as an empty schema.
type AdditionalItems struct {
startIndex int
Schema *Schema
}

// Validate implements the Validator interface for AdditionalItems
func (a *AdditionalItems) Validate(data interface{}) error {
if a.startIndex >= 0 {
if arr, ok := data.([]interface{}); ok {
for i, elem := range arr {
if i < a.startIndex {
continue
}
if err := a.Schema.Validate(elem); err != nil {
return fmt.Errorf("element %d: %s", i, err.Error())
}
}
}
}
return nil
}

// UnmarshalJSON implements the json.Unmarshaler interface for AdditionalItems
func (a *AdditionalItems) UnmarshalJSON(data []byte) error {
sch := &Schema{}
if err := json.Unmarshal(data, sch); err != nil {
return err
}
// begin with -1 as default index to prevent AdditionalItems from evaluating
// unless startIndex is explicitly set
*a = AdditionalItems{startIndex: -1, Schema: sch}
return nil
}

// MaxItems MUST be a non-negative integer.
// An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword.
type MaxItems int

// Validate implements the Validator interface for MaxItems
func (m MaxItems) Validate(data interface{}) error {
if arr, ok := data.([]interface{}); ok {
if len(arr) > int(m) {
return fmt.Errorf("%d array items exceeds %d max", len(arr), m)
}
}
return nil
}

// MinItems MUST be a non-negative integer.
// An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword.
// Omitting this keyword has the same behavior as a value of 0.
type MinItems int

// Validate implements the Validator interface for MinItems
func (m MinItems) Validate(data interface{}) error {
if arr, ok := data.([]interface{}); ok {
if len(arr) < int(m) {
return fmt.Errorf("%d array items below %d minimum", len(arr), m)
}
}
return nil
}

// UniqueItems requires array instance elements be unique
// If this keyword has boolean value false, the instance validates successfully. If it has
// boolean value true, the instance validates successfully if all of its elements are unique.
// Omitting this keyword has the same behavior as a value of false.
type UniqueItems bool

// Validate implements the Validator interface for UniqueItems
func (u *UniqueItems) Validate(data interface{}) error {
if arr, ok := data.([]interface{}); ok {
found := []interface{}{}
for _, elem := range arr {
for _, f := range found {
if reflect.DeepEqual(f, elem) {
return fmt.Errorf("arry must be unique: %v", arr)
}
}
found = append(found, elem)
}
}
return nil
}

// Contains validates that an array instance is valid against "contains" if at
// least one of its elements is valid against the given schema.
type Contains Schema

// Validate implements the Validator interface for Contains
func (c *Contains) Validate(data interface{}) error {
v := Schema(*c)
if arr, ok := data.([]interface{}); ok {
for _, elem := range arr {
if err := v.Validate(elem); err == nil {
return nil
}
}
return fmt.Errorf("expected %v to contain at least one of: %s", data, c)
}
return nil
}

// UnmarshalJSON implements the json.Unmarshaler interface for Contains
func (c *Contains) UnmarshalJSON(data []byte) error {
var sch Schema
if err := json.Unmarshal(data, &sch); err != nil {
return err
}
*c = Contains(sch)
return nil
}
Loading

0 comments on commit b620f19

Please sign in to comment.