From a350926b59456530f8eb44af716482e12d9dfe0c Mon Sep 17 00:00:00 2001 From: Pak Youngrok Date: Fri, 17 Aug 2018 13:04:49 +0900 Subject: [PATCH 1/6] feat(compiler): allow unicode characters for component name resolve #8564 --- src/compiler/parser/html-parser.js | 7 ++++--- src/core/util/options.js | 6 +++--- test/unit/features/options/name.spec.js | 12 ++++++++++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/compiler/parser/html-parser.js b/src/compiler/parser/html-parser.js index e2203613204..996178245ff 100644 --- a/src/compiler/parser/html-parser.js +++ b/src/compiler/parser/html-parser.js @@ -14,9 +14,10 @@ import { isNonPhrasingTag } from 'web/compiler/util' // Regular Expressions for parsing tags and attributes const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/ -// could use https://www.w3.org/TR/1999/REC-xml-names-19990114/#NT-QName -// but for Vue templates we can enforce a simple charset -const ncname = '[a-zA-Z_][\\w\\-\\.]*' +// use https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname +// except \u10000-\uEFFFF because of performance problem +export const pcenchars = '[\\-\\.0-9_a-zA-Z\\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]' +const ncname = `[a-zA-Z_]${pcenchars}*` const qnameCapture = `((?:${ncname}\\:)?${ncname})` const startTagOpen = new RegExp(`^<${qnameCapture}`) const startTagClose = /^\s*(\/?)>/ diff --git a/src/core/util/options.js b/src/core/util/options.js index 5f0d10d3361..b85269fe4a0 100644 --- a/src/core/util/options.js +++ b/src/core/util/options.js @@ -4,6 +4,7 @@ import config from '../config' import { warn } from './debug' import { nativeWatch } from './env' import { set } from '../observer/index' +import { pcenchars } from '../../compiler/parser/html-parser' import { ASSET_TYPES, @@ -253,11 +254,10 @@ function checkComponents (options: Object) { } export function validateComponentName (name: string) { - if (!/^[a-zA-Z][\w-]*$/.test(name)) { + if (!new RegExp(`^[a-zA-Z]${pcenchars}*$`).test(name)) { warn( 'Invalid component name: "' + name + '". Component names ' + - 'can only contain alphanumeric characters and the hyphen, ' + - 'and must start with a letter.' + 'should conform to valid custom element name in html5 specification.' ) } if (isBuiltInTag(name) || config.isReservedTag(name)) { diff --git a/test/unit/features/options/name.spec.js b/test/unit/features/options/name.spec.js index 2f586f85893..051ea403064 100644 --- a/test/unit/features/options/name.spec.js +++ b/test/unit/features/options/name.spec.js @@ -15,7 +15,7 @@ describe('Options name', () => { }) /* eslint-disable */ - expect(`Invalid component name: "Hyper*Vue". Component names can only contain alphanumeric characters and the hyphen, and must start with a letter.`) + expect(`Invalid component name: "Hyper*Vue".`) .toHaveBeenWarned() /* eslint-enable */ @@ -24,7 +24,7 @@ describe('Options name', () => { }) /* eslint-disable */ - expect(`Invalid component name: "2Cool2BValid". Component names can only contain alphanumeric characters and the hyphen, and must start with a letter.`) + expect(`Invalid component name: "2Cool2BValid".`) .toHaveBeenWarned() /* eslint-enable */ }) @@ -37,4 +37,12 @@ describe('Options name', () => { expect(SuperComponent.options.components['SuperVue']).toEqual(SuperComponent) expect(SuperComponent.options.components['super-component']).toEqual(SuperComponent) }) + + it('should allow all potential custom element name for component name including non-alphanumeric characters', () => { + Vue.extend({ + name: 'my-컴포넌트' + }) + + expect(`Invalid component name`).not.toHaveBeenWarned() + }) }) From ee393db9dd79846035af2845088aa2be16158148 Mon Sep 17 00:00:00 2001 From: Pak Youngrok Date: Fri, 17 Aug 2018 15:40:07 +0900 Subject: [PATCH 2/6] feat(core): allow unicode characters for property path in watcher - use unicode letters when parsing path for watcher instead of only ascii letters - extract const `unicodeLetters` from html-parser to lang --- src/compiler/parser/html-parser.js | 6 ++---- src/core/util/lang.js | 9 ++++++++- src/core/util/options.js | 4 ++-- test/unit/features/instance/methods-data.spec.js | 12 ++++++++++++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/compiler/parser/html-parser.js b/src/compiler/parser/html-parser.js index 996178245ff..c5e4cd12b9c 100644 --- a/src/compiler/parser/html-parser.js +++ b/src/compiler/parser/html-parser.js @@ -11,13 +11,11 @@ import { makeMap, no } from 'shared/util' import { isNonPhrasingTag } from 'web/compiler/util' +import { unicodeLetters } from '../../core/util/lang' // Regular Expressions for parsing tags and attributes const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/ -// use https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname -// except \u10000-\uEFFFF because of performance problem -export const pcenchars = '[\\-\\.0-9_a-zA-Z\\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]' -const ncname = `[a-zA-Z_]${pcenchars}*` +const ncname = `[a-zA-Z_][\\-\\.0-9_a-zA-Z${unicodeLetters}]*` const qnameCapture = `((?:${ncname}\\:)?${ncname})` const startTagOpen = new RegExp(`^<${qnameCapture}`) const startTagClose = /^\s*(\/?)>/ diff --git a/src/core/util/lang.js b/src/core/util/lang.js index 96b8219a045..45f9d1ae59e 100644 --- a/src/core/util/lang.js +++ b/src/core/util/lang.js @@ -1,5 +1,12 @@ /* @flow */ +/** + * unicode letters used for parsing html tags, component names and property paths. + * use https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname + * except \u10000-\uEFFFF because of performance problem + */ +export const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD' + /** * Check if a string starts with $ or _ */ @@ -23,7 +30,7 @@ export function def (obj: Object, key: string, val: any, enumerable?: boolean) { /** * Parse simple path. */ -const bailRE = /[^\w.$]/ +const bailRE = new RegExp(`[^${unicodeLetters}.$]`) export function parsePath (path: string): any { if (bailRE.test(path)) { return diff --git a/src/core/util/options.js b/src/core/util/options.js index b85269fe4a0..38fbea15413 100644 --- a/src/core/util/options.js +++ b/src/core/util/options.js @@ -4,7 +4,7 @@ import config from '../config' import { warn } from './debug' import { nativeWatch } from './env' import { set } from '../observer/index' -import { pcenchars } from '../../compiler/parser/html-parser' +import { unicodeLetters } from '../../core/util/lang' import { ASSET_TYPES, @@ -254,7 +254,7 @@ function checkComponents (options: Object) { } export function validateComponentName (name: string) { - if (!new RegExp(`^[a-zA-Z]${pcenchars}*$`).test(name)) { + if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_a-zA-Z${unicodeLetters}]*$`).test(name)) { warn( 'Invalid component name: "' + name + '". Component names ' + 'should conform to valid custom element name in html5 specification.' diff --git a/test/unit/features/instance/methods-data.spec.js b/test/unit/features/instance/methods-data.spec.js index 8684c69eb3a..050b534f01b 100644 --- a/test/unit/features/instance/methods-data.spec.js +++ b/test/unit/features/instance/methods-data.spec.js @@ -26,6 +26,9 @@ describe('Instance methods data', () => { data: { a: { b: 1 + }, + 유니코드: { + なまえ: 'ok' } }, methods: { @@ -108,6 +111,15 @@ describe('Instance methods data', () => { expect(spy).toHaveBeenCalledWith(1) }) + it('handler option in string', () => { + vm.$watch('유니코드.なまえ', { + handler: 'foo', + immediate: true + }) + expect(spy.calls.count()).toBe(1) + expect(spy).toHaveBeenCalledWith('ok') + }) + it('warn expression', () => { vm.$watch('a + b', spy) expect('Watcher only accepts simple dot-delimited paths').toHaveBeenWarned() From 9ef245e32ce4e0e1462f4db12aab679f3ba29565 Mon Sep 17 00:00:00 2001 From: GU Yiling Date: Thu, 20 Dec 2018 18:59:06 +0900 Subject: [PATCH 3/6] Update src/core/util/options.js Co-Authored-By: youngrok --- src/core/util/options.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/util/options.js b/src/core/util/options.js index 38fbea15413..1af3bba12cd 100644 --- a/src/core/util/options.js +++ b/src/core/util/options.js @@ -254,7 +254,7 @@ function checkComponents (options: Object) { } export function validateComponentName (name: string) { - if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_a-zA-Z${unicodeLetters}]*$`).test(name)) { + if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeLetters}]*$`).test(name)) { warn( 'Invalid component name: "' + name + '". Component names ' + 'should conform to valid custom element name in html5 specification.' From dff7849dbb035258776cf6afe7ce9cd1c2463d51 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 26 Dec 2018 09:35:44 -0500 Subject: [PATCH 4/6] Update lang.js --- src/core/util/lang.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/core/util/lang.js b/src/core/util/lang.js index 45f9d1ae59e..efdaca408ca 100644 --- a/src/core/util/lang.js +++ b/src/core/util/lang.js @@ -2,10 +2,9 @@ /** * unicode letters used for parsing html tags, component names and property paths. - * use https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname - * except \u10000-\uEFFFF because of performance problem + * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname */ -export const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD' +export const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF' /** * Check if a string starts with $ or _ From d845cf133ce2e783ed3a87db8f4227185903d9cf Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 26 Dec 2018 09:51:30 -0500 Subject: [PATCH 5/6] Update lang.js --- src/core/util/lang.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/util/lang.js b/src/core/util/lang.js index efdaca408ca..f90f4ddfd9f 100644 --- a/src/core/util/lang.js +++ b/src/core/util/lang.js @@ -3,8 +3,9 @@ /** * unicode letters used for parsing html tags, component names and property paths. * using https://www.w3.org/TR/html53/semantics-scripting.html#potentialcustomelementname + * skipping \u10000-\uEFFFF due to it freezing up PhantomJS */ -export const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\u10000-\uEFFFF' +export const unicodeLetters = 'a-zA-Z\u00B7\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u037D\u037F-\u1FFF\u200C-\u200D\u203F-\u2040\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD' /** * Check if a string starts with $ or _ From dfc51bf1fe4069a55af425af456c7777fe6a9e98 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 26 Dec 2018 09:57:36 -0500 Subject: [PATCH 6/6] Update html-parser.js --- src/compiler/parser/html-parser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/parser/html-parser.js b/src/compiler/parser/html-parser.js index 42605a70fb4..1b304fbdb6a 100644 --- a/src/compiler/parser/html-parser.js +++ b/src/compiler/parser/html-parser.js @@ -11,7 +11,7 @@ import { makeMap, no } from 'shared/util' import { isNonPhrasingTag } from 'web/compiler/util' -import { unicodeLetters } from '../../core/util/lang' +import { unicodeLetters } from 'core/util/lang' // Regular Expressions for parsing tags and attributes const attribute = /^\s*([^\s"'<>\/=]+)(?:\s*(=)\s*(?:"([^"]*)"+|'([^']*)'+|([^\s"'=<>`]+)))?/