Skip to content

Commit

Permalink
refactor(files): Clean code; Split utils to uri and schema; Move tran…
Browse files Browse the repository at this point in the history
…sforms to environment #51
  • Loading branch information
korzio committed Sep 22, 2017
1 parent 1fe9339 commit 7c497fb
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 202 deletions.
2 changes: 1 addition & 1 deletion lib/djv.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const { head } = require('./utils');
const { head } = require('./utils/uri');
const { restore } = require('./utils/template');
const formats = require('./utils/formats');
const { generate, State } = require('./utils/state');
Expand Down
13 changes: 10 additions & 3 deletions lib/utils/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ const properties = require('./properties');
const keywords = require('./keywords');
const validators = require('../validators');
const formats = require('./formats');
const { keys } = require('./');
const { keys } = require('./uri');
const { transformation } = require('./schema');

const contains = require('../validators/contains');
const constant = require('../validators/const');
const propertyNames = require('../validators/propertyNames');

const environmentConfig = {
// TODO remove side effects
// TODO make draft-06 default
'draft-06': () => {
Object.assign(properties, {
exclusiveMinimum(schema) {
Expand Down Expand Up @@ -66,7 +66,14 @@ const environmentConfig = {
'uri-template': '!/^(?:(?:[^\\x00-\\x20"\'<>%\\\\^`{|}]|%[0-9a-f]{2})|\\{[+#.\\/;?&=,!@|]?(?:[a-z0-9_]|%[0-9a-f]{2})+(?:\\:[1-9][0-9]{0,3}|\\*)?(?:,(?:[a-z0-9_]|%[0-9a-f]{2})+(?:\\:[1-9][0-9]{0,3}|\\*)?)*\\})*$/i.test(%s)',
});

keys.id = '$id';
Object.assign(keys, {
id: '$id',
});

Object.assign(transformation, {
ANY_SCHEMA: {},
NOT_ANY_SCHEMA: { not: {} },
});
},
};

Expand Down
208 changes: 17 additions & 191 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,219 +1,45 @@
/**
* @module utils
* @description
* Contains small utilities for djv project
* Basic utilities for djv project
*/

const REGEXP_URI = /:\/\//;
const REGEXP_URI_FRAGMENT = /#\/?/;
const REGEXP_URI_PATH = /(^[^:]+:\/\/[^?#]*\/).*/;

// TODO move to environment
const ANY_SCHEMA = {};
const NOT_ANY_SCHEMA = { not: {} };

function asExpression(fn, schema, tpl) {
if (typeof fn !== 'function') {
return fn;
}

return fn(schema, tpl);
}

/**
* @name head
* @name asExpression
* @type {function}
* @description
* Clean an id from its fragment
* @example
* head('http://domain.domain:2020/test/a#test')
* // returns 'http://domain.domain:2020/test/a'
* @param {string} id
* @returns {string} cleaned
* Transform function or string to expression
* @see validators
* @param {function/string} fn
* @param {object} schema
* @param {object} tpl templater instance
* @returns {string} expression
*/
function head(uri) {
if (typeof uri !== 'string') {
return uri;
function asExpression(fn, schema, tpl) {
if (typeof fn !== 'function') {
return fn;
}

const parts = uri.split(REGEXP_URI_FRAGMENT);
return parts[0];
}

function isFullUri(uri) {
return REGEXP_URI.test(uri);
return fn(schema, tpl);
}

/**
* @name path
* @name hasProperty
* @type {function}
* @description
* Gets a scheme, domain and a path part from the uri
* @example
* path('http://domain.domain:2020/test/a?test')
* // returns 'http://domain.domain:2020/test/'
* @param {string} uri
* @returns {string} path
* Check if the property exists in a given object
* @param {object} object
* @param {string} property
* @returns {boolean} exists
*/
function path(uri) {
return uri.replace(REGEXP_URI_PATH, '$1');
}

/**
* @description
* Get the fragment (#...) part of the uri
* @see https://tools.ietf.org/html/rfc3986#section-3
* @param {string} uri
* @returns {string} fragment
*/
function fragment(uri) {
if (typeof uri !== 'string') {
return uri;
}

const parts = uri.split(REGEXP_URI_FRAGMENT);
return parts[1];
}

/**
* @name makePath
* @type function
* @description
* Concat parts into single uri
* @see https://tools.ietf.org/html/rfc3986#section-3
* @param {array[string]} parts
* @returns {string} uri
*/
function makePath(parts) {
return parts
.filter(part => typeof part === 'string')
.reduce((uri, id) => {
// if id is full replace uri
if (!uri.length || isFullUri(id)) {
return id;
}
if (!id) {
return uri;
}

// if fragment found
if (id.indexOf('#') === 0) {
// should replace uri's sharp with id
const sharpUriIndex = uri.indexOf('#');
if (sharpUriIndex === -1) {
return uri + id;
}

return uri.slice(0, sharpUriIndex) + id;
}

// get path part of uri
// and replace the rest with id
const partialUri = path(uri) + id;
return partialUri + (partialUri.indexOf('#') === -1 ? '#' : '');
}, '');
}

function hasProperty(object, property) {
return (
typeof object === 'object' &&
Object.prototype.hasOwnProperty.call(object, property)
);
}

/**
* @name isSchema
* @type {function}
* @description
* Verify the object could be a schema
* Since draft-06 supports boolean as a schema definition
* @param {object} schema
* @returns {boolean} isSchema
*/
function isSchema(schema) {
return (
typeof schema === 'object' ||
typeof schema === 'boolean'
);
}

/**
* @name transformSchema
* @type {function}
* @description
* Transform a schema pseudo presentation
* Since draft-06 supports boolean as a schema definition
* @param {object} schema
* @returns {object} schema
*/
function transformSchema(schema) {
if (schema === true) {
return ANY_SCHEMA;
} else if (schema === false) {
return NOT_ANY_SCHEMA;
}
return schema;
}

function normalize(uri) {
return decodeURIComponent(uri.replace(/~1/g, '/').replace(/~0/g, '~'));
}

/**
* @name makeSchema
* @type {function}
* @description
* Generate a simple schema by a given object
* @param {any} instance
* @returns {object} schema
*/
function makeSchema(instance) {
if (typeof instance !== 'object' || instance === null) {
return { enum: [instance] };
}

if (Array.isArray(instance)) {
return {
items: instance.map(makeSchema),
// other items should be valid by `false` schema, aka not exist at all
additionalItems: false
};
}

const required = Object.keys(instance);
return {
properties: required.reduce((memo, key) => (
Object.assign({}, memo, {
[key]: makeSchema(instance[key])
})
), {}),
required,
// other properties should be valid by `false` schema, aka not exist at all
// additionalProperties: false,
};
}

/**
* @name keys
* @type {object}
* @description
* Keys to access schema attributes
*/
const keys = {
id: 'id',
};

module.exports = {
asExpression,
hasProperty,
isSchema,
transformSchema,
makeSchema,
// TODO move to utils/uri
makePath,
isFullUri,
head,
fragment,
normalize,
keys,
};
91 changes: 91 additions & 0 deletions lib/utils/schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* @module schema
* @description
* Low-level utilities to check, create and transform schemas
*/

/**
* @name transformation
* @type {object}
* @description
* Schema values transformation
*/
const transformation = {
ANY_SCHEMA: true,
NOT_ANY_SCHEMA: false,
};

/**
* @name is
* @type {function}
* @description
* Verify the object could be a schema
* Since draft-06 supports boolean as a schema definition
* @param {object} schema
* @returns {boolean} isSchema
*/
function is(schema) {
return (
typeof schema === 'object' ||
typeof schema === 'boolean'
);
}

/**
* @name transform
* @type {function}
* @description
* Transform a schema pseudo presentation
* Since draft-06 supports boolean as a schema definition
* @param {object} schema
* @returns {object} schema
*/
function transform(schema) {
if (schema === true) {
return transformation.ANY_SCHEMA;
} else if (schema === false) {
return transformation.NOT_ANY_SCHEMA;
}
return schema;
}

/**
* @name make
* @type {function}
* @description
* Generate a simple schema by a given object
* @param {any} instance
* @returns {object} schema
*/
function make(instance) {
if (typeof instance !== 'object' || instance === null) {
return { enum: [instance] };
}

if (Array.isArray(instance)) {
return {
items: instance.map(make),
// other items should be valid by `false` schema, aka not exist at all
additionalItems: false
};
}

const required = Object.keys(instance);
return {
properties: required.reduce((memo, key) => (
Object.assign({}, memo, {
[key]: make(instance[key])
})
), {}),
required,
// other properties should be valid by `false` schema, aka not exist at all
// additionalProperties: false,
};
}

module.exports = {
is,
make,
transform,
transformation,
};
10 changes: 6 additions & 4 deletions lib/utils/state.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
const { list: validators } = require('../validators');
const { body, restore, template } = require('./template');
const { hasProperty } = require('./');
const {
normalize,
makePath,
head,
isFullUri,
hasProperty,
fragment,
transformSchema,
keys,
isSchema,
} = require('./');
} = require('./uri');
const {
is: isSchema,
transform: transformSchema,
} = require('./schema');

function State(schema = {}, env) {
Object.assign(this, {
Expand Down
Loading

0 comments on commit 7c497fb

Please sign in to comment.