Bläddra i källkod

feat: detect and warn invalid dynamic argument expressions

Evan You 7 år sedan
förälder
incheckning
c9e3a5d1d9

+ 2 - 1
src/compiler/parser/html-parser.js

@@ -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

+ 22 - 6
src/compiler/parser/index.js

@@ -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()) {

+ 17 - 0
test/unit/modules/compiler/parser.spec.js

@@ -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)