Comparing version 1.0.0-pre-3 to 1.0.0-pre-30
import { isDryvValidatable } from './'; | ||
export function annotate(model, ruleSet, options) { | ||
annotateObject(model.$dryv, ruleSet, options); | ||
annotateObject(model.$validatable, ruleSet, options); | ||
} | ||
@@ -22,6 +22,5 @@ function annotateObject(validatable, ruleSet, options) { | ||
function annotateValidatable(validatable, ruleSet) { | ||
var _a, _b, _c; | ||
validatable.required = | ||
(_c = (_b = (_a = ruleSet.validators) === null || _a === void 0 ? void 0 : _a[validatable.field]) === null || _b === void 0 ? void 0 : _b.find((rule) => { var _a; return (_a = rule.annotations) === null || _a === void 0 ? void 0 : _a.required; })) !== null && _c !== void 0 ? _c : false; | ||
var _a, _b; | ||
validatable.required = !!((_b = (_a = ruleSet.validators) === null || _a === void 0 ? void 0 : _a[validatable.field]) === null || _b === void 0 ? void 0 : _b.find((rule) => { var _a; return (_a = rule.annotations) === null || _a === void 0 ? void 0 : _a.required; })); | ||
} | ||
//# sourceMappingURL=annotate.js.map |
import { dryvProxyHandler } from './dryvProxyHandler'; | ||
import { defaultDryvOptions } from './defaultDryvOptions'; | ||
import { isDryvProxy } from '@/core'; | ||
import { isDryvProxy } from './isDryvProxy'; | ||
export function dryvProxy(model, field, session, options) { | ||
@@ -5,0 +5,0 @@ if (!model) { |
@@ -1,100 +0,108 @@ | ||
import { dryvProxy, isDryvProxy } from '.' | ||
import { isDryvValidatable } from '@/core' | ||
import { dryvValidatableObject } from './dryvValidatableObject' | ||
import { dryvValidatableValue } from './dryvValidatableValue' | ||
import { dryvProxy, isDryvProxy } from '.'; | ||
import { isDryvValidatable } from './isDryvValidatable'; | ||
import { dryvValidatableObject } from './dryvValidatableObject'; | ||
import { dryvValidatableValue } from './dryvValidatableValue'; | ||
export function dryvProxyHandler(field, session, options) { | ||
const _excludedFields = {} | ||
let _dryv = null | ||
return { | ||
return new DryvProxyHandler(field, session, options); | ||
} | ||
class DryvProxyHandler { | ||
constructor(field, session, options) { | ||
this.field = field; | ||
this.session = session; | ||
this.options = options; | ||
this._excludedFields = {}; | ||
this._validatable = null; | ||
this._values = {}; | ||
} | ||
get(target, fieldSymbol, receiver) { | ||
const fieldName = String(fieldSymbol) | ||
if (fieldName === '$dryv') { | ||
return getDryv(receiver) | ||
} | ||
if (isExcludedField(fieldName)) { | ||
return Reflect.get(target, fieldName, receiver) | ||
} | ||
const originalValue = Reflect.get(target, fieldName, receiver) | ||
const field = fieldName | ||
let resultValue | ||
if (originalValue && typeof originalValue === 'object') { | ||
resultValue = ensureObjectProxy(originalValue, field, receiver, session) | ||
if (resultValue !== originalValue) { | ||
Reflect.set(target, fieldName, resultValue) | ||
const fieldName = String(fieldSymbol); | ||
if (fieldName === '$validatable') { | ||
return this.getDryv(receiver); | ||
} | ||
} else if (typeof originalValue !== 'function') { | ||
ensureValueProxy(field, receiver) | ||
resultValue = originalValue | ||
} | ||
return resultValue | ||
}, | ||
if (this.isExcludedField(fieldName)) { | ||
return Reflect.get(target, fieldName, receiver); | ||
} | ||
if (this._values[fieldName] !== undefined) { | ||
return this._values[fieldName]; | ||
} | ||
const originalValue = Reflect.get(target, fieldName, receiver); | ||
const field = fieldName; | ||
let resultValue; | ||
if (originalValue && typeof originalValue === 'object' && !Array.isArray(originalValue)) { | ||
resultValue = this.ensureObjectProxy(originalValue, field, receiver, this.session); | ||
if (resultValue !== originalValue) { | ||
this._values[fieldName] = resultValue; | ||
} | ||
} | ||
else if (typeof originalValue !== 'function') { | ||
this.ensureValueProxy(field, receiver, this.session); | ||
resultValue = originalValue; | ||
} | ||
return resultValue; | ||
} | ||
set(target, fieldSymbol, value, receiver) { | ||
const fieldName = String(fieldSymbol) | ||
if (fieldName === '$dryv') { | ||
throw new Error('The $dryv property is read-only.') | ||
} | ||
const field = fieldName | ||
if (value && typeof value === 'function') { | ||
return Reflect.set(target, field, value) | ||
} | ||
if (isExcludedField(fieldName)) { | ||
return Reflect.set(target, field, value) | ||
} | ||
const originalValue = Reflect.get(target, field, receiver) | ||
if (!value && isDryvProxy(originalValue)) { | ||
originalValue.$dryv.parent = undefined | ||
} | ||
let targetValue | ||
let proxy = undefined | ||
if (typeof value === 'object') { | ||
targetValue = ensureObjectProxy(value, field, receiver, session) | ||
} else { | ||
proxy = ensureValueProxy(field, receiver) | ||
targetValue = value | ||
} | ||
const result = Reflect.set(target, field, targetValue) | ||
proxy === null || proxy === void 0 ? void 0 : proxy.validate().catch(console.error) | ||
return result | ||
var _a; | ||
const fieldName = String(fieldSymbol); | ||
if (fieldName === '$validatable') { | ||
throw new Error('The $validatable property is read-only.'); | ||
} | ||
const field = fieldName; | ||
if (typeof value === 'function') { | ||
return Reflect.set(target, field, value, receiver); | ||
} | ||
if (this.isExcludedField(fieldName)) { | ||
return Reflect.set(target, field, value, receiver); | ||
} | ||
const originalValue = (_a = this._values[fieldName]) !== null && _a !== void 0 ? _a : Reflect.get(target, field, receiver); | ||
if (!value && isDryvProxy(originalValue)) { | ||
originalValue.$validatable.parent = undefined; | ||
} | ||
let targetValue; | ||
let proxy = undefined; | ||
if (value && typeof value === 'object' && !Array.isArray(value)) { | ||
targetValue = this.ensureObjectProxy(value, field, receiver, this.session); | ||
} | ||
else { | ||
proxy = this.ensureValueProxy(field, receiver, this.session); | ||
targetValue = value; | ||
} | ||
this._values[fieldName] = targetValue; | ||
const result = Reflect.set(target, field, value, receiver); | ||
proxy === null || proxy === void 0 ? void 0 : proxy.validate().catch(console.error); | ||
return result; | ||
} | ||
} | ||
function ensureObjectProxy(value, field, receiver, session) { | ||
const proxy = !isDryvProxy(value) ? dryvProxy(value, field, session, options) : value | ||
const dryv = getDryv(receiver) | ||
dryv.value[field] = proxy.$dryv.value | ||
proxy.$dryv.parent = dryv | ||
return proxy | ||
} | ||
function ensureValueProxy(field, receiver) { | ||
const dryv = getDryv(receiver) | ||
const dryvObject = dryv.value | ||
if (isDryvValidatable(dryvObject[field])) { | ||
return dryvObject[field] | ||
ensureObjectProxy(value, field, receiver, session) { | ||
const proxy = !isDryvProxy(value) | ||
? dryvProxy(value, field, session, this.options) | ||
: value; | ||
const dryv = this.getDryv(receiver); | ||
dryv.value[field] = proxy.$validatable.value; | ||
proxy.$validatable.parent = dryv; | ||
return proxy; | ||
} | ||
const validatable = dryvValidatableValue( | ||
field, | ||
dryv, | ||
options, | ||
() => receiver[field], | ||
(value) => (receiver[field] = value) | ||
) | ||
const proxy = options.objectWrapper(validatable) | ||
dryvObject[field] = proxy | ||
return proxy | ||
} | ||
function getDryv(model) { | ||
if (!_dryv) { | ||
_dryv = dryvValidatableObject(field, session, model, options) | ||
ensureValueProxy(field, receiver, session) { | ||
const dryv = this.getDryv(receiver); | ||
const dryvObject = dryv.value; | ||
if (isDryvValidatable(dryvObject[field])) { | ||
return dryvObject[field]; | ||
} | ||
const validatable = dryvValidatableValue(field, dryv, session, this.options, () => receiver[field], (value) => (receiver[field] = value)); | ||
const proxy = this.options.objectWrapper(validatable); | ||
dryvObject[field] = proxy; | ||
return proxy; | ||
} | ||
return _dryv | ||
} | ||
function isExcludedField(field) { | ||
var _a | ||
if (_excludedFields[field] === undefined) { | ||
_excludedFields[field] = !!((_a = options.excludedFields) === null || _a === void 0 | ||
? void 0 | ||
: _a.find((regexp) => (regexp === null || regexp === void 0 ? void 0 : regexp.test(field)))) | ||
getDryv(model) { | ||
if (!this._validatable) { | ||
this._validatable = dryvValidatableObject(this.field, this.session, model, this.options); | ||
} | ||
return this._validatable; | ||
} | ||
return _excludedFields[field] | ||
} | ||
isExcludedField(field) { | ||
var _a; | ||
if (this._excludedFields[field] === undefined) { | ||
this._excludedFields[field] = !!((_a = this.options.excludedFields) === null || _a === void 0 ? void 0 : _a.find((regexp) => regexp === null || regexp === void 0 ? void 0 : regexp.test(field))); | ||
} | ||
return this._excludedFields[field]; | ||
} | ||
} | ||
//# sourceMappingURL=dryvProxyHandler.js.map | ||
//# sourceMappingURL=dryvProxyHandler.js.map |
@@ -10,11 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
import { isDryvValidatable } from '@/core'; | ||
import { dryvValidatableValue } from '@/core/dryvValidatableValue'; | ||
import { isDryvValidatable } from './isDryvValidatable'; | ||
import { dryvValidatableValue } from './dryvValidatableValue'; | ||
import { isDryvProxy } from './isDryvProxy'; | ||
const excludedFromUpdate = { | ||
$model: true, | ||
toJSON: true, | ||
parent: true, | ||
_isDryvValidatable: true, | ||
session: true | ||
}; | ||
export function dryvValidatableObject(field, parentOrSession, model, options) { | ||
let _parent = isDryvValidatable(parentOrSession) | ||
? parentOrSession | ||
: undefined; | ||
const _session = _parent | ||
? undefined | ||
: parentOrSession; | ||
const parentIsValidatable = isDryvValidatable(parentOrSession); | ||
const handler = new DryvValidatableObjectHandler(model, parentIsValidatable ? parentOrSession : undefined, parentIsValidatable ? undefined : parentOrSession, options); | ||
const _value = new Proxy({ | ||
@@ -25,9 +29,3 @@ $model: model, | ||
} | ||
}, { | ||
set(target, field, value, receiver) { | ||
return target.hasOwnProperty(field) || isDryvValidatable(value) | ||
? Reflect.set(target, field, value) | ||
: Reflect.set(target, field, dryvValidatableValue(field, receiver, options, () => model[field], (value) => (model[field] = value))); | ||
} | ||
}); | ||
}, handler); | ||
const validatable = options.objectWrapper({ | ||
@@ -38,3 +36,3 @@ _isDryvValidatable: true, | ||
group: null, | ||
status: null, | ||
type: null, | ||
required: null, | ||
@@ -45,24 +43,26 @@ get value() { | ||
get parent() { | ||
return _parent; | ||
return handler.parent; | ||
}, | ||
set parent(value) { | ||
_parent = value; | ||
handler.parent = value; | ||
}, | ||
get session() { | ||
var _a; | ||
return (_a = _parent === null || _parent === void 0 ? void 0 : _parent.session) !== null && _a !== void 0 ? _a : _session; | ||
return handler.session; | ||
}, | ||
get hasError() { | ||
return this.status === 'error'; | ||
return this.type === 'error'; | ||
}, | ||
get hasWarning() { | ||
return this.status === 'warning'; | ||
return this.type === 'warning'; | ||
}, | ||
get isSuccess() { | ||
return !this.hasError && !this.hasWarning; | ||
}, | ||
get path() { | ||
return ((_parent === null || _parent === void 0 ? void 0 : _parent.path) ? _parent.path + '.' : '') + (field ? String(field) : ''); | ||
var _a; | ||
return (((_a = handler.parent) === null || _a === void 0 ? void 0 : _a.path) ? handler.parent.path + '.' : '') + (field ? String(field) : ''); | ||
}, | ||
validate() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const session = (_a = _parent === null || _parent === void 0 ? void 0 : _parent.session) !== null && _a !== void 0 ? _a : _session; | ||
const session = handler.session; | ||
if (!session) { | ||
@@ -75,3 +75,3 @@ throw new Error('No validation session found'); | ||
clear() { | ||
validatable.status = null; | ||
validatable.type = null; | ||
validatable.text = null; | ||
@@ -84,8 +84,29 @@ validatable.group = null; | ||
set(response) { | ||
Object.values(_value) | ||
return Object.values(_value) | ||
.filter((v) => isDryvValidatable(v)) | ||
.forEach((v) => v.set(response)); | ||
.reduce((acc, v) => v.set(response) && acc, true); | ||
}, | ||
updateValue(value) { | ||
const model = this.value; | ||
const keys = Array.from(new Set([ | ||
...Object.keys(value), | ||
...Object.keys(model).filter((k) => !excludedFromUpdate[k]) | ||
])); | ||
keys.forEach((key) => { | ||
const entry = value[key]; | ||
const newValue = isDryvValidatable(entry) ? entry.value : entry; | ||
const oldValue = model[key]; | ||
if (isDryvValidatable(oldValue)) { | ||
oldValue.updateValue(newValue); | ||
} | ||
else if (isDryvValidatable(oldValue === null || oldValue === void 0 ? void 0 : oldValue.$model.$validatable)) { | ||
oldValue.$model.$validatable.updateValue(newValue); | ||
} | ||
else { | ||
model[key] = newValue; | ||
} | ||
}); | ||
}, | ||
toJSON() { | ||
return Object.assign(Object.assign({}, this), { parent: undefined, _isDryvValidatable: undefined }); | ||
return Object.assign(Object.assign({}, this), { parent: undefined, _isDryvValidatable: undefined, session: undefined }); | ||
} | ||
@@ -95,2 +116,19 @@ }); | ||
} | ||
class DryvValidatableObjectHandler { | ||
get session() { | ||
var _a, _b; | ||
return (_b = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.session) !== null && _b !== void 0 ? _b : this._session; | ||
} | ||
constructor(model, parent, session, options) { | ||
this.model = model; | ||
this.parent = parent; | ||
this.options = options; | ||
this._session = session; | ||
} | ||
set(target, field, value, receiver) { | ||
return target.hasOwnProperty(field) || isDryvValidatable(value) || isDryvProxy(value) | ||
? Reflect.set(target, field, value) | ||
: Reflect.set(target, field, dryvValidatableValue(field, receiver, this.session, this.options, () => this.model[field], (value) => (this.model[field] = value))); | ||
} | ||
} | ||
//# sourceMappingURL=dryvValidatableObject.js.map |
@@ -1,2 +0,2 @@ | ||
import type { DryvOptions, DryvValidatableInternal } from './typings'; | ||
export declare function dryvValidatableValue<TModel extends object = any, TValue = any>(field: keyof TModel | undefined, parent: DryvValidatableInternal | undefined, options: DryvOptions, getter: () => TValue, setter: (value: TValue) => void): DryvValidatableInternal<TModel, TValue>; | ||
import type { DryvValidationSession, DryvOptions, DryvValidatableInternal } from './typings'; | ||
export declare function dryvValidatableValue<TModel extends object = any, TValue = any>(field: keyof TModel | undefined, parent: DryvValidatableInternal | undefined, session: DryvValidationSession<TModel> | undefined, options: DryvOptions, getter: () => TValue, setter: (value: TValue) => void): DryvValidatableInternal<TModel, TValue>; |
@@ -10,9 +10,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
export function dryvValidatableValue(field, parent, options, getter, setter) { | ||
export function dryvValidatableValue(field, parent, session, options, getter, setter) { | ||
let _text = null; | ||
const validatable = options.objectWrapper({ | ||
_isDryvValidatable: true, | ||
field, | ||
text: null, | ||
get text() { | ||
return _text; | ||
}, | ||
set text(value) { | ||
_text = value; | ||
}, | ||
group: null, | ||
status: null, | ||
type: null, | ||
get value() { | ||
@@ -34,14 +40,18 @@ return getter(); | ||
get hasError() { | ||
return this.status === 'error'; | ||
return this.type === 'error'; | ||
}, | ||
get hasWarning() { | ||
return this.status === 'warning'; | ||
return this.type === 'warning'; | ||
}, | ||
get isSuccess() { | ||
return !this.hasError && !this.hasWarning; | ||
}, | ||
validate() { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const session = parent === null || parent === void 0 ? void 0 : parent.session; | ||
if (!session) { | ||
const _session = (_a = parent === null || parent === void 0 ? void 0 : parent.session) !== null && _a !== void 0 ? _a : session; | ||
if (!_session) { | ||
throw new Error('No validation session found'); | ||
} | ||
return session.validateField(this); | ||
return _session.validateField(validatable); | ||
}); | ||
@@ -53,3 +63,12 @@ }, | ||
clear() { | ||
validatable.status = null; | ||
var _a; | ||
const _session = (_a = parent === null || parent === void 0 ? void 0 : parent.session) !== null && _a !== void 0 ? _a : session; | ||
if (!_session) { | ||
throw new Error('No validation session found'); | ||
} | ||
_session.results.fields[this.path] = undefined; | ||
if (validatable.group) { | ||
_session.results.groups[validatable.group] = undefined; | ||
} | ||
validatable.type = null; | ||
validatable.text = null; | ||
@@ -61,6 +80,6 @@ validatable.group = null; | ||
const message = messages === null || messages === void 0 ? void 0 : messages[this.path]; | ||
if (message && message.status !== 'success') { | ||
if (message && message.type !== 'success') { | ||
validatable.text = message.text; | ||
validatable.group = message.group; | ||
validatable.status = message.status; | ||
validatable.type = message.type; | ||
} | ||
@@ -70,7 +89,11 @@ else { | ||
validatable.group = undefined; | ||
validatable.status = undefined; | ||
validatable.type = undefined; | ||
} | ||
return validatable.isSuccess; | ||
}, | ||
updateValue(value) { | ||
this.value = value; | ||
}, | ||
toJSON() { | ||
return Object.assign(Object.assign({}, this), { parent: undefined, _isDryvValidatable: undefined }); | ||
return Object.assign(Object.assign({}, this), { parent: undefined, _isDryvValidatable: undefined, session: undefined }); | ||
} | ||
@@ -77,0 +100,0 @@ }); |
@@ -10,4 +10,4 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
}; | ||
import { isDryvProxy, isDryvValidatable } from '@/core'; | ||
import { getMemberByPath } from '@/core/getMemberByPath'; | ||
import { isDryvProxy, isDryvValidatable } from '.'; | ||
import { getMemberByPath } from './getMemberByPath'; | ||
export function dryvValidationSession(options, ruleSet) { | ||
@@ -36,6 +36,10 @@ if (!options.callServer) { | ||
}, | ||
results: options.objectWrapper({ | ||
fields: {}, | ||
groups: {} | ||
}), | ||
validateObject(objOrProxy) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const obj = isDryvProxy(objOrProxy) | ||
? objOrProxy.$dryv | ||
? objOrProxy.$validatable | ||
: objOrProxy; | ||
@@ -48,16 +52,10 @@ if (!obj) { | ||
try { | ||
const results = (yield Promise.all(Object.entries(obj.value) | ||
.filter(([key, value]) => isDryvValidatable(value) && !isExcludedField(key)) | ||
.map(([_, value]) => value.validate()))).filter((result) => !!result); | ||
const fieldResults = results.filter((r) => r).flatMap((r) => r.results); | ||
const warnings = fieldResults.filter((r) => r.status === 'warning'); | ||
const hasErrors = fieldResults.some((r) => r.status === 'error'); | ||
obj.status = hasErrors ? 'error' : warnings.length > 0 ? 'warning' : 'success'; | ||
return { | ||
results: fieldResults, | ||
hasErrors: hasErrors, | ||
hasWarnings: warnings.length > 0, | ||
warningHash: fieldResults.map((r) => r.text).join('|'), | ||
success: !hasErrors && warnings.length === 0 | ||
}; | ||
const newValidationChain = startValidationChain(); | ||
const fieldResults = yield Promise.all(Array.from(traverseFields(obj.value)).map(([field, value]) => value.validate().then((result) => { var _a; return (Object.assign(Object.assign({}, result), { path: (_a = value.path) !== null && _a !== void 0 ? _a : undefined })); }))); | ||
const result = createObjectResults(fieldResults.filter((r) => !!r)); | ||
obj.type = result.hasErrors ? 'error' : result.hasWarnings ? 'warning' : 'success'; | ||
if (newValidationChain) { | ||
endValidationChain(); | ||
} | ||
return result; | ||
} | ||
@@ -70,56 +68,20 @@ finally { | ||
validateField(field, model) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function* () { | ||
switch (options.validationTrigger) { | ||
case 'auto': | ||
if (session.$initializing) { | ||
return success(); | ||
} | ||
break; | ||
case 'manual': | ||
if (!isValidating()) { | ||
return success(); | ||
} | ||
break; | ||
case 'autoAfterManual': | ||
if (!_isTriggered && !isValidating()) { | ||
return success(); | ||
} | ||
break; | ||
if (!canValidateFields() || (_processedFields === null || _processedFields === void 0 ? void 0 : _processedFields[field.field])) { | ||
return success(field.path); | ||
} | ||
if (_processedFields === null || _processedFields === void 0 ? void 0 : _processedFields[field.field]) { | ||
return success(); | ||
} | ||
if (!model) { | ||
model = getModel(field); | ||
} | ||
const newValidationChain = !_processedFields; | ||
if (newValidationChain) { | ||
_processedFields = {}; | ||
const newValidationChain = startValidationChain(); | ||
const fieldResult = yield validateFieldInternal(session, ruleSet, model, field, options); | ||
const result = createFieldValidationResult(fieldResult, field); | ||
session.results.fields[field.path] = result.success ? undefined : fieldResult !== null && fieldResult !== void 0 ? fieldResult : undefined; | ||
if (fieldResult === null || fieldResult === void 0 ? void 0 : fieldResult.group) { | ||
session.results.groups[fieldResult === null || fieldResult === void 0 ? void 0 : fieldResult.group] = result.success ? undefined : fieldResult; | ||
} | ||
const result = yield validateFieldInternal(session, ruleSet, model, field, options); | ||
if (newValidationChain) { | ||
_processedFields = undefined; | ||
endValidationChain(); | ||
} | ||
if (result) { | ||
field.status = result.status; | ||
field.text = result.text; | ||
field.group = result.group; | ||
const status = (_a = result.status) === null || _a === void 0 ? void 0 : _a.toLowerCase(); | ||
return status === 'success' | ||
? success() | ||
: { | ||
results: [result], | ||
hasErrors: status === 'error', | ||
hasWarnings: status === 'warning', | ||
warningHash: status === 'warning' ? result.text : null, | ||
success: status === 'success' || !status | ||
}; | ||
} | ||
else { | ||
field.status = 'success'; | ||
field.text = null; | ||
field.group = null; | ||
return success(); | ||
} | ||
return result; | ||
}); | ||
@@ -129,2 +91,49 @@ } | ||
return session; | ||
function canValidateFields() { | ||
switch (options.validationTrigger) { | ||
case 'auto': | ||
if (session.$initializing) { | ||
return false; | ||
} | ||
break; | ||
case 'manual': | ||
if (!isValidating()) { | ||
return false; | ||
} | ||
break; | ||
case 'autoAfterManual': | ||
if (!_isTriggered && !isValidating()) { | ||
return false; | ||
} | ||
break; | ||
} | ||
return true; | ||
} | ||
function startValidationChain() { | ||
const newValidationChain = !_processedFields; | ||
if (newValidationChain) { | ||
_processedFields = {}; | ||
} | ||
return newValidationChain; | ||
} | ||
function endValidationChain() { | ||
_processedFields = undefined; | ||
} | ||
function* traverseFields(obj) { | ||
for (const key in obj) { | ||
if (!(!isExcludedField(key) && obj.hasOwnProperty(key))) { | ||
continue; | ||
} | ||
const value = obj[key]; | ||
if (typeof value !== 'object') { | ||
continue; | ||
} | ||
if (isDryvValidatable(value)) { | ||
yield [key, value]; | ||
} | ||
else { | ||
yield* traverseFields(value); | ||
} | ||
} | ||
} | ||
function isExcludedField(fieldName, path) { | ||
@@ -150,3 +159,3 @@ if (!options.excludedFields) { | ||
} | ||
const rules = (_a = ruleSet === null || ruleSet === void 0 ? void 0 : ruleSet.validators) === null || _a === void 0 ? void 0 : _a[field]; | ||
const rules = (_a = ruleSet === null || ruleSet === void 0 ? void 0 : ruleSet.validators) === null || _a === void 0 ? void 0 : _a[validatable.path]; | ||
if (!rules || rules.length <= 0) { | ||
@@ -182,3 +191,9 @@ return Promise.resolve(null); | ||
(_a = rule.related) === null || _a === void 0 ? void 0 : _a.forEach((relatedField) => { | ||
const field = getMemberByPath(model.$dryv.value, relatedField); | ||
if (!relatedField || relatedField === validatable.path) { | ||
return; | ||
} | ||
const field = getMemberByPath(model.$validatable.value, relatedField); | ||
if (!field) { | ||
model[relatedField] = null; | ||
} | ||
session.validateField(field, model); | ||
@@ -192,10 +207,13 @@ }); | ||
path: validatable.path, | ||
status: 'error', | ||
type: 'error', | ||
text: r, | ||
group: null | ||
group: rule.group | ||
}; | ||
break; | ||
} | ||
else if (r.status !== 'success') { | ||
else if (r.type !== 'success') { | ||
result = r; | ||
if (!result.group) { | ||
result.group = rule.group; | ||
} | ||
break; | ||
@@ -210,3 +228,3 @@ } | ||
path: validatable.path, | ||
status: 'error', | ||
type: 'error', | ||
text: 'Validation failed.', | ||
@@ -217,3 +235,3 @@ group: null | ||
} | ||
return result && result.status !== 'success' ? result : null; | ||
return result && result.type !== 'success' ? result : null; | ||
}); | ||
@@ -223,8 +241,9 @@ } | ||
function getModel(parent) { | ||
var _a; | ||
while (parent.parent) { | ||
parent = parent.parent; | ||
} | ||
return parent.value.$model; | ||
return (_a = parent.$model) !== null && _a !== void 0 ? _a : parent.value.$model; | ||
} | ||
function success() { | ||
function success(path) { | ||
return { | ||
@@ -235,5 +254,60 @@ results: [], | ||
hasWarnings: false, | ||
warningHash: null | ||
warningHash: null, | ||
path | ||
}; | ||
} | ||
function createObjectResults(results) { | ||
const fieldResults = results | ||
.filter((r) => r) | ||
.flatMap((r) => r.results.map((r2) => (Object.assign(Object.assign({}, r2), { path: r.path })))); | ||
const hasWarnings = fieldResults.some((r) => r.type === 'warning'); | ||
const hasErrors = fieldResults.some((r) => r.type === 'error'); | ||
return { | ||
results: fieldResults, | ||
hasErrors: hasErrors, | ||
hasWarnings: hasWarnings, | ||
warningHash: hashCode(fieldResults | ||
.filter((r) => r.type === 'warning') | ||
.map((r) => r.text) | ||
.join()), | ||
success: !hasErrors && !hasWarnings | ||
}; | ||
} | ||
function createFieldValidationResult(result, field) { | ||
var _a; | ||
if (result) { | ||
field.type = result.type; | ||
field.text = result.text; | ||
field.group = result.group; | ||
const type = (_a = result.type) === null || _a === void 0 ? void 0 : _a.toLowerCase(); | ||
return type === 'success' | ||
? success(field.path) | ||
: { | ||
results: [result], | ||
hasErrors: type === 'error', | ||
hasWarnings: type === 'warning', | ||
warningHash: type === 'warning' ? result.text : null, | ||
success: type === 'success' || !type, | ||
path: String(field.path) | ||
}; | ||
} | ||
else { | ||
field.type = 'success'; | ||
field.text = null; | ||
field.group = null; | ||
return success(field.path); | ||
} | ||
} | ||
function hashCode(text) { | ||
if (!text || text.length === 0) { | ||
return ''; | ||
} | ||
let hash = 0; | ||
for (let i = 0; i < text.length; i++) { | ||
const chr = text.charCodeAt(i); | ||
hash = (hash << 5) - hash + chr; | ||
hash |= 0; | ||
} | ||
return Math.abs(hash).toString(16); | ||
} | ||
//# sourceMappingURL=dryvValidationSession.js.map |
@@ -1,1 +0,1 @@ | ||
export declare function getMemberByPath<TResult = any>(obj: any, path: string | symbol): TResult; | ||
export declare function getMemberByPath<TModel extends object, TResult = any>(obj: TModel, path: string | symbol): TResult | TModel; |
export * from './dryvProxy'; | ||
export * from './dryvValidationSession'; | ||
export * from './isDryvValidatableValue'; | ||
export * from './isDryvValidatable'; | ||
export * from './isDryvProxy'; | ||
@@ -5,0 +5,0 @@ export * from './dryvOptions'; |
export * from './dryvProxy'; | ||
export * from './dryvValidationSession'; | ||
export * from './isDryvValidatableValue'; | ||
export * from './isDryvValidatable'; | ||
export * from './isDryvProxy'; | ||
@@ -5,0 +5,0 @@ export * from './dryvOptions'; |
export function isDryvProxy(model) { | ||
return !!(model === null || model === void 0 ? void 0 : model.$dryv); | ||
return !!(model === null || model === void 0 ? void 0 : model.$validatable); | ||
} | ||
//# sourceMappingURL=isDryvProxy.js.map |
@@ -8,3 +8,4 @@ export type DryvValidateFunctionResult = DryvFieldValidationResult | string | null | undefined | Promise<DryvFieldValidationResult | string | null | undefined>; | ||
}; | ||
related?: (string | symbol)[]; | ||
related?: (keyof TModel)[]; | ||
group?: string; | ||
validate: ($m: TModel, session: DryvValidationSession<TModel>) => DryvValidateFunctionResult; | ||
@@ -14,2 +15,4 @@ } | ||
[Property in keyof TModel]?: DryvValidationRule<TModel>[]; | ||
} & { | ||
[path: string]: DryvValidationRule<TModel>[]; | ||
}; | ||
@@ -25,3 +28,3 @@ export interface DryvValidationRuleSet<TModel extends object, TParameters = object> { | ||
} | ||
export interface DryvValidationResult<TModel extends object> { | ||
export interface DryvValidationResult { | ||
results: DryvFieldValidationResult[]; | ||
@@ -32,12 +35,13 @@ success: boolean; | ||
warningHash: string | undefined | null; | ||
path?: string; | ||
} | ||
export interface DryvFieldValidationResult { | ||
path?: string; | ||
status?: DryvValidationResultStatus; | ||
type?: DryvValidationResultType; | ||
text?: string | null; | ||
group?: string | null; | ||
} | ||
export type DryvValidationResultStatus = 'error' | 'warning' | 'success' | string; | ||
export type DryvValidationResultType = 'error' | 'warning' | 'success' | string; | ||
export type DryvProxy<TModel extends object> = TModel & { | ||
$dryv: DryvValidatable<TModel, DryvObject<TModel>>; | ||
$validatable: DryvValidatable<TModel, DryvObject<TModel>>; | ||
}; | ||
@@ -47,3 +51,3 @@ export interface DryvGroupValidationResult { | ||
results: { | ||
status: DryvValidationResultStatus; | ||
type: DryvValidationResultType; | ||
texts: string[]; | ||
@@ -59,12 +63,17 @@ }[]; | ||
groupShown?: boolean | null; | ||
status?: DryvValidationResultStatus | null; | ||
value: TValue | undefined; | ||
parent: DryvValidatable | undefined; | ||
field: keyof TModel | undefined; | ||
type?: DryvValidationResultType | null; | ||
value?: TValue | undefined; | ||
parent?: DryvValidatable | undefined; | ||
field?: keyof TModel | undefined; | ||
get hasError(): boolean; | ||
get hasWarning(): boolean; | ||
validate(): Promise<DryvValidationResult<TModel>>; | ||
get isSuccess(): boolean; | ||
validate(): Promise<DryvValidationResult>; | ||
clear(): void; | ||
set(response: DryvServerValidationResponse | DryvServerErrors): void; | ||
set(response: DryvServerValidationResponse | DryvServerErrors): boolean; | ||
updateValue(value: any): void; | ||
} | ||
export interface DryvValidatableInternal<TModel extends object = any, TValue = any> extends DryvValidatable<TModel, TValue> { | ||
get session(): DryvValidationSession<TModel> | undefined; | ||
} | ||
export interface DryvValidationGroup<TModel extends object> { | ||
@@ -74,6 +83,6 @@ name: string; | ||
text?: string | null; | ||
status?: DryvValidationResultStatus | null; | ||
type?: DryvValidationResultType | null; | ||
} | ||
export type DryvObject<TModel extends object> = { | ||
[Property in keyof TModel]: TModel[Property] extends boolean ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends string ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends Date ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends Array<infer ArrayType> ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends object ? DryvObject<TModel[Property]> : TModel[Property] extends object ? DryvObject<TModel[Property]> : DryvValidatable<TModel, TModel[Property]>; | ||
[Property in keyof TModel]: TModel[Property] extends boolean ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends string ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends Date ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends Array<infer ArrayType> ? DryvValidatable<TModel, TModel[Property]> : TModel[Property] extends object ? DryvObject<TModel[Property]> : DryvValidatable<TModel, TModel[Property]>; | ||
} & { | ||
@@ -87,2 +96,8 @@ $model: DryvProxy<TModel> | undefined; | ||
export interface DryvValidationSession<TModel extends object> { | ||
results: { | ||
fields: Record<string, DryvFieldValidationResult | undefined>; | ||
groups: Record<string, DryvFieldValidationResult | undefined>; | ||
}; | ||
validateObject(objOrProxy: DryvValidatable<TModel> | DryvProxy<TModel>): Promise<DryvValidationResult>; | ||
validateField<TValue>(field: DryvValidatable<TModel, TValue>, model?: DryvProxy<TModel>): Promise<DryvValidationResult>; | ||
dryv: { | ||
@@ -93,4 +108,2 @@ callServer(url: string, method: string, data: any): Promise<any>; | ||
}; | ||
validateObject(objOrProxy: DryvValidatable<TModel> | DryvProxy<TModel>): Promise<DryvValidationResult<TModel>>; | ||
validateField<TValue>(field: DryvValidatable<TModel, TValue>, model?: DryvProxy<TModel>): Promise<DryvValidationResult<TModel>>; | ||
} | ||
@@ -97,0 +110,0 @@ export interface DryvOptions { |
@@ -9,1 +9,2 @@ import { DryvOptions } from '../core'; | ||
export declare function dryvTransaction<TModel extends object>(model: TModel, options?: DryvOptions): DryTransaction<TModel>; | ||
export declare function isDryvTransaction(obj: any): boolean; |
import { defaultDryvOptions } from '../core'; | ||
export function dryvTransaction(model, options) { | ||
options = Object.assign(defaultDryvOptions, options); | ||
const originalValues = Object.assign({}, model); | ||
const originalKeys = Object.keys(model).reduce((acc, key) => { | ||
acc[key] = true; | ||
return acc; | ||
}, {}); | ||
const values = options.objectWrapper(Object.assign({}, model)); | ||
const dirty = options.objectWrapper({ value: false }); | ||
let dirtyFields = {}; | ||
const proxy = new Proxy(model, { | ||
get(target, prop, receiver) { | ||
var _a; | ||
return (_a = values[prop]) !== null && _a !== void 0 ? _a : Reflect.get(target, prop, receiver); | ||
}, | ||
set(_, fieldName, value) { | ||
var _a; | ||
const field = fieldName; | ||
if (typeof originalValues[field] !== 'object' && typeof value !== 'object') { | ||
dirtyFields[String(fieldName)] = value !== originalValues[field]; | ||
} | ||
values[field] = value; | ||
dirty.value = (_a = Object.values(dirtyFields).find((x) => x)) !== null && _a !== void 0 ? _a : false; | ||
return true; | ||
} | ||
}); | ||
const handlers = options.objectWrapper([]); | ||
const proxy = new Proxy(model, new DryvTransactionProxyHandler(model, options, handlers)); | ||
return { | ||
commit() { | ||
Object.assign(model, values); | ||
dirtyFields = {}; | ||
dirty.value = false; | ||
handlers.forEach((handler) => handler.commit()); | ||
}, | ||
rollback() { | ||
Object.assign(values, model); | ||
Object.keys(values) | ||
.filter((key) => !originalKeys[key]) | ||
.forEach((key) => (values[key] = undefined)); | ||
dirtyFields = {}; | ||
dirty.value = false; | ||
handlers.forEach((handler) => handler.rollback()); | ||
}, | ||
model: proxy, | ||
dirty() { | ||
return dirty.value; | ||
return handlers.some((handler) => handler.dirty.value); | ||
} | ||
}; | ||
} | ||
export function isDryvTransaction(obj) { | ||
return obj && obj[DryvTransactionProxyHandler.isTransactionProp]; | ||
} | ||
class DryvTransactionProxyHandler { | ||
constructor(model, options, handlers) { | ||
this.model = model; | ||
this.options = options; | ||
this.handlers = handlers; | ||
this.dirtyFields = {}; | ||
handlers.push(this); | ||
this.dirty = this.options.objectWrapper({ value: false }); | ||
this.originalValues = Object.assign({}, model); | ||
this.originalKeys = Object.keys(model).reduce((acc, key) => { | ||
acc[key] = true; | ||
return acc; | ||
}, {}); | ||
const values = Object.keys(model).reduce((acc, key) => { | ||
const value = model[key]; | ||
acc[key] = | ||
typeof value === 'object' && !Array.isArray(value) | ||
? new Proxy(value, new DryvTransactionProxyHandler(value, this.options, this.handlers)) | ||
: value; | ||
return acc; | ||
}, {}); | ||
this.values = this.options.objectWrapper(values); | ||
} | ||
get(target, prop, receiver) { | ||
var _a; | ||
return prop === DryvTransactionProxyHandler.isTransactionProp | ||
? true | ||
: (_a = this.values[prop]) !== null && _a !== void 0 ? _a : Reflect.get(target, prop, receiver); | ||
} | ||
set(target, prop, value) { | ||
var _a; | ||
const field = prop; | ||
const isTransaction = isDryvTransaction(value); | ||
const isObject = typeof value === 'object'; | ||
if (isObject && !isTransaction && !Array.isArray(value)) { | ||
value = new Proxy(value, new DryvTransactionProxyHandler(value, this.options, this.handlers)); | ||
} | ||
this.values[field] = value; | ||
if (!isObject) { | ||
this.dirtyFields[String(prop)] = value !== this.originalValues[field]; | ||
this.dirty.value = (_a = Object.values(this.dirtyFields).find((x) => x)) !== null && _a !== void 0 ? _a : false; | ||
} | ||
return true; | ||
} | ||
commit() { | ||
Object.assign(this.model, this.values); | ||
this.dirtyFields = {}; | ||
this.dirty.value = false; | ||
} | ||
rollback() { | ||
Object.assign(this.values, this.model); | ||
Object.keys(this.values) | ||
.filter((key) => !this.originalKeys[key]) | ||
.forEach((key) => (this.values[key] = undefined)); | ||
this.dirtyFields = {}; | ||
this.dirty.value = false; | ||
} | ||
} | ||
DryvTransactionProxyHandler.isTransactionProp = '____trans'; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "dryvjs", | ||
"version": "1.0.0-pre-3", | ||
"version": "1.0.0-pre-30", | ||
"main": "dist/index.js", | ||
@@ -5,0 +5,0 @@ "types": "dist/index.d.ts", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
82550
56
1114