Repository: vuejs/vue
Pull request: fix(parser): fixed `dynamicArgAttribute` RegExp

<!--
Please make sure to read the Pull Request Guidelines:
https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#pull-request-guidelines
-->

<!-- PULL REQUEST TEMPLATE -->
<!-- (Update "[ ]" to "[x]" to check a box) -->

**What kind of change does this PR introduce?** (check at least one)

- [x] Bugfix
- [ ] Feature
- [ ] Code style update
- [ ] Refactor
- [ ] Build-related changes
- [ ] Other, please describe:

**Does this PR introduce a breaking change?** (check one)

- [ ] Yes
- [x] No

If yes, please describe the impact and migration path for existing applications:

**The PR fulfills these requirements:**

- [x] It's submitted to the `dev` branch for v2.x (or to a previous version branch), _not_ the `master` branch
- [x] When resolving a specific issue, it's referenced in the PR's title (e.g. `fix #xxx[,#xxx]`, where "xxx" is the issue number)
- [x] All tests are passing: https://github.com/vuejs/vue/blob/dev/.github/CONTRIBUTING.md#development-setup
- [ ] New/updated tests are included

If adding a **new feature**, the PR's description includes:
- [ ] A convincing reason for adding this feature (to avoid wasting your time, it's best to open a suggestion issue first and wait for approval before working on it)

**Other information:**
fixed #9781.

code explain:

``` javascript
const before = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;
const after = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/;

let s = ' #[foo]>foo</template><template #[bar]>bar</template>';

let beforeMatch = s.match(before);
let afterMatch = s.match(after);

console.log(beforeMatch[0]);     // '#[foo]>foo</template><template #[bar]'
console.log(afterMatch[0]);        // '#[foo]'
```

Changed files:
filename: src/compiler/parser/html-parser.js
patch: @@ -15,7 +15,7 @@ import { unicodeRegExp } 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 dynamicArgAttribute = /^\s*((?:v-[\w-]+:|@|:|#)\[[^=]+?\][^\s"'<>\/=]*)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/
 const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeRegExp.source}]*`
 const qnameCapture = `((?:${ncname}\\:)?${ncname})`
 const startTagOpen = new RegExp(`^<${qnameCapture}`)

filename: test/unit/modules/compiler/parser.spec.js
patch: @@ -569,6 +569,26 @@ describe('parser', () => {
     })
   })
 
+  // #9781
+  it('multiple dynamic slot names without warning', () => {
+    const ast = parse(`<my-component>
+      <template #[foo]>foo</template>
+      <template #[data]="scope">scope</template>
+      <template #[bar]>bar</template>
+    </my-component>`, baseOptions)
+
+    expect(`Invalid dynamic argument expression`).not.toHaveBeenWarned()
+    expect(ast.scopedSlots.foo).not.toBeUndefined()
+    expect(ast.scopedSlots.data).not.toBeUndefined()
+    expect(ast.scopedSlots.bar).not.toBeUndefined()
+    expect(ast.scopedSlots.foo.type).toBe(1)
+    expect(ast.scopedSlots.data.type).toBe(1)
+    expect(ast.scopedSlots.bar.type).toBe(1)
+    expect(ast.scopedSlots.foo.attrsMap['#[foo]']).toBe('')
+    expect(ast.scopedSlots.bar.attrsMap['#[bar]']).toBe('')
+    expect(ast.scopedSlots.data.attrsMap['#[data]']).toBe('scope')
+  })
+
   // #6887
   it('special case static attribute that must be props', () => {
     const ast = parse('<video muted></video>', baseOptions)