Skip to content

Commit

Permalink
minor: hard coded version of tabs, removed extra prism
Browse files Browse the repository at this point in the history
  • Loading branch information
liquidg3 committed May 11, 2020
1 parent fa67c95 commit 5003e95
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 15 deletions.
42 changes: 36 additions & 6 deletions errors/index.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Errors
Build errors that solve problems.
Flexible and informative error reporting.

```bash
# Create a new error definition
Expand Down Expand Up @@ -138,6 +138,8 @@ export interface IYouMustBe18OrOlderErrorOptions extends SchemaDefinitionValues<

Once you create your error definition, you'll want to edit it. Jump into `./src/errors/youMustBe18OrOlder.definition.ts` and update the fields.

Since errors are defined using schemas, you can learn a lot more by reading the [Schema docs](/schemas/index.md).

```ts
// ./src/errors/youMustBe18OrOlder.definition.**ts**

Expand All @@ -151,7 +153,8 @@ const genericDefinition = buildErrorDefinition({
fields: {
suppliedBirthDate: {
type: FieldType.Date,
label: 'Supplied birth date'
label: 'Supplied birth date',
isRequired: true
},
ipAddress: {
type: FieldType.Text,
Expand All @@ -174,25 +177,52 @@ to ensure all the types are updated too.
## Throwing an error

```ts
// import Error class and error codes
import SpruceError from '../errors/SpruceError'
import { ErrorCode } from '#spruce/errors/codes.types'

throw new SpruceError({
code: ErrorCode.YouMustBe18OrOlder,
suppliedBirthDate: someUserSuppliedInput
suppliedBirthDate: someUserSuppliedInput // only field that is required based on definition
})
```

## Catching an error

Catching an error is pretty simple, but since `SpruceError` was designed to be chained, you can throw more relevant errors while passing through
```ts
import { ErrorCode } from '#spruce/errors/codes.types'

try {
assertOldEnough(someUserSuppliedInput)
} catch (err) {
if (err instanceof SpruceError && err.options.code === ErrorCode) {
console.log(err.friendlyMessage()) //
// after checking if the error is a SpruceError you can check the error code
if (err instanceof SpruceError && err.options.code === ErrorCode.YouMustBe18OrOlder) {
console.log(err.friendlyMessage())
console.log(err.options.suppliedBirthDate); // Typescript knows suppliedBirthDate is required
console.log(err.options) // { code: 'YouMustBe18OrOlder', suppliedBirthDate: 1/1/10'}
}

// OR you can do a switch for the code
if (err instanceof SpruceError) {
switch(err.options.code) {
case ErrorCode.YouMustBe18OrOlder:
console.log(`NOT OLD ENOUGH: ${err.options.ipAddress ? `IP Address: ${err.options.ipAddress}` : ''}`)

// chain this error with a new one with a more helpful message
throw new SpruceError({
code: ErrorCode.SignUpFailed,
originalError: err,
friendlyReason: 'Uh oh! I couldn\'t sign you up, check the following errors for more details.'
})
break
case ErrorCode.SomeOtherError:
console.log('Error!!')
break
}
}
}
```
```
## Chaining errors

## Serializing errors
6 changes: 2 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@
greedy: !0,
inside: null,
},
keyword: /\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type|typeof|undefined|var|void|while|with|yield)\b/,
keyword: /\b(?:abstract|as|asserts|async|await|break|case|catch|class|const|constructor|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|is|keyof|let|module|namespace|new|null|of|package|private|protected|public|readonly|return|require|set|static|super|switch|this|throw|try|type[!:]|FieldType\..*|typeof|undefined|var|void|while|with|yield)\b/,
builtin: /\b(?:string|Function|any|number|boolean|Array|symbol|console|Promise|unknown|never)\b/,
}
)),
Expand Down Expand Up @@ -185,11 +185,9 @@
<script src="//unpkg.com/docsify/lib/plugins/search.min.js"></script>
<!-- <script src="//unpkg.com/docsify-glossary/dist/docsify-glossary.min.js"></script> -->
<script src="//cdn.jsdelivr.net/npm/docsify-example-panels"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-tabs@1"></script>
<script src="//cdn.jsdelivr.net/npm/docsify-tabs@1.1.2"></script>

<script src="//cdn.jsdelivr.net/npm/docsify-prism@latest/dist/docsify-prism.min.js"></script>
<script src="//unpkg.com/prismjs@1.17.1/prism.js"></script>
<!-- javascript language prism component -->
<script src="//unpkg.com/prismjs@1.17.1/components/prism-javascript.min.js"></script>
</body>
</html>
174 changes: 171 additions & 3 deletions schemas/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ const shirtDefinition: ISchemaDefinition = buildSchemaDefinition({
// always export the definition as the default from a .definition.ts file
export default shirtDefinition


```

#### ** Validate **
Expand Down Expand Up @@ -151,15 +150,184 @@ phoneNumberField.validate('232324234234234') // throws FieldValidationError

## Building your first schema

Lets start by defining a Ball. From that, we'll create a sub-schemas and a related schema.

```bash
spruce schema:create "Ball"
spruce schema:create "Soccer ball"
spruce schema:create "Vendor"
```

## Updating definitions

We'll start by defining our Vendor schema since it's required for the ball schemas.

```ts
// ./src/schemas/vendor.definition.ts

import Schema, { FieldType, buildSchemaDefinition } from '@sprucelabs/schema'

const vendorDefinition = buildSchemaDefinition({
id: 'vendor',
name: 'Vendor',
description: 'A vendor is a company that makes balls',
fields: {
id: {
type: FieldType.Id,
label: 'Id',
},
name: {
type: FieldType.Text,
label: 'Weight',
hint: 'In ounces',
options: {
min: 0
}
}
}
})

export default vendorDefinition


```
Lets define the fields for the "base" definition that all balls will mixin.
```ts
// ./src/schemas/ball.definition.ts

import Schema, { FieldType, buildSchemaDefinition } from '@sprucelabs/schema'

// import the related definition
import vendorDefinition from './vendor.definition'

const ballDefinition = buildSchemaDefinition({
id: 'ball',
name: 'Ball',
description: 'All balls extend this ball',
fields: {
id: {
type: FieldType.Id,
label: 'Id',
},
weightOz: {
type: FieldType.Number,
label: 'Weight',
hint: 'In ounces',
options: {
min: 0
}
},
color: {
type: FieldType.Select,
label: 'Color',
options: {
choices: [
{ value: 'red', label: 'Red'}
{ value: 'green', label: 'Green'},
{ value: 'blue', label: 'Blue'}
]
}
},
vendor: {
type: FieldType.Schema,
label: 'Vendor',
isRequired: true,
options: {
schema: vendorDefinition
}
}
}
})

export default ballDefinition

```

Now lets define our sub-schema that will extend a Ball.
```ts

// ./src/schemas/soccerBall.definition.ts

import Schema, { FieldType, buildSchemaDefinition } from '@sprucelabs/schema'

// import the "parent" schema definition
import ballDefinition from './ball.definition'

const soccerBallDefinition = buildSchemaDefinition({
id: 'soccerBall',
name: 'Soccer ball',
description: 'A ball that is kicked.',
fields: {
// mixin all ball fields
...ballDefinition.fields,
color: {
// preserve color field props
...ballDefinition.fields.color,
options: {
// preserve color field options
...ballDefinition.fields.color.options,
choices: [
// preserve color choices but add in a new one
...ballDefinition.fields.color.options.choices,
{ value: 'blackAndWhite', label: 'Black and white'}
]
}
}
}
})

export default soccerBallDefinition

```

After you are done editing your definitions you'll need to sync the type files.

```bash
spruce schema:sync
```

## Extending definitions

There is no concept of inheritance in schemas and their definitions. Instead, as you see in the examples above, schemas use a mixin approach with the `...spread` operator.

## Using your definitions
## Using your definitions (instantiating schemas)

I make it really easy to import a definition from anywhere.

`import { SpruceSchemas } from '#spruce/schemas/schemas.types'`

All your definitions will be attached under `SpruceSchemas.local`.
All your definitions will are located at `SpruceSchemas.Local`.

```ts
import { SpruceSchemas } from '#spruce/schemas/schemas.types'
import Schema from '@sprucelabs/schema'

// create a vendor and pass values on instantiation
const vendor = new Schema(SpruceSchemas.Local.Vendor, { name: 'Adidas' })

// create a soccer ball
const ball = new Schema(SpruceSchemas.Local.SoccerBall)

// set values
ball.set('vendor', vendor)
ball.set('color', 'blackAndWhite')

// should pass
if (ball.isValid()) {
console.log('great work')
}

```

## Schema class API

The `Schema` class uses definitions for data validation and normalization. Putting a `Schema` behind your REST, GQL, or Mercury events ensures world class validation and error reporting in an instant.

* `constructor`
* `definition`: [ISchemaDefinition](https://github.com/sprucelabsai/spruce-schema/blob/dev/src/schema.types.ts#L42) - the definition to base this schema on. You can pass it as an object literal or pull it off `SpruceSchemas`
* `values`: [SchemaDefinitionPartialValues<definition>]()




## Field Types
Expand Down
8 changes: 6 additions & 2 deletions spruce.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,12 @@
--code-theme-punctuation: #F6F6F4;
--code-theme-function: #CCF1DF;
--code-theme-operator: #FEF6D8;
--code-theme-selector: #c6c6c6;
--code-inline-border-radius: 6px;
--code-theme-selector: #c6c6c6;

/* inline code */
--code-inline-border-radius: 6px;
--code-inline-background: var(--theme-color) !important;
--code-inline-color: var(--dark-theme-color) !important;

/* panels */
--docsify-example-panels-left-panel-width: 50%;
Expand Down

0 comments on commit 5003e95

Please sign in to comment.