Skip to content

Commit

Permalink
docs(state): Add state description #41
Browse files Browse the repository at this point in the history
  • Loading branch information
korzio committed Sep 13, 2017
1 parent 1ef4745 commit ff1b7a7
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 1 deletion.
56 changes: 56 additions & 0 deletions docs/state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# State <a name="title"></a>

The **state document** describes basic concepts of resolving schemas inside the `djv` validator.

## Table of contents <a name="content"></a>

* [State](#title)
* [History](#history)
* [Overview](#overview)
* [State Flow](#state_flow)
* [References](#references)

## History <a name="history"></a>

The state functionality is responsible for the resolving schemas inside `djv` library.
Historically, up to [draft-04 version](https://tools.ietf.org/html/draft-zyp-json-schema-04#section-7.2.3) of json-schema specification there was described two different ways of resolving resources inside a validator. It could be an **canonical** or **inline** dereferencing algorithms. The main difference between two of them was in a way how to interpreter references met during the work of a validator. **canonical** approach assumed that a library will recognize or transform a given uri and then fetch a corresponding resource. Meanwhile the **inline** approach proposed to solve a uri and a resource inside the validator stored schemas.
Most validators implemented the further approach, as there is no need for fetching external resources code. That said the **inline** way of resolving schema is a current standard within the json-schema specification.

## Overview <a name="overview"></a>

The **djv** package contains a few conceptual attendees inside a library:
- [`djv`](https://github.com/korzio/djv/blob/master/lib/djv.js) environment class, by instantiating which allows to use [public methods](https://github.com/korzio/djv#api) such as `addSchema`, `validate`, etc.
- A set of [`validators`](https://github.com/korzio/djv/tree/master/lib/validators) used inside the library. This is a core of an [validation specification](https://tools.ietf.org/html/draft-wright-json-schema-validation-01) implementation.
- [`template`](https://github.com/korzio/djv/blob/master/lib/utils/template.js) utility with a minimum methods to generate high optimized validation functions.
- [`state`](https://github.com/korzio/djv/blob/master/lib/utils/state.js) an internal schema resolution algorithm.

**State** is a key part for resolving schemas inside the validator. Every time the validation function is generating, there are methods in templater which can help resolve sub-schema.

### State Flow <a name="state_flow"></a>

The state remembers all the schemas which were parsed during the schema processing. Each validator has `template` instance injected as an argument, and through its api subschemas can be parsed.

Template API
- **visit** - Create new cache scope and visit given schema
- **resolve** - Get schema validator function by url

State API and actors
- **context** - states or schemas stack. During the parsing validators via calling state API may or may not save subschema in a `context` stack. This stack is used during the resolution process (@see `link` below).
- **link** - A way to generate (or get cached) internal function utility to be used inside final validator function. Contains logic of caching functions and checking for doubled schemas processing.
- **visit** - Calls each registered validator with given schema and template instance. Validator may or may not add code to generated validator function. `Visit` is partially responsible for saving current schema. After executing all validators it reverts the states stack to original length. The `visit` is a general way of parsing schema.

### Why change

Tests are not passing, the resolving process doesn't work perfect.

- `validation of URIs, an invalid protocol-relative URI Reference`
- `ref overrides any sibling keywords, ref valid, maxItems ignored`
- `base URI change - change folder in subschema, number is valid`
- `root ref in remote ref, string is valid`
- `root ref in remote ref, object is invalid`

## Refactoring

### Process

### Example
39 changes: 39 additions & 0 deletions lib/utils/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@ function generate(env, schema, state = new State(schema, env), options) {

State.prototype = Object.assign(Object.create(Array.prototype), {
// template related methods
/**
* @name addEntry
* @type {function}
* @description
* Generates an internal function.
* Usually necessary for `allOf` types of validators.
* Caches generated functions by schema object key.
* @param {string} url
* @param {object} schema
* @returns {number/boolean} index
*/
addEntry(url, schema) {
if (!isSchema(schema)) {
return schema;
Expand All @@ -44,6 +55,15 @@ State.prototype = Object.assign(Object.create(Array.prototype), {

return this.context.push(entry);
},
/**
* @name addReference
* @type {function}
* @description
* Checks for an existing schema in a context stack to avoid double parsing and generation.
* @param {string} url
* @param {object} schema
* @returns {number/boolean} index
*/
addReference(url, schema) {
const schemaIndex = this.indexOf(schema);
// reference to itself
Expand All @@ -65,6 +85,15 @@ State.prototype = Object.assign(Object.create(Array.prototype), {
this.context[doubled] = this.context.length;
}
},
/**
* @name link
* @type {function}
* @description
* Resolves schema by given url and current registered context stack.
* Returns either an index of an entry in a context stack.
* @param {string} url
* @returns {string} entry
*/
link(url) {
const schema = this.resolve(url);
const entry = this.addReference(url, schema) || this.addEntry(url, schema);
Expand Down Expand Up @@ -159,6 +188,16 @@ State.prototype = Object.assign(Object.create(Array.prototype), {

return resolved;
},
/**
* @name visit
* @type {function}
* @description
* Calls each registered validator with given schema and template instance.
* Validator may or may not add code to generated validator function.
* @param {object} pseudoSchema
* @param {object} tpl
* @returns {void}
*/
visit(pseudoSchema, tpl) {
const initialStateLength = this.length;
const initialResolutionLength = this.resolution.length;
Expand Down
19 changes: 18 additions & 1 deletion lib/utils/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,28 @@ function template(state, options) {
data: ['data'],
error,
lines: [],
schema: ['schema'],
push: tpl,
/**
* @name resolve
* @description
* Get schema validator by url
* Call state link to generate or get cached function
* @type {function}
* @param {string} url
* @return {string} functionName
*/
resolve(url) {
return `f${state.link(url)}`;
},
schema: ['schema'],
/**
* @name visit
* @description
* Create new cache scope and visit given schema
* @type {function}
* @param {object} schema
* @return {void}
*/
visit(schema) {
tpl.cached.push({});
state.visit(schema, tpl);
Expand Down

0 comments on commit ff1b7a7

Please sign in to comment.