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 { arrayify, has } from '@/libs/utils'
|
||||
import fauxUploader from '@/libs/faux-uploader'
|
||||
import merge from '@/utils/merge'
|
||||
|
||||
import FormularioForm from '@/FormularioForm.vue'
|
||||
import FormularioInput from '@/FormularioInput.vue'
|
||||
@ -113,46 +114,12 @@ export default class Formulario {
|
||||
*/
|
||||
extend (extendWith: FormularioOptions) {
|
||||
if (typeof extendWith === 'object') {
|
||||
this.options = this.merge(this.options as FormularioOptions, extendWith)
|
||||
this.options = merge(this.options as FormularioOptions, extendWith)
|
||||
return this
|
||||
}
|
||||
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".
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@ import { arrayify, getNested, has, setNested, shallowEqualObjects } from '@/libs
|
||||
import { ObjectType } from '@/common.types'
|
||||
import Registry from '@/libs/registry'
|
||||
import FormSubmission from '@/FormSubmission'
|
||||
import FormularioInput from '@/FormularioInput'
|
||||
import FormularioInput from '@/FormularioInput.vue'
|
||||
|
||||
@Component
|
||||
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'
|
||||
|
||||
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', () => {
|
||||
const components = [
|
||||
'FormularioForm',
|
||||
|
@ -8,12 +8,12 @@ import FormularioGrouping from '@/FormularioGrouping.vue'
|
||||
Vue.use(Formulario)
|
||||
|
||||
describe('FormularioGrouping', () => {
|
||||
it('grouped fields to be setted', async () => {
|
||||
it('Grouped fields to be set', async () => {
|
||||
const wrapper = mount(FormularioForm, {
|
||||
propsData: { name: 'form', },
|
||||
propsData: { name: 'form' },
|
||||
slots: {
|
||||
default: `
|
||||
<FormularioGrouping name="sub">
|
||||
<FormularioGrouping name="group">
|
||||
<FormularioInput name="text" v-slot="{ context }">
|
||||
<input type="text" v-model="context.model">
|
||||
</FormularioInput>
|
||||
@ -25,38 +25,40 @@ describe('FormularioGrouping', () => {
|
||||
wrapper.find('input[type="text"]').setValue('test')
|
||||
|
||||
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, {
|
||||
propsData: { name: 'form', formularioValue: { sub: {text: 'initial value'}, text: 'simple text' } },
|
||||
propsData: {
|
||||
name: 'form',
|
||||
formularioValue: {
|
||||
group: { text: 'Group text' },
|
||||
text: 'Text',
|
||||
}
|
||||
},
|
||||
slots: {
|
||||
default: `
|
||||
<FormularioGrouping name="sub">
|
||||
<FormularioInput name="text" v-slot="vSlot">
|
||||
<input type="text" v-model="vSlot.context.model">
|
||||
<FormularioGrouping name="group">
|
||||
<FormularioInput name="text" v-slot="{ context }">
|
||||
<input type="text" v-model="context.model">
|
||||
</FormularioInput>
|
||||
</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({
|
||||
data () {
|
||||
return {
|
||||
formValues: {}
|
||||
}
|
||||
},
|
||||
data: () => ({ values: {} }),
|
||||
template: `
|
||||
<FormularioForm name="form" v-model="formValues">
|
||||
<FormularioGrouping name="sub">
|
||||
<FormularioInput name="text" v-slot="vSlot">
|
||||
<input type="text" v-model="vSlot.context.model">
|
||||
<span>{{ formValues.sub.text }}</span>
|
||||
<FormularioForm name="form" v-model="values">
|
||||
<FormularioGrouping name="group">
|
||||
<FormularioInput name="text" v-slot="{ context }">
|
||||
<input type="text" v-model="context.model">
|
||||
<span>{{ values.group.text }}</span>
|
||||
</FormularioInput>
|
||||
</FormularioGrouping>
|
||||
</FormularioForm>
|
||||
@ -68,18 +70,20 @@ describe('FormularioGrouping', () => {
|
||||
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({
|
||||
data () {
|
||||
return {
|
||||
formValues: {}
|
||||
}
|
||||
},
|
||||
data: () => ({ values: {} }),
|
||||
template: `
|
||||
<FormularioForm name="form" v-model="formValues" :errors="{'sub.text': 'Test error'}">
|
||||
<FormularioGrouping name="sub">
|
||||
<FormularioInput name="text" v-slot="vSlot">
|
||||
<span v-for="error in vSlot.context.allErrors">{{ error }}</span>
|
||||
<FormularioForm
|
||||
v-model="values"
|
||||
:errors="{'group.text': 'Test error'}"
|
||||
name="form"
|
||||
>
|
||||
<FormularioGrouping name="group">
|
||||
<FormularioInput name="text" v-slot="{ context }">
|
||||
<span v-for="error in context.allErrors">
|
||||
{{ error }}
|
||||
</span>
|
||||
</FormularioInput>
|
||||
</FormularioGrouping>
|
||||
</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…
Reference in New Issue
Block a user