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