🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

nativemodels

Package Overview
Dependencies
Maintainers
1
Versions
47
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nativemodels - npm Package Compare versions

Comparing version
2.8.0
to
2.8.1
+37
src/createModel.js
const defaultOptions = require('./lib/defaultOptions');
const defaultRecord = require('./lib/defaultRecord');
const mapRecord = require('./lib/mapRecord');
const parseRecord = require('./lib/parseRecord');
const proxyHandler = require('./lib/proxyHandler');
const recaseKeys = require('./lib/recaseKeys');
const requireAllKeys = require('./lib/requireAllKeys');
const requiredCheck = require('./lib/requiredCheck');
const stripUndefinedKeys = require('./lib/stripUndefinedKeys');
const transformRecord = require('./lib/transformRecord');
const buildRecord = (schema, record, options) => {
const mappedRecord = mapRecord(schema, record, options.caseSensitive);
const transformedRecord = transformRecord(schema, mappedRecord);
const stripedRecord = options.stripUndefined ? stripUndefinedKeys(schema, transformedRecord) : transformedRecord;
const casedRecord = options.caseSensitive ? stripedRecord : recaseKeys(schema, stripedRecord);
const defaultedRecord = defaultRecord(schema, casedRecord);
return defaultedRecord;
};
const createModel = (schema, modelOptions = {}, context = {}) => (record = {}) => {
const options = { ...defaultOptions, ...modelOptions };
const builtRecord = buildRecord(schema, record, options);
if (options.strict) {
requireAllKeys(schema, builtRecord);
}
requiredCheck(schema, builtRecord);
const proxyTarget = parseRecord(schema, builtRecord, options);
return new Proxy(proxyTarget, proxyHandler(schema, options, context));
};
module.exports = createModel;
const base = require('./datatypes/base');
const createType = (overrides, extended = base()) => ({
...extended,
...overrides,
});
module.exports = createType;
/* eslint max-len: off, no-control-regex: off */
const regex = require('./regex');
const email = () =>
regex(
/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/iu,
'email',
);
module.exports = email;
const createType = require('./../createType');
const enumerable = (enumerableValues) =>
createType({
name: 'enumerable',
validCheck: (key, value) => {
if (enumerableValues.indexOf(value) > -1) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not in the list of enumerable values`);
},
});
module.exports = enumerable;
const createType = require('./../createType');
const guid = () =>
createType({
name: 'guid',
parse: (key, value) => value.toUpperCase(),
validCheck: (key, value) => {
if (value === '00000000-0000-0000-0000-000000000000') {
return true;
} else if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not a GUID`);
},
});
module.exports = guid;
const email = require('./email');
const enumerable = require('./enumerable');
const guid = require('./guid');
const phone = require('./phone');
const regex = require('./regex');
const url = require('./url');
module.exports = {
email,
enumerable,
guid,
phone,
regex,
url,
};
const regex = require('./regex');
const phone = () => regex(/^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/iu, 'phone');
module.exports = phone;
const createType = require('./../createType');
const { isRegex } = require('./../lib/checks/types');
const regex = (expression, typeName) =>
createType({
name: typeName,
validCheck: (key, value) => {
if (isRegex(expression) && expression.test(value)) {
return true;
}
if (!isRegex(expression)) {
throw new Error(`NativeModels - Regex expression provided isn't a valid regex`);
}
throw new Error(`NativeModels - Property ${key} (${value}) is not a/an ${typeName}`);
},
});
module.exports = regex;
const regex = require('./regex');
const url = () => regex(/^(https?|ftp):\/\/(-\.)?([^\s/?.#]+\.?)+(\/[^\s]*)?$/iu, 'url');
module.exports = url;
const createType = require('./../createType');
const any = () => createType({ name: 'any' });
module.exports = any;
const createType = require('./../createType');
const parseValue = require('./../lib/parseValue');
const { isArray } = require('./../lib/checks/types');
const array = (type) =>
createType({
name: 'array',
parse: (key, values, parentOptions) => values.map((value) => parseValue(type, key, value, parentOptions)),
validCheck: (key, value) => {
if (isArray(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not an array`);
},
});
module.exports = array;
const overrides = {
name: 'base',
parse: (key, value) => value,
requiredCheck: (key, value) => {
if (value) {
return true;
}
throw new Error(`NativeModels - Property: '${key}' is required`);
},
strictCheck: () => true,
validCheck: () => true,
};
const chainable = {
default(value) {
this.hasDefault = true;
this.defaultValue = value;
return this;
},
from(key, options = {}) {
this.fromKeys = Array.isArray(key) ? key : [key];
this.fromOptions = options;
return this;
},
nullable() {
this.allowNull = true;
return this;
},
required() {
this.isRequired = true;
return this;
},
strict() {
this.requireStrict = true;
return this;
},
transform(fn, type = 'post') {
this.transforms = this.transforms || {};
this.transforms[type] = fn;
return this;
},
};
const base = () => ({
...overrides,
...chainable,
});
module.exports = base;
const createType = require('./../createType');
const { isBoolean, isUndefined } = require('./../lib/checks/types');
const boolean = () =>
createType({
name: 'boolean',
parse: (key, value) => Boolean(value),
requiredCheck: (key, value) => {
if (isUndefined(value) || value === '' || value === null) {
throw new Error(`NativeModels - Property: '${key}' is required`);
}
return true;
},
strictCheck: (key, value) => {
if (isBoolean(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not a boolean`);
},
});
module.exports = boolean;
const createType = require('./../createType');
const { isBuffer } = require('./../lib/checks/types');
const bufferCheck = (key, value, strict) => {
if (isBuffer(value)) {
return true;
}
if (!strict && isBuffer(Buffer.from(value))) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not a buffer`);
};
const buffer = () =>
createType({
name: 'buffer',
parse: (key, value) => Buffer.from(value),
strictCheck: (key, value) => bufferCheck(key, value, true),
validCheck: (key, value) => bufferCheck(key, value),
});
module.exports = buffer;
const createType = require('./../createType');
const createModel = require('./../createModel');
const parseValue = (type, key, value) => createModel({ [key]: type })({ [key]: value })[key];
const getOverridedValue = (type, key, record) => (type ? parseValue(type, key, record[key]) : record[key]);
const isAsync = (fn) => fn && (fn.then || fn.constructor.name === 'AsyncFunction');
const resolve = (response, type, key) => Promise.resolve(response).then((value) => parseValue(type, key, value));
const computeWithType = (userFn, type, { context, key, record }) => {
if (isAsync(userFn)) {
return resolve(userFn(record, key), type, key, context);
}
const response = userFn(record, key, context);
return isAsync(response) ? resolve(response, type, key) : parseValue(type, key, response);
};
const computed = (userFn, type, options = { allowOverride: false }) =>
createType({
fn: (record, key, context) => {
if (options.allowOverride && record[key]) {
return getOverridedValue(type, key, record);
} else if (type) {
return computeWithType(userFn, type, { context, key, record });
}
return userFn(record, key, context);
},
name: 'computed',
type: options.allowOverride ? type : undefined,
});
module.exports = computed;
const createType = require('./../createType');
const { isDate } = require('./../lib/checks/types');
const isValidDate = (key, value, strict = false) => {
if (isDate(value)) {
return true;
}
if (!strict) {
const test = new Date(value);
if (value && test instanceof Date && !isNaN(test)) {
return true;
}
}
throw new Error(`NativeModels - Property ${key} is not a date`);
};
const date = () =>
createType({
name: 'date',
parse: (key, value) => (value instanceof Date ? value : new Date(value)),
strictCheck: (key, value) => isValidDate(key, value, true),
validCheck: (key, value) => isValidDate(key, value),
});
module.exports = date;
const createType = require('./../createType');
const { isNumber } = require('./../lib/checks/types');
const int = require('./int');
const isValidFloat = (key, value, strict = false) => {
if (isNumber(value)) {
return true;
}
if (!strict) {
if (!isNaN(parseFloat(value)) && value !== true && value !== false && value !== '') {
return true;
}
}
throw new Error(`NativeModels - Property ${key} is not a float`);
};
const float = () =>
createType(
{
name: 'float',
parse: (key, value) => parseFloat(value),
strictCheck: (key, value) => isValidFloat(key, value, true),
validCheck: (key, value) => isValidFloat(key, value),
},
int(),
);
module.exports = float;
const any = require('./any');
const array = require('./array');
const base = require('./base');
const boolean = require('./boolean');
const buffer = require('./buffer');
const computed = require('./computed');
const date = require('./date');
const float = require('./float');
const int = require('./int');
const object = require('./object');
const string = require('./string');
module.exports = {
any,
array,
base,
boolean,
buffer,
computed,
date,
float,
int,
object,
string,
};
const createType = require('./../createType');
const isValidInt = (key, value, strict = false) => {
if (Number.isInteger(value)) {
return true;
}
if (!strict && Number.isInteger(parseInt(value)) && parseInt(value) === parseFloat(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not an int`);
};
const int = () =>
createType({
name: 'int',
parse: (key, value) => parseInt(value),
requiredCheck: (key, value) => {
if (value || value === 0) {
return true;
}
throw new Error(`NativeModels - Property: '${key}' is required`);
},
strictCheck: (key, value) => isValidInt(key, value, true),
validCheck: (key, value) => isValidInt(key, value),
});
module.exports = int;
const createType = require('./../createType');
const createModel = require('./../createModel');
const { isObject } = require('./../lib/checks/types');
const object = (schema, options) =>
createType({
name: 'object',
parse: (key, value, parentOptions) =>
schema ? createModel(schema, { ...parentOptions, ...options })(value) : value,
validCheck: (key, value) => {
if (isObject(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not an object`);
},
});
module.exports = object;
const createType = require('./../createType');
const { isString } = require('./../lib/checks/types');
const strictCheck = (key, value, options) => {
if (isString(value)) {
if (options.length && value.length > options.length) {
throw new Error(`NativeModels - Property ${key} is longer than ${options.length}`);
}
return true;
}
throw new Error(`NativeModels - Property ${key} is not a string`);
};
const validCheck = (key, value) => {
if (value === null) {
throw new Error(`NativeModels - Property ${key} is not a string`);
}
return true;
};
const string = (options = {}) =>
createType({
name: 'string',
parse: (key, value) => {
if (options.length) {
return `${value}`.slice(0, options.length);
}
return `${value}`;
},
strictCheck: (key, value) => strictCheck(key, value, options),
validCheck,
});
module.exports = string;
const customtypes = require('./customtypes');
const datatypes = require('./datatypes');
const generateType = require('./lib/type/generate');
module.exports = (schema, usertypes = {}, fns = {}) => {
const obj = typeof schema === 'string' ? JSON.parse(schema) : schema;
const types = { ...datatypes, ...customtypes, ...usertypes };
return Object.keys(obj).reduce((result, key) => ({ ...result, [key]: generateType(obj[key], types, fns) }), {});
};
const createModel = require('./createModel');
const createType = require('./createType');
const customtypes = require('./customtypes');
const datatypes = require('./datatypes');
const generateSchema = require('./generateSchema');
const resolve = require('./resolve');
/* istanbul ignore next */
const resolver = (data, schema) =>
console.warn('DEPRECATION NOTICE: Please use resolve() instead of resolver()') || resolve(data, schema);
module.exports = {
createModel,
createType,
customtypes,
datatypes,
generateSchema,
resolve,
resolver,
};
const invalidTypeCheck = (type, key) => {
if (!type.validCheck || !type.parse) {
console.log(`Schema Key: '${key}' is not a valid datatype or customtype`);
return true;
}
return false;
};
module.exports = invalidTypeCheck;
const requiredCheck = (type, key, value) => (type.isRequired ? type.requiredCheck(key, value) : true);
module.exports = requiredCheck;
const strictCheck = (type, key, value) =>
type.requireStrict && type.strictCheck ? type.strictCheck(key, value) : true;
module.exports = strictCheck;
// Pre ES5 => value && typeof value === 'object' && value.constructor === Array;
const isArray = (value) => Array.isArray(value);
const isBoolean = (value) => typeof value === 'boolean';
const isBuffer = (value) => Buffer.isBuffer(value);
const isDate = (value) => value instanceof Date;
// const isError = (value) => value instanceof Error && typeof value.message !== 'undefined';
// const isFunction = (value) => typeof value === 'function';
const isNull = (value) => value === null;
const isNumber = (value) => typeof value === 'number' && isFinite(value);
const isObject = (value) => value && typeof value === 'object' && value.constructor === Object;
const isRegex = (value) => value && typeof value === 'object' && value.constructor === RegExp;
const isString = (value) => typeof value === 'string' || value instanceof String;
// const isSymbol = (value) => typeof value === 'symbol';
const isUndefined = (value) => typeof value === 'undefined';
module.exports = {
isArray,
isBoolean,
isBuffer,
isDate,
// isError,
// isFunction,
isNull,
isNumber,
isObject,
isRegex,
isString,
// isSymbol,
isUndefined,
};
const validCheck = (type, key, value) => type.validCheck(key, value);
module.exports = validCheck;
const defaultOptions = {
// Allow nulls on all columns
allowNulls: false,
// Ignores case when initializing object from model
caseSensitive: true,
// Pass options to all children
passOptions: false,
// Throws an error if key is not in schema
strict: false,
// Strip undefined values passed in
stripUndefined: true,
};
module.exports = defaultOptions;
const defaultValue = require('./defaultValue');
const defaultRecord = (schema, record) => ({
...record,
...Object.keys(schema).reduce(
(result, key) => ({
...result,
...(schema[key].hasDefault ? { [key]: record[key] || defaultValue(schema[key].defaultValue) } : {}),
}),
{},
),
});
module.exports = defaultRecord;
const defaultValue = (value) => (typeof value === 'function' ? value() : value);
module.exports = defaultValue;
const recaseRecord = (record) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
[key.toLowerCase()]: record[key],
}),
{},
);
const getFromKeyValue = (schema, record, { caseSensitive, key }) => {
const {
fromOptions: { caseSensitive: fromOptionsCaseSensitive },
} = schema[key];
const lowerCase = typeof fromOptionsCaseSensitive === 'undefined' ? !caseSensitive : !fromOptionsCaseSensitive;
const fromKeys = [key, ...schema[key].fromKeys].map((key) => (lowerCase ? key.toLowerCase() : key));
const recasedRecord = lowerCase ? recaseRecord(record) : record;
const value = fromKeys.find((fromKey) => typeof recasedRecord[fromKey] !== 'undefined');
return recasedRecord[value];
};
const mapRecord = (schema, record, caseSensitive) => ({
...record,
...Object.keys(schema)
.filter((key) => schema[key].fromKeys)
.reduce(
(result, key) => ({
...result,
...{ [key]: getFromKeyValue(schema, record, { caseSensitive, key }) },
}),
{},
),
});
module.exports = mapRecord;
const parseValue = require('./parseValue');
const parseRecord = (schema, record, options) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
...(schema[key] ? { [key]: parseValue(schema[key], key, record[key], options) } : {}),
}),
{},
);
module.exports = parseRecord;
/* eslint-disable max-params */
const invalidTypeCheck = require('./checks/invalidType');
const { isNull } = require('./checks/types');
const transformValue = require('./transformValue');
const checks = {
required: require('./checks/required'),
strict: require('./checks/strict'),
valid: require('./checks/valid'),
};
const runChecks = (type, key, value) => {
Object.keys(checks).forEach((name) => {
if (!checks[name](type, key, value)) {
throw new Error(`NativeModels - Failed ${name} check. Key: ${key} | Value: ${value}`);
}
});
};
const parseValue = (type, key, value, options) => {
if ((type.allowNull || (options && options.allowNulls)) && isNull(value)) {
return null;
} else if (invalidTypeCheck(type, key, value)) {
return value;
}
runChecks(type, key, value);
const parsedValue = type.parse(key, value, options && options.passOptions ? options : {});
return transformValue(type, parsedValue, 'post');
};
module.exports = parseValue;
/* eslint max-params: off */
const parseValue = require('./parseValue');
const get = (schema, target, property, context) => {
if (schema[property]) {
return schema[property].fn ? schema[property].fn(target, property, context) : target[property];
}
return undefined;
};
const getOwnPropertyDescriptor = (schema, target, property) =>
schema[property]
? {
configurable: true,
enumerable: true,
value: schema[property].fn ? '[computedValue]' : target[property],
writable: true,
}
: undefined;
const ownKeys = (schema, target) => {
const allKeys = [...Object.keys(target), ...Object.keys(schema).filter((key) => schema[key].fn)];
return [...new Set(allKeys)];
};
const set = (schema, target, property, value, options) => {
if (!schema[property]) {
throw new Error(`NativeModels - ${property} is not a property of model`);
}
const type = schema[property].fn && schema[property].type ? schema[property].type : schema[property];
target[property] = parseValue(type, property, value, options);
return true;
};
const proxyHandler = (schema, options, context) => ({
get: (target, property) => get(schema, target, property, context),
getOwnPropertyDescriptor: (target, property) => getOwnPropertyDescriptor(schema, target, property),
ownKeys: (target) => ownKeys(schema, target),
set: (target, property, value) => set(schema, target, property, value, options),
});
module.exports = proxyHandler;
const recaseKeys = (schema, record) => {
const keyMap = Object.keys(schema).reduce(
(result, key) => ({
...result,
[key.toLowerCase()]: key,
}),
{},
);
return Object.keys(record).reduce(
(result, key) => ({
...result,
[keyMap[key.toLowerCase()] || key]: record[key],
}),
{},
);
};
module.exports = recaseKeys;
const strictCheck = (schema, record) =>
Object.keys(record).forEach((key) => {
if (!schema[key]) {
throw new Error(`NativeModels - Property: '${key}' is not defined in the schema`);
}
});
module.exports = strictCheck;
const required = require('./checks/required');
const requiredCheck = (schema, record) =>
Object.keys(schema).forEach((key) => {
required(schema[key], key, record[key]);
});
module.exports = requiredCheck;
const stripUndefinedKeys = (schema, record) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
...(typeof record[key] === 'undefined' ? {} : { [key]: record[key] }),
}),
{},
);
module.exports = stripUndefinedKeys;
const transformValue = require('./transformValue');
const transformRecord = (schema, record) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
[key]: schema[key] ? transformValue(schema[key], record[key], 'pre') : record[key],
}),
{},
);
module.exports = transformRecord;
const transformValue = (type, value, key) =>
type.transforms && type.transforms[key] ? type.transforms[key](value) : value;
module.exports = transformValue;
module.exports = (value, types, fns) => {
if (value.type === 'computed') {
return types[value.type](fns[value.fn]);
} else if (value.type === 'object') {
return types[value.type](require('./../../generateSchema')(value.schema, types, fns));
} else if (value.type === 'array') {
return types[value.type](require('./generate')(value.item, types, fns));
}
return types[value.type]();
};
module.exports = (value, type, fns) => {
value.default && type.default(value.default);
value.nullable && type.nullable();
value.required && type.required();
value.strict && type.strict();
value.transform && type.transform(fns[value.transform]);
return type;
};
const buildType = require('./build');
const extendType = require('./extend');
module.exports = (value, types, fns) => {
if (typeof value === 'string') {
if (types[value]) {
return types[value]();
}
throw new Error(`NativeModels - ${value} is not a valid type`);
} else if (types[value.type]) {
const type = buildType(value, types, fns);
return extendType(value, type, fns);
}
throw new Error(`NativeModels - ${value} is not a valid type`);
};
/* eslint-disable no-use-before-define */
const { isArray, isObject } = require('./lib/checks/types');
const createModel = require('./createModel');
const cascadeResolve = (value) => {
if (isArray(value)) {
return Promise.all(value.map(cascadeResolve));
} else if (isObject(value) && !value.then) {
return resolve(value);
}
return value;
};
const resolved = (keys, values, schema) => {
const data = keys.reduce((result, key, index) => ({ ...result, [key]: values[index] }), {});
return schema ? createModel(schema)(data) : data;
};
const resolve = (data, schema) => {
const keys = Object.keys(data);
return Promise.all(keys.map((key) => cascadeResolve(data[key]))).then((values) => resolved(keys, values, schema));
};
module.exports = resolve;
+12
-15

@@ -9,15 +9,12 @@ {

"devDependencies": {
"codecov": "^3.5.0",
"eslint": "^6.1.0",
"eslint-config-prettier": "^6.0.0",
"eslint-plugin-jest": "^22.14.0",
"eslint-plugin-react": "^7.14.3",
"gh-pages": "^2.0.1",
"husky": "^3.0.1",
"jest": "^24.8.0",
"jest-junit": "^7.0.0",
"js-yaml": "^3.13.1",
"lint-staged": "^9.2.1",
"lodash.isequal": "^4.5.0",
"prettier": "^1.18.2"
"eslint": "6.7.2",
"eslint-config-prettier": "6.7.0",
"eslint-plugin-jest": "23.1.1",
"gh-pages": "2.1.1",
"husky": "3.1.0",
"jest": "24.9.0",
"js-yaml": "3.13.1",
"lint-staged": "9.5.0",
"lodash.isequal": "4.5.0",
"prettier": "1.19.1"
},

@@ -56,5 +53,5 @@ "engines": {

"staged": "lint-staged",
"test": "jest --coverage"
"test": "./node_modules/.bin/jest"
},
"version": "2.8.0"
"version": "2.8.1"
}

@@ -10,44 +10,12 @@ <h1 align="center">

<!-- NPM -->
[![Version](https://img.shields.io/npm/v/nativemodels?style=for-the-badge)](https://npmjs.org/package/nativemodels)
[![Version](https://flat.badgen.net/npm/v/nativemodels)](https://npmjs.org/package/nativemodels)
[![Weekly Downloads](https://flat.badgen.net/npm/dw/nativemodels)](https://npmjs.org/package/nativemodels)
[![License](https://flat.badgen.net/npm/license/nativemodels)](https://npmjs.org/package/nativemodels)
[![Build Status](https://img.shields.io/github/workflow/status/Prefinem/nativemodels/ci?style=for-the-badge)](https://github.com/Prefinem/nativemodels/actions) [![Maintainability](https://img.shields.io/codeclimate/coverage-letter/Prefinem/nativemodels?style=for-the-badge)](https://codeclimate.com/github/Prefinem/nativemodels/maintainability) [![Test Coverage](https://img.shields.io/codecov/c/github/Prefinem/nativemodels?style=for-the-badge)](https://codecov.io/gh/Prefinem/nativemodels)
<!-- GitHub -->
![Monthly Downloads](https://img.shields.io/npm/dm/nativemodels?style=for-the-badge)
[![Open Issues](https://flat.badgen.net/github/open-issues/Prefinem/nativemodels)](https://github.com/Prefinem/nativemodels)
[![Stars](https://flat.badgen.net/github/stars/Prefinem/nativemodels)](https://github.com/Prefinem/nativemodels)
[![Open PRs](https://flat.badgen.net/github/open-prs/Prefinem/nativemodels)](https://github.com/Prefinem/nativemodels)
![Issues](https://img.shields.io/github/issues/Prefinem/nativemodels?style=for-the-badge) ![Pull Requests](https://img.shields.io/github/issues-pr/Prefinem/nativemodels?style=for-the-badge)
<!-- Dependencies -->
![Dependencies](https://img.shields.io/david/Prefinem/nativemodels?style=for-the-badge) ![Dev Dependencies](https://img.shields.io/david/dev/Prefinem/nativemodels?style=for-the-badge)
[![Dependencies](https://flat.badgen.net/david/dep/Prefinem/nativemodels)](https://david-dm.org/Prefinem/nativemodels)
[![DevDependencies](https://flat.badgen.net/david/dev/Prefinem/nativemodels)](https://david-dm.org/Prefinem/nativemodels?type=dev)
[![PeerDependencies](https://flat.badgen.net/david/peer/Prefinem/nativemodels)](https://david-dm.org/Prefinem/nativemodels?type=peer)
<!-- PackagePhobia -->
[![Install Size](https://flat.badgen.net/packagephobia/install/nativemodels)](https://packagephobia.now.sh/result?p=nativemodels)
[![Publish Size](https://flat.badgen.net/packagephobia/publish/nativemodels)](https://packagephobia.now.sh/result?p=nativemodels)
<!-- Travis -->
[![Build Status](https://flat.badgen.net/travis/Prefinem/nativemodels)](https://travis-ci.com/Prefinem/nativemodels)
<!-- CircleCI -->
[![Build Status](https://flat.badgen.net/circleci/github/Prefinem/nativemodels)](https://circleci.com/gh/Prefinem/nativemodels)
<!-- CodeCov -->
[![Code Coverage](https://flat.badgen.net/codecov/c/github/Prefinem/nativemodels)](https://codecov.io/gh/Prefinem/nativemodels)
<!-- CodeClimate -->
[![Technical Debt](https://flat.badgen.net/codeclimate/tech-debt/Prefinem/nativemodels)](https://codeclimate.com/github/Prefinem/nativemodels)
[![Maintainability](https://flat.badgen.net/codeclimate/maintainability/Prefinem/nativemodels)](https://codeclimate.com/github/Prefinem/nativemodels)
[![Coverage](https://flat.badgen.net/codeclimate/coverage/Prefinem/nativemodels)](https://codeclimate.com/github/Prefinem/nativemodels)
[![Lines of Code](https://flat.badgen.net/codeclimate/loc/Prefinem/nativemodels)](https://codeclimate.com/github/Prefinem/nativemodels)
Native Models provides a way to map objects in a clean and typed way. The main goal is to ensure runtime type checking and consistent models for APIs.

@@ -57,6 +25,6 @@

* [Yup](https://www.npmjs.com/package/yup)
* [Joi](https://www.npmjs.com/package/joi)
* [Schema Object](https://www.npmjs.com/package/schema-object)
* [ObjectModel](https://www.npmjs.com/package/objectmodel)
- [Yup](https://www.npmjs.com/package/yup)
- [Joi](https://www.npmjs.com/package/joi)
- [Schema Object](https://www.npmjs.com/package/schema-object)
- [ObjectModel](https://www.npmjs.com/package/objectmodel)

@@ -63,0 +31,0 @@ ## Getting Started

const defaultOptions = require('./lib/defaultOptions');
const defaultRecord = require('./lib/defaultRecord');
const mapRecord = require('./lib/mapRecord');
const parseRecord = require('./lib/parseRecord');
const proxyHandler = require('./lib/proxyHandler');
const recaseKeys = require('./lib/recaseKeys');
const requireAllKeys = require('./lib/requireAllKeys');
const requiredCheck = require('./lib/requiredCheck');
const stripUndefinedKeys = require('./lib/stripUndefinedKeys');
const transformRecord = require('./lib/transformRecord');
const buildRecord = (schema, record, options) => {
const mappedRecord = mapRecord(schema, record, options.caseSensitive);
const transformedRecord = transformRecord(schema, mappedRecord);
const stripedRecord = options.stripUndefined ? stripUndefinedKeys(schema, transformedRecord) : transformedRecord;
const casedRecord = options.caseSensitive ? stripedRecord : recaseKeys(schema, stripedRecord);
const defaultedRecord = defaultRecord(schema, casedRecord);
return defaultedRecord;
};
const createModel = (schema, modelOptions = {}, context = {}) => (record = {}) => {
const options = { ...defaultOptions, ...modelOptions };
const builtRecord = buildRecord(schema, record, options);
if (options.strict) {
requireAllKeys(schema, builtRecord);
}
requiredCheck(schema, builtRecord);
const proxyTarget = parseRecord(schema, builtRecord, options);
return new Proxy(proxyTarget, proxyHandler(schema, options, context));
};
module.exports = createModel;
const base = require('./datatypes/base');
const createType = (overrides, extended = base()) => ({
...extended,
...overrides,
});
module.exports = createType;
/* eslint max-len: off, no-control-regex: off */
const regex = require('./regex');
const email = () =>
regex(
/^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/iu,
'email',
);
module.exports = email;
const createType = require('./../createType');
const enumerable = (enumerableValues) =>
createType({
name: 'enumerable',
validCheck: (key, value) => {
if (enumerableValues.indexOf(value) > -1) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not in the list of enumerable values`);
},
});
module.exports = enumerable;
const createType = require('./../createType');
const guid = () =>
createType({
name: 'guid',
parse: (key, value) => value.toUpperCase(),
validCheck: (key, value) => {
if (value === '00000000-0000-0000-0000-000000000000') {
return true;
} else if (/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not a GUID`);
},
});
module.exports = guid;
const email = require('./email');
const enumerable = require('./enumerable');
const guid = require('./guid');
const phone = require('./phone');
const regex = require('./regex');
const url = require('./url');
module.exports = {
email,
enumerable,
guid,
phone,
regex,
url,
};
const regex = require('./regex');
const phone = () => regex(/^(\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}$/iu, 'phone');
module.exports = phone;
const createType = require('./../createType');
const { isRegex } = require('./../lib/checks/types');
const regex = (expression, typeName) =>
createType({
name: typeName,
validCheck: (key, value) => {
if (isRegex(expression) && expression.test(value)) {
return true;
}
if (!isRegex(expression)) {
throw new Error(`NativeModels - Regex expression provided isn't a valid regex`);
}
throw new Error(`NativeModels - Property ${key} (${value}) is not a/an ${typeName}`);
},
});
module.exports = regex;
const regex = require('./regex');
const url = () => regex(/^(https?|ftp):\/\/(-\.)?([^\s/?.#]+\.?)+(\/[^\s]*)?$/iu, 'url');
module.exports = url;
const createType = require('./../createType');
const any = () => createType({ name: 'any' });
module.exports = any;
const createType = require('./../createType');
const parseValue = require('./../lib/parseValue');
const { isArray } = require('./../lib/checks/types');
const array = (type) =>
createType({
name: 'array',
parse: (key, values, parentOptions) => values.map((value) => parseValue(type, key, value, parentOptions)),
validCheck: (key, value) => {
if (isArray(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not an array`);
},
});
module.exports = array;
const overrides = {
name: 'base',
parse: (key, value) => value,
requiredCheck: (key, value) => {
if (value) {
return true;
}
throw new Error(`NativeModels - Property: '${key}' is required`);
},
strictCheck: () => true,
validCheck: () => true,
};
const chainable = {
default(value) {
this.hasDefault = true;
this.defaultValue = value;
return this;
},
from(key, options = {}) {
this.fromKeys = Array.isArray(key) ? key : [key];
this.fromOptions = options;
return this;
},
nullable() {
this.allowNull = true;
return this;
},
required() {
this.isRequired = true;
return this;
},
strict() {
this.requireStrict = true;
return this;
},
transform(fn, type = 'post') {
this.transforms = this.transforms || {};
this.transforms[type] = fn;
return this;
},
};
const base = () => ({
...overrides,
...chainable,
});
module.exports = base;
const createType = require('./../createType');
const { isBoolean, isUndefined } = require('./../lib/checks/types');
const boolean = () =>
createType({
name: 'boolean',
parse: (key, value) => Boolean(value),
requiredCheck: (key, value) => {
if (isUndefined(value) || value === '' || value === null) {
throw new Error(`NativeModels - Property: '${key}' is required`);
}
return true;
},
strictCheck: (key, value) => {
if (isBoolean(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not a boolean`);
},
});
module.exports = boolean;
const createType = require('./../createType');
const { isBuffer } = require('./../lib/checks/types');
const bufferCheck = (key, value, strict) => {
if (isBuffer(value)) {
return true;
}
if (!strict && isBuffer(Buffer.from(value))) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not a buffer`);
};
const buffer = () =>
createType({
name: 'buffer',
parse: (key, value) => Buffer.from(value),
strictCheck: (key, value) => bufferCheck(key, value, true),
validCheck: (key, value) => bufferCheck(key, value),
});
module.exports = buffer;
const createType = require('./../createType');
const createModel = require('./../createModel');
const parseValue = (type, key, value) => createModel({ [key]: type })({ [key]: value })[key];
const getOverridedValue = (type, key, record) => (type ? parseValue(type, key, record[key]) : record[key]);
const isAsync = (fn) => fn && (fn.then || fn.constructor.name === 'AsyncFunction');
const resolve = (response, type, key) => Promise.resolve(response).then((value) => parseValue(type, key, value));
const computeWithType = (userFn, type, { context, key, record }) => {
if (isAsync(userFn)) {
return resolve(userFn(record, key), type, key, context);
}
const response = userFn(record, key, context);
return isAsync(response) ? resolve(response, type, key) : parseValue(type, key, response);
};
const computed = (userFn, type, options = { allowOverride: false }) =>
createType({
fn: (record, key, context) => {
if (options.allowOverride && record[key]) {
return getOverridedValue(type, key, record);
} else if (type) {
return computeWithType(userFn, type, { context, key, record });
}
return userFn(record, key, context);
},
name: 'computed',
type: options.allowOverride ? type : undefined,
});
module.exports = computed;
const createType = require('./../createType');
const { isDate } = require('./../lib/checks/types');
const isValidDate = (key, value, strict = false) => {
if (isDate(value)) {
return true;
}
if (!strict) {
const test = new Date(value);
if (value && test instanceof Date && !isNaN(test)) {
return true;
}
}
throw new Error(`NativeModels - Property ${key} is not a date`);
};
const date = () =>
createType({
name: 'date',
parse: (key, value) => (value instanceof Date ? value : new Date(value)),
strictCheck: (key, value) => isValidDate(key, value, true),
validCheck: (key, value) => isValidDate(key, value),
});
module.exports = date;
const createType = require('./../createType');
const { isNumber } = require('./../lib/checks/types');
const int = require('./int');
const isValidFloat = (key, value, strict = false) => {
if (isNumber(value)) {
return true;
}
if (!strict) {
if (!isNaN(parseFloat(value)) && value !== true && value !== false && value !== '') {
return true;
}
}
throw new Error(`NativeModels - Property ${key} is not a float`);
};
const float = () =>
createType(
{
name: 'float',
parse: (key, value) => parseFloat(value),
strictCheck: (key, value) => isValidFloat(key, value, true),
validCheck: (key, value) => isValidFloat(key, value),
},
int(),
);
module.exports = float;
const any = require('./any');
const array = require('./array');
const base = require('./base');
const boolean = require('./boolean');
const buffer = require('./buffer');
const computed = require('./computed');
const date = require('./date');
const float = require('./float');
const int = require('./int');
const object = require('./object');
const string = require('./string');
module.exports = {
any,
array,
base,
boolean,
buffer,
computed,
date,
float,
int,
object,
string,
};
const createType = require('./../createType');
const isValidInt = (key, value, strict = false) => {
if (Number.isInteger(value)) {
return true;
}
if (!strict && Number.isInteger(parseInt(value)) && parseInt(value) === parseFloat(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not an int`);
};
const int = () =>
createType({
name: 'int',
parse: (key, value) => parseInt(value),
requiredCheck: (key, value) => {
if (value || value === 0) {
return true;
}
throw new Error(`NativeModels - Property: '${key}' is required`);
},
strictCheck: (key, value) => isValidInt(key, value, true),
validCheck: (key, value) => isValidInt(key, value),
});
module.exports = int;
const createType = require('./../createType');
const createModel = require('./../createModel');
const { isObject } = require('./../lib/checks/types');
const object = (schema, options) =>
createType({
name: 'object',
parse: (key, value, parentOptions) =>
schema ? createModel(schema, { ...parentOptions, ...options })(value) : value,
validCheck: (key, value) => {
if (isObject(value)) {
return true;
}
throw new Error(`NativeModels - Property ${key} is not an object`);
},
});
module.exports = object;
const createType = require('./../createType');
const { isString } = require('./../lib/checks/types');
const strictCheck = (key, value, options) => {
if (isString(value)) {
if (options.length && value.length > options.length) {
throw new Error(`NativeModels - Property ${key} is longer than ${options.length}`);
}
return true;
}
throw new Error(`NativeModels - Property ${key} is not a string`);
};
const validCheck = (key, value) => {
if (value === null) {
throw new Error(`NativeModels - Property ${key} is not a string`);
}
return true;
};
const string = (options = {}) =>
createType({
name: 'string',
parse: (key, value) => {
if (options.length) {
return `${value}`.slice(0, options.length);
}
return `${value}`;
},
strictCheck: (key, value) => strictCheck(key, value, options),
validCheck,
});
module.exports = string;
const customtypes = require('./customtypes');
const datatypes = require('./datatypes');
const generateType = require('./lib/type/generate');
module.exports = (schema, usertypes = {}, fns = {}) => {
const obj = typeof schema === 'string' ? JSON.parse(schema) : schema;
const types = { ...datatypes, ...customtypes, ...usertypes };
return Object.keys(obj).reduce((result, key) => ({ ...result, [key]: generateType(obj[key], types, fns) }), {});
};
const createModel = require('./createModel');
const createType = require('./createType');
const customtypes = require('./customtypes');
const datatypes = require('./datatypes');
const generateSchema = require('./generateSchema');
const resolve = require('./resolve');
/* istanbul ignore next */
const resolver = (data, schema) =>
console.warn('DEPRECATION NOTICE: Please use resolve() instead of resolver()') || resolve(data, schema);
module.exports = {
createModel,
createType,
customtypes,
datatypes,
generateSchema,
resolve,
resolver,
};
const invalidTypeCheck = (type, key) => {
if (!type.validCheck || !type.parse) {
console.log(`Schema Key: '${key}' is not a valid datatype or customtype`);
return true;
}
return false;
};
module.exports = invalidTypeCheck;
const requiredCheck = (type, key, value) => (type.isRequired ? type.requiredCheck(key, value) : true);
module.exports = requiredCheck;
const strictCheck = (type, key, value) =>
type.requireStrict && type.strictCheck ? type.strictCheck(key, value) : true;
module.exports = strictCheck;
// Pre ES5 => value && typeof value === 'object' && value.constructor === Array;
const isArray = (value) => Array.isArray(value);
const isBoolean = (value) => typeof value === 'boolean';
const isBuffer = (value) => Buffer.isBuffer(value);
const isDate = (value) => value instanceof Date;
// const isError = (value) => value instanceof Error && typeof value.message !== 'undefined';
// const isFunction = (value) => typeof value === 'function';
const isNull = (value) => value === null;
const isNumber = (value) => typeof value === 'number' && isFinite(value);
const isObject = (value) => value && typeof value === 'object' && value.constructor === Object;
const isRegex = (value) => value && typeof value === 'object' && value.constructor === RegExp;
const isString = (value) => typeof value === 'string' || value instanceof String;
// const isSymbol = (value) => typeof value === 'symbol';
const isUndefined = (value) => typeof value === 'undefined';
module.exports = {
isArray,
isBoolean,
isBuffer,
isDate,
// isError,
// isFunction,
isNull,
isNumber,
isObject,
isRegex,
isString,
// isSymbol,
isUndefined,
};
const validCheck = (type, key, value) => type.validCheck(key, value);
module.exports = validCheck;
const defaultOptions = {
// Allow nulls on all columns
allowNulls: false,
// Ignores case when initializing object from model
caseSensitive: true,
// Pass options to all children
passOptions: false,
// Throws an error if key is not in schema
strict: false,
// Strip undefined values passed in
stripUndefined: true,
};
module.exports = defaultOptions;
const defaultValue = require('./defaultValue');
const defaultRecord = (schema, record) => ({
...record,
...Object.keys(schema).reduce(
(result, key) => ({
...result,
...(schema[key].hasDefault ? { [key]: record[key] || defaultValue(schema[key].defaultValue) } : {}),
}),
{},
),
});
module.exports = defaultRecord;
const defaultValue = (value) => (typeof value === 'function' ? value() : value);
module.exports = defaultValue;
const recaseRecord = (record) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
[key.toLowerCase()]: record[key],
}),
{},
);
const getFromKeyValue = (schema, record, { caseSensitive, key }) => {
const {
fromOptions: { caseSensitive: fromOptionsCaseSensitive },
} = schema[key];
const lowerCase = typeof fromOptionsCaseSensitive === 'undefined' ? !caseSensitive : !fromOptionsCaseSensitive;
const fromKeys = [key, ...schema[key].fromKeys].map((key) => (lowerCase ? key.toLowerCase() : key));
const recasedRecord = lowerCase ? recaseRecord(record) : record;
const value = fromKeys.find((fromKey) => typeof recasedRecord[fromKey] !== 'undefined');
return recasedRecord[value];
};
const mapRecord = (schema, record, caseSensitive) => ({
...record,
...Object.keys(schema)
.filter((key) => schema[key].fromKeys)
.reduce(
(result, key) => ({
...result,
...{ [key]: getFromKeyValue(schema, record, { caseSensitive, key }) },
}),
{},
),
});
module.exports = mapRecord;
const parseValue = require('./parseValue');
const parseRecord = (schema, record, options) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
...(schema[key] ? { [key]: parseValue(schema[key], key, record[key], options) } : {}),
}),
{},
);
module.exports = parseRecord;
/* eslint-disable max-params */
const invalidTypeCheck = require('./checks/invalidType');
const { isNull } = require('./checks/types');
const transformValue = require('./transformValue');
const checks = {
required: require('./checks/required'),
strict: require('./checks/strict'),
valid: require('./checks/valid'),
};
const runChecks = (type, key, value) => {
Object.keys(checks).forEach((name) => {
if (!checks[name](type, key, value)) {
throw new Error(`NativeModels - Failed ${name} check. Key: ${key} | Value: ${value}`);
}
});
};
const parseValue = (type, key, value, options) => {
if ((type.allowNull || (options && options.allowNulls)) && isNull(value)) {
return null;
} else if (invalidTypeCheck(type, key, value)) {
return value;
}
runChecks(type, key, value);
const parsedValue = type.parse(key, value, options && options.passOptions ? options : {});
return transformValue(type, parsedValue, 'post');
};
module.exports = parseValue;
/* eslint max-params: off */
const parseValue = require('./parseValue');
const get = (schema, target, property, context) => {
if (schema[property]) {
return schema[property].fn ? schema[property].fn(target, property, context) : target[property];
}
return undefined;
};
const getOwnPropertyDescriptor = (schema, target, property) =>
schema[property]
? {
configurable: true,
enumerable: true,
value: schema[property].fn ? '[computedValue]' : target[property],
writable: true,
}
: undefined;
const ownKeys = (schema, target) => {
const allKeys = [...Object.keys(target), ...Object.keys(schema).filter((key) => schema[key].fn)];
return [...new Set(allKeys)];
};
const set = (schema, target, property, value, options) => {
if (!schema[property]) {
throw new Error(`NativeModels - ${property} is not a property of model`);
}
const type = schema[property].fn && schema[property].type ? schema[property].type : schema[property];
target[property] = parseValue(type, property, value, options);
return true;
};
const proxyHandler = (schema, options, context) => ({
get: (target, property) => get(schema, target, property, context),
getOwnPropertyDescriptor: (target, property) => getOwnPropertyDescriptor(schema, target, property),
ownKeys: (target) => ownKeys(schema, target),
set: (target, property, value) => set(schema, target, property, value, options),
});
module.exports = proxyHandler;
const recaseKeys = (schema, record) => {
const keyMap = Object.keys(schema).reduce(
(result, key) => ({
...result,
[key.toLowerCase()]: key,
}),
{},
);
return Object.keys(record).reduce(
(result, key) => ({
...result,
[keyMap[key.toLowerCase()] || key]: record[key],
}),
{},
);
};
module.exports = recaseKeys;
const strictCheck = (schema, record) =>
Object.keys(record).forEach((key) => {
if (!schema[key]) {
throw new Error(`NativeModels - Property: '${key}' is not defined in the schema`);
}
});
module.exports = strictCheck;
const required = require('./checks/required');
const requiredCheck = (schema, record) =>
Object.keys(schema).forEach((key) => {
required(schema[key], key, record[key]);
});
module.exports = requiredCheck;
const stripUndefinedKeys = (schema, record) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
...(typeof record[key] === 'undefined' ? {} : { [key]: record[key] }),
}),
{},
);
module.exports = stripUndefinedKeys;
const transformValue = require('./transformValue');
const transformRecord = (schema, record) =>
Object.keys(record).reduce(
(result, key) => ({
...result,
[key]: schema[key] ? transformValue(schema[key], record[key], 'pre') : record[key],
}),
{},
);
module.exports = transformRecord;
const transformValue = (type, value, key) =>
type.transforms && type.transforms[key] ? type.transforms[key](value) : value;
module.exports = transformValue;
module.exports = (value, types, fns) => {
if (value.type === 'computed') {
return types[value.type](fns[value.fn]);
} else if (value.type === 'object') {
return types[value.type](require('./../../generateSchema')(value.schema, types, fns));
} else if (value.type === 'array') {
return types[value.type](require('./generate')(value.item, types, fns));
}
return types[value.type]();
};
module.exports = (value, type, fns) => {
value.default && type.default(value.default);
value.nullable && type.nullable();
value.required && type.required();
value.strict && type.strict();
value.transform && type.transform(fns[value.transform]);
return type;
};
const buildType = require('./build');
const extendType = require('./extend');
module.exports = (value, types, fns) => {
if (typeof value === 'string') {
if (types[value]) {
return types[value]();
}
throw new Error(`NativeModels - ${value} is not a valid type`);
} else if (types[value.type]) {
const type = buildType(value, types, fns);
return extendType(value, type, fns);
}
throw new Error(`NativeModels - ${value} is not a valid type`);
};
/* eslint-disable no-use-before-define */
const { isArray, isObject } = require('./lib/checks/types');
const createModel = require('./createModel');
const cascadeResolve = (value) => {
if (isArray(value)) {
return Promise.all(value.map(cascadeResolve));
} else if (isObject(value) && !value.then) {
return resolve(value);
}
return value;
};
const resolved = (keys, values, schema) => {
const data = keys.reduce((result, key, index) => ({ ...result, [key]: values[index] }), {});
return schema ? createModel(schema)(data) : data;
};
const resolve = (data, schema) => {
const keys = Object.keys(data);
return Promise.all(keys.map((key) => cascadeResolve(data[key]))).then((values) => resolved(keys, values, schema));
};
module.exports = resolve;