]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(core): use makeMap for faster string match checks (#282)
authorAyush Goyal <ayush987goyal@gmail.com>
Tue, 15 Oct 2019 16:11:08 +0000 (21:41 +0530)
committerEvan You <yyx990803@gmail.com>
Tue, 15 Oct 2019 16:11:08 +0000 (12:11 -0400)
packages/compiler-core/src/transforms/transformExpression.ts
packages/runtime-core/src/componentProxy.ts
packages/shared/src/element.ts
packages/shared/src/globalsWhitelist.ts
packages/shared/src/index.ts
packages/shared/src/makeMap.ts [new file with mode: 0644]

index 2bac56a8423f34979120847c1d29c1e3fff6b4f6..10637543fd4fc7e595eabb7ec0ec88d942557557 100644 (file)
@@ -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) {
@@ -87,8 +87,8 @@ export function processExpression(
     if (
       !asParams &&
       !context.identifiers[rawExp] &&
-      !globalsWhitelist.has(rawExp) &&
-      !literalsWhitelist.has(rawExp)
+      !isGloballyWhitelisted(rawExp) &&
+      !isLiteralWhitelisted(rawExp)
     ) {
       node.content = `_ctx.${rawExp}`
     } else if (!context.identifiers[rawExp]) {
@@ -261,7 +261,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
index 02a2ca2d841b5e67abdb45fc859c5b9a48c406ee..3d31bc218efcd991082e481ae14a7495ae284fa7 100644 (file)
@@ -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)
   }
 }
index 340d2d8264f38140c7c74d79700b736097c34086..04d5e9fd91d7cc95445b32f5f6e07a27df8a7d26 100644 (file)
-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)
index 198d66a97e5903252e7e320df329b1a056c19e55..8af8c079773f4217243568e543bca1de14082e5e 100644 (file)
@@ -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)
index 2b8a1023f4f12faae54c3c490d299c351775fab1..6e64483a5a72e995f87dd29cacd2f192df67cde9 100644 (file)
@@ -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 (file)
index 0000000..87291cd
--- /dev/null
@@ -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]
+}