Skip to content

Commit

Permalink
fix(reactivity-transform): fix props access codegen for non-identifie…
Browse files Browse the repository at this point in the history
…r prop names (#5436)

fix #5425
  • Loading branch information
edison1105 authored May 13, 2022
1 parent 0c07f12 commit 242914d
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 10 deletions.
14 changes: 10 additions & 4 deletions packages/compiler-core/src/transforms/transformExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,13 @@ import {
walkIdentifiers
} from '../babelUtils'
import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
import { isGloballyWhitelisted, makeMap, hasOwn, isString } from '@vue/shared'
import {
isGloballyWhitelisted,
makeMap,
hasOwn,
isString,
genPropsAccessExp
} from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors'
import {
Node,
Expand Down Expand Up @@ -185,17 +191,17 @@ export function processExpression(
} else if (type === BindingTypes.PROPS) {
// use __props which is generated by compileScript so in ts mode
// it gets correct type
return `__props.${raw}`
return genPropsAccessExp(raw)
} else if (type === BindingTypes.PROPS_ALIASED) {
// prop with a different local alias (from defineProps() destructure)
return `__props.${bindingMetadata.__propsAliases![raw]}`
return genPropsAccessExp(bindingMetadata.__propsAliases![raw])
}
} else {
if (type && type.startsWith('setup')) {
// setup bindings in non-inline mode
return `$setup.${raw}`
} else if (type === BindingTypes.PROPS_ALIASED) {
return `$props.${bindingMetadata.__propsAliases![raw]}`
return `$props['${bindingMetadata.__propsAliases![raw]}']`
} else if (type) {
return `$${type}.${raw}`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,25 @@ return () => {}
}"
`;

exports[`sfc props transform non-identifier prop names 1`] = `
"import { toDisplayString as _toDisplayString } from \\"vue\\"
export default {
props: { 'foo.bar': Function },
setup(__props) {
let x = __props[\\"foo.bar\\"]
return (_ctx, _cache) => {
return _toDisplayString(__props[\\"foo.bar\\"])
}
}
}"
`;

exports[`sfc props transform rest spread 1`] = `
"import { createPropsRestProxy as _createPropsRestProxy } from 'vue'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,28 @@ describe('sfc props transform', () => {
})
})

// #5425
test('non-identifier prop names', () => {
const { content, bindings } = compile(`
<script setup>
const { 'foo.bar': fooBar } = defineProps({ 'foo.bar': Function })
let x = fooBar
</script>
<template>{{ fooBar }}</template>
`)
expect(content).toMatch(`x = __props["foo.bar"]`)
expect(content).toMatch(`toDisplayString(__props["foo.bar"])`)
assertCode(content)
expect(bindings).toStrictEqual({
x: BindingTypes.SETUP_LET,
'foo.bar': BindingTypes.PROPS,
fooBar: BindingTypes.PROPS_ALIASED,
__propsAliases: {
fooBar: 'foo.bar'
}
})
})

test('rest spread', () => {
const { content, bindings } = compile(`
<script setup>
Expand Down
6 changes: 5 additions & 1 deletion packages/compiler-sfc/src/compileScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,7 +431,11 @@ export function compileScript(
prop.key
)
}
const propKey = (prop.key as Identifier).name

const propKey = prop.key.type === 'StringLiteral'
? prop.key.value
: (prop.key as Identifier).name

if (prop.value.type === 'AssignmentPattern') {
// default value { foo = 123 }
const { left, right } = prop.value
Expand Down
10 changes: 5 additions & 5 deletions packages/reactivity-transform/src/reactivityTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
walkFunctionParams
} from '@vue/compiler-core'
import { parse, ParserPlugin } from '@babel/parser'
import { hasOwn, isArray, isString } from '@vue/shared'
import { hasOwn, isArray, isString, genPropsAccessExp } from '@vue/shared'

const CONVERT_SYMBOL = '$'
const ESCAPE_SYMBOL = '$$'
Expand Down Expand Up @@ -489,17 +489,17 @@ export function transformAST(
if (isProp) {
if (escapeScope) {
// prop binding in $$()
// { prop } -> { prop: __prop_prop }
// { prop } -> { prop: __props_prop }
registerEscapedPropBinding(id)
s.appendLeft(
id.end! + offset,
`: __props_${propsLocalToPublicMap[id.name]}`
)
} else {
// { prop } -> { prop: __prop.prop }
// { prop } -> { prop: __props.prop }
s.appendLeft(
id.end! + offset,
`: __props.${propsLocalToPublicMap[id.name]}`
`: ${genPropsAccessExp(propsLocalToPublicMap[id.name])}`
)
}
} else {
Expand All @@ -522,7 +522,7 @@ export function transformAST(
s.overwrite(
id.start! + offset,
id.end! + offset,
`__props.${propsLocalToPublicMap[id.name]}`
genPropsAccessExp(propsLocalToPublicMap[id.name])
)
}
} else {
Expand Down
8 changes: 8 additions & 0 deletions packages/shared/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,11 @@ export const getGlobalThis = (): any => {
: {})
)
}

const identRE = /^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/

export function genPropsAccessExp(name: string) {
return identRE.test(name)
? `__props.${name}`
: `__props[${JSON.stringify(name)}]`
}

0 comments on commit 242914d

Please sign in to comment.