mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 03:57:36 +08:00
feat: detect and warn invalid dynamic argument expressions
This commit is contained in:
parent
624c79930a
commit
c9e3a5d1d9
@ -15,6 +15,7 @@ import { unicodeLetters } from 'core/util/lang'
|
||||
|
||||
// Regular Expressions for parsing tags and attributes
|
||||
const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
|
||||
const dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
|
||||
const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeLetters}]*`
|
||||
const qnameCapture = `((?:${ncname}\\:)?${ncname})`
|
||||
const startTagOpen = new RegExp(`^<${qnameCapture}`)
|
||||
@ -192,7 +193,7 @@ export function parseHTML (html, options) {
|
||||
}
|
||||
advance(start[0].length)
|
||||
let end, attr
|
||||
while (!(end = html.match(startTagClose)) && (attr = html.match(attribute))) {
|
||||
while (!(end = html.match(startTagClose)) && (attr = html.match(dynamicArgAttribute) || html.match(attribute))) {
|
||||
attr.start = index
|
||||
advance(attr[0].length)
|
||||
attr.end = index
|
||||
|
@ -38,6 +38,8 @@ const slotRE = /^v-slot(:|$)|^#/
|
||||
const lineBreakRE = /[\r\n]/
|
||||
const whitespaceRE = /\s+/g
|
||||
|
||||
const invalidAttributeRE = /[\s"'<>\/=]/
|
||||
|
||||
const decodeHTMLCached = cached(he.decode)
|
||||
|
||||
// configurable state
|
||||
@ -194,12 +196,26 @@ export function parse (
|
||||
element.ns = ns
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== 'production' && options.outputSourceRange) {
|
||||
element.start = start
|
||||
element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) => {
|
||||
cumulated[attr.name] = attr
|
||||
return cumulated
|
||||
}, {})
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (options.outputSourceRange) {
|
||||
element.start = start
|
||||
element.rawAttrsMap = element.attrsList.reduce((cumulated, attr) => {
|
||||
cumulated[attr.name] = attr
|
||||
return cumulated
|
||||
}, {})
|
||||
}
|
||||
attrs.forEach(attr => {
|
||||
if (invalidAttributeRE.test(attr.name)) {
|
||||
warn(
|
||||
`Invalid dynamic argument expression: attribute names cannot contain ` +
|
||||
`spaces, quotes, <, >, / or =.`,
|
||||
{
|
||||
start: attr.start + attr.name.indexOf(`[`),
|
||||
end: attr.start + attr.name.length
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (isForbiddenTag(element) && !isServerRendering()) {
|
||||
|
@ -550,6 +550,23 @@ describe('parser', () => {
|
||||
expect(ast.props).toEqual([{ name: 'id', value: 'foo', dynamic: true }])
|
||||
})
|
||||
|
||||
// This only works for string templates.
|
||||
// In-DOM templates will be malformed before Vue can parse it.
|
||||
describe('parse and warn invalid dynamic arguments', () => {
|
||||
[
|
||||
`<div v-bind:['foo' + bar]="baz"/>`,
|
||||
`<div :['foo' + bar]="baz"/>`,
|
||||
`<div @['foo' + bar]="baz"/>`,
|
||||
`<foo #['foo' + bar]="baz"/>`,
|
||||
`<div :['foo' + bar].some.mod="baz"/>`
|
||||
].forEach(template => {
|
||||
it(template, () => {
|
||||
const ast = parse(template, baseOptions)
|
||||
expect(`Invalid dynamic argument expression`).toHaveBeenWarned()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// #6887
|
||||
it('special case static attribute that must be props', () => {
|
||||
const ast = parse('<video muted></video>', baseOptions)
|
||||
|
Loading…
Reference in New Issue
Block a user