@backland/schema
Version:
TypeScript schema declaration and validation library with static type inference
153 lines • 6.11 kB
JavaScript
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); }
function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
import { customError, EmailRegex, entries, getTypeName, IndexCursor, inspectObject, isPlainObject, joinPathsCamelCase, stringCase } from '@backland/utils';
import { CircularDeps } from './CircularDeps';
import { createType } from './GraphType/GraphType';
import { createObjectType } from './ObjectType';
import { ULID_REGEX } from './fields/UlidField';
var record = CircularDeps.record({
keyType: 'string',
type: 'any'
});
export var JSONFieldCase = Object.keys(stringCase).concat('camelCase');
export var JSONToSchemaOptions = createObjectType({
fieldCase: {
enum: JSONFieldCase,
optional: true
},
examples: 'boolean?',
name: 'string?',
json: {
record: {
type: 'any',
keyType: 'string'
}
}
});
export function jsonToType(init) {
var {
name
} = init;
var definition = valueToTypeDef(_objectSpread(_objectSpread({}, init), {}, {
value: init.json
}));
var type = createType(definition);
if (name) {
type.identify(name);
}
return type;
}
export function jsonToSchemaDefinition(options) {
record.parse(options.json, 'jsonToSchema: Invalid input.');
var res = valueToTypeDef(_objectSpread(_objectSpread({}, options), {}, {
value: options.json
}));
if ('object' in res && typeof res.object === 'object') {
return res.object;
}
throw customError({
message: 'Invalid field',
details: res,
stackFrom: jsonToSchemaDefinition
});
}
export function isCursorString(value) {
if (!value || typeof value !== 'string') return false;
try {
IndexCursor.parse(value, {
destination: 'document'
});
return true;
} catch (e) {
return false;
}
}
var phoneType = CircularDeps.phone({});
export var valuesToBacklandTypeRecord = {
null: value => value === null,
undefined: function (_undefined) {
function undefined(_x) {
return _undefined.apply(this, arguments);
}
undefined.toString = function () {
return _undefined.toString();
};
return undefined;
}(value => value === undefined),
string: value => typeof value === 'string',
boolean: value => typeof value === 'boolean',
float: value => getTypeName(value) === 'Number' && !!"".concat(value).match(/^\d*\.\d*$/),
int: value => getTypeName(value) === 'Number' && !!"".concat(value).match(/^\d*$/),
array: Array.isArray,
object: value => isPlainObject(value),
cursor: isCursorString,
date: value => getTypeName(value) === 'Date',
email: value => Boolean(value && typeof value === 'string' && EmailRegex.test(value)),
ID: value => !!value && typeof value === 'string' && ULID_REGEX.test(value),
phone: phoneType.is,
record: value => !!value && typeof value === 'object' && !isPlainObject(value),
ulid: value => typeof value === 'string' && ULID_REGEX.test(value),
union: () => false,
unknown: () => false,
alias: () => false,
any: () => false,
literal: () => false,
meta: () => false,
enum: () => false
};
export var backlandValueTypeCheckEntries = entries(valuesToBacklandTypeRecord);
export function valueToTypeDef(options) {
var {
fieldCase = 'keep',
examples,
value
} = options;
var typename = function iifeTypename() {
var _backlandValueTypeChe;
return ((_backlandValueTypeChe = backlandValueTypeCheckEntries.find(_ref => {
var [, check] = _ref;
return check(value);
})) === null || _backlandValueTypeChe === void 0 ? void 0 : _backlandValueTypeChe[0]) || 'unknown';
}();
var field = {
[typename]: {}
};
if (examples && typename !== 'object') {
field.description = "Eg: ".concat(inspectObject(value).trim());
}
if ('array' in field) {
var child = value.map(el => {
return valueToTypeDef(_objectSpread(_objectSpread({}, options), {}, {
value: el
}));
});
field.array.of = function iife() {
if (!child.length) return 'unknown';
return child.length === 1 ? child[0] : {
union: child
};
}();
}
if (typename === 'object') {
field[typename] = entries(value).reduce((acc, _ref2) => {
var [key, subValue] = _ref2;
if (fieldCase) {
if (fieldCase === 'camelCase') {
key = joinPathsCamelCase(key);
} else {
key = stringCase[fieldCase](key);
}
}
return _objectSpread(_objectSpread({}, acc), {}, {
[key]: valueToTypeDef(_objectSpread(_objectSpread({}, options), {}, {
value: subValue
}))
});
}, {});
}
return field;
}
//# sourceMappingURL=jsonToType.js.map