Skip to content

Commit

Permalink
Merge branch 'main' into fix-jsx-dom-augmentation
Browse files Browse the repository at this point in the history
  • Loading branch information
sodatea committed Mar 29, 2023
2 parents 241d222 + ff60b93 commit 5566fc0
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 18 deletions.
Expand Up @@ -13,6 +13,7 @@ import {
} from '../../src'
import { transformIf } from '../../src/transforms/vIf'
import { transformExpression } from '../../src/transforms/transformExpression'
import { PatchFlagNames, PatchFlags } from '../../../shared/src'

function parseWithExpressionTransform(
template: string,
Expand Down Expand Up @@ -494,7 +495,9 @@ describe('compiler: expression transform', () => {
setup: BindingTypes.SETUP_MAYBE_REF,
setupConst: BindingTypes.SETUP_CONST,
data: BindingTypes.DATA,
options: BindingTypes.OPTIONS
options: BindingTypes.OPTIONS,
reactive: BindingTypes.SETUP_REACTIVE_CONST,
literal: BindingTypes.LITERAL_CONST
}

function compileWithBindingMetadata(
Expand Down Expand Up @@ -532,5 +535,25 @@ describe('compiler: expression transform', () => {
expect(code).toMatch(`_ctx.options`)
expect(code).toMatchSnapshot()
})

test('literal const handling', () => {
const { code } = compileWithBindingMetadata(`<div>{{ literal }}</div>`, {
inline: true
})
// #7973 should skip patch for literal const
expect(code).not.toMatch(
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
)
})

test('reactive const handling', () => {
const { code } = compileWithBindingMetadata(`<div>{{ reactive }}</div>`, {
inline: true
})
// #7973 should not skip patch for reactive const
expect(code).toMatch(
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
)
})
})
})
10 changes: 6 additions & 4 deletions packages/compiler-core/src/transforms/transformExpression.ts
Expand Up @@ -128,7 +128,11 @@ export function processExpression(
const isDestructureAssignment =
parent && isInDestructureAssignment(parent, parentStack)

if (isConst(type) || localVars[raw]) {
if (
isConst(type) ||
type === BindingTypes.SETUP_REACTIVE_CONST ||
localVars[raw]
) {
return raw
} else if (type === BindingTypes.SETUP_REF) {
return `${raw}.value`
Expand Down Expand Up @@ -371,8 +375,6 @@ export function stringifyExpression(exp: ExpressionNode | string): string {

function isConst(type: unknown) {
return (
type === BindingTypes.SETUP_CONST ||
type === BindingTypes.LITERAL_CONST ||
type === BindingTypes.SETUP_REACTIVE_CONST
type === BindingTypes.SETUP_CONST || type === BindingTypes.LITERAL_CONST
)
}
Expand Up @@ -1715,7 +1715,9 @@ export default /*#__PURE__*/_defineComponent({
foo: { type: [Function, null], required: true },
unknown: { type: null, required: true },
unknownUnion: { type: null, required: true },
unknownIntersection: { type: Object, required: true }
unknownIntersection: { type: Object, required: true },
unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },
unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }
},
setup(__props: any, { expose: __expose }) {
__expose();
Expand Down
14 changes: 12 additions & 2 deletions packages/compiler-sfc/__tests__/compileScript.spec.ts
Expand Up @@ -1042,6 +1042,8 @@ const emit = defineEmits(['a', 'b'])
unknown: UnknownType
unknownUnion: UnknownType | string
unknownIntersection: UnknownType & Object
unknownUnionWithBoolean: UnknownType | boolean
unknownUnionWithFunction: UnknownType | (() => any)
}>()
</script>`)
assertCode(content)
Expand Down Expand Up @@ -1093,7 +1095,13 @@ const emit = defineEmits(['a', 'b'])
expect(content).toMatch(`unknownUnion: { type: null, required: true }`)
// intersection containing unknown type: narrow to the known types
expect(content).toMatch(
`unknownIntersection: { type: Object, required: true }`
`unknownIntersection: { type: Object, required: true },`
)
expect(content).toMatch(
`unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`
)
expect(content).toMatch(
`unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`
)
expect(bindings).toStrictEqual({
string: BindingTypes.PROPS,
Expand Down Expand Up @@ -1131,7 +1139,9 @@ const emit = defineEmits(['a', 'b'])
nonNull: BindingTypes.PROPS,
unknown: BindingTypes.PROPS,
unknownUnion: BindingTypes.PROPS,
unknownIntersection: BindingTypes.PROPS
unknownIntersection: BindingTypes.PROPS,
unknownUnionWithBoolean: BindingTypes.PROPS,
unknownUnionWithFunction: BindingTypes.PROPS
})
})

Expand Down
16 changes: 12 additions & 4 deletions packages/compiler-sfc/src/compileScript.ts
Expand Up @@ -888,11 +888,11 @@ export function compileScript(
}
}
const { type, required } = props[key]
const { type, required, skipCheck } = props[key]
if (!isProd) {
return `${key}: { type: ${toRuntimeTypeString(
type
)}, required: ${required}${
)}, required: ${required}${skipCheck ? ', skipCheck: true' : ''}${
defaultString ? `, ${defaultString}` : ``
} }`
} else if (
Expand Down Expand Up @@ -1964,6 +1964,7 @@ interface PropTypeData {
key: string
type: string[]
required: boolean
skipCheck: boolean
}

function recordType(node: Node, declaredTypes: Record<string, string[]>) {
Expand Down Expand Up @@ -1993,19 +1994,26 @@ function extractRuntimeProps(
m.key.type === 'Identifier'
) {
let type: string[] | undefined
let skipCheck = false
if (m.type === 'TSMethodSignature') {
type = ['Function']
} else if (m.typeAnnotation) {
type = inferRuntimeType(m.typeAnnotation.typeAnnotation, declaredTypes)
// skip check for result containing unknown types
if (type.includes(UNKNOWN_TYPE)) {
type = [`null`]
if (type.includes('Boolean') || type.includes('Function')) {
type = type.filter(t => t !== UNKNOWN_TYPE)
skipCheck = true
} else {
type = ['null']
}
}
}
props[m.key.name] = {
key: m.key.name,
required: !m.optional,
type: type || [`null`]
type: type || [`null`],
skipCheck
}
}
}
Expand Down
9 changes: 7 additions & 2 deletions packages/runtime-core/__tests__/componentProps.spec.ts
Expand Up @@ -335,7 +335,8 @@ describe('component props', () => {
arr: { type: Array },
obj: { type: Object },
cls: { type: MyClass },
fn: { type: Function }
fn: { type: Function },
skipCheck: { type: [Boolean, Function], skipCheck: true }
},
setup() {
return () => null
Expand All @@ -349,7 +350,8 @@ describe('component props', () => {
arr: {},
obj: 'false',
cls: {},
fn: true
fn: true,
skipCheck: 'foo'
}),
nodeOps.createElement('div')
)
Expand All @@ -374,6 +376,9 @@ describe('component props', () => {
expect(
`Invalid prop: type check failed for prop "cls". Expected MyClass, got Object`
).toHaveBeenWarned()
expect(
`Invalid prop: type check failed for prop "skipCheck". Expected Boolean | Function, got String with value "foo".`
).not.toHaveBeenWarned()
})

// #3495
Expand Down
5 changes: 3 additions & 2 deletions packages/runtime-core/src/componentProps.ts
Expand Up @@ -58,6 +58,7 @@ export interface PropOptions<T = any, D = T> {
required?: boolean
default?: D | DefaultFactory<D> | null | undefined | object
validator?(value: unknown): boolean
skipCheck?: boolean
}

export type PropType<T> = PropConstructor<T> | PropConstructor<T>[]
Expand Down Expand Up @@ -608,7 +609,7 @@ function validateProp(
prop: PropOptions,
isAbsent: boolean
) {
const { type, required, validator } = prop
const { type, required, validator, skipCheck } = prop
// required!
if (required && isAbsent) {
warn('Missing required prop: "' + name + '"')
Expand All @@ -619,7 +620,7 @@ function validateProp(
return
}
// type check
if (type != null && type !== true) {
if (type != null && type !== true && !skipCheck) {
let isValid = false
const types = isArray(type) ? type : [type]
const expectedTypes = []
Expand Down
7 changes: 6 additions & 1 deletion packages/vue/jsx-runtime/index.js
@@ -1,6 +1,11 @@
const { h, Fragment } = require('vue')

function jsx(type, { children, ...props }) {
function jsx(type, props, key) {
const { children } = props
delete props.children
if (arguments.length > 2) {
props.key = key
}
return h(type, props, children)
}

Expand Down
7 changes: 6 additions & 1 deletion packages/vue/jsx-runtime/index.mjs
@@ -1,6 +1,11 @@
import { h, Fragment } from 'vue'

function jsx(type, { children, ...props }) {
function jsx(type, props, key) {
const { children } = props
delete props.children
if (arguments.length > 2) {
props.key = key
}
return h(type, props, children)
}

Expand Down
2 changes: 2 additions & 0 deletions packages/vue/types/jsx-register.d.ts
Expand Up @@ -2,3 +2,5 @@
// imports the global JSX namespace registration for compat.
// TODO: remove in 3.4
import '../jsx'

export * from '../jsx-runtime/dom'

0 comments on commit 5566fc0

Please sign in to comment.