refactor: Merge utility moved to a separated file
This commit is contained in:
parent
c5bb8076e6
commit
ec1035a9a0
@ -8,6 +8,7 @@ import FileUpload from '@/FileUpload'
|
|||||||
import RuleValidationMessages from '@/RuleValidationMessages'
|
import RuleValidationMessages from '@/RuleValidationMessages'
|
||||||
import { arrayify, has } from '@/libs/utils'
|
import { arrayify, has } from '@/libs/utils'
|
||||||
import fauxUploader from '@/libs/faux-uploader'
|
import fauxUploader from '@/libs/faux-uploader'
|
||||||
|
import merge from '@/utils/merge'
|
||||||
|
|
||||||
import FormularioForm from '@/FormularioForm.vue'
|
import FormularioForm from '@/FormularioForm.vue'
|
||||||
import FormularioInput from '@/FormularioInput.vue'
|
import FormularioInput from '@/FormularioInput.vue'
|
||||||
@ -113,46 +114,12 @@ export default class Formulario {
|
|||||||
*/
|
*/
|
||||||
extend (extendWith: FormularioOptions) {
|
extend (extendWith: FormularioOptions) {
|
||||||
if (typeof extendWith === 'object') {
|
if (typeof extendWith === 'object') {
|
||||||
this.options = this.merge(this.options as FormularioOptions, extendWith)
|
this.options = merge(this.options as FormularioOptions, extendWith)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
throw new Error(`VueFormulario extend() should be passed an object (was ${typeof extendWith})`)
|
throw new Error(`VueFormulario extend() should be passed an object (was ${typeof extendWith})`)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new object by copying properties of base and mergeWith.
|
|
||||||
* Note: arrays don't overwrite - they push
|
|
||||||
*
|
|
||||||
* @param {Object} base
|
|
||||||
* @param {Object} mergeWith
|
|
||||||
* @param {boolean} concatArrays
|
|
||||||
*/
|
|
||||||
merge (base: ObjectType, mergeWith: ObjectType, concatArrays: boolean = true) {
|
|
||||||
const merged: ObjectType = {}
|
|
||||||
|
|
||||||
for (const key in base) {
|
|
||||||
if (has(mergeWith, key)) {
|
|
||||||
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
|
|
||||||
merged[key] = this.merge(base[key], mergeWith[key], concatArrays)
|
|
||||||
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
|
|
||||||
merged[key] = base[key].concat(mergeWith[key])
|
|
||||||
} else {
|
|
||||||
merged[key] = mergeWith[key]
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
merged[key] = base[key]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const prop in mergeWith) {
|
|
||||||
if (!has(merged, prop)) {
|
|
||||||
merged[prop] = mergeWith[prop]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return merged
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine what "class" of input this element is given the "type".
|
* Determine what "class" of input this element is given the "type".
|
||||||
*/
|
*/
|
||||||
|
@ -20,7 +20,7 @@ import { arrayify, getNested, has, setNested, shallowEqualObjects } from '@/libs
|
|||||||
import { ObjectType } from '@/common.types'
|
import { ObjectType } from '@/common.types'
|
||||||
import Registry from '@/libs/registry'
|
import Registry from '@/libs/registry'
|
||||||
import FormSubmission from '@/FormSubmission'
|
import FormSubmission from '@/FormSubmission'
|
||||||
import FormularioInput from '@/FormularioInput'
|
import FormularioInput from '@/FormularioInput.vue'
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
export default class FormularioForm extends Vue {
|
export default class FormularioForm extends Vue {
|
||||||
|
37
src/utils/merge.ts
Normal file
37
src/utils/merge.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import isPlainObject from 'is-plain-object'
|
||||||
|
import { ObjectType } from '@/common.types.ts'
|
||||||
|
import { has } from '@/libs/utils.ts'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new object by copying properties of base and mergeWith.
|
||||||
|
* Note: arrays don't overwrite - they push
|
||||||
|
*
|
||||||
|
* @param {Object} base
|
||||||
|
* @param {Object} mergeWith
|
||||||
|
* @param {boolean} concatArrays
|
||||||
|
*/
|
||||||
|
export default function merge (base: ObjectType, mergeWith: ObjectType, concatArrays: boolean = true) {
|
||||||
|
const merged: ObjectType = {}
|
||||||
|
|
||||||
|
for (const key in base) {
|
||||||
|
if (has(mergeWith, key)) {
|
||||||
|
if (isPlainObject(mergeWith[key]) && isPlainObject(base[key])) {
|
||||||
|
merged[key] = merge(base[key], mergeWith[key], concatArrays)
|
||||||
|
} else if (concatArrays && Array.isArray(base[key]) && Array.isArray(mergeWith[key])) {
|
||||||
|
merged[key] = base[key].concat(mergeWith[key])
|
||||||
|
} else {
|
||||||
|
merged[key] = mergeWith[key]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
merged[key] = base[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const prop in mergeWith) {
|
||||||
|
if (!has(merged, prop)) {
|
||||||
|
merged[prop] = mergeWith[prop]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return merged
|
||||||
|
}
|
@ -1,65 +1,6 @@
|
|||||||
import Formulario from '@/index.ts'
|
import Formulario from '@/index.ts'
|
||||||
|
|
||||||
describe('Formulario', () => {
|
describe('Formulario', () => {
|
||||||
it('can merge simple object', () => {
|
|
||||||
let a = {
|
|
||||||
optionA: true,
|
|
||||||
optionB: '1234'
|
|
||||||
}
|
|
||||||
let b = {
|
|
||||||
optionA: false
|
|
||||||
}
|
|
||||||
expect(Formulario.merge(a, b)).toEqual({
|
|
||||||
optionA: false,
|
|
||||||
optionB: '1234'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can add to simple array', () => {
|
|
||||||
let a = {
|
|
||||||
optionA: true,
|
|
||||||
optionB: ['first', 'second']
|
|
||||||
}
|
|
||||||
let b = {
|
|
||||||
optionB: ['third']
|
|
||||||
}
|
|
||||||
expect(Formulario.merge(a, b, true)).toEqual({
|
|
||||||
optionA: true,
|
|
||||||
optionB: ['first', 'second', 'third']
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can merge recursively', () => {
|
|
||||||
let a = {
|
|
||||||
optionA: true,
|
|
||||||
optionC: {
|
|
||||||
first: '123',
|
|
||||||
third: {
|
|
||||||
a: 'b'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
optionB: '1234'
|
|
||||||
}
|
|
||||||
let b = {
|
|
||||||
optionB: '567',
|
|
||||||
optionC: {
|
|
||||||
first: '1234',
|
|
||||||
second: '789',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(Formulario.merge(a, b)).toEqual({
|
|
||||||
optionA: true,
|
|
||||||
optionC: {
|
|
||||||
first: '1234',
|
|
||||||
third: {
|
|
||||||
a: 'b'
|
|
||||||
},
|
|
||||||
second: '789'
|
|
||||||
},
|
|
||||||
optionB: '567'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('installs on vue instance', () => {
|
it('installs on vue instance', () => {
|
||||||
const components = [
|
const components = [
|
||||||
'FormularioForm',
|
'FormularioForm',
|
||||||
|
@ -8,12 +8,12 @@ import FormularioGrouping from '@/FormularioGrouping.vue'
|
|||||||
Vue.use(Formulario)
|
Vue.use(Formulario)
|
||||||
|
|
||||||
describe('FormularioGrouping', () => {
|
describe('FormularioGrouping', () => {
|
||||||
it('grouped fields to be setted', async () => {
|
it('Grouped fields to be set', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { name: 'form', },
|
propsData: { name: 'form' },
|
||||||
slots: {
|
slots: {
|
||||||
default: `
|
default: `
|
||||||
<FormularioGrouping name="sub">
|
<FormularioGrouping name="group">
|
||||||
<FormularioInput name="text" v-slot="{ context }">
|
<FormularioInput name="text" v-slot="{ context }">
|
||||||
<input type="text" v-model="context.model">
|
<input type="text" v-model="context.model">
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
@ -25,38 +25,40 @@ describe('FormularioGrouping', () => {
|
|||||||
wrapper.find('input[type="text"]').setValue('test')
|
wrapper.find('input[type="text"]').setValue('test')
|
||||||
|
|
||||||
const submission = await wrapper.vm.formSubmitted()
|
const submission = await wrapper.vm.formSubmitted()
|
||||||
expect(submission).toEqual({sub: {text: 'test'}})
|
expect(submission).toEqual({ group: { text: 'test' } })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('grouped fields to be getted', async () => {
|
it('Grouped fields to be got', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { name: 'form', formularioValue: { sub: {text: 'initial value'}, text: 'simple text' } },
|
propsData: {
|
||||||
|
name: 'form',
|
||||||
|
formularioValue: {
|
||||||
|
group: { text: 'Group text' },
|
||||||
|
text: 'Text',
|
||||||
|
}
|
||||||
|
},
|
||||||
slots: {
|
slots: {
|
||||||
default: `
|
default: `
|
||||||
<FormularioGrouping name="sub">
|
<FormularioGrouping name="group">
|
||||||
<FormularioInput name="text" v-slot="vSlot">
|
<FormularioInput name="text" v-slot="{ context }">
|
||||||
<input type="text" v-model="vSlot.context.model">
|
<input type="text" v-model="context.model">
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioGrouping>
|
</FormularioGrouping>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(wrapper.find('input[type="text"]').element.value).toBe('initial value')
|
expect(wrapper.find('input[type="text"]').element.value).toBe('Group text')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('data reactive with grouped fields', async () => {
|
it('Data reactive with grouped fields', async () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({ values: {} }),
|
||||||
return {
|
|
||||||
formValues: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm name="form" v-model="formValues">
|
<FormularioForm name="form" v-model="values">
|
||||||
<FormularioGrouping name="sub">
|
<FormularioGrouping name="group">
|
||||||
<FormularioInput name="text" v-slot="vSlot">
|
<FormularioInput name="text" v-slot="{ context }">
|
||||||
<input type="text" v-model="vSlot.context.model">
|
<input type="text" v-model="context.model">
|
||||||
<span>{{ formValues.sub.text }}</span>
|
<span>{{ values.group.text }}</span>
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioGrouping>
|
</FormularioGrouping>
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
@ -68,18 +70,20 @@ describe('FormularioGrouping', () => {
|
|||||||
expect(wrapper.find('span').text()).toBe('test')
|
expect(wrapper.find('span').text()).toBe('test')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('errors are setted for grouped fields', async () => {
|
it('Errors are set for grouped fields', async () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({ values: {} }),
|
||||||
return {
|
|
||||||
formValues: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm name="form" v-model="formValues" :errors="{'sub.text': 'Test error'}">
|
<FormularioForm
|
||||||
<FormularioGrouping name="sub">
|
v-model="values"
|
||||||
<FormularioInput name="text" v-slot="vSlot">
|
:errors="{'group.text': 'Test error'}"
|
||||||
<span v-for="error in vSlot.context.allErrors">{{ error }}</span>
|
name="form"
|
||||||
|
>
|
||||||
|
<FormularioGrouping name="group">
|
||||||
|
<FormularioInput name="text" v-slot="{ context }">
|
||||||
|
<span v-for="error in context.allErrors">
|
||||||
|
{{ error }}
|
||||||
|
</span>
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioGrouping>
|
</FormularioGrouping>
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
|
56
test/unit/merge.test.js
Normal file
56
test/unit/merge.test.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import merge from '@/utils/merge.ts'
|
||||||
|
|
||||||
|
describe('merge', () => {
|
||||||
|
it('Can merge simple object', () => {
|
||||||
|
expect(merge({
|
||||||
|
optionA: true,
|
||||||
|
optionB: '1234',
|
||||||
|
}, {
|
||||||
|
optionA: false,
|
||||||
|
})).toEqual({
|
||||||
|
optionA: false,
|
||||||
|
optionB: '1234',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can add to simple array', () => {
|
||||||
|
expect(merge({
|
||||||
|
optionA: true,
|
||||||
|
optionB: ['first', 'second']
|
||||||
|
}, {
|
||||||
|
optionB: ['third']
|
||||||
|
}, true)).toEqual({
|
||||||
|
optionA: true,
|
||||||
|
optionB: ['first', 'second', 'third']
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can merge recursively', () => {
|
||||||
|
expect(merge({
|
||||||
|
optionA: true,
|
||||||
|
optionC: {
|
||||||
|
first: '123',
|
||||||
|
third: {
|
||||||
|
a: 'b',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
optionB: '1234',
|
||||||
|
}, {
|
||||||
|
optionB: '567',
|
||||||
|
optionC: {
|
||||||
|
first: '1234',
|
||||||
|
second: '789',
|
||||||
|
}
|
||||||
|
})).toEqual({
|
||||||
|
optionA: true,
|
||||||
|
optionC: {
|
||||||
|
first: '1234',
|
||||||
|
third: {
|
||||||
|
a: 'b',
|
||||||
|
},
|
||||||
|
second: '789',
|
||||||
|
},
|
||||||
|
optionB: '567',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user