diff --git a/packages/compiler-core/src/transforms/transformExpression.ts b/packages/compiler-core/src/transforms/transformExpression.ts index e3c2c028b80..6003fe8b319 100644 --- a/packages/compiler-core/src/transforms/transformExpression.ts +++ b/packages/compiler-core/src/transforms/transformExpression.ts @@ -23,9 +23,9 @@ import { parseJS, walkJS } from '../utils' -import { globalsWhitelist } from '@vue/shared' +import { isGloballyWhitelisted, makeMap } from '@vue/shared' -const literalsWhitelist = new Set([`true`, `false`, `null`, `this`]) +const isLiteralWhitelisted = makeMap('true,false,null,this') export const transformExpression: NodeTransform = (node, context) => { if (node.type === NodeTypes.INTERPOLATION) { @@ -86,8 +86,8 @@ export function processExpression( if ( !asParams && !context.identifiers[rawExp] && - !globalsWhitelist.has(rawExp) && - !literalsWhitelist.has(rawExp) + !isGloballyWhitelisted(rawExp) && + !isLiteralWhitelisted(rawExp) ) { node.content = `_ctx.${rawExp}` } @@ -246,7 +246,7 @@ function shouldPrefix(identifier: Identifier, parent: Node) { // not in an Array destructure pattern !(parent.type === 'ArrayPattern') && // skip whitelisted globals - !globalsWhitelist.has(identifier.name) && + !isGloballyWhitelisted(identifier.name) && // special case for webpack compilation identifier.name !== `require` && // is a special keyword but parsed as identifier diff --git a/packages/runtime-core/src/componentProxy.ts b/packages/runtime-core/src/componentProxy.ts index 02a2ca2d841..3d31bc218ef 100644 --- a/packages/runtime-core/src/componentProxy.ts +++ b/packages/runtime-core/src/componentProxy.ts @@ -1,7 +1,7 @@ import { ComponentInternalInstance, Data } from './component' import { nextTick } from './scheduler' import { instanceWatch } from './apiWatch' -import { EMPTY_OBJ, hasOwn, globalsWhitelist } from '@vue/shared' +import { EMPTY_OBJ, hasOwn, isGloballyWhitelisted } from '@vue/shared' import { ExtractComputedReturns } from './apiOptions' import { UnwrapRef, ReactiveEffect } from '@vue/reactivity' import { warn } from './warning' @@ -106,6 +106,6 @@ if (__RUNTIME_COMPILE__) { // this trap is only called in browser-compiled render functions that use // `with (this) {}` PublicInstanceProxyHandlers.has = (_: any, key: string): boolean => { - return key[0] !== '_' && !globalsWhitelist.has(key) + return key[0] !== '_' && !isGloballyWhitelisted(key) } } diff --git a/packages/shared/src/element.ts b/packages/shared/src/element.ts index 340d2d8264f..04d5e9fd91d 100644 --- a/packages/shared/src/element.ts +++ b/packages/shared/src/element.ts @@ -1,176 +1,28 @@ -const HTMLTagSet = new Set([ - 'html', - 'body', - 'base', - 'head', - 'link', - 'meta', - 'style', - 'title', - 'address', - 'article', - 'aside', - 'footer', - 'header', - 'h1', - 'h2', - 'h3', - 'h4', - 'h5', - 'h6', - 'hgroup', - 'nav', - 'section', - 'div', - 'dd', - 'dl', - 'dt', - 'figcaption', - 'figure', - 'picture', - 'hr', - 'img', - 'li', - 'main', - 'ol', - 'p', - 'pre', - 'ul', - 'a', - 'b', - 'abbr', - 'bdi', - 'bdo', - 'br', - 'cite', - 'code', - 'data', - 'dfn', - 'em', - 'i', - 'kbd', - 'mark', - 'q', - 'rp', - 'rt', - 'rtc', - 'ruby', - 's', - 'samp', - 'small', - 'span', - 'strong', - 'sub', - 'sup', - 'time', - 'u', - 'var', - 'wbr', - 'area', - 'audio', - 'map', - 'track', - 'video', - 'embed', - 'object', - 'param', - 'source', - 'canvas', - 'script', - 'noscript', - 'del', - 'ins', - 'caption', - 'col', - 'colgroup', - 'table', - 'thead', - 'tbody', - 'td', - 'th', - 'tr', - 'button', - 'datalist', - 'fieldset', - 'form', - 'input', - 'label', - 'legend', - 'meter', - 'optgroup', - 'option', - 'output', - 'progress', - 'select', - 'textarea', - 'details', - 'dialog', - 'menu', - 'menuitem', - 'summary', - 'content', - 'element', - 'shadow', - 'template', - 'blockquote', - 'iframe', - 'tfoot' -]) +import { makeMap } from './makeMap' + +const HTML_TAGS = + 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + + 'header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,' + + 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + + 'data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,' + + 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + + 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + + 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + + 'option,output,progress,select,textarea,details,dialog,menu,menuitem,' + + 'summary,content,element,shadow,template,blockquote,iframe,tfoot' /** * this list is intentionally selective, only covering SVG elements that may * contain child elements. */ -const SVGTagSet = new Set([ - 'svg', - 'animate', - 'circle', - 'clippath', - 'cursor', - 'defs', - 'desc', - 'ellipse', - 'filter', - 'font-face', - 'foreignObject', - 'g', - 'glyph', - 'image', - 'line', - 'marker', - 'mask', - 'missing-glyph', - 'path', - 'pattern', - 'polygon', - 'polyline', - 'rect', - 'switch', - 'symbol', - 'text', - 'textpath', - 'tspan', - 'use', - 'view' -]) +const SVG_TAGS = + 'svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' + + 'foreignObject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' + + 'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view' -const VoidTagSet = new Set([ - 'area', - 'base', - 'br', - 'col', - 'embed', - 'hr', - 'img', - 'input', - 'link', - 'meta', - 'param', - 'source', - 'track', - 'wbr' -]) +const VOID_TAGS = + 'area,base,br,col,embed,hr,img,input,link,meta,param,source,track,wbr' -export const isVoidTag = (tag: string) => VoidTagSet.has(tag) -export const isHTMLTag = (tag: string) => HTMLTagSet.has(tag) -export const isSVGTag = (tag: string) => SVGTagSet.has(tag) +export const isHTMLTag = makeMap(HTML_TAGS) +export const isSVGTag = makeMap(SVG_TAGS) +export const isVoidTag = makeMap(VOID_TAGS) diff --git a/packages/shared/src/globalsWhitelist.ts b/packages/shared/src/globalsWhitelist.ts index 198d66a97e5..8af8c079773 100644 --- a/packages/shared/src/globalsWhitelist.ts +++ b/packages/shared/src/globalsWhitelist.ts @@ -1,25 +1,8 @@ -export const globalsWhitelist = new Set([ - 'Infinity', - 'undefined', - 'NaN', - 'isFinite', - 'isNaN', - 'parseFloat', - 'parseInt', - 'decodeURI', - 'decodeURIComponent', - 'encodeURI', - 'encodeURIComponent', - 'Math', - 'Number', - 'Date', - 'Array', - 'Object', - 'Boolean', - 'String', - 'RegExp', - 'Map', - 'Set', - 'JSON', - 'Intl' -]) +import { makeMap } from './makeMap' + +const GLOBALS_WHITE_LISTED = + 'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' + + 'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' + + 'Object,Boolean,String,RegExp,Map,Set,JSON,Intl' + +export const isGloballyWhitelisted = makeMap(GLOBALS_WHITE_LISTED) diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index f4ce62a49ad..fe3d800bacb 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -1,6 +1,7 @@ export * from './patchFlags' export * from './element' -export { globalsWhitelist } from './globalsWhitelist' +export { isGloballyWhitelisted } from './globalsWhitelist' +export { makeMap } from './makeMap' export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__ ? Object.freeze({}) diff --git a/packages/shared/src/makeMap.ts b/packages/shared/src/makeMap.ts new file mode 100644 index 00000000000..87291cddc27 --- /dev/null +++ b/packages/shared/src/makeMap.ts @@ -0,0 +1,15 @@ +/** + * Make a map and return a function for checking if a key + * is in that map. + */ +export function makeMap( + str: string, + expectsLowerCase?: boolean +): (key: string) => boolean { + const map: Record = Object.create(null) + const list: Array = str.split(',') + for (let i = 0; i < list.length; i++) { + map[list[i]] = true + } + return expectsLowerCase ? val => !!map[val.toLowerCase()] : val => !!map[val] +}