1
0
mirror of synced 2024-11-29 00:26:12 +03:00

style: Addition of the eslint rules

This commit is contained in:
Zaytsev Kirill 2020-10-09 22:58:28 +03:00
parent 095f406fea
commit acb6357433
25 changed files with 754 additions and 555 deletions

View File

@ -1,22 +1,42 @@
module.exports = { module.exports = {
root: true, root: true,
parserOptions: { parserOptions: {
parser: 'babel-eslint', parser: 'babel-eslint',
sourceType: 'module' sourceType: 'module',
}, },
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: [ extends: [
'standard', 'standard',
'plugin:vue/recommended' '@vue/standard',
'plugin:vue/recommended',
], ],
env: { env: {
browser: true, browser: true,
}, },
// add your custom rules here
'rules': { rules: {
// allow paren-less arrow functions // allow paren-less arrow functions
'arrow-parens': 0, 'arrow-parens': 0,
'comma-dangle': ['error', 'only-multiline'],
'indent': ['error', 4],
'max-depth': ['error', 3],
'max-lines-per-function': ['error', 40],
'no-console': ['warn', {allow: ['warn', 'error']}],
// allow debugger during development // allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
} 'vue/html-closing-bracket-spacing': ['error', {
startTag: 'never',
endTag: 'never',
selfClosingTag: 'always',
}],
'vue/html-indent': ['error', 4, {
attribute: 1,
closeBracket: 0,
alignAttributesVertically: true,
ignores: [],
}],
},
} }

View File

@ -26,6 +26,7 @@ import SpecimenSelect from './specimens/SpecimenSelect'
export default { export default {
name: 'App', name: 'App',
components: { components: {
SpecimenButton, SpecimenButton,
SpecimenBox, SpecimenBox,
@ -34,21 +35,22 @@ export default {
SpecimenGroup, SpecimenGroup,
SpecimenFile, SpecimenFile,
SpecimenSlider, SpecimenSlider,
SpecimenSelect SpecimenSelect,
},
data () {
return {
}
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
$formulate-font-stack: Arial, sans-serif;
$formulate-gray: gray;
$formulate-green: green;
body { body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: $formulate-font-stack; font-family: $formulate-font-stack;
} }
h2 { h2 {
display: block; display: block;
width: 100%; width: 100%;
@ -61,6 +63,7 @@ h2 {
margin: 2em 0 0 0; margin: 2em 0 0 0;
z-index: 10; z-index: 10;
} }
.specimen-list { .specimen-list {
padding: 1em; padding: 1em;
max-width: 1200px; max-width: 1200px;
@ -68,8 +71,8 @@ h2 {
@media (min-width: 756px) { @media (min-width: 756px) {
padding: 2em; padding: 2em;
} }
} }
.specimens { .specimens {
@media (min-width: 500px) { @media (min-width: 500px) {
display: flex; display: flex;

View File

@ -1,10 +1,9 @@
import Vue from 'vue' import Vue from 'vue'
import VueFormulate from '../src/Formulate' import VueFormulario from '../src/Formulario'
import FormulateSpecimens from './FormulateSpecimens.vue' import FormulateSpecimens from './FormulateSpecimens.vue'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.use(VueFormulario)
Vue.use(VueFormulate)
new Vue({ new Vue({
render: h => h(FormulateSpecimens) render: h => h(FormulateSpecimens)

View File

@ -47,9 +47,3 @@
</div> </div>
</div> </div>
</template> </template>
<script>
export default {
}
</script>

View File

@ -51,6 +51,7 @@
"@vue/cli-plugin-eslint": "^4.3.1", "@vue/cli-plugin-eslint": "^4.3.1",
"@vue/cli-service": "^4.5.4", "@vue/cli-service": "^4.5.4",
"@vue/component-compiler-utils": "^3.1.2", "@vue/component-compiler-utils": "^3.1.2",
"@vue/eslint-config-standard": "^5.1.2",
"@vue/test-utils": "^1.0.2", "@vue/test-utils": "^1.0.2",
"autoprefixer": "^9.7.6", "autoprefixer": "^9.7.6",
"babel-core": "^7.0.0-bridge.0", "babel-core": "^7.0.0-bridge.0",

View File

@ -1,5 +1,6 @@
import nanoid from 'nanoid/non-secure' import nanoid from 'nanoid/non-secure'
// noinspection JSUnusedGlobalSymbols
/** /**
* The file upload class holds and represents a files upload state durring * The file upload class holds and represents a files upload state durring
* the upload flow. * the upload flow.
@ -7,8 +8,9 @@ import nanoid from 'nanoid/non-secure'
class FileUpload { class FileUpload {
/** /**
* Create a file upload object. * Create a file upload object.
* @param {FileList} fileList * @param {FileList} input
* @param {object} context * @param {object} context
* @param {object} options
*/ */
constructor (input, context, options = {}) { constructor (input, context, options = {}) {
this.input = input this.input = input
@ -27,7 +29,6 @@ class FileUpload {
/** /**
* Given a pre-existing array of files, create a faux FileList. * Given a pre-existing array of files, create a faux FileList.
* @param {array} items expects an array of objects [{ url: '/uploads/file.pdf' }] * @param {array} items expects an array of objects [{ url: '/uploads/file.pdf' }]
* @param {string} pathKey the object-key to access the url (defaults to "url")
*/ */
rehydrateFileList (items) { rehydrateFileList (items) {
const fauxFileList = items.reduce((fileList, item) => { const fauxFileList = items.reduce((fileList, item) => {
@ -48,15 +49,12 @@ class FileUpload {
/** /**
* Produce an array of files and alert the callback. * Produce an array of files and alert the callback.
* @param {FileList} * @param {FileList} fileList
*/ */
addFileList (fileList) { addFileList (fileList) {
for (let i = 0; i < fileList.length; i++) { for (let i = 0; i < fileList.length; i++) {
const file = fileList[i] const file = fileList[i]
const uuid = nanoid() const uuid = nanoid()
const removeFile = function () {
this.removeFile(uuid)
}
this.files.push({ this.files.push({
progress: false, progress: false,
error: false, error: false,
@ -66,7 +64,7 @@ class FileUpload {
file, file,
uuid, uuid,
path: false, path: false,
removeFile: removeFile.bind(this), removeFile: () => this.removeFile(uuid),
previewData: file.previewData || false previewData: file.previewData || false
}) })
} }
@ -86,16 +84,11 @@ class FileUpload {
* https://github.com/axios/axios/issues/737 * https://github.com/axios/axios/issues/737
*/ */
uploaderIsAxios () { uploaderIsAxios () {
if ( return this.hasUploader &&
this.hasUploader &&
typeof this.context.uploader.request === 'function' && typeof this.context.uploader.request === 'function' &&
typeof this.context.uploader.get === 'function' && typeof this.context.uploader.get === 'function' &&
typeof this.context.uploader.delete === 'function' && typeof this.context.uploader.delete === 'function' &&
typeof this.context.uploader.post === 'function' typeof this.context.uploader.post === 'function'
) {
return true
}
return false
} }
/** /**

View File

@ -3,13 +3,15 @@ import rules from './libs/rules'
import mimes from './libs/mimes' import mimes from './libs/mimes'
import FileUpload from './FileUpload' import FileUpload from './FileUpload'
import RuleValidationMessages from './RuleValidationMessages' import RuleValidationMessages from './RuleValidationMessages'
import { arrayify, parseLocale, has } from './libs/utils' import { arrayify } from './libs/utils'
import isPlainObject from 'is-plain-object' import isPlainObject from 'is-plain-object'
import fauxUploader from './libs/faux-uploader' import fauxUploader from './libs/faux-uploader'
import FormularioForm from './FormularioForm.vue' import FormularioForm from './FormularioForm.vue'
import FormularioInput from './FormularioInput.vue' import FormularioInput from './FormularioInput.vue'
import FormularioGrouping from './FormularioGrouping.vue' import FormularioGrouping from './FormularioGrouping.vue'
// noinspection JSUnusedGlobalSymbols
/** /**
* The base formulario library. * The base formulario library.
*/ */
@ -23,7 +25,7 @@ class Formulario {
components: { components: {
FormularioForm, FormularioForm,
FormularioInput, FormularioInput,
FormularioGrouping, FormularioGrouping
}, },
library, library,
rules, rules,
@ -48,16 +50,18 @@ class Formulario {
install (Vue, options) { install (Vue, options) {
Vue.prototype.$formulario = this Vue.prototype.$formulario = this
this.options = this.defaults this.options = this.defaults
var plugins = this.defaults.plugins let plugins = this.defaults.plugins
if (options && Array.isArray(options.plugins) && options.plugins.length) { if (options && Array.isArray(options.plugins) && options.plugins.length) {
plugins = plugins.concat(options.plugins) plugins = plugins.concat(options.plugins)
} }
plugins.forEach(plugin => (typeof plugin === 'function') ? plugin(this) : null) plugins.forEach(plugin => (typeof plugin === 'function') ? plugin(this) : null)
this.extend(options || {}) this.extend(options || {})
for (var componentName in this.options.components) { for (const componentName in this.options.components) {
if (Object.prototype.hasOwnProperty.call(this.options.components, componentName)) {
Vue.component(componentName, this.options.components[componentName]) Vue.component(componentName, this.options.components[componentName])
} }
} }
}
/** /**
* Produce a deterministically generated id based on the sequence by which it * Produce a deterministically generated id based on the sequence by which it
@ -95,9 +99,10 @@ class Formulario {
* @param {boolean} concatArrays * @param {boolean} concatArrays
*/ */
merge (base, mergeWith, concatArrays = true) { merge (base, mergeWith, concatArrays = true) {
var merged = {} const merged = {}
for (var key in base) {
if (mergeWith.hasOwnProperty(key)) { for (const key in base) {
if (Object.prototype.hasOwnProperty.call(mergeWith, key)) {
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) { if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
merged[key] = this.merge(base[key], mergeWith[key], concatArrays) merged[key] = this.merge(base[key], mergeWith[key], concatArrays)
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) { } else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
@ -109,11 +114,13 @@ class Formulario {
merged[key] = base[key] merged[key] = base[key]
} }
} }
for (var prop in mergeWith) {
if (!merged.hasOwnProperty(prop)) { for (const prop in mergeWith) {
if (!Object.prototype.hasOwnProperty.call(merged, prop)) {
merged[prop] = mergeWith[prop] merged[prop] = mergeWith[prop]
} }
} }
return merged return merged
} }
@ -122,9 +129,10 @@ class Formulario {
* @param {string} type * @param {string} type
*/ */
classify (type) { classify (type) {
if (this.options.library.hasOwnProperty(type)) { if (Object.prototype.hasOwnProperty.call(this.options.library, type)) {
return this.options.library[type].classification return this.options.library[type].classification
} }
return 'unknown' return 'unknown'
} }
@ -133,9 +141,10 @@ class Formulario {
* @param {string} type * @param {string} type
*/ */
component (type) { component (type) {
if (this.options.library.hasOwnProperty(type)) { if (Object.prototype.hasOwnProperty.call(this.options.library, type)) {
return this.options.library[type].component return this.options.library[type].component
} }
return false return false
} }
@ -151,16 +160,16 @@ class Formulario {
* Get the validation message for a particular error. * Get the validation message for a particular error.
*/ */
validationMessage (rule, validationContext, vm) { validationMessage (rule, validationContext, vm) {
if (this.options.validationMessages.hasOwnProperty(rule)) { if (Object.prototype.hasOwnProperty.call(this.options.validationMessages, rule)) {
return this.options.validationMessages[rule](vm, validationContext) return this.options.validationMessages[rule](vm, validationContext)
} else { } else {
return this.options.validationMessages['default'](vm, validationContext) return this.options.validationMessages.default(vm, validationContext)
} }
} }
/** /**
* Given an instance of a FormularioForm register it. * Given an instance of a FormularioForm register it.
* @param {vm} form * @param {Vue} form
*/ */
register (form) { register (form) {
if (form.$options.name === 'FormularioForm' && form.name) { if (form.$options.name === 'FormularioForm' && form.name) {
@ -170,7 +179,7 @@ class Formulario {
/** /**
* Given an instance of a form, remove it from the registry. * Given an instance of a form, remove it from the registry.
* @param {vm} form * @param {Vue} form
*/ */
deregister (form) { deregister (form) {
if ( if (
@ -188,7 +197,7 @@ class Formulario {
* *
* @param {error} err * @param {error} err
* @param {string} formName * @param {string} formName
* @param {error} * @param {boolean} skip
*/ */
handle (err, formName, skip = false) { handle (err, formName, skip = false) {
const e = skip ? err : this.options.errorHandler(err, formName) const e = skip ? err : this.options.errorHandler(err, formName)

View File

@ -16,13 +16,16 @@
> >
<img <img
:src="file.previewData" :src="file.previewData"
alt=""
> >
</div> </div>
<div <div
class="formulario-file-name" class="formulario-file-name"
:title="file.name" :title="file.name"
v-text="file.name" v-text="file.name"
/> />
<div <div
v-if="file.progress !== false" v-if="file.progress !== false"
:data-just-finished="file.justFinished" :data-just-finished="file.justFinished"
@ -34,12 +37,14 @@
:style="{width: file.progress + '%'}" :style="{width: file.progress + '%'}"
/> />
</div> </div>
<div <div
v-if="(file.complete && !file.justFinished) || file.progress === false" v-if="(file.complete && !file.justFinished) || file.progress === false"
class="formulario-file-remove" class="formulario-file-remove"
@click="file.removeFile" @click="file.removeFile"
/> />
</div> </div>
<div <div
v-if="file.error" v-if="file.error"
class="formulario-file-upload-error" class="formulario-file-upload-error"
@ -54,21 +59,25 @@ import FileUpload from './FileUpload'
export default { export default {
name: 'FormularioFiles', name: 'FormularioFiles',
props: { props: {
files: { files: {
type: FileUpload, type: FileUpload,
required: true required: true
}, },
imagePreview: { imagePreview: {
type: Boolean, type: Boolean,
default: false default: false
} }
}, },
computed: { computed: {
fileUploads () { fileUploads () {
return this.files.files || [] return this.files.files || []
} }
}, },
watch: { watch: {
files () { files () {
if (this.imagePreview) { if (this.imagePreview) {
@ -76,6 +85,7 @@ export default {
} }
} }
}, },
mounted () { mounted () {
if (this.imagePreview) { if (this.imagePreview) {
this.files.loadPreviews() this.files.loadPreviews()

View File

@ -13,6 +13,8 @@ import useRegistry, { useRegistryComputed, useRegistryMethods, useRegistryProvid
import FormSubmission from './FormSubmission' import FormSubmission from './FormSubmission'
export default { export default {
name: 'FormularioForm',
provide () { provide () {
return { return {
...useRegistryProviders(this), ...useRegistryProviders(this),
@ -22,33 +24,39 @@ export default {
path: '' path: ''
} }
}, },
name: 'FormularioForm',
model: { model: {
prop: 'formularioValue', prop: 'formularioValue',
event: 'input' event: 'input'
}, },
props: { props: {
name: { name: {
type: [String, Boolean], type: [String, Boolean],
default: false default: false
}, },
formularioValue: { formularioValue: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
values: { values: {
type: [Object, Boolean], type: [Object, Boolean],
default: false default: false
}, },
errors: { errors: {
type: [Object, Boolean], type: [Object, Boolean],
default: false default: false
}, },
formErrors: { formErrors: {
type: Array, type: Array,
default: () => ([]) default: () => ([])
} }
}, },
data () { data () {
return { return {
...useRegistry(this), ...useRegistry(this),
@ -58,51 +66,58 @@ export default {
namedFieldErrors: {} namedFieldErrors: {}
} }
}, },
computed: { computed: {
...useRegistryComputed(), ...useRegistryComputed(),
classes () { classes () {
const classes = { 'formulario-form': true } return {
if (this.name) { 'formulario-form': true,
classes[`formulario-form--${this.name}`] = true [`formulario-form--${this.name}`]: !!this.name
} }
return classes
}, },
mergedFormErrors () { mergedFormErrors () {
return this.formErrors.concat(this.namedErrors) return this.formErrors.concat(this.namedErrors)
}, },
mergedFieldErrors () { mergedFieldErrors () {
const errors = {} const errors = {}
if (this.errors) { if (this.errors) {
for (const fieldName in this.errors) { for (const fieldName in this.errors) {
errors[fieldName] = arrayify(this.errors[fieldName]) errors[fieldName] = arrayify(this.errors[fieldName])
} }
} }
for (const fieldName in this.namedFieldErrors) { for (const fieldName in this.namedFieldErrors) {
errors[fieldName] = arrayify(this.namedFieldErrors[fieldName]) errors[fieldName] = arrayify(this.namedFieldErrors[fieldName])
} }
return errors return errors
}, },
hasFormErrorObservers () { hasFormErrorObservers () {
return !!this.errorObservers.filter(o => o.type === 'form').length return !!this.errorObservers.filter(o => o.type === 'form').length
} }
}, },
watch: { watch: {
formularioValue: { formularioValue: {
handler (values) { handler (values) {
if (this.isVmodeled && if (this.isVmodeled && values && typeof values === 'object') {
values &&
typeof values === 'object'
) {
this.setValues(values) this.setValues(values)
} }
}, },
deep: true deep: true
}, },
mergedFormErrors (errors) { mergedFormErrors (errors) {
this.errorObservers this.errorObservers
.filter(o => o.type === 'form') .filter(o => o.type === 'form')
.forEach(o => o.callback(errors)) .forEach(o => o.callback(errors))
}, },
mergedFieldErrors: { mergedFieldErrors: {
handler (errors) { handler (errors) {
this.errorObservers this.errorObservers
@ -112,20 +127,25 @@ export default {
immediate: true immediate: true
} }
}, },
created () { created () {
this.$formulario.register(this) this.$formulario.register(this)
this.applyInitialValues() this.applyInitialValues()
}, },
destroyed () { destroyed () {
this.$formulario.deregister(this) this.$formulario.deregister(this)
}, },
methods: { methods: {
...useRegistryMethods(), ...useRegistryMethods(),
applyErrors ({ formErrors, inputErrors }) { applyErrors ({ formErrors, inputErrors }) {
// given an object of errors, apply them to this form // given an object of errors, apply them to this form
this.namedErrors = formErrors this.namedErrors = formErrors
this.namedFieldErrors = inputErrors this.namedFieldErrors = inputErrors
}, },
addErrorObserver (observer) { addErrorObserver (observer) {
if (!this.errorObservers.find(obs => observer.callback === obs.callback)) { if (!this.errorObservers.find(obs => observer.callback === obs.callback)) {
this.errorObservers.push(observer) this.errorObservers.push(observer)
@ -136,14 +156,17 @@ export default {
} }
} }
}, },
removeErrorObserver (observer) { removeErrorObserver (observer) {
this.errorObservers = this.errorObservers.filter(obs => obs.callback !== observer) this.errorObservers = this.errorObservers.filter(obs => obs.callback !== observer)
}, },
registerErrorComponent (component) { registerErrorComponent (component) {
if (!this.errorComponents.includes(component)) { if (!this.errorComponents.includes(component)) {
this.errorComponents.push(component) this.errorComponents.push(component)
} }
}, },
formSubmitted () { formSubmitted () {
// perform validation here // perform validation here
this.showErrors() this.showErrors()
@ -159,6 +182,7 @@ export default {
return undefined return undefined
}) })
}, },
formularioFieldValidation (errorObject) { formularioFieldValidation (errorObject) {
this.$emit('validation', errorObject) this.$emit('validation', errorObject)
} }

View File

@ -10,33 +10,38 @@
<script> <script>
export default { export default {
name: 'FormularioGrouping', name: 'FormularioGrouping',
props: {
name: {
type: String,
required: true
},
isArrayItem: {
type: Boolean,
default: false
},
},
provide () { provide () {
return { return {
path: this.groupPath path: this.groupPath
} }
}, },
inject: ['path'], inject: ['path'],
props: {
name: {
type: String,
required: true
},
isArrayItem: {
type: Boolean,
default: false
}
},
computed: { computed: {
groupPath () { groupPath () {
if (this.isArrayItem) { if (this.isArrayItem) {
return this.path + '[' + this.name + ']'; return `${this.path}[${this.name}]`
} else {
if (this.path === '') {
return this.name;
} }
return this.path + '.' + this.name; if (this.path === '') {
return this.name
} }
return `${this.path}.${this.name}`
} }
} }
} }

View File

@ -5,7 +5,12 @@
:data-is-showing-errors="hasVisibleErrors" :data-is-showing-errors="hasVisibleErrors"
:data-type="type" :data-type="type"
> >
<slot :id="id" :context="context" :errors="errors" :validationErrors="validationErrors" /> <slot
:id="id"
:context="context"
:errors="errors"
:validationErrors="validationErrors"
/>
</div> </div>
</template> </template>
@ -15,7 +20,9 @@ import { shallowEqualObjects, parseRules, snakeToCamel, has, arrayify, groupBail
export default { export default {
name: 'FormularioInput', name: 'FormularioInput',
inheritAttrs: false, inheritAttrs: false,
provide () { provide () {
return { return {
// Allows sub-components of this input to register arbitrary rules. // Allows sub-components of this input to register arbitrary rules.
@ -23,6 +30,7 @@ export default {
formularioRemoveRule: this.removeRule formularioRemoveRule: this.removeRule
} }
}, },
inject: { inject: {
formularioSetter: { default: undefined }, formularioSetter: { default: undefined },
formularioFieldValidation: { default: () => () => ({}) }, formularioFieldValidation: { default: () => () => ({}) },
@ -33,87 +41,107 @@ export default {
removeErrorObserver: { default: undefined }, removeErrorObserver: { default: undefined },
path: { default: '' } path: { default: '' }
}, },
model: { model: {
prop: 'formularioValue', prop: 'formularioValue',
event: 'input' event: 'input'
}, },
props: { props: {
type: { type: {
type: String, type: String,
default: 'text' default: 'text'
}, },
name: { name: {
type: String, type: String,
required: true required: true
}, },
/* eslint-disable */ /* eslint-disable */
formularioValue: { formularioValue: {
default: '' default: ''
}, },
value: { value: {
default: false default: false
}, },
/* eslint-enable */ /* eslint-enable */
id: { id: {
type: [String, Boolean, Number], type: [String, Boolean, Number],
default: false default: false
}, },
errors: { errors: {
type: [String, Array, Boolean], type: [String, Array, Boolean],
default: false default: false
}, },
validation: { validation: {
type: [String, Boolean, Array], type: [String, Boolean, Array],
default: false default: false
}, },
validationName: { validationName: {
type: [String, Boolean], type: [String, Boolean],
default: false default: false
}, },
errorBehavior: { errorBehavior: {
type: String, type: String,
default: 'blur', default: 'blur',
validator: function (value) { validator (value) {
return ['blur', 'live', 'submit'].includes(value) return ['blur', 'live', 'submit'].includes(value)
} }
}, },
showErrors: { showErrors: {
type: Boolean, type: Boolean,
default: false default: false
}, },
imageBehavior: { imageBehavior: {
type: String, type: String,
default: 'preview' default: 'preview'
}, },
uploadUrl: { uploadUrl: {
type: [String, Boolean], type: [String, Boolean],
default: false default: false
}, },
uploader: { uploader: {
type: [Function, Object, Boolean], type: [Function, Object, Boolean],
default: false default: false
}, },
uploadBehavior: { uploadBehavior: {
type: String, type: String,
default: 'live' default: 'live'
}, },
preventWindowDrops: { preventWindowDrops: {
type: Boolean, type: Boolean,
default: true default: true
}, },
validationMessages: { validationMessages: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
validationRules: { validationRules: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
}, },
disableErrors: { disableErrors: {
type: Boolean, type: Boolean,
default: false default: false
} }
}, },
data () { data () {
return { return {
defaultId: this.$formulario.nextId(this), defaultId: this.$formulario.nextId(this),
@ -129,8 +157,10 @@ export default {
messageRegistry: {} messageRegistry: {}
} }
}, },
computed: { computed: {
...context, ...context,
parsedValidationRules () { parsedValidationRules () {
const parsedValidationRules = {} const parsedValidationRules = {}
Object.keys(this.validationRules).forEach(key => { Object.keys(this.validationRules).forEach(key => {
@ -138,6 +168,7 @@ export default {
}) })
return parsedValidationRules return parsedValidationRules
}, },
messages () { messages () {
const messages = {} const messages = {}
Object.keys(this.validationMessages).forEach((key) => { Object.keys(this.validationMessages).forEach((key) => {
@ -149,24 +180,28 @@ export default {
return messages return messages
} }
}, },
watch: { watch: {
'$attrs': { $attrs: {
handler (value) { handler (value) {
this.updateLocalAttributes(value) this.updateLocalAttributes(value)
}, },
deep: true deep: true
}, },
proxy (newValue, oldValue) { proxy (newValue, oldValue) {
this.performValidation() this.performValidation()
if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) { if (!this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) {
this.context.model = newValue this.context.model = newValue
} }
}, },
formularioValue (newValue, oldValue) { formularioValue (newValue, oldValue) {
if (this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) { if (this.isVmodeled && !shallowEqualObjects(newValue, oldValue)) {
this.context.model = newValue this.context.model = newValue
} }
}, },
showValidationErrors: { showValidationErrors: {
handler (val) { handler (val) {
this.$emit('error-visibility', val) this.$emit('error-visibility', val)
@ -174,6 +209,7 @@ export default {
immediate: true immediate: true
} }
}, },
created () { created () {
this.applyInitialValue() this.applyInitialValue()
if (this.formularioRegister && typeof this.formularioRegister === 'function') { if (this.formularioRegister && typeof this.formularioRegister === 'function') {
@ -187,6 +223,7 @@ export default {
this.performValidation() this.performValidation()
} }
}, },
beforeDestroy () { beforeDestroy () {
if (!this.disableErrors && typeof this.removeErrorObserver === 'function') { if (!this.disableErrors && typeof this.removeErrorObserver === 'function') {
this.removeErrorObserver(this.setErrors) this.removeErrorObserver(this.setErrors)
@ -195,6 +232,7 @@ export default {
this.formularioDeregister(this.nameOrFallback) this.formularioDeregister(this.nameOrFallback)
} }
}, },
methods: { methods: {
getInitialValue () { getInitialValue () {
if (has(this.$options.propsData, 'value')) { if (has(this.$options.propsData, 'value')) {
@ -204,6 +242,7 @@ export default {
} }
return '' return ''
}, },
applyInitialValue () { applyInitialValue () {
// This should only be run immediately on created and ensures that the // This should only be run immediately on created and ensures that the
// proxy and the model are both the same before any additional registration. // proxy and the model are both the same before any additional registration.
@ -211,11 +250,13 @@ export default {
this.context.model = this.proxy this.context.model = this.proxy
} }
}, },
updateLocalAttributes (value) { updateLocalAttributes (value) {
if (!shallowEqualObjects(value, this.localAttributes)) { if (!shallowEqualObjects(value, this.localAttributes)) {
this.localAttributes = value this.localAttributes = value
} }
}, },
performValidation () { performValidation () {
let rules = parseRules(this.validation, this.$formulario.rules(this.parsedValidationRules)) let rules = parseRules(this.validation, this.$formulario.rules(this.parsedValidationRules))
// Add in ruleRegistry rules. These are added directly via injection from // Add in ruleRegistry rules. These are added directly via injection from
@ -225,6 +266,7 @@ export default {
.then(messages => this.didValidate(messages)) .then(messages => this.didValidate(messages))
return this.pendingValidation return this.pendingValidation
}, },
runRules (rules) { runRules (rules) {
const run = ([rule, args, ruleName, modifier]) => { const run = ([rule, args, ruleName, modifier]) => {
var res = rule({ var res = rule({
@ -257,6 +299,7 @@ export default {
resolveGroups(groupBails(rules)) resolveGroups(groupBails(rules))
}) })
}, },
didValidate (messages) { didValidate (messages) {
const validationChanged = !shallowEqualObjects(messages, this.validationErrors) const validationChanged = !shallowEqualObjects(messages, this.validationErrors)
this.validationErrors = messages this.validationErrors = messages
@ -268,15 +311,16 @@ export default {
} }
} }
}, },
getMessageObject (ruleName, args) { getMessageObject (ruleName, args) {
let context = { const context = {
args, args,
name: this.mergedValidationName, name: this.mergedValidationName,
value: this.context.model, value: this.context.model,
vm: this, vm: this,
formValues: this.getFormValues() formValues: this.getFormValues()
}; }
let message = this.getMessageFunc(ruleName)(context); const message = this.getMessageFunc(ruleName)(context)
return { return {
message: message, message: message,
@ -284,6 +328,7 @@ export default {
context: context context: context
} }
}, },
getMessageFunc (ruleName) { getMessageFunc (ruleName) {
ruleName = snakeToCamel(ruleName) ruleName = snakeToCamel(ruleName)
if (this.messages && typeof this.messages[ruleName] !== 'undefined') { if (this.messages && typeof this.messages[ruleName] !== 'undefined') {
@ -297,6 +342,7 @@ export default {
} }
return (context) => this.$formulario.validationMessage(ruleName, context, this) return (context) => this.$formulario.validationMessage(ruleName, context, this)
}, },
hasValidationErrors () { hasValidationErrors () {
return new Promise(resolve => { return new Promise(resolve => {
this.$nextTick(() => { this.$nextTick(() => {
@ -304,11 +350,13 @@ export default {
}) })
}) })
}, },
getValidationErrors () { getValidationErrors () {
return new Promise(resolve => { return new Promise(resolve => {
this.$nextTick(() => this.pendingValidation.then(() => resolve(this.getErrorObject()))) this.$nextTick(() => this.pendingValidation.then(() => resolve(this.getErrorObject())))
}) })
}, },
getErrorObject () { getErrorObject () {
return { return {
name: this.context.nameOrFallback || this.context.name, name: this.context.nameOrFallback || this.context.name,
@ -316,9 +364,11 @@ export default {
hasErrors: !!this.validationErrors.length hasErrors: !!this.validationErrors.length
} }
}, },
setErrors (errors) { setErrors (errors) {
this.localErrors = arrayify(errors) this.localErrors = arrayify(errors)
}, },
registerRule (rule, args, ruleName, message = null) { registerRule (rule, args, ruleName, message = null) {
if (!this.ruleRegistry.some(r => r[2] === ruleName)) { if (!this.ruleRegistry.some(r => r[2] === ruleName)) {
// These are the raw rule format since they will be used directly. // These are the raw rule format since they will be used directly.
@ -328,6 +378,7 @@ export default {
} }
} }
}, },
removeRule (key) { removeRule (key) {
const ruleIndex = this.ruleRegistry.findIndex(r => r[2] === key) const ruleIndex = this.ruleRegistry.findIndex(r => r[2] === key)
if (ruleIndex >= 0) { if (ruleIndex >= 0) {

View File

@ -18,14 +18,14 @@ const validationMessages = {
* The default render method for error messages. * The default render method for error messages.
*/ */
default: function (vm, context) { default: function (vm, context) {
return vm.$t(`validation.default`, context) return vm.$t('validation.default', context)
}, },
/** /**
* Valid accepted value. * Valid accepted value.
*/ */
accepted: function (vm, context) { accepted: function (vm, context) {
return vm.$t(`validation.accepted`, context) return vm.$t('validation.accepted', context)
}, },
/** /**
@ -33,25 +33,25 @@ const validationMessages = {
*/ */
after: function (vm, context) { after: function (vm, context) {
if (Array.isArray(context.args) && context.args.length) { if (Array.isArray(context.args) && context.args.length) {
context['compare'] = context.args[0] context.compare = context.args[0]
return vm.$t(`validation.after.compare`, context) return vm.$t('validation.after.compare', context)
} }
return vm.$t(`validation.after.default`, context) return vm.$t('validation.after.default', context)
}, },
/** /**
* The value is not a letter. * The value is not a letter.
*/ */
alpha: function (vm, context) { alpha: function (vm, context) {
return vm.$t(`validation.alpha`, context) return vm.$t('validation.alpha', context)
}, },
/** /**
* Rule: checks if the value is alpha numeric * Rule: checks if the value is alpha numeric
*/ */
alphanumeric: function (vm, context) { alphanumeric: function (vm, context) {
return vm.$t(`validation.alphanumeric`, context) return vm.$t('validation.alphanumeric', context)
}, },
/** /**
@ -59,33 +59,33 @@ const validationMessages = {
*/ */
before: function (vm, context) { before: function (vm, context) {
if (Array.isArray(context.args) && context.args.length) { if (Array.isArray(context.args) && context.args.length) {
context['compare'] = context.args[0] context.compare = context.args[0]
return vm.$t(`validation.before.compare`, context) return vm.$t('validation.before.compare', context)
} }
return vm.$t(`validation.before.default`, context) return vm.$t('validation.before.default', context)
}, },
/** /**
* The value is not between two numbers or lengths * The value is not between two numbers or lengths
*/ */
between: function (vm, context) { between: function (vm, context) {
context['from'] = context.args[0] context.from = context.args[0]
context['to'] = context.args[1] context.to = context.args[1]
const force = Array.isArray(context.args) && context.args[2] ? context.args[2] : false const force = Array.isArray(context.args) && context.args[2] ? context.args[2] : false
if ((!isNaN(value) && force !== 'length') || force === 'value') { if ((!isNaN(value) && force !== 'length') || force === 'value') {
return vm.$t(`validation.between.force`, context) return vm.$t('validation.between.force', context)
} }
return vm.$t(`validation.between.default`, context) return vm.$t('validation.between.default', context)
}, },
/** /**
* The confirmation field does not match * The confirmation field does not match
*/ */
confirm: function (vm, context) { confirm: function (vm, context) {
return vm.$t(`validation.confirm`, context) return vm.$t('validation.confirm', context)
}, },
/** /**
@ -93,25 +93,25 @@ const validationMessages = {
*/ */
date: function (vm, context) { date: function (vm, context) {
if (Array.isArray(context.args) && context.args.length) { if (Array.isArray(context.args) && context.args.length) {
context['format'] = context.args[0] context.format = context.args[0]
return vm.$t(`validation.date.format`, context) return vm.$t('validation.date.format', context)
} }
return vm.$t(`validation.date.default`, context) return vm.$t('validation.date.default', context)
}, },
/** /**
* Is not a valid email address. * Is not a valid email address.
*/ */
email: function (vm, context) { email: function (vm, context) {
return vm.$t(`validation.email.default`, context) return vm.$t('validation.email.default', context)
}, },
/** /**
* Ends with specified value * Ends with specified value
*/ */
endsWith: function (vm, context) { endsWith: function (vm, context) {
return vm.$t(`validation.endsWith.default`, context) return vm.$t('validation.endsWith.default', context)
}, },
/** /**
@ -119,44 +119,44 @@ const validationMessages = {
*/ */
in: function (vm, context) { in: function (vm, context) {
if (typeof context.value === 'string' && context.value) { if (typeof context.value === 'string' && context.value) {
return vm.$t(`validation.in.string`, context) return vm.$t('validation.in.string', context)
} }
return vm.$t(`validation.in.default`, context) return vm.$t('validation.in.default', context)
}, },
/** /**
* Value is not a match. * Value is not a match.
*/ */
matches: function (vm, context) { matches: function (vm, context) {
return vm.$t(`validation.matches.default`, context) return vm.$t('validation.matches.default', context)
}, },
/** /**
* The maximum value allowed. * The maximum value allowed.
*/ */
max: function (vm, context) { max: function (vm, context) {
context['maximum'] = context.args[0] context.maximum = context.args[0]
if (Array.isArray(context.value)) { if (Array.isArray(context.value)) {
return vm.$tc(`validation.max.array`, context['maximum'], context) return vm.$tc('validation.max.array', context.maximum, context)
} }
const force = Array.isArray(context.args) && context.args[1] ? context.args[1] : false const force = Array.isArray(context.args) && context.args[1] ? context.args[1] : false
if ((!isNaN(context.value) && force !== 'length') || force === 'value') { if ((!isNaN(context.value) && force !== 'length') || force === 'value') {
return vm.$tc(`validation.max.force`, context['maximum'], context) return vm.$tc('validation.max.force', context.maximum, context)
} }
return vm.$tc(`validation.max.default`, context['maximum'], context) return vm.$tc('validation.max.default', context.maximum, context)
}, },
/** /**
* The (field-level) error message for mime errors. * The (field-level) error message for mime errors.
*/ */
mime: function (vm, context) { mime: function (vm, context) {
context['types'] = context.args[0] context.types = context.args[0]
if (context['types']) { if (context.types) {
return vm.$t(`validation.mime.default`, context) return vm.$t('validation.mime.default', context)
} else { } else {
return vm.$t(`validation.mime.no_formats_allowed`, context) return vm.$t('validation.mime.no_formats_allowed', context)
} }
}, },
@ -164,51 +164,51 @@ const validationMessages = {
* The maximum value allowed. * The maximum value allowed.
*/ */
min: function (vm, context) { min: function (vm, context) {
context['minimum'] = context.args[0] context.minimum = context.args[0]
if (Array.isArray(context.value)) { if (Array.isArray(context.value)) {
return vm.$tc(`validation.min.array`, context['minimum'], context) return vm.$tc('validation.min.array', context.minimum, context)
} }
const force = Array.isArray(context.args) && context.args[1] ? context.args[1] : false const force = Array.isArray(context.args) && context.args[1] ? context.args[1] : false
if ((!isNaN(context.value) && force !== 'length') || force === 'value') { if ((!isNaN(context.value) && force !== 'length') || force === 'value') {
return vm.$tc(`validation.min.force`, context['minimum'], context) return vm.$tc('validation.min.force', context.minimum, context)
} }
return vm.$tc(`validation.min.default`, context['minimum'], context) return vm.$tc('validation.min.default', context.minimum, context)
}, },
/** /**
* The field is not an allowed value * The field is not an allowed value
*/ */
not: function (vm, context) { not: function (vm, context) {
return vm.$t(`validation.not.default`, context) return vm.$t('validation.not.default', context)
}, },
/** /**
* The field is not a number * The field is not a number
*/ */
number: function (vm, context) { number: function (vm, context) {
return vm.$t(`validation.number.default`, context) return vm.$t('validation.number.default', context)
}, },
/** /**
* Required field. * Required field.
*/ */
required: function (vm, context) { required: function (vm, context) {
return vm.$t(`validation.required.default`, context) return vm.$t('validation.required.default', context)
}, },
/** /**
* Starts with specified value * Starts with specified value
*/ */
startsWith: function (vm, context) { startsWith: function (vm, context) {
return vm.$t(`validation.startsWith.default`, context) return vm.$t('validation.startsWith.default', context)
}, },
/** /**
* Value is not a url. * Value is not a url.
*/ */
url: function (vm, context) { url: function (vm, context) {
return vm.$t(`validation.url.default`, context) return vm.$t('validation.url.default', context)
} }
} }
@ -218,6 +218,6 @@ const validationMessages = {
*/ */
export default function (instance) { export default function (instance) {
instance.extend({ instance.extend({
validationMessages: validationMessages validationMessages
}) })
} }

View File

@ -1,10 +1,10 @@
const i = 'image/' const i = 'image/'
export default { export default {
'csv': 'text/csv', csv: 'text/csv',
'gif': i + 'gif', gif: i + 'gif',
'jpg': i + 'jpeg', jpg: i + 'jpeg',
'jpeg': i + 'jpeg', jpeg: i + 'jpeg',
'png': i + 'png', png: i + 'png',
'pdf': 'application/pdf', pdf: 'application/pdf',
'svg': i + 'svg+xml' svg: i + 'svg+xml'
} }

View File

@ -16,7 +16,7 @@ class Registry {
/** /**
* Add an item to the registry. * Add an item to the registry.
* @param {string|array} key * @param {string|array} name
* @param {vue} component * @param {vue} component
*/ */
add (name, component) { add (name, component) {
@ -104,6 +104,7 @@ class Registry {
/** /**
* Reduce the registry. * Reduce the registry.
* @param {function} callback * @param {function} callback
* @param accumulator
*/ */
reduce (callback, accumulator) { reduce (callback, accumulator) {
this.registry.forEach((component, field) => { this.registry.forEach((component, field) => {
@ -148,7 +149,7 @@ export function useRegistryComputed () {
) )
}, },
isVmodeled () { isVmodeled () {
return !!(this.$options.propsData.hasOwnProperty('formularioValue') && return !!(Object.prototype.hasOwnProperty.call(this.$options.propsData, 'formularioValue') &&
this._events && this._events &&
Array.isArray(this._events.input) && Array.isArray(this._events.input) &&
this._events.input.length) this._events.input.length)
@ -191,7 +192,7 @@ export function useRegistryMethods (without = []) {
const { [field]: value, ...proxy } = this.proxy const { [field]: value, ...proxy } = this.proxy
this.proxy = proxy this.proxy = proxy
} else { } else {
setNested(this.proxy, field, value); setNested(this.proxy, field, value)
} }
this.$emit('input', Object.assign({}, this.proxy)) this.$emit('input', Object.assign({}, this.proxy))
}, },

View File

@ -1,7 +1,6 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import flushPromises from 'flush-promises' import flushPromises from 'flush-promises'
import { mount, createLocalVue } from '@vue/test-utils' import { mount, createLocalVue } from '@vue/test-utils'
import Formulario from '@/Formulario.js' import Formulario from '@/Formulario.js'
import FormularioForm from '@/FormularioForm.vue' import FormularioForm from '@/FormularioForm.vue'
import FormularioInput from '@/FormularioInput.vue' import FormularioInput from '@/FormularioInput.vue'
@ -19,7 +18,9 @@ function validationMessages (instance) {
}) })
} }
Vue.use(Formulario, { const localVue = createLocalVue()
localVue.use(Formulario, {
plugins: [validationMessages], plugins: [validationMessages],
rules: { rules: {
globalRule globalRule
@ -29,6 +30,7 @@ Vue.use(Formulario, {
describe('FormularioInput', () => { describe('FormularioInput', () => {
it('allows custom field-rule level validation strings', async () => { it('allows custom field-rule level validation strings', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test', name: 'test',
validation: 'required|in:abcdef', validation: 'required|in:abcdef',
@ -38,7 +40,7 @@ describe('FormularioInput', () => {
}, },
scopedSlots: { scopedSlots: {
default: `<div><span v-for="error in props.context.allErrors">{{ error.message }}</span></div>` default: `<div><span v-for="error in props.context.allErrors">{{ error.message }}</span></div>`
} },
}) })
await flushPromises() await flushPromises()
expect(wrapper.find('span').text()).toBe('the value was different than expected') expect(wrapper.find('span').text()).toBe('the value was different than expected')
@ -62,6 +64,7 @@ describe('FormularioInput', () => {
it('allows custom field-rule level validation functions', async () => { it('allows custom field-rule level validation functions', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test', name: 'test',
validation: 'required|in:abcdef', validation: 'required|in:abcdef',
@ -79,6 +82,7 @@ describe('FormularioInput', () => {
it('uses custom async validation rules on defined on the field', async () => { it('uses custom async validation rules on defined on the field', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test', name: 'test',
validation: 'required|foobar', validation: 'required|foobar',
@ -101,6 +105,7 @@ describe('FormularioInput', () => {
it('uses custom sync validation rules on defined on the field', async () => { it('uses custom sync validation rules on defined on the field', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test', name: 'test',
validation: 'required|foobar', validation: 'required|foobar',
@ -123,6 +128,7 @@ describe('FormularioInput', () => {
it('uses global custom validation rules', async () => { it('uses global custom validation rules', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test', name: 'test',
validation: 'required|globalRule', validation: 'required|globalRule',
@ -135,13 +141,15 @@ describe('FormularioInput', () => {
}) })
it('emits correct validation event', async () => { it('emits correct validation event', async () => {
const wrapper = mount(FormularioInput, { propsData: { const wrapper = mount(FormularioInput, {
name: 'test', localVue,
propsData: {
validation: 'required', validation: 'required',
errorBehavior: 'live', errorBehavior: 'live',
value: '', value: '',
name: 'testinput', name: 'testinput',
} }) }
})
await flushPromises() await flushPromises()
const errorObject = wrapper.emitted('validation')[0][0] const errorObject = wrapper.emitted('validation')[0][0]
expect(errorObject).toEqual({ expect(errorObject).toEqual({
@ -159,8 +167,8 @@ describe('FormularioInput', () => {
it('emits a error-visibility event on blur', async () => { it('emits a error-visibility event on blur', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test',
validation: 'required', validation: 'required',
errorBehavior: 'blur', errorBehavior: 'blur',
value: '', value: '',
@ -178,21 +186,23 @@ describe('FormularioInput', () => {
}) })
it('emits error-visibility event immediately when live', async () => { it('emits error-visibility event immediately when live', async () => {
const wrapper = mount(FormularioInput, { propsData: { const wrapper = mount(FormularioInput, {
name: 'test', localVue,
propsData: {
validation: 'required', validation: 'required',
errorBehavior: 'live', errorBehavior: 'live',
value: '', value: '',
name: 'testinput', name: 'testinput',
} }) }
})
await flushPromises() await flushPromises()
expect(wrapper.emitted('error-visibility').length).toBe(1) expect(wrapper.emitted('error-visibility').length).toBe(1)
}) })
it('Does not emit an error-visibility event if visibility did not change', async () => { it('Does not emit an error-visibility event if visibility did not change', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
name: 'test',
validation: 'in:xyz', validation: 'in:xyz',
errorBehavior: 'live', errorBehavior: 'live',
value: 'bar', value: 'bar',
@ -211,6 +221,7 @@ describe('FormularioInput', () => {
it('can bail on validation when encountering the bail rule', async () => { it('can bail on validation when encountering the bail rule', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { name: 'test', validation: 'bail|required|in:xyz', errorBehavior: 'live' } propsData: { name: 'test', validation: 'bail|required|in:xyz', errorBehavior: 'live' }
}) })
await flushPromises(); await flushPromises();
@ -219,6 +230,7 @@ describe('FormularioInput', () => {
it('can show multiple validation errors if they occur before the bail rule', async () => { it('can show multiple validation errors if they occur before the bail rule', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { name: 'test', validation: 'required|in:xyz|bail', errorBehavior: 'live' } propsData: { name: 'test', validation: 'required|in:xyz|bail', errorBehavior: 'live' }
}) })
await flushPromises(); await flushPromises();
@ -227,6 +239,7 @@ describe('FormularioInput', () => {
it('can avoid bail behavior by using modifier', async () => { it('can avoid bail behavior by using modifier', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { name: 'test', validation: '^required|in:xyz|min:10,length', errorBehavior: 'live', value: '123' } propsData: { name: 'test', validation: '^required|in:xyz|min:10,length', errorBehavior: 'live', value: '123' }
}) })
await flushPromises(); await flushPromises();
@ -235,6 +248,7 @@ describe('FormularioInput', () => {
it('prevents later error messages when modified rule fails', async () => { it('prevents later error messages when modified rule fails', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { name: 'test', validation: '^required|in:xyz|min:10,length', errorBehavior: 'live' } propsData: { name: 'test', validation: '^required|in:xyz|min:10,length', errorBehavior: 'live' }
}) })
await flushPromises(); await flushPromises();
@ -243,6 +257,7 @@ describe('FormularioInput', () => {
it('can bail in the middle of the rule set with a modifier', async () => { it('can bail in the middle of the rule set with a modifier', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { name: 'test', validation: 'required|^in:xyz|min:10,length', errorBehavior: 'live' } propsData: { name: 'test', validation: 'required|^in:xyz|min:10,length', errorBehavior: 'live' }
}) })
await flushPromises(); await flushPromises();
@ -251,6 +266,7 @@ describe('FormularioInput', () => {
it('does not show errors on blur when set error-behavior is submit', async () => { it('does not show errors on blur when set error-behavior is submit', async () => {
const wrapper = mount(FormularioInput, { const wrapper = mount(FormularioInput, {
localVue,
propsData: { propsData: {
validation: 'required', validation: 'required',
errorBehavior: 'submit', errorBehavior: 'submit',
@ -275,6 +291,7 @@ describe('FormularioInput', () => {
it('displays errors when error-behavior is submit and form is submitted', async () => { it('displays errors when error-behavior is submit and form is submitted', async () => {
const wrapper = mount(FormularioForm, { const wrapper = mount(FormularioForm, {
localVue,
propsData: {name: 'test'}, propsData: {name: 'test'},
slots: { slots: {
default: ` default: `

View File

@ -1729,6 +1729,15 @@
sass "^1.18.0" sass "^1.18.0"
stylus "^0.54.5" stylus "^0.54.5"
"@vue/eslint-config-standard@^5.1.2":
version "5.1.2"
resolved "https://registry.yarnpkg.com/@vue/eslint-config-standard/-/eslint-config-standard-5.1.2.tgz#c5d55af894a3ae23b65b1af4a425777ac0170b42"
integrity sha512-FTz0k77dIrj9r3xskt9jsZyL/YprrLiPRf4m3k7G6dZ5PKuD6OPqYrHR9eduUmHDFpTlRgFpTVQrq+1el9k3QQ==
dependencies:
eslint-config-standard "^14.1.0"
eslint-import-resolver-node "^0.3.3"
eslint-import-resolver-webpack "^0.12.1"
"@vue/preload-webpack-plugin@^1.1.0": "@vue/preload-webpack-plugin@^1.1.0":
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.1.tgz#18723530d304f443021da2292d6ec9502826104a" resolved "https://registry.yarnpkg.com/@vue/preload-webpack-plugin/-/preload-webpack-plugin-1.1.1.tgz#18723530d304f443021da2292d6ec9502826104a"
@ -2158,6 +2167,11 @@ array-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
array-find@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8"
integrity sha1-bI4obRHtdoMn+OYuzuhzU8o+eLg=
array-flatten@1.1.1: array-flatten@1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@ -4186,6 +4200,15 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies: dependencies:
once "^1.4.0" once "^1.4.0"
enhanced-resolve@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e"
integrity sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=
dependencies:
graceful-fs "^4.1.2"
memory-fs "^0.2.0"
tapable "^0.1.8"
enhanced-resolve@^4.1.0: enhanced-resolve@^4.1.0:
version "4.1.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz#2937e2b8066cd0fe7ce0990a98f0d71a35189f66"
@ -4279,6 +4302,11 @@ eslint-config-standard@^12.0.0:
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz#638b4c65db0bd5a41319f96bba1f15ddad2107d9" resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-12.0.0.tgz#638b4c65db0bd5a41319f96bba1f15ddad2107d9"
integrity sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ== integrity sha512-COUz8FnXhqFitYj4DTqHzidjIL/t4mumGZto5c7DrBpvWoie+Sn3P4sLEzUGeYhRElWuFEf8K1S1EfvD1vixCQ==
eslint-config-standard@^14.1.0:
version "14.1.1"
resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-14.1.1.tgz#830a8e44e7aef7de67464979ad06b406026c56ea"
integrity sha512-Z9B+VR+JIXRxz21udPTL9HpFMyoMUEeX1G251EQ6e05WD9aPVtVBn09XUmZ259wCMlCDmYDSZG62Hhm+ZTJcUg==
eslint-import-resolver-node@^0.3.2: eslint-import-resolver-node@^0.3.2:
version "0.3.3" version "0.3.3"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.3.tgz#dbaa52b6b2816b50bc6711af75422de808e98404"
@ -4287,6 +4315,30 @@ eslint-import-resolver-node@^0.3.2:
debug "^2.6.9" debug "^2.6.9"
resolve "^1.13.1" resolve "^1.13.1"
eslint-import-resolver-node@^0.3.3:
version "0.3.4"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717"
integrity sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==
dependencies:
debug "^2.6.9"
resolve "^1.13.1"
eslint-import-resolver-webpack@^0.12.1:
version "0.12.2"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.12.2.tgz#769e86cd0c752a1536c19855ebd90aa14ce384ee"
integrity sha512-7Jnm4YAoNNkvqPaZkKdIHsKGmv8/uNnYC5QsXkiSodvX4XEEfH2AKOna98FK52fCDXm3q4HzuX+7pRMKkJ64EQ==
dependencies:
array-find "^1.0.0"
debug "^2.6.9"
enhanced-resolve "^0.9.1"
find-root "^1.1.0"
has "^1.0.3"
interpret "^1.2.0"
lodash "^4.17.15"
node-libs-browser "^1.0.0 || ^2.0.0"
resolve "^1.13.1"
semver "^5.7.1"
eslint-loader@^2.2.1: eslint-loader@^2.2.1:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337" resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337"
@ -4881,6 +4933,11 @@ find-cache-dir@^3.0.0, find-cache-dir@^3.3.1:
make-dir "^3.0.2" make-dir "^3.0.2"
pkg-dir "^4.1.0" pkg-dir "^4.1.0"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@^1.0.0: find-up@^1.0.0:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
@ -5691,6 +5748,11 @@ internal-ip@^4.3.0:
default-gateway "^4.2.0" default-gateway "^4.2.0"
ipaddr.js "^1.9.0" ipaddr.js "^1.9.0"
interpret@^1.2.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
invariant@^2.2.2, invariant@^2.2.4: invariant@^2.2.2, invariant@^2.2.4:
version "2.2.4" version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@ -7006,6 +7068,11 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
memory-fs@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290"
integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA=
memory-fs@^0.4.1: memory-fs@^0.4.1:
version "0.4.1" version "0.4.1"
resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
@ -7357,7 +7424,7 @@ node-ipc@^9.1.1:
js-message "1.0.5" js-message "1.0.5"
js-queue "2.0.0" js-queue "2.0.0"
node-libs-browser@^2.2.1: "node-libs-browser@^1.0.0 || ^2.0.0", node-libs-browser@^2.2.1:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
@ -9361,7 +9428,7 @@ selfsigned@^1.10.7:
dependencies: dependencies:
node-forge "0.9.0" node-forge "0.9.0"
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: "semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1:
version "5.7.1" version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
@ -10064,6 +10131,11 @@ table@^5.2.3:
slice-ansi "^2.1.0" slice-ansi "^2.1.0"
string-width "^3.0.0" string-width "^3.0.0"
tapable@^0.1.8:
version "0.1.10"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4"
integrity sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=
tapable@^1.0.0, tapable@^1.1.3: tapable@^1.0.0, tapable@^1.1.3:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"