From: nandi95 <41805560+nandi95@users.noreply.github.com>
Date: Tue, 5 Dec 2023 09:14:17 +0000 (+0000)
Subject: feat(runtime-core): provide full props to props validator functions (#3258)
X-Git-Tag: v3.4.0-beta.1~36
X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e27692029a4645cd54287f776c0420f2b82740b;p=thirdparty%2Fvuejs%2Fcore.git
feat(runtime-core): provide full props to props validator functions (#3258)
---
diff --git a/packages/runtime-core/__tests__/componentProps.spec.ts b/packages/runtime-core/__tests__/componentProps.spec.ts
index 885e80090a..3a16840b4f 100644
--- a/packages/runtime-core/__tests__/componentProps.spec.ts
+++ b/packages/runtime-core/__tests__/componentProps.spec.ts
@@ -282,6 +282,56 @@ describe('component props', () => {
expect(root.innerHTML).toBe('
2
')
})
+ describe('validator', () => {
+ test('validator should be called with two arguments', async () => {
+ const mockFn = vi.fn((...args: any[]) => true)
+ const Comp = defineComponent({
+ props: {
+ foo: {
+ type: Number,
+ validator: (value, props) => mockFn(value, props)
+ },
+ bar: {
+ type: Number
+ }
+ },
+ template: ``
+ })
+
+ // Note this one is using the main Vue render so it can compile template
+ // on the fly
+ const root = document.createElement('div')
+ domRender(h(Comp, { foo: 1, bar: 2 }), root)
+ expect(mockFn).toHaveBeenCalledWith(1, { foo: 1, bar: 2 })
+ })
+
+ test('validator should not be able to mutate other props', async () => {
+ const mockFn = vi.fn((...args: any[]) => true)
+ const Comp = defineComponent({
+ props: {
+ foo: {
+ type: Number,
+ validator: (value, props) => !!(props.bar = 1)
+ },
+ bar: {
+ type: Number,
+ validator: value => mockFn(value)
+ }
+ },
+ template: ``
+ })
+
+ // Note this one is using the main Vue render so it can compile template
+ // on the fly
+ const root = document.createElement('div')
+ domRender(h(Comp, { foo: 1, bar: 2 }), root)
+ expect(
+ `Set operation on key "bar" failed: target is readonly.`
+ ).toHaveBeenWarnedLast()
+ expect(mockFn).toHaveBeenCalledWith(2)
+ })
+ })
+
test('warn props mutation', () => {
let instance: ComponentInternalInstance
let setupProps: any
diff --git a/packages/runtime-core/src/componentProps.ts b/packages/runtime-core/src/componentProps.ts
index bbe88bf7b8..4b7be8a8e7 100644
--- a/packages/runtime-core/src/componentProps.ts
+++ b/packages/runtime-core/src/componentProps.ts
@@ -2,7 +2,8 @@ import {
toRaw,
shallowReactive,
trigger,
- TriggerOpTypes
+ TriggerOpTypes,
+ shallowReadonly
} from '@vue/reactivity'
import {
EMPTY_OBJ,
@@ -57,7 +58,7 @@ export interface PropOptions {
type?: PropType | true | null
required?: boolean
default?: D | DefaultFactory | null | undefined | object
- validator?(value: unknown): boolean
+ validator?(value: unknown, props: Data): boolean
/**
* @internal
*/
@@ -634,6 +635,7 @@ function validateProps(
key,
resolvedValues[key],
opt,
+ __DEV__ ? shallowReadonly(resolvedValues) : resolvedValues,
!hasOwn(rawProps, key) && !hasOwn(rawProps, hyphenate(key))
)
}
@@ -646,6 +648,7 @@ function validateProp(
name: string,
value: unknown,
prop: PropOptions,
+ props: Data,
isAbsent: boolean
) {
const { type, required, validator, skipCheck } = prop
@@ -675,7 +678,7 @@ function validateProp(
}
}
// custom validator
- if (validator && !validator(value)) {
+ if (validator && !validator(value, props)) {
warn('Invalid prop: custom validator check failed for prop "' + name + '".')
}
}