-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(files): Clean code; Split utils to uri and schema; Move tran…
…sforms to environment #51
- Loading branch information
Showing
9 changed files
with
263 additions
and
202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.