2023-12-18 13:12:25 +08:00
'use strict' ;
Object . defineProperty ( exports , '__esModule' , { value : true } ) ;
2024-01-16 21:26:16 +08:00
var deindent = require ( 'de-indent' ) ;
var he = require ( 'he' ) ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function _interopDefaultLegacy ( e ) { return e && typeof e === 'object' && 'default' in e ? e : { 'default' : e } ; }
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
var deindent _ _default = /*#__PURE__*/ _interopDefaultLegacy ( deindent ) ;
var he _ _default = /*#__PURE__*/ _interopDefaultLegacy ( he ) ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
const emptyObject = Object . freeze ( { } ) ;
const isArray = Array . isArray ;
2023-12-18 13:12:25 +08:00
// These helpers produce better VM code in JS engines due to their
// explicitness and function inlining.
2024-01-16 21:26:16 +08:00
function isUndef ( v ) {
return v === undefined || v === null ;
}
function isDef ( v ) {
return v !== undefined && v !== null ;
}
function isTrue ( v ) {
return v === true ;
}
function isFalse ( v ) {
return v === false ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Check if value is primitive .
* /
2024-01-16 21:26:16 +08:00
function isPrimitive ( value ) {
return ( typeof value === 'string' ||
typeof value === 'number' ||
// $flow-disable-line
typeof value === 'symbol' ||
typeof value === 'boolean' ) ;
}
function isFunction ( value ) {
return typeof value === 'function' ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Quick object check - this is primarily used to tell
2024-01-16 21:26:16 +08:00
* objects from primitive values when we know the value
2023-12-18 13:12:25 +08:00
* is a JSON - compliant type .
* /
2024-01-16 21:26:16 +08:00
function isObject ( obj ) {
return obj !== null && typeof obj === 'object' ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Get the raw type string of a value , e . g . , [ object Object ] .
* /
2024-01-16 21:26:16 +08:00
const _toString = Object . prototype . toString ;
function toRawType ( value ) {
return _toString . call ( value ) . slice ( 8 , - 1 ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Strict object type check . Only returns true
* for plain JavaScript objects .
* /
2024-01-16 21:26:16 +08:00
function isPlainObject ( obj ) {
return _toString . call ( obj ) === '[object Object]' ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Check if val is a valid array index .
* /
2024-01-16 21:26:16 +08:00
function isValidArrayIndex ( val ) {
const n = parseFloat ( String ( val ) ) ;
return n >= 0 && Math . floor ( n ) === n && isFinite ( val ) ;
}
function isPromise ( val ) {
return ( isDef ( val ) &&
typeof val . then === 'function' &&
typeof val . catch === 'function' ) ;
}
/ * *
* Convert a value to a string that is actually rendered .
* /
function toString ( val ) {
return val == null
? ''
: Array . isArray ( val ) || ( isPlainObject ( val ) && val . toString === _toString )
? JSON . stringify ( val , replacer , 2 )
: String ( val ) ;
}
function replacer ( _key , val ) {
// avoid circular deps from v3
if ( val && val . _ _v _isRef ) {
return val . value ;
}
return val ;
}
/ * *
* Convert an input value to a number for persistence .
* If the conversion fails , return original string .
* /
function toNumber ( val ) {
const n = parseFloat ( val ) ;
return isNaN ( n ) ? val : n ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Make a map and return a function for checking if a key
* is in that map .
* /
2024-01-16 21:26:16 +08:00
function makeMap ( str , expectsLowerCase ) {
const map = Object . create ( null ) ;
const list = str . split ( ',' ) ;
for ( let i = 0 ; i < list . length ; i ++ ) {
map [ list [ i ] ] = true ;
}
return expectsLowerCase ? val => map [ val . toLowerCase ( ) ] : val => map [ val ] ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Check if a tag is a built - in tag .
* /
2024-01-16 21:26:16 +08:00
const isBuiltInTag = makeMap ( 'slot,component' , true ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Check if an attribute is a reserved attribute .
* /
2024-01-16 21:26:16 +08:00
const isReservedAttribute = makeMap ( 'key,ref,slot,slot-scope,is' ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Check whether an object has the property .
* /
2024-01-16 21:26:16 +08:00
const hasOwnProperty = Object . prototype . hasOwnProperty ;
function hasOwn ( obj , key ) {
return hasOwnProperty . call ( obj , key ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Create a cached version of a pure function .
* /
2024-01-16 21:26:16 +08:00
function cached ( fn ) {
const cache = Object . create ( null ) ;
return function cachedFn ( str ) {
const hit = cache [ str ] ;
return hit || ( cache [ str ] = fn ( str ) ) ;
} ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Camelize a hyphen - delimited string .
* /
2024-01-16 21:26:16 +08:00
const camelizeRE = /-(\w)/g ;
const camelize = cached ( ( str ) => {
return str . replace ( camelizeRE , ( _ , c ) => ( c ? c . toUpperCase ( ) : '' ) ) ;
} ) ;
/ * *
* Capitalize a string .
* /
const capitalize = cached ( ( str ) => {
return str . charAt ( 0 ) . toUpperCase ( ) + str . slice ( 1 ) ;
2023-12-18 13:12:25 +08:00
} ) ;
/ * *
* Hyphenate a camelCase string .
* /
2024-01-16 21:26:16 +08:00
const hyphenateRE = /\B([A-Z])/g ;
const hyphenate = cached ( ( str ) => {
return str . replace ( hyphenateRE , '-$1' ) . toLowerCase ( ) ;
2023-12-18 13:12:25 +08:00
} ) ;
/ * *
2024-01-16 21:26:16 +08:00
* Mix properties into target object .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function extend ( to , _from ) {
for ( const key in _from ) {
to [ key ] = _from [ key ] ;
}
return to ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Merge an Array of Objects into a single Object .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function toObject ( arr ) {
const res = { } ;
for ( let i = 0 ; i < arr . length ; i ++ ) {
if ( arr [ i ] ) {
extend ( res , arr [ i ] ) ;
}
}
return res ;
2023-12-18 13:12:25 +08:00
}
/* eslint-disable no-unused-vars */
/ * *
* Perform no operation .
* Stubbing args to make Flow happy without leaving useless transpiled code
* with ... rest ( https : //flow.org/blog/2017/05/07/Strict-Function-Call-Arity/).
* /
2024-01-16 21:26:16 +08:00
function noop ( a , b , c ) { }
2023-12-18 13:12:25 +08:00
/ * *
* Always return false .
* /
2024-01-16 21:26:16 +08:00
const no = ( a , b , c ) => false ;
2023-12-18 13:12:25 +08:00
/* eslint-enable no-unused-vars */
/ * *
* Return the same value .
* /
2024-01-16 21:26:16 +08:00
const identity = ( _ ) => _ ;
2023-12-18 13:12:25 +08:00
/ * *
* Generate a string containing static keys from compiler modules .
* /
2024-01-16 21:26:16 +08:00
function genStaticKeys$1 ( modules ) {
return modules
. reduce ( ( keys , m ) => keys . concat ( m . staticKeys || [ ] ) , [ ] )
. join ( ',' ) ;
}
/ * *
* Check if two values are loosely equal - that is ,
* if they are plain objects , do they have the same shape ?
* /
function looseEqual ( a , b ) {
if ( a === b )
return true ;
const isObjectA = isObject ( a ) ;
const isObjectB = isObject ( b ) ;
if ( isObjectA && isObjectB ) {
try {
const isArrayA = Array . isArray ( a ) ;
const isArrayB = Array . isArray ( b ) ;
if ( isArrayA && isArrayB ) {
return ( a . length === b . length &&
a . every ( ( e , i ) => {
return looseEqual ( e , b [ i ] ) ;
} ) ) ;
}
else if ( a instanceof Date && b instanceof Date ) {
return a . getTime ( ) === b . getTime ( ) ;
}
else if ( ! isArrayA && ! isArrayB ) {
const keysA = Object . keys ( a ) ;
const keysB = Object . keys ( b ) ;
return ( keysA . length === keysB . length &&
keysA . every ( key => {
return looseEqual ( a [ key ] , b [ key ] ) ;
} ) ) ;
}
else {
/* istanbul ignore next */
return false ;
}
}
catch ( e ) {
/* istanbul ignore next */
return false ;
}
}
else if ( ! isObjectA && ! isObjectB ) {
return String ( a ) === String ( b ) ;
}
else {
return false ;
}
}
/ * *
* Return the first index at which a loosely equal value can be
* found in the array ( if value is a plain object , the array must
* contain an object of the same shape ) , or - 1 if it is not present .
* /
function looseIndexOf ( arr , val ) {
for ( let i = 0 ; i < arr . length ; i ++ ) {
if ( looseEqual ( arr [ i ] , val ) )
return i ;
}
return - 1 ;
}
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#polyfill
function hasChanged ( x , y ) {
if ( x === y ) {
return x === 0 && 1 / x !== 1 / y ;
}
else {
return x === x || y === y ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const isUnaryTag = makeMap ( 'area,base,br,col,embed,frame,hr,img,input,isindex,keygen,' +
'link,meta,param,source,track,wbr' ) ;
2023-12-18 13:12:25 +08:00
// Elements that you can, intentionally, leave open
// (and which close themselves)
2024-01-16 21:26:16 +08:00
const canBeLeftOpenTag = makeMap ( 'colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr,source' ) ;
2023-12-18 13:12:25 +08:00
// HTML5 tags https://html.spec.whatwg.org/multipage/indices.html#elements-3
// Phrasing Content https://html.spec.whatwg.org/multipage/dom.html#phrasing-content
2024-01-16 21:26:16 +08:00
const isNonPhrasingTag = makeMap ( 'address,article,aside,base,blockquote,body,caption,col,colgroup,dd,' +
'details,dialog,div,dl,dt,fieldset,figcaption,figure,footer,form,' +
'h1,h2,h3,h4,h5,h6,head,header,hgroup,hr,html,legend,li,menuitem,meta,' +
'optgroup,option,param,rp,rt,source,style,summary,tbody,td,tfoot,th,thead,' +
'title,tr,track' ) ;
2023-12-18 13:12:25 +08:00
/ * *
* 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
* /
2024-01-16 21:26:16 +08:00
const unicodeRegExp = /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/ ;
2023-12-18 13:12:25 +08:00
/ * *
* Define a property .
* /
2024-01-16 21:26:16 +08:00
function def ( obj , key , val , enumerable ) {
Object . defineProperty ( obj , key , {
value : val ,
enumerable : ! ! enumerable ,
writable : true ,
configurable : true
} ) ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Not type - checking this file because it ' s mostly vendor code .
* /
// Regular Expressions for parsing tags and attributes
2024-01-16 21:26:16 +08:00
const attribute = /^\s*([^\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 } ` ) ;
const startTagClose = /^\s*(\/?)>/ ;
const endTag = new RegExp ( ` ^< \\ / ${ qnameCapture } [^>]*> ` ) ;
const doctype = /^<!DOCTYPE [^>]+>/i ;
2023-12-18 13:12:25 +08:00
// #7298: escape - to avoid being passed as HTML comment when inlined in page
2024-01-16 21:26:16 +08:00
const comment = /^<!\--/ ;
const conditionalComment = /^<!\[/ ;
2023-12-18 13:12:25 +08:00
// Special Elements (can contain anything)
2024-01-16 21:26:16 +08:00
const isPlainTextElement = makeMap ( 'script,style,textarea' , true ) ;
const reCache = { } ;
const decodingMap = {
'<' : '<' ,
'>' : '>' ,
'"' : '"' ,
'&' : '&' ,
' ' : '\n' ,
'	' : '\t' ,
''' : "'"
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const encodedAttr = /&(?:lt|gt|quot|amp|#39);/g ;
const encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#39|#10|#9);/g ;
2023-12-18 13:12:25 +08:00
// #5992
2024-01-16 21:26:16 +08:00
const isIgnoreNewlineTag = makeMap ( 'pre,textarea' , true ) ;
const shouldIgnoreFirstNewline = ( tag , html ) => tag && isIgnoreNewlineTag ( tag ) && html [ 0 ] === '\n' ;
function decodeAttr ( value , shouldDecodeNewlines ) {
const re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr ;
return value . replace ( re , match => decodingMap [ match ] ) ;
}
function parseHTML ( html , options ) {
const stack = [ ] ;
const expectHTML = options . expectHTML ;
const isUnaryTag = options . isUnaryTag || no ;
const canBeLeftOpenTag = options . canBeLeftOpenTag || no ;
let index = 0 ;
let last , lastTag ;
while ( html ) {
last = html ;
// Make sure we're not in a plaintext content element like script/style
if ( ! lastTag || ! isPlainTextElement ( lastTag ) ) {
let textEnd = html . indexOf ( '<' ) ;
if ( textEnd === 0 ) {
// Comment:
if ( comment . test ( html ) ) {
const commentEnd = html . indexOf ( '-->' ) ;
if ( commentEnd >= 0 ) {
if ( options . shouldKeepComment && options . comment ) {
options . comment ( html . substring ( 4 , commentEnd ) , index , index + commentEnd + 3 ) ;
}
advance ( commentEnd + 3 ) ;
continue ;
}
}
// https://en.wikipedia.org/wiki/Conditional_comment#Downlevel-revealed_conditional_comment
if ( conditionalComment . test ( html ) ) {
const conditionalEnd = html . indexOf ( ']>' ) ;
if ( conditionalEnd >= 0 ) {
advance ( conditionalEnd + 2 ) ;
continue ;
}
}
// Doctype:
const doctypeMatch = html . match ( doctype ) ;
if ( doctypeMatch ) {
advance ( doctypeMatch [ 0 ] . length ) ;
continue ;
}
// End tag:
const endTagMatch = html . match ( endTag ) ;
if ( endTagMatch ) {
const curIndex = index ;
advance ( endTagMatch [ 0 ] . length ) ;
parseEndTag ( endTagMatch [ 1 ] , curIndex , index ) ;
continue ;
}
// Start tag:
const startTagMatch = parseStartTag ( ) ;
if ( startTagMatch ) {
handleStartTag ( startTagMatch ) ;
if ( shouldIgnoreFirstNewline ( startTagMatch . tagName , html ) ) {
advance ( 1 ) ;
}
continue ;
}
}
let text , rest , next ;
if ( textEnd >= 0 ) {
rest = html . slice ( textEnd ) ;
while ( ! endTag . test ( rest ) &&
! startTagOpen . test ( rest ) &&
! comment . test ( rest ) &&
! conditionalComment . test ( rest ) ) {
// < in plain text, be forgiving and treat it as text
next = rest . indexOf ( '<' , 1 ) ;
if ( next < 0 )
break ;
textEnd += next ;
rest = html . slice ( textEnd ) ;
}
text = html . substring ( 0 , textEnd ) ;
}
if ( textEnd < 0 ) {
text = html ;
}
if ( text ) {
advance ( text . length ) ;
}
if ( options . chars && text ) {
options . chars ( text , index - text . length , index ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
else {
let endTagLength = 0 ;
const stackedTag = lastTag . toLowerCase ( ) ;
const reStackedTag = reCache [ stackedTag ] ||
( reCache [ stackedTag ] = new RegExp ( '([\\s\\S]*?)(</' + stackedTag + '[^>]*>)' , 'i' ) ) ;
const rest = html . replace ( reStackedTag , function ( all , text , endTag ) {
endTagLength = endTag . length ;
if ( ! isPlainTextElement ( stackedTag ) && stackedTag !== 'noscript' ) {
text = text
. replace ( /<!\--([\s\S]*?)-->/g , '$1' ) // #7298
. replace ( /<!\[CDATA\[([\s\S]*?)]]>/g , '$1' ) ;
}
if ( shouldIgnoreFirstNewline ( stackedTag , text ) ) {
text = text . slice ( 1 ) ;
}
if ( options . chars ) {
options . chars ( text ) ;
}
return '' ;
} ) ;
index += html . length - rest . length ;
html = rest ;
parseEndTag ( stackedTag , index - endTagLength , index ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( html === last ) {
options . chars && options . chars ( html ) ;
if ( process . env . NODE _ENV !== 'production' && ! stack . length && options . warn ) {
options . warn ( ` Mal-formatted tag at end of template: " ${ html } " ` , {
start : index + html . length
} ) ;
}
break ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
// Clean up any remaining tags
parseEndTag ( ) ;
function advance ( n ) {
index += n ;
html = html . substring ( n ) ;
}
function parseStartTag ( ) {
const start = html . match ( startTagOpen ) ;
if ( start ) {
const match = {
tagName : start [ 1 ] ,
attrs : [ ] ,
start : index
} ;
advance ( start [ 0 ] . length ) ;
let end , attr ;
while ( ! ( end = html . match ( startTagClose ) ) &&
( attr = html . match ( dynamicArgAttribute ) || html . match ( attribute ) ) ) {
attr . start = index ;
advance ( attr [ 0 ] . length ) ;
attr . end = index ;
match . attrs . push ( attr ) ;
}
if ( end ) {
match . unarySlash = end [ 1 ] ;
advance ( end [ 0 ] . length ) ;
match . end = index ;
return match ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function handleStartTag ( match ) {
const tagName = match . tagName ;
const unarySlash = match . unarySlash ;
if ( expectHTML ) {
if ( lastTag === 'p' && isNonPhrasingTag ( tagName ) ) {
parseEndTag ( lastTag ) ;
}
if ( canBeLeftOpenTag ( tagName ) && lastTag === tagName ) {
parseEndTag ( tagName ) ;
}
}
const unary = isUnaryTag ( tagName ) || ! ! unarySlash ;
const l = match . attrs . length ;
const attrs = new Array ( l ) ;
for ( let i = 0 ; i < l ; i ++ ) {
const args = match . attrs [ i ] ;
const value = args [ 3 ] || args [ 4 ] || args [ 5 ] || '' ;
const shouldDecodeNewlines = tagName === 'a' && args [ 1 ] === 'href'
? options . shouldDecodeNewlinesForHref
: options . shouldDecodeNewlines ;
attrs [ i ] = {
name : args [ 1 ] ,
value : decodeAttr ( value , shouldDecodeNewlines )
} ;
if ( process . env . NODE _ENV !== 'production' && options . outputSourceRange ) {
attrs [ i ] . start = args . start + args [ 0 ] . match ( /^\s*/ ) . length ;
attrs [ i ] . end = args . end ;
}
}
if ( ! unary ) {
stack . push ( {
tag : tagName ,
lowerCasedTag : tagName . toLowerCase ( ) ,
attrs : attrs ,
start : match . start ,
end : match . end
} ) ;
lastTag = tagName ;
}
if ( options . start ) {
options . start ( tagName , attrs , unary , match . start , match . end ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function parseEndTag ( tagName , start , end ) {
let pos , lowerCasedTagName ;
if ( start == null )
start = index ;
if ( end == null )
end = index ;
// Find the closest opened tag of the same type
if ( tagName ) {
lowerCasedTagName = tagName . toLowerCase ( ) ;
for ( pos = stack . length - 1 ; pos >= 0 ; pos -- ) {
if ( stack [ pos ] . lowerCasedTag === lowerCasedTagName ) {
break ;
}
}
}
else {
// If no tag name is provided, clean shop
pos = 0 ;
}
if ( pos >= 0 ) {
// Close all the open elements, up the stack
for ( let i = stack . length - 1 ; i >= pos ; i -- ) {
if ( process . env . NODE _ENV !== 'production' && ( i > pos || ! tagName ) && options . warn ) {
options . warn ( ` tag < ${ stack [ i ] . tag } > has no matching end tag. ` , {
start : stack [ i ] . start ,
end : stack [ i ] . end
} ) ;
}
if ( options . end ) {
options . end ( stack [ i ] . tag , start , end ) ;
}
}
// Remove the open elements from the stack
stack . length = pos ;
lastTag = pos && stack [ pos - 1 ] . tag ;
}
else if ( lowerCasedTagName === 'br' ) {
if ( options . start ) {
options . start ( tagName , [ ] , true , start , end ) ;
}
}
else if ( lowerCasedTagName === 'p' ) {
if ( options . start ) {
options . start ( tagName , [ ] , false , start , end ) ;
}
if ( options . end ) {
options . end ( tagName , start , end ) ;
}
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
const DEFAULT _FILENAME = 'anonymous.vue' ;
const splitRE = /\r?\n/g ;
const replaceRE = /./g ;
const isSpecialTag = makeMap ( 'script,style,template' , true ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Parse a single - file component ( * . vue ) file into an SFC Descriptor Object .
* /
2024-01-16 21:26:16 +08:00
function parseComponent ( source , options = { } ) {
const sfc = {
source ,
filename : DEFAULT _FILENAME ,
template : null ,
script : null ,
scriptSetup : null ,
styles : [ ] ,
customBlocks : [ ] ,
cssVars : [ ] ,
errors : [ ] ,
shouldForceReload : null // attached in parse() by compiler-sfc
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
let depth = 0 ;
let currentBlock = null ;
let warn = msg => {
sfc . errors . push ( msg ) ;
} ;
if ( process . env . NODE _ENV !== 'production' && options . outputSourceRange ) {
warn = ( msg , range ) => {
const data = { msg } ;
if ( range . start != null ) {
data . start = range . start ;
}
if ( range . end != null ) {
data . end = range . end ;
}
sfc . errors . push ( data ) ;
} ;
}
function start ( tag , attrs , unary , start , end ) {
if ( depth === 0 ) {
currentBlock = {
type : tag ,
content : '' ,
start : end ,
end : 0 ,
attrs : attrs . reduce ( ( cumulated , { name , value } ) => {
cumulated [ name ] = value || true ;
return cumulated ;
} , { } )
} ;
if ( typeof currentBlock . attrs . src === 'string' ) {
currentBlock . src = currentBlock . attrs . src ;
}
if ( isSpecialTag ( tag ) ) {
checkAttrs ( currentBlock , attrs ) ;
if ( tag === 'script' ) {
const block = currentBlock ;
if ( block . attrs . setup ) {
block . setup = currentBlock . attrs . setup ;
sfc . scriptSetup = block ;
}
else {
sfc . script = block ;
}
}
else if ( tag === 'style' ) {
sfc . styles . push ( currentBlock ) ;
}
else {
sfc [ tag ] = currentBlock ;
}
}
else {
// custom blocks
sfc . customBlocks . push ( currentBlock ) ;
}
}
if ( ! unary ) {
depth ++ ;
}
}
function checkAttrs ( block , attrs ) {
for ( let i = 0 ; i < attrs . length ; i ++ ) {
const attr = attrs [ i ] ;
if ( attr . name === 'lang' ) {
block . lang = attr . value ;
}
if ( attr . name === 'scoped' ) {
block . scoped = true ;
}
if ( attr . name === 'module' ) {
block . module = attr . value || true ;
}
}
}
function end ( tag , start ) {
if ( depth === 1 && currentBlock ) {
currentBlock . end = start ;
let text = source . slice ( currentBlock . start , currentBlock . end ) ;
if ( options . deindent === true ||
// by default, deindent unless it's script with default lang or (j/t)sx?
( options . deindent !== false &&
! ( currentBlock . type === 'script' &&
( ! currentBlock . lang || /^(j|t)sx?$/ . test ( currentBlock . lang ) ) ) ) ) {
text = deindent _ _default [ "default" ] ( text ) ;
}
// pad content so that linters and pre-processors can output correct
// line numbers in errors and warnings
if ( currentBlock . type !== 'template' && options . pad ) {
text = padContent ( currentBlock , options . pad ) + text ;
}
currentBlock . content = text ;
currentBlock = null ;
}
depth -- ;
}
function padContent ( block , pad ) {
if ( pad === 'space' ) {
return source . slice ( 0 , block . start ) . replace ( replaceRE , ' ' ) ;
}
else {
const offset = source . slice ( 0 , block . start ) . split ( splitRE ) . length ;
const padChar = block . type === 'script' && ! block . lang ? '//\n' : '\n' ;
return Array ( offset ) . join ( padChar ) ;
}
}
parseHTML ( source , {
warn ,
start ,
end ,
outputSourceRange : options . outputSourceRange
} ) ;
return sfc ;
2023-12-18 13:12:25 +08:00
}
// can we use __proto__?
2024-01-16 21:26:16 +08:00
const hasProto = '__proto__' in { } ;
2023-12-18 13:12:25 +08:00
// Browser environment sniffing
2024-01-16 21:26:16 +08:00
const inBrowser = typeof window !== 'undefined' ;
const UA = inBrowser && window . navigator . userAgent . toLowerCase ( ) ;
const isIE = UA && /msie|trident/ . test ( UA ) ;
UA && UA . indexOf ( 'msie 9.0' ) > 0 ;
const isEdge = UA && UA . indexOf ( 'edge/' ) > 0 ;
UA && UA . indexOf ( 'android' ) > 0 ;
UA && /iphone|ipad|ipod|ios/ . test ( UA ) ;
UA && /chrome\/\d+/ . test ( UA ) && ! isEdge ;
UA && /phantomjs/ . test ( UA ) ;
UA && UA . match ( /firefox\/(\d+)/ ) ;
2023-12-18 13:12:25 +08:00
// Firefox has a "watch" function on Object.prototype...
2024-01-16 21:26:16 +08:00
// @ts-expect-error firebox support
const nativeWatch = { } . watch ;
let supportsPassive = false ;
2023-12-18 13:12:25 +08:00
if ( inBrowser ) {
2024-01-16 21:26:16 +08:00
try {
const opts = { } ;
Object . defineProperty ( opts , 'passive' , {
get ( ) {
/* istanbul ignore next */
supportsPassive = true ;
}
} ) ; // https://github.com/facebook/flow/issues/285
window . addEventListener ( 'test-passive' , null , opts ) ;
}
catch ( e ) { }
2023-12-18 13:12:25 +08:00
}
// this needs to be lazy-evaled because vue may be required before
// vue-server-renderer can set VUE_ENV
2024-01-16 21:26:16 +08:00
let _isServer ;
const isServerRendering = ( ) => {
if ( _isServer === undefined ) {
/* istanbul ignore if */
if ( ! inBrowser && typeof global !== 'undefined' ) {
// detect presence of vue-server-renderer and avoid
// Webpack shimming the process
_isServer =
global [ 'process' ] && global [ 'process' ] . env . VUE _ENV === 'server' ;
}
else {
_isServer = false ;
}
}
return _isServer ;
2023-12-18 13:12:25 +08:00
} ;
/* istanbul ignore next */
2024-01-16 21:26:16 +08:00
function isNative ( Ctor ) {
return typeof Ctor === 'function' && /native code/ . test ( Ctor . toString ( ) ) ;
}
const hasSymbol = typeof Symbol !== 'undefined' &&
isNative ( Symbol ) &&
typeof Reflect !== 'undefined' &&
isNative ( Reflect . ownKeys ) ;
let _Set ; // $flow-disable-line
/* istanbul ignore if */ if ( typeof Set !== 'undefined' && isNative ( Set ) ) {
// use native Set when available.
_Set = Set ;
}
else {
// a non-standard Set polyfill that only works with primitive keys.
_Set = class Set {
constructor ( ) {
this . set = Object . create ( null ) ;
}
has ( key ) {
return this . set [ key ] === true ;
}
add ( key ) {
this . set [ key ] = true ;
}
clear ( ) {
this . set = Object . create ( null ) ;
}
2023-12-18 13:12:25 +08:00
} ;
}
2024-01-16 21:26:16 +08:00
const ASSET _TYPES = [ 'component' , 'directive' , 'filter' ] ;
const LIFECYCLE _HOOKS = [
'beforeCreate' ,
'created' ,
'beforeMount' ,
'mounted' ,
'beforeUpdate' ,
'updated' ,
'beforeDestroy' ,
'destroyed' ,
'activated' ,
'deactivated' ,
'errorCaptured' ,
'serverPrefetch' ,
'renderTracked' ,
'renderTriggered'
2023-12-18 13:12:25 +08:00
] ;
2024-01-16 21:26:16 +08:00
var config = {
/ * *
* Option merge strategies ( used in core / util / options )
* /
// $flow-disable-line
optionMergeStrategies : Object . create ( null ) ,
/ * *
* Whether to suppress warnings .
* /
silent : false ,
/ * *
* Show production mode tip message on boot ?
* /
productionTip : process . env . NODE _ENV !== 'production' ,
/ * *
* Whether to enable devtools
* /
devtools : process . env . NODE _ENV !== 'production' ,
/ * *
* Whether to record perf
* /
performance : false ,
/ * *
* Error handler for watcher errors
* /
errorHandler : null ,
/ * *
* Warn handler for watcher warns
* /
warnHandler : null ,
/ * *
* Ignore certain custom elements
* /
ignoredElements : [ ] ,
/ * *
* Custom user key aliases for v - on
* /
// $flow-disable-line
keyCodes : Object . create ( null ) ,
/ * *
* Check if a tag is reserved so that it cannot be registered as a
* component . This is platform - dependent and may be overwritten .
* /
isReservedTag : no ,
/ * *
* Check if an attribute is reserved so that it cannot be used as a component
* prop . This is platform - dependent and may be overwritten .
* /
isReservedAttr : no ,
/ * *
* Check if a tag is an unknown element .
* Platform - dependent .
* /
isUnknownElement : no ,
/ * *
* Get the namespace of an element
* /
getTagNamespace : noop ,
/ * *
* Parse the real tag name for the specific platform .
* /
parsePlatformTagName : identity ,
/ * *
* Check if an attribute must be bound using property , e . g . value
* Platform - dependent .
* /
mustUseProp : no ,
/ * *
* Perform updates asynchronously . Intended to be used by Vue Test Utils
* This will significantly reduce performance if set to false .
* /
async : true ,
/ * *
* Exposed for legacy reasons
* /
_lifecycleHooks : LIFECYCLE _HOOKS
} ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let currentInstance = null ;
/ * *
* @ internal
* /
function setCurrentInstance ( vm = null ) {
if ( ! vm )
currentInstance && currentInstance . _scope . off ( ) ;
currentInstance = vm ;
vm && vm . _scope . on ( ) ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
/ * *
* @ internal
* /
class VNode {
constructor ( tag , data , children , text , elm , context , componentOptions , asyncFactory ) {
this . tag = tag ;
this . data = data ;
this . children = children ;
this . text = text ;
this . elm = elm ;
this . ns = undefined ;
this . context = context ;
this . fnContext = undefined ;
this . fnOptions = undefined ;
this . fnScopeId = undefined ;
this . key = data && data . key ;
this . componentOptions = componentOptions ;
this . componentInstance = undefined ;
this . parent = undefined ;
this . raw = false ;
this . isStatic = false ;
this . isRootInsert = true ;
this . isComment = false ;
this . isCloned = false ;
this . isOnce = false ;
this . asyncFactory = asyncFactory ;
this . asyncMeta = undefined ;
this . isAsyncPlaceholder = false ;
}
// DEPRECATED: alias for componentInstance for backwards compat.
/* istanbul ignore next */
get child ( ) {
return this . componentInstance ;
}
}
const createEmptyVNode = ( text = '' ) => {
const node = new VNode ( ) ;
node . text = text ;
node . isComment = true ;
return node ;
} ;
function createTextVNode ( val ) {
return new VNode ( undefined , undefined , undefined , String ( val ) ) ;
}
// optimized shallow clone
// used for static nodes and slot nodes because they may be reused across
// multiple renders, cloning them avoids errors when DOM manipulations rely
// on their elm reference.
function cloneVNode ( vnode ) {
const cloned = new VNode ( vnode . tag , vnode . data ,
// #7975
// clone children array to avoid mutating original in case of cloning
// a child.
vnode . children && vnode . children . slice ( ) , vnode . text , vnode . elm , vnode . context , vnode . componentOptions , vnode . asyncFactory ) ;
cloned . ns = vnode . ns ;
cloned . isStatic = vnode . isStatic ;
cloned . key = vnode . key ;
cloned . isComment = vnode . isComment ;
cloned . fnContext = vnode . fnContext ;
cloned . fnOptions = vnode . fnOptions ;
cloned . fnScopeId = vnode . fnScopeId ;
cloned . asyncMeta = vnode . asyncMeta ;
cloned . isCloned = true ;
return cloned ;
}
/* not type checking this file because flow doesn't play well with Proxy */
2023-12-18 13:12:25 +08:00
if ( process . env . NODE _ENV !== 'production' ) {
2024-01-16 21:26:16 +08:00
makeMap ( 'Infinity,undefined,NaN,isFinite,isNaN,' +
'parseFloat,parseInt,decodeURI,decodeURIComponent,encodeURI,encodeURIComponent,' +
'Math,Number,Date,Array,Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,' +
'require' // for Webpack/Browserify
) ;
const hasProxy = typeof Proxy !== 'undefined' && isNative ( Proxy ) ;
if ( hasProxy ) {
const isBuiltInModifier = makeMap ( 'stop,prevent,self,ctrl,shift,alt,meta,exact' ) ;
config . keyCodes = new Proxy ( config . keyCodes , {
set ( target , key , value ) {
if ( isBuiltInModifier ( key ) ) {
warn$2 ( ` Avoid overwriting built-in modifier in config.keyCodes: . ${ key } ` ) ;
return false ;
}
else {
target [ key ] = value ;
return true ;
}
}
} ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
let uid = 0 ;
2023-12-18 13:12:25 +08:00
/ * *
* A dep is an observable that can have multiple
* directives subscribing to it .
2024-01-16 21:26:16 +08:00
* @ internal
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
class Dep {
constructor ( ) {
// pending subs cleanup
this . _pending = false ;
this . id = uid ++ ;
this . subs = [ ] ;
}
addSub ( sub ) {
this . subs . push ( sub ) ;
}
removeSub ( sub ) {
// #12696 deps with massive amount of subscribers are extremely slow to
// clean up in Chromium
// to workaround this, we unset the sub for now, and clear them on
// next scheduler flush.
this . subs [ this . subs . indexOf ( sub ) ] = null ;
if ( ! this . _pending ) {
this . _pending = true ;
}
}
depend ( info ) {
if ( Dep . target ) {
Dep . target . addDep ( this ) ;
if ( process . env . NODE _ENV !== 'production' && info && Dep . target . onTrack ) {
Dep . target . onTrack ( Object . assign ( { effect : Dep . target } , info ) ) ;
}
}
}
notify ( info ) {
// stabilize the subscriber list first
const subs = this . subs . filter ( s => s ) ;
if ( process . env . NODE _ENV !== 'production' && ! config . async ) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs . sort ( ( a , b ) => a . id - b . id ) ;
}
for ( let i = 0 , l = subs . length ; i < l ; i ++ ) {
const sub = subs [ i ] ;
if ( process . env . NODE _ENV !== 'production' && info ) {
sub . onTrigger &&
sub . onTrigger ( Object . assign ( { effect : subs [ i ] } , info ) ) ;
}
sub . update ( ) ;
}
}
}
2023-12-18 13:12:25 +08:00
// The current target watcher being evaluated.
// This is globally unique because only one watcher
// can be evaluated at a time.
Dep . target = null ;
2024-01-16 21:26:16 +08:00
const targetStack = [ ] ;
function pushTarget ( target ) {
targetStack . push ( target ) ;
Dep . target = target ;
}
function popTarget ( ) {
targetStack . pop ( ) ;
Dep . target = targetStack [ targetStack . length - 1 ] ;
}
2023-12-18 13:12:25 +08:00
/ *
* not type checking this file because flow doesn ' t play well with
* dynamically accessing methods on Array prototype
* /
2024-01-16 21:26:16 +08:00
const arrayProto = Array . prototype ;
const arrayMethods = Object . create ( arrayProto ) ;
const methodsToPatch = [
'push' ,
'pop' ,
'shift' ,
'unshift' ,
'splice' ,
'sort' ,
'reverse'
2023-12-18 13:12:25 +08:00
] ;
/ * *
* Intercept mutating methods and emit events
* /
methodsToPatch . forEach ( function ( method ) {
2024-01-16 21:26:16 +08:00
// cache original method
const original = arrayProto [ method ] ;
def ( arrayMethods , method , function mutator ( ... args ) {
const result = original . apply ( this , args ) ;
const ob = this . _ _ob _ _ ;
let inserted ;
switch ( method ) {
case 'push' :
case 'unshift' :
inserted = args ;
break ;
case 'splice' :
inserted = args . slice ( 2 ) ;
break ;
}
if ( inserted )
ob . observeArray ( inserted ) ;
// notify change
if ( process . env . NODE _ENV !== 'production' ) {
ob . dep . notify ( {
type : "array mutation" /* TriggerOpTypes.ARRAY_MUTATION */ ,
target : this ,
key : method
} ) ;
}
else {
ob . dep . notify ( ) ;
}
return result ;
} ) ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
const arrayKeys = Object . getOwnPropertyNames ( arrayMethods ) ;
const NO _INITIAL _VALUE = { } ;
2023-12-18 13:12:25 +08:00
/ * *
* In some cases we may want to disable observation inside a component ' s
* update computation .
* /
2024-01-16 21:26:16 +08:00
let shouldObserve = true ;
function toggleObserving ( value ) {
shouldObserve = value ;
}
// ssr mock dep
const mockDep = {
notify : noop ,
depend : noop ,
addSub : noop ,
removeSub : noop
} ;
2023-12-18 13:12:25 +08:00
/ * *
* Observer class that is attached to each observed
* object . Once attached , the observer converts the target
* object ' s property keys into getter / setters that
* collect dependencies and dispatch updates .
* /
2024-01-16 21:26:16 +08:00
class Observer {
constructor ( value , shallow = false , mock = false ) {
this . value = value ;
this . shallow = shallow ;
this . mock = mock ;
// this.value = value
this . dep = mock ? mockDep : new Dep ( ) ;
this . vmCount = 0 ;
def ( value , '__ob__' , this ) ;
if ( isArray ( value ) ) {
if ( ! mock ) {
if ( hasProto ) {
value . _ _proto _ _ = arrayMethods ;
/* eslint-enable no-proto */
}
else {
for ( let i = 0 , l = arrayKeys . length ; i < l ; i ++ ) {
const key = arrayKeys [ i ] ;
def ( value , key , arrayMethods [ key ] ) ;
}
}
}
if ( ! shallow ) {
this . observeArray ( value ) ;
}
}
else {
/ * *
* Walk through all properties and convert them into
* getter / setters . This method should only be called when
* value type is Object .
* /
const keys = Object . keys ( value ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
const key = keys [ i ] ;
defineReactive ( value , key , NO _INITIAL _VALUE , undefined , shallow , mock ) ;
}
}
}
/ * *
* Observe a list of Array items .
* /
observeArray ( value ) {
for ( let i = 0 , l = value . length ; i < l ; i ++ ) {
observe ( value [ i ] , false , this . mock ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// helpers
2023-12-18 13:12:25 +08:00
/ * *
* Attempt to create an observer instance for a value ,
* returns the new observer if successfully observed ,
* or the existing observer if the value already has one .
* /
2024-01-16 21:26:16 +08:00
function observe ( value , shallow , ssrMockReactivity ) {
if ( value && hasOwn ( value , '__ob__' ) && value . _ _ob _ _ instanceof Observer ) {
return value . _ _ob _ _ ;
}
if ( shouldObserve &&
( ssrMockReactivity || ! isServerRendering ( ) ) &&
( isArray ( value ) || isPlainObject ( value ) ) &&
Object . isExtensible ( value ) &&
! value . _ _v _skip /* ReactiveFlags.SKIP */ &&
! isRef ( value ) &&
! ( value instanceof VNode ) ) {
return new Observer ( value , shallow , ssrMockReactivity ) ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
* Define a reactive property on an Object .
* /
2024-01-16 21:26:16 +08:00
function defineReactive ( obj , key , val , customSetter , shallow , mock , observeEvenIfShallow = false ) {
const dep = new Dep ( ) ;
const property = Object . getOwnPropertyDescriptor ( obj , key ) ;
if ( property && property . configurable === false ) {
return ;
}
// cater for pre-defined getter/setters
const getter = property && property . get ;
const setter = property && property . set ;
if ( ( ! getter || setter ) &&
( val === NO _INITIAL _VALUE || arguments . length === 2 ) ) {
val = obj [ key ] ;
}
let childOb = shallow ? val && val . _ _ob _ _ : observe ( val , false , mock ) ;
Object . defineProperty ( obj , key , {
enumerable : true ,
configurable : true ,
get : function reactiveGetter ( ) {
const value = getter ? getter . call ( obj ) : val ;
if ( Dep . target ) {
if ( process . env . NODE _ENV !== 'production' ) {
dep . depend ( {
target : obj ,
type : "get" /* TrackOpTypes.GET */ ,
key
} ) ;
}
else {
dep . depend ( ) ;
}
if ( childOb ) {
childOb . dep . depend ( ) ;
if ( isArray ( value ) ) {
dependArray ( value ) ;
}
}
}
return isRef ( value ) && ! shallow ? value . value : value ;
} ,
set : function reactiveSetter ( newVal ) {
const value = getter ? getter . call ( obj ) : val ;
if ( ! hasChanged ( value , newVal ) ) {
return ;
}
if ( process . env . NODE _ENV !== 'production' && customSetter ) {
customSetter ( ) ;
}
if ( setter ) {
setter . call ( obj , newVal ) ;
}
else if ( getter ) {
// #7981: for accessor properties without setter
return ;
}
else if ( ! shallow && isRef ( value ) && ! isRef ( newVal ) ) {
value . value = newVal ;
return ;
}
else {
val = newVal ;
}
childOb = shallow ? newVal && newVal . _ _ob _ _ : observe ( newVal , false , mock ) ;
if ( process . env . NODE _ENV !== 'production' ) {
dep . notify ( {
type : "set" /* TriggerOpTypes.SET */ ,
target : obj ,
key ,
newValue : newVal ,
oldValue : value
} ) ;
}
else {
dep . notify ( ) ;
}
}
} ) ;
return dep ;
}
function set ( target , key , val ) {
if ( process . env . NODE _ENV !== 'production' && ( isUndef ( target ) || isPrimitive ( target ) ) ) {
warn$2 ( ` Cannot set reactive property on undefined, null, or primitive value: ${ target } ` ) ;
}
if ( isReadonly ( target ) ) {
process . env . NODE _ENV !== 'production' && warn$2 ( ` Set operation on key " ${ key } " failed: target is readonly. ` ) ;
return ;
}
const ob = target . _ _ob _ _ ;
if ( isArray ( target ) && isValidArrayIndex ( key ) ) {
target . length = Math . max ( target . length , key ) ;
target . splice ( key , 1 , val ) ;
// when mocking for SSR, array methods are not hijacked
if ( ob && ! ob . shallow && ob . mock ) {
observe ( val , false , true ) ;
}
return val ;
}
if ( key in target && ! ( key in Object . prototype ) ) {
target [ key ] = val ;
return val ;
}
if ( target . _isVue || ( ob && ob . vmCount ) ) {
process . env . NODE _ENV !== 'production' &&
warn$2 ( 'Avoid adding reactive properties to a Vue instance or its root $data ' +
'at runtime - declare it upfront in the data option.' ) ;
return val ;
}
if ( ! ob ) {
target [ key ] = val ;
return val ;
}
defineReactive ( ob . value , key , val , undefined , ob . shallow , ob . mock ) ;
if ( process . env . NODE _ENV !== 'production' ) {
ob . dep . notify ( {
type : "add" /* TriggerOpTypes.ADD */ ,
target : target ,
key ,
newValue : val ,
oldValue : undefined
} ) ;
}
else {
ob . dep . notify ( ) ;
}
return val ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Collect dependencies on array elements when the array is touched , since
* we cannot intercept array element access like property getters .
* /
2024-01-16 21:26:16 +08:00
function dependArray ( value ) {
for ( let e , i = 0 , l = value . length ; i < l ; i ++ ) {
e = value [ i ] ;
if ( e && e . _ _ob _ _ ) {
e . _ _ob _ _ . dep . depend ( ) ;
}
if ( isArray ( e ) ) {
dependArray ( e ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function isReadonly ( value ) {
return ! ! ( value && value . _ _v _isReadonly ) ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function isRef ( r ) {
return ! ! ( r && r . _ _v _isRef === true ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
if ( process . env . NODE _ENV !== 'production' ) ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
const normalizeEvent = cached ( ( name ) => {
const passive = name . charAt ( 0 ) === '&' ;
name = passive ? name . slice ( 1 ) : name ;
const once = name . charAt ( 0 ) === '~' ; // Prefixed last, checked first
name = once ? name . slice ( 1 ) : name ;
const capture = name . charAt ( 0 ) === '!' ;
name = capture ? name . slice ( 1 ) : name ;
return {
name ,
once ,
capture ,
passive
} ;
} ) ;
function createFnInvoker ( fns , vm ) {
function invoker ( ) {
const fns = invoker . fns ;
if ( isArray ( fns ) ) {
const cloned = fns . slice ( ) ;
for ( let i = 0 ; i < cloned . length ; i ++ ) {
invokeWithErrorHandling ( cloned [ i ] , null , arguments , vm , ` v-on handler ` ) ;
}
}
else {
// return handler return value for single handlers
return invokeWithErrorHandling ( fns , null , arguments , vm , ` v-on handler ` ) ;
}
}
invoker . fns = fns ;
return invoker ;
}
function updateListeners ( on , oldOn , add , remove , createOnceHandler , vm ) {
let name , cur , old , event ;
for ( name in on ) {
cur = on [ name ] ;
old = oldOn [ name ] ;
event = normalizeEvent ( name ) ;
if ( isUndef ( cur ) ) {
process . env . NODE _ENV !== 'production' &&
warn$2 ( ` Invalid handler for event " ${ event . name } ": got ` + String ( cur ) , vm ) ;
}
else if ( isUndef ( old ) ) {
if ( isUndef ( cur . fns ) ) {
cur = on [ name ] = createFnInvoker ( cur , vm ) ;
}
if ( isTrue ( event . once ) ) {
cur = on [ name ] = createOnceHandler ( event . name , cur , event . capture ) ;
}
add ( event . name , cur , event . capture , event . passive , event . params ) ;
}
else if ( cur !== old ) {
old . fns = cur ;
on [ name ] = old ;
}
}
for ( name in oldOn ) {
if ( isUndef ( on [ name ] ) ) {
event = normalizeEvent ( name ) ;
remove ( event . name , oldOn [ name ] , event . capture ) ;
}
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function extractPropsFromVNodeData ( data , Ctor , tag ) {
// we are only extracting raw values here.
// validation and default values are handled in the child
// component itself.
const propOptions = Ctor . options . props ;
if ( isUndef ( propOptions ) ) {
return ;
}
const res = { } ;
const { attrs , props } = data ;
if ( isDef ( attrs ) || isDef ( props ) ) {
for ( const key in propOptions ) {
const altKey = hyphenate ( key ) ;
if ( process . env . NODE _ENV !== 'production' ) {
const keyInLowerCase = key . toLowerCase ( ) ;
if ( key !== keyInLowerCase && attrs && hasOwn ( attrs , keyInLowerCase ) ) {
tip ( ` Prop " ${ keyInLowerCase } " is passed to component ` +
` ${ formatComponentName (
// @ts-expect-error tag is string
tag || Ctor ) } , but the declared prop name is ` +
` " ${ key } ". ` +
` Note that HTML attributes are case-insensitive and camelCased ` +
` props need to use their kebab-case equivalents when using in-DOM ` +
` templates. You should probably use " ${ altKey } " instead of " ${ key } ". ` ) ;
}
}
checkProp ( res , props , key , altKey , true ) ||
checkProp ( res , attrs , key , altKey , false ) ;
}
}
return res ;
}
function checkProp ( res , hash , key , altKey , preserve ) {
if ( isDef ( hash ) ) {
if ( hasOwn ( hash , key ) ) {
res [ key ] = hash [ key ] ;
if ( ! preserve ) {
delete hash [ key ] ;
}
return true ;
}
else if ( hasOwn ( hash , altKey ) ) {
res [ key ] = hash [ altKey ] ;
if ( ! preserve ) {
delete hash [ altKey ] ;
}
return true ;
}
}
return false ;
}
// The template compiler attempts to minimize the need for normalization by
// statically analyzing the template at compile time.
//
// For plain HTML markup, normalization can be completely skipped because the
// generated render function is guaranteed to return Array<VNode>. There are
// two cases where extra normalization is needed:
// 1. When the children contains components - because a functional component
// may return an Array instead of a single root. In this case, just a simple
// normalization is needed - if any child is an Array, we flatten the whole
// thing with Array.prototype.concat. It is guaranteed to be only 1-level deep
// because functional components already normalize their own children.
function simpleNormalizeChildren ( children ) {
for ( let i = 0 ; i < children . length ; i ++ ) {
if ( isArray ( children [ i ] ) ) {
return Array . prototype . concat . apply ( [ ] , children ) ;
}
}
return children ;
}
// 2. When the children contains constructs that always generated nested Arrays,
// e.g. <template>, <slot>, v-for, or when the children is provided by user
// with hand-written render functions / JSX. In such cases a full normalization
// is needed to cater to all possible types of children values.
function normalizeChildren ( children ) {
return isPrimitive ( children )
? [ createTextVNode ( children ) ]
: isArray ( children )
? normalizeArrayChildren ( children )
: undefined ;
}
function isTextNode ( node ) {
return isDef ( node ) && isDef ( node . text ) && isFalse ( node . isComment ) ;
}
function normalizeArrayChildren ( children , nestedIndex ) {
const res = [ ] ;
let i , c , lastIndex , last ;
for ( i = 0 ; i < children . length ; i ++ ) {
c = children [ i ] ;
if ( isUndef ( c ) || typeof c === 'boolean' )
continue ;
lastIndex = res . length - 1 ;
last = res [ lastIndex ] ;
// nested
if ( isArray ( c ) ) {
if ( c . length > 0 ) {
c = normalizeArrayChildren ( c , ` ${ nestedIndex || '' } _ ${ i } ` ) ;
// merge adjacent text nodes
if ( isTextNode ( c [ 0 ] ) && isTextNode ( last ) ) {
res [ lastIndex ] = createTextVNode ( last . text + c [ 0 ] . text ) ;
c . shift ( ) ;
}
res . push . apply ( res , c ) ;
}
}
else if ( isPrimitive ( c ) ) {
if ( isTextNode ( last ) ) {
// merge adjacent text nodes
// this is necessary for SSR hydration because text nodes are
// essentially merged when rendered to HTML strings
res [ lastIndex ] = createTextVNode ( last . text + c ) ;
}
else if ( c !== '' ) {
// convert primitive to vnode
res . push ( createTextVNode ( c ) ) ;
}
}
else {
if ( isTextNode ( c ) && isTextNode ( last ) ) {
// merge adjacent text nodes
res [ lastIndex ] = createTextVNode ( last . text + c . text ) ;
}
else {
// default key for nested array children (likely generated by v-for)
if ( isTrue ( children . _isVList ) &&
isDef ( c . tag ) &&
isUndef ( c . key ) &&
isDef ( nestedIndex ) ) {
c . key = ` __vlist ${ nestedIndex } _ ${ i } __ ` ;
}
res . push ( c ) ;
}
}
}
return res ;
}
const SIMPLE _NORMALIZE = 1 ;
const ALWAYS _NORMALIZE = 2 ;
// wrapper function for providing a more flexible interface
// without getting yelled at by flow
function createElement ( context , tag , data , children , normalizationType , alwaysNormalize ) {
if ( isArray ( data ) || isPrimitive ( data ) ) {
normalizationType = children ;
children = data ;
data = undefined ;
}
if ( isTrue ( alwaysNormalize ) ) {
normalizationType = ALWAYS _NORMALIZE ;
}
return _createElement ( context , tag , data , children , normalizationType ) ;
}
function _createElement ( context , tag , data , children , normalizationType ) {
if ( isDef ( data ) && isDef ( data . _ _ob _ _ ) ) {
process . env . NODE _ENV !== 'production' &&
warn$2 ( ` Avoid using observed data object as vnode data: ${ JSON . stringify ( data ) } \n ` + 'Always create fresh vnode data objects in each render!' , context ) ;
return createEmptyVNode ( ) ;
}
// object syntax in v-bind
if ( isDef ( data ) && isDef ( data . is ) ) {
tag = data . is ;
}
if ( ! tag ) {
// in case of component :is set to falsy value
return createEmptyVNode ( ) ;
}
// warn against non-primitive key
if ( process . env . NODE _ENV !== 'production' && isDef ( data ) && isDef ( data . key ) && ! isPrimitive ( data . key ) ) {
warn$2 ( 'Avoid using non-primitive value as key, ' +
'use string/number value instead.' , context ) ;
}
// support single function children as default scoped slot
if ( isArray ( children ) && isFunction ( children [ 0 ] ) ) {
data = data || { } ;
data . scopedSlots = { default : children [ 0 ] } ;
children . length = 0 ;
}
if ( normalizationType === ALWAYS _NORMALIZE ) {
children = normalizeChildren ( children ) ;
}
else if ( normalizationType === SIMPLE _NORMALIZE ) {
children = simpleNormalizeChildren ( children ) ;
}
let vnode , ns ;
if ( typeof tag === 'string' ) {
let Ctor ;
ns = ( context . $vnode && context . $vnode . ns ) || config . getTagNamespace ( tag ) ;
if ( ( ! data || ! data . pre ) &&
isDef ( ( Ctor = resolveAsset ( context . $options , 'components' , tag ) ) ) ) {
// component
vnode = createComponent ( Ctor , data , context , children , tag ) ;
}
else {
// unknown or unlisted namespaced elements
// check at runtime because it may get assigned a namespace when its
// parent normalizes children
vnode = new VNode ( tag , data , children , undefined , undefined , context ) ;
}
}
else {
// direct component options / constructor
vnode = createComponent ( tag , data , context , children ) ;
}
if ( isArray ( vnode ) ) {
return vnode ;
}
else if ( isDef ( vnode ) ) {
if ( isDef ( ns ) )
applyNS ( vnode , ns ) ;
if ( isDef ( data ) )
registerDeepBindings ( data ) ;
return vnode ;
}
else {
return createEmptyVNode ( ) ;
}
}
function applyNS ( vnode , ns , force ) {
vnode . ns = ns ;
if ( vnode . tag === 'foreignObject' ) {
// use default namespace inside foreignObject
ns = undefined ;
force = true ;
}
if ( isDef ( vnode . children ) ) {
for ( let i = 0 , l = vnode . children . length ; i < l ; i ++ ) {
const child = vnode . children [ i ] ;
if ( isDef ( child . tag ) &&
( isUndef ( child . ns ) || ( isTrue ( force ) && child . tag !== 'svg' ) ) ) {
applyNS ( child , ns , force ) ;
}
}
}
}
// ref #5318
// necessary to ensure parent re-render when deep bindings like :style and
// :class are used on slot nodes
function registerDeepBindings ( data ) {
if ( isObject ( data . style ) ) {
traverse ( data . style ) ;
}
if ( isObject ( data . class ) ) {
traverse ( data . class ) ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Runtime helper for rendering v - for lists .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function renderList ( val , render ) {
let ret = null , i , l , keys , key ;
if ( isArray ( val ) || typeof val === 'string' ) {
ret = new Array ( val . length ) ;
for ( i = 0 , l = val . length ; i < l ; i ++ ) {
ret [ i ] = render ( val [ i ] , i ) ;
}
}
else if ( typeof val === 'number' ) {
ret = new Array ( val ) ;
for ( i = 0 ; i < val ; i ++ ) {
ret [ i ] = render ( i + 1 , i ) ;
}
}
else if ( isObject ( val ) ) {
if ( hasSymbol && val [ Symbol . iterator ] ) {
ret = [ ] ;
const iterator = val [ Symbol . iterator ] ( ) ;
let result = iterator . next ( ) ;
while ( ! result . done ) {
ret . push ( render ( result . value , ret . length ) ) ;
result = iterator . next ( ) ;
}
}
else {
keys = Object . keys ( val ) ;
ret = new Array ( keys . length ) ;
for ( i = 0 , l = keys . length ; i < l ; i ++ ) {
key = keys [ i ] ;
ret [ i ] = render ( val [ key ] , key , i ) ;
}
}
}
if ( ! isDef ( ret ) ) {
ret = [ ] ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
ret . _isVList = true ;
return ret ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* Runtime helper for rendering < slot >
* /
function renderSlot ( name , fallbackRender , props , bindObject ) {
const scopedSlotFn = this . $scopedSlots [ name ] ;
let nodes ;
if ( scopedSlotFn ) {
// scoped slot
props = props || { } ;
if ( bindObject ) {
if ( process . env . NODE _ENV !== 'production' && ! isObject ( bindObject ) ) {
warn$2 ( 'slot v-bind without argument expects an Object' , this ) ;
}
props = extend ( extend ( { } , bindObject ) , props ) ;
}
nodes =
scopedSlotFn ( props ) ||
( isFunction ( fallbackRender ) ? fallbackRender ( ) : fallbackRender ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
nodes =
this . $slots [ name ] ||
( isFunction ( fallbackRender ) ? fallbackRender ( ) : fallbackRender ) ;
}
const target = props && props . slot ;
if ( target ) {
return this . $createElement ( 'template' , { slot : target } , nodes ) ;
}
else {
return nodes ;
}
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Runtime helper for resolving filters
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function resolveFilter ( id ) {
return resolveAsset ( this . $options , 'filters' , id , true ) || identity ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isKeyNotMatch ( expect , actual ) {
if ( isArray ( expect ) ) {
return expect . indexOf ( actual ) === - 1 ;
}
else {
return expect !== actual ;
2023-12-18 13:12:25 +08:00
}
}
/ * *
2024-01-16 21:26:16 +08:00
* Runtime helper for checking keyCodes from config .
* exposed as Vue . prototype . _k
* passing in eventKeyName as last argument separately for backwards compat
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function checkKeyCodes ( eventKeyCode , key , builtInKeyCode , eventKeyName , builtInKeyName ) {
const mappedKeyCode = config . keyCodes [ key ] || builtInKeyCode ;
if ( builtInKeyName && eventKeyName && ! config . keyCodes [ key ] ) {
return isKeyNotMatch ( builtInKeyName , eventKeyName ) ;
}
else if ( mappedKeyCode ) {
return isKeyNotMatch ( mappedKeyCode , eventKeyCode ) ;
}
else if ( eventKeyName ) {
return hyphenate ( eventKeyName ) !== key ;
}
return eventKeyCode === undefined ;
2023-12-18 13:12:25 +08:00
}
/ * *
2024-01-16 21:26:16 +08:00
* Runtime helper for merging v - bind = "object" into a VNode ' s data .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function bindObjectProps ( data , tag , value , asProp , isSync ) {
if ( value ) {
if ( ! isObject ( value ) ) {
process . env . NODE _ENV !== 'production' &&
warn$2 ( 'v-bind without argument expects an Object or Array value' , this ) ;
}
else {
if ( isArray ( value ) ) {
value = toObject ( value ) ;
}
let hash ;
for ( const key in value ) {
if ( key === 'class' || key === 'style' || isReservedAttribute ( key ) ) {
hash = data ;
}
else {
const type = data . attrs && data . attrs . type ;
hash =
asProp || config . mustUseProp ( tag , type , key )
? data . domProps || ( data . domProps = { } )
: data . attrs || ( data . attrs = { } ) ;
}
const camelizedKey = camelize ( key ) ;
const hyphenatedKey = hyphenate ( key ) ;
if ( ! ( camelizedKey in hash ) && ! ( hyphenatedKey in hash ) ) {
hash [ key ] = value [ key ] ;
if ( isSync ) {
const on = data . on || ( data . on = { } ) ;
on [ ` update: ${ key } ` ] = function ( $event ) {
value [ key ] = $event ;
} ;
}
}
}
}
}
return data ;
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Runtime helper for rendering static trees .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function renderStatic ( index , isInFor ) {
const cached = this . _staticTrees || ( this . _staticTrees = [ ] ) ;
let tree = cached [ index ] ;
// if has already-rendered static tree and not inside v-for,
// we can reuse the same tree.
if ( tree && ! isInFor ) {
return tree ;
}
// otherwise, render a fresh tree.
tree = cached [ index ] = this . $options . staticRenderFns [ index ] . call ( this . _renderProxy , this . _c , this // for render fns generated for functional component templates
) ;
markStatic$1 ( tree , ` __static__ ${ index } ` , false ) ;
return tree ;
}
2023-12-18 13:12:25 +08:00
/ * *
2024-01-16 21:26:16 +08:00
* Runtime helper for v - once .
* Effectively it means marking the node as static with a unique key .
2023-12-18 13:12:25 +08:00
* /
2024-01-16 21:26:16 +08:00
function markOnce ( tree , index , key ) {
markStatic$1 ( tree , ` __once__ ${ index } ${ key ? ` _ ${ key } ` : ` ` } ` , true ) ;
return tree ;
}
function markStatic$1 ( tree , key , isOnce ) {
if ( isArray ( tree ) ) {
for ( let i = 0 ; i < tree . length ; i ++ ) {
if ( tree [ i ] && typeof tree [ i ] !== 'string' ) {
markStaticNode ( tree [ i ] , ` ${ key } _ ${ i } ` , isOnce ) ;
}
}
}
else {
markStaticNode ( tree , key , isOnce ) ;
}
}
function markStaticNode ( node , key , isOnce ) {
node . isStatic = true ;
node . key = key ;
node . isOnce = isOnce ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function bindObjectListeners ( data , value ) {
if ( value ) {
if ( ! isPlainObject ( value ) ) {
process . env . NODE _ENV !== 'production' && warn$2 ( 'v-on without argument expects an Object value' , this ) ;
}
else {
const on = ( data . on = data . on ? extend ( { } , data . on ) : { } ) ;
for ( const key in value ) {
const existing = on [ key ] ;
const ours = value [ key ] ;
on [ key ] = existing ? [ ] . concat ( existing , ours ) : ours ;
}
}
}
return data ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function resolveScopedSlots ( fns , res ,
// the following are added in 2.6
hasDynamicKeys , contentHashKey ) {
res = res || { $stable : ! hasDynamicKeys } ;
for ( let i = 0 ; i < fns . length ; i ++ ) {
const slot = fns [ i ] ;
if ( isArray ( slot ) ) {
resolveScopedSlots ( slot , res , hasDynamicKeys ) ;
}
else if ( slot ) {
// marker for reverse proxying v-slot without scope on this.$slots
// @ts-expect-error
if ( slot . proxy ) {
// @ts-expect-error
slot . fn . proxy = true ;
}
res [ slot . key ] = slot . fn ;
}
}
if ( contentHashKey ) {
res . $key = contentHashKey ;
}
return res ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
// helper to process dynamic keys for dynamic arguments in v-bind and v-on.
function bindDynamicKeys ( baseObj , values ) {
for ( let i = 0 ; i < values . length ; i += 2 ) {
const key = values [ i ] ;
if ( typeof key === 'string' && key ) {
baseObj [ values [ i ] ] = values [ i + 1 ] ;
}
else if ( process . env . NODE _ENV !== 'production' && key !== '' && key !== null ) {
// null is a special value for explicitly removing a binding
warn$2 ( ` Invalid value for dynamic directive argument (expected string or null): ${ key } ` , this ) ;
}
}
return baseObj ;
}
// helper to dynamically append modifier runtime markers to event names.
// ensure only append when value is already string, otherwise it will be cast
// to string and cause the type check to miss.
function prependModifier ( value , symbol ) {
return typeof value === 'string' ? symbol + value : value ;
}
function installRenderHelpers ( target ) {
target . _o = markOnce ;
target . _n = toNumber ;
target . _s = toString ;
target . _l = renderList ;
target . _t = renderSlot ;
target . _q = looseEqual ;
target . _i = looseIndexOf ;
target . _m = renderStatic ;
target . _f = resolveFilter ;
target . _k = checkKeyCodes ;
target . _b = bindObjectProps ;
target . _v = createTextVNode ;
target . _e = createEmptyVNode ;
target . _u = resolveScopedSlots ;
target . _g = bindObjectListeners ;
target . _d = bindDynamicKeys ;
target . _p = prependModifier ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
/ * *
* Runtime helper for resolving raw children VNodes into a slot object .
* /
function resolveSlots ( children , context ) {
if ( ! children || ! children . length ) {
return { } ;
}
const slots = { } ;
for ( let i = 0 , l = children . length ; i < l ; i ++ ) {
const child = children [ i ] ;
const data = child . data ;
// remove slot attribute if the node is resolved as a Vue slot node
if ( data && data . attrs && data . attrs . slot ) {
delete data . attrs . slot ;
}
// named slots should only be respected if the vnode was rendered in the
// same context.
if ( ( child . context === context || child . fnContext === context ) &&
data &&
data . slot != null ) {
const name = data . slot ;
const slot = slots [ name ] || ( slots [ name ] = [ ] ) ;
if ( child . tag === 'template' ) {
slot . push . apply ( slot , child . children || [ ] ) ;
}
else {
slot . push ( child ) ;
}
}
else {
( slots . default || ( slots . default = [ ] ) ) . push ( child ) ;
}
}
// ignore slots that contains only whitespace
for ( const name in slots ) {
if ( slots [ name ] . every ( isWhitespace ) ) {
delete slots [ name ] ;
}
}
return slots ;
}
function isWhitespace ( node ) {
return ( node . isComment && ! node . asyncFactory ) || node . text === ' ' ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function isAsyncPlaceholder ( node ) {
// @ts-expect-error not really boolean type
return node . isComment && node . asyncFactory ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function normalizeScopedSlots ( ownerVm , scopedSlots , normalSlots , prevScopedSlots ) {
let res ;
const hasNormalSlots = Object . keys ( normalSlots ) . length > 0 ;
const isStable = scopedSlots ? ! ! scopedSlots . $stable : ! hasNormalSlots ;
const key = scopedSlots && scopedSlots . $key ;
if ( ! scopedSlots ) {
res = { } ;
}
else if ( scopedSlots . _normalized ) {
// fast path 1: child component re-render only, parent did not change
return scopedSlots . _normalized ;
}
else if ( isStable &&
prevScopedSlots &&
prevScopedSlots !== emptyObject &&
key === prevScopedSlots . $key &&
! hasNormalSlots &&
! prevScopedSlots . $hasNormal ) {
// fast path 2: stable scoped slots w/ no normal slots to proxy,
// only need to normalize once
return prevScopedSlots ;
}
else {
res = { } ;
for ( const key in scopedSlots ) {
if ( scopedSlots [ key ] && key [ 0 ] !== '$' ) {
res [ key ] = normalizeScopedSlot ( ownerVm , normalSlots , key , scopedSlots [ key ] ) ;
}
}
}
// expose normal slots on scopedSlots
for ( const key in normalSlots ) {
if ( ! ( key in res ) ) {
res [ key ] = proxyNormalSlot ( normalSlots , key ) ;
}
}
// avoriaz seems to mock a non-extensible $scopedSlots object
// and when that is passed down this would cause an error
if ( scopedSlots && Object . isExtensible ( scopedSlots ) ) {
scopedSlots . _normalized = res ;
}
def ( res , '$stable' , isStable ) ;
def ( res , '$key' , key ) ;
def ( res , '$hasNormal' , hasNormalSlots ) ;
return res ;
}
function normalizeScopedSlot ( vm , normalSlots , key , fn ) {
const normalized = function ( ) {
const cur = currentInstance ;
setCurrentInstance ( vm ) ;
let res = arguments . length ? fn . apply ( null , arguments ) : fn ( { } ) ;
res =
res && typeof res === 'object' && ! isArray ( res )
? [ res ] // single vnode
: normalizeChildren ( res ) ;
const vnode = res && res [ 0 ] ;
setCurrentInstance ( cur ) ;
return res &&
( ! vnode ||
( res . length === 1 && vnode . isComment && ! isAsyncPlaceholder ( vnode ) ) ) // #9658, #10391
? undefined
: res ;
} ;
// this is a slot using the new v-slot syntax without scope. although it is
// compiled as a scoped slot, render fn users would expect it to be present
// on this.$slots because the usage is semantically a normal slot.
if ( fn . proxy ) {
Object . defineProperty ( normalSlots , key , {
get : normalized ,
enumerable : true ,
configurable : true
} ) ;
}
return normalized ;
}
function proxyNormalSlot ( slots , key ) {
return ( ) => slots [ key ] ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function syncSetupProxy ( to , from , prev , instance , type ) {
let changed = false ;
for ( const key in from ) {
if ( ! ( key in to ) ) {
changed = true ;
defineProxyAttr ( to , key , instance , type ) ;
}
else if ( from [ key ] !== prev [ key ] ) {
changed = true ;
}
}
for ( const key in to ) {
if ( ! ( key in from ) ) {
changed = true ;
delete to [ key ] ;
}
}
return changed ;
}
function defineProxyAttr ( proxy , key , instance , type ) {
Object . defineProperty ( proxy , key , {
enumerable : true ,
configurable : true ,
get ( ) {
return instance [ type ] [ key ] ;
}
} ) ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function createAsyncPlaceholder ( factory , data , context , children , tag ) {
const node = createEmptyVNode ( ) ;
node . asyncFactory = factory ;
node . asyncMeta = { data , context , children , tag } ;
return node ;
}
function resolveAsyncComponent ( factory , baseCtor ) {
if ( isTrue ( factory . error ) && isDef ( factory . errorComp ) ) {
return factory . errorComp ;
}
if ( isDef ( factory . resolved ) ) {
return factory . resolved ;
}
if ( isTrue ( factory . loading ) && isDef ( factory . loadingComp ) ) {
return factory . loadingComp ;
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let target ;
function add ( event , fn ) {
target . $on ( event , fn ) ;
}
function remove ( event , fn ) {
target . $off ( event , fn ) ;
}
function createOnceHandler ( event , fn ) {
const _target = target ;
return function onceHandler ( ) {
const res = fn . apply ( null , arguments ) ;
if ( res !== null ) {
_target . $off ( event , onceHandler ) ;
}
} ;
}
function updateComponentListeners ( vm , listeners , oldListeners ) {
target = vm ;
updateListeners ( listeners , oldListeners || { } , add , remove , createOnceHandler , vm ) ;
target = undefined ;
}
let activeInstance = null ;
function updateChildComponent ( vm , propsData , listeners , parentVnode , renderChildren ) {
if ( process . env . NODE _ENV !== 'production' ) ;
// determine whether component has slot children
// we need to do this before overwriting $options._renderChildren.
// check if there are dynamic scopedSlots (hand-written or compiled but with
// dynamic slot names). Static scoped slots compiled from template has the
// "$stable" marker.
const newScopedSlots = parentVnode . data . scopedSlots ;
const oldScopedSlots = vm . $scopedSlots ;
const hasDynamicScopedSlot = ! ! ( ( newScopedSlots && ! newScopedSlots . $stable ) ||
( oldScopedSlots !== emptyObject && ! oldScopedSlots . $stable ) ||
( newScopedSlots && vm . $scopedSlots . $key !== newScopedSlots . $key ) ||
( ! newScopedSlots && vm . $scopedSlots . $key ) ) ;
// Any static slot children from the parent may have changed during parent's
// update. Dynamic scoped slots may also have changed. In such cases, a forced
// update is necessary to ensure correctness.
let needsForceUpdate = ! ! ( renderChildren || // has new static slots
vm . $options . _renderChildren || // has old static slots
hasDynamicScopedSlot ) ;
const prevVNode = vm . $vnode ;
vm . $options . _parentVnode = parentVnode ;
vm . $vnode = parentVnode ; // update vm's placeholder node without re-render
if ( vm . _vnode ) {
// update child tree's parent
vm . _vnode . parent = parentVnode ;
}
vm . $options . _renderChildren = renderChildren ;
// update $attrs and $listeners hash
// these are also reactive so they may trigger child update if the child
// used them during render
const attrs = parentVnode . data . attrs || emptyObject ;
if ( vm . _attrsProxy ) {
// force update if attrs are accessed and has changed since it may be
// passed to a child component.
if ( syncSetupProxy ( vm . _attrsProxy , attrs , ( prevVNode . data && prevVNode . data . attrs ) || emptyObject , vm , '$attrs' ) ) {
needsForceUpdate = true ;
}
}
vm . $attrs = attrs ;
// update listeners
listeners = listeners || emptyObject ;
const prevListeners = vm . $options . _parentListeners ;
if ( vm . _listenersProxy ) {
syncSetupProxy ( vm . _listenersProxy , listeners , prevListeners || emptyObject , vm , '$listeners' ) ;
}
vm . $listeners = vm . $options . _parentListeners = listeners ;
updateComponentListeners ( vm , listeners , prevListeners ) ;
// update props
if ( propsData && vm . $options . props ) {
toggleObserving ( false ) ;
const props = vm . _props ;
const propKeys = vm . $options . _propKeys || [ ] ;
for ( let i = 0 ; i < propKeys . length ; i ++ ) {
const key = propKeys [ i ] ;
const propOptions = vm . $options . props ; // wtf flow?
props [ key ] = validateProp ( key , propOptions , propsData , vm ) ;
}
toggleObserving ( true ) ;
// keep a copy of raw propsData
vm . $options . propsData = propsData ;
}
// resolve slots + force update if has children
if ( needsForceUpdate ) {
vm . $slots = resolveSlots ( renderChildren , parentVnode . context ) ;
vm . $forceUpdate ( ) ;
}
if ( process . env . NODE _ENV !== 'production' ) ;
}
function isInInactiveTree ( vm ) {
while ( vm && ( vm = vm . $parent ) ) {
if ( vm . _inactive )
return true ;
}
return false ;
}
function activateChildComponent ( vm , direct ) {
if ( direct ) {
vm . _directInactive = false ;
if ( isInInactiveTree ( vm ) ) {
return ;
}
}
else if ( vm . _directInactive ) {
return ;
}
if ( vm . _inactive || vm . _inactive === null ) {
vm . _inactive = false ;
for ( let i = 0 ; i < vm . $children . length ; i ++ ) {
activateChildComponent ( vm . $children [ i ] ) ;
}
callHook ( vm , 'activated' ) ;
}
}
function deactivateChildComponent ( vm , direct ) {
if ( direct ) {
vm . _directInactive = true ;
if ( isInInactiveTree ( vm ) ) {
return ;
}
}
if ( ! vm . _inactive ) {
vm . _inactive = true ;
for ( let i = 0 ; i < vm . $children . length ; i ++ ) {
deactivateChildComponent ( vm . $children [ i ] ) ;
}
callHook ( vm , 'deactivated' ) ;
}
}
function callHook ( vm , hook , args , setContext = true ) {
// #7573 disable dep collection when invoking lifecycle hooks
pushTarget ( ) ;
const prevInst = currentInstance ;
setContext && setCurrentInstance ( vm ) ;
const handlers = vm . $options [ hook ] ;
const info = ` ${ hook } hook ` ;
if ( handlers ) {
for ( let i = 0 , j = handlers . length ; i < j ; i ++ ) {
invokeWithErrorHandling ( handlers [ i ] , vm , args || null , vm , info ) ;
}
}
if ( vm . _hasHookEvent ) {
vm . $emit ( 'hook:' + hook ) ;
}
if ( setContext ) {
setCurrentInstance ( prevInst ) ;
}
popTarget ( ) ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
// Async edge case fix requires storing an event listener's attach timestamp.
let getNow = Date . now ;
// Determine what event timestamp the browser is using. Annoyingly, the
// timestamp can either be hi-res (relative to page load) or low-res
// (relative to UNIX epoch), so in order to compare time we have to use the
// same timestamp type when saving the flush timestamp.
// All IE versions use low-res event timestamps, and have problematic clock
// implementations (#9632)
if ( inBrowser && ! isIE ) {
const performance = window . performance ;
if ( performance &&
typeof performance . now === 'function' &&
getNow ( ) > document . createEvent ( 'Event' ) . timeStamp ) {
// if the event timestamp, although evaluated AFTER the Date.now(), is
// smaller than it, it means the event is using a hi-res timestamp,
// and we need to use the hi-res version for event listener timestamps as
// well.
getNow = ( ) => performance . now ( ) ;
}
}
/ * *
* Queue a kept - alive component that was activated during patch .
* The queue will be processed after the entire tree has been patched .
* /
function queueActivatedComponent ( vm ) {
// setting _inactive to false here so that a render function can
// rely on checking whether it's in an inactive tree (e.g. router-view)
vm . _inactive = false ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function handleError ( err , vm , info ) {
// Deactivate deps tracking while processing error handler to avoid possible infinite rendering.
// See: https://github.com/vuejs/vuex/issues/1505
pushTarget ( ) ;
try {
if ( vm ) {
let cur = vm ;
while ( ( cur = cur . $parent ) ) {
const hooks = cur . $options . errorCaptured ;
if ( hooks ) {
for ( let i = 0 ; i < hooks . length ; i ++ ) {
try {
const capture = hooks [ i ] . call ( cur , err , vm , info ) === false ;
if ( capture )
return ;
}
catch ( e ) {
globalHandleError ( e , cur , 'errorCaptured hook' ) ;
}
}
}
}
}
globalHandleError ( err , vm , info ) ;
}
finally {
popTarget ( ) ;
}
}
function invokeWithErrorHandling ( handler , context , args , vm , info ) {
let res ;
try {
res = args ? handler . apply ( context , args ) : handler . call ( context ) ;
if ( res && ! res . _isVue && isPromise ( res ) && ! res . _handled ) {
res . catch ( e => handleError ( e , vm , info + ` (Promise/async) ` ) ) ;
res . _handled = true ;
}
}
catch ( e ) {
handleError ( e , vm , info ) ;
}
return res ;
}
function globalHandleError ( err , vm , info ) {
logError ( err , vm , info ) ;
}
function logError ( err , vm , info ) {
if ( process . env . NODE _ENV !== 'production' ) {
warn$2 ( ` Error in ${ info } : " ${ err . toString ( ) } " ` , vm ) ;
}
/* istanbul ignore else */
if ( inBrowser && typeof console !== 'undefined' ) {
console . error ( err ) ;
}
else {
throw err ;
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
/* globals MutationObserver */
const callbacks = [ ] ;
function flushCallbacks ( ) {
const copies = callbacks . slice ( 0 ) ;
callbacks . length = 0 ;
for ( let i = 0 ; i < copies . length ; i ++ ) {
copies [ i ] ( ) ;
}
}
// The nextTick behavior leverages the microtask queue, which can be accessed
// via either native Promise.then or MutationObserver.
// MutationObserver has wider support, however it is seriously bugged in
// UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
// completely stops working after triggering a few times... so, if native
// Promise is available, we will use it:
/* istanbul ignore next, $flow-disable-line */
if ( typeof Promise !== 'undefined' && isNative ( Promise ) ) {
Promise . resolve ( ) ;
}
else if ( ! isIE &&
typeof MutationObserver !== 'undefined' &&
( isNative ( MutationObserver ) ||
// PhantomJS and iOS 7.x
MutationObserver . toString ( ) === '[object MutationObserverConstructor]' ) ) {
// Use MutationObserver where native Promise is not available,
// e.g. PhantomJS, iOS7, Android 4.4
// (#6466 MutationObserver is unreliable in IE11)
let counter = 1 ;
const observer = new MutationObserver ( flushCallbacks ) ;
const textNode = document . createTextNode ( String ( counter ) ) ;
observer . observe ( textNode , {
characterData : true
} ) ;
}
else if ( typeof setImmediate !== 'undefined' && isNative ( setImmediate ) ) ;
else ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
const seenObjects = new _Set ( ) ;
/ * *
* Recursively traverse an object to evoke all converted
* getters , so that every nested property inside the object
* is collected as a "deep" dependency .
* /
function traverse ( val ) {
_traverse ( val , seenObjects ) ;
seenObjects . clear ( ) ;
return val ;
}
function _traverse ( val , seen ) {
let i , keys ;
const isA = isArray ( val ) ;
if ( ( ! isA && ! isObject ( val ) ) ||
val . _ _v _skip /* ReactiveFlags.SKIP */ ||
Object . isFrozen ( val ) ||
val instanceof VNode ) {
return ;
}
if ( val . _ _ob _ _ ) {
const depId = val . _ _ob _ _ . dep . id ;
if ( seen . has ( depId ) ) {
return ;
}
seen . add ( depId ) ;
}
if ( isA ) {
i = val . length ;
while ( i -- )
_traverse ( val [ i ] , seen ) ;
}
else if ( isRef ( val ) ) {
_traverse ( val . value , seen ) ;
}
else {
keys = Object . keys ( val ) ;
i = keys . length ;
while ( i -- )
_traverse ( val [ keys [ i ] ] , seen ) ;
}
}
function resolveInject ( inject , vm ) {
if ( inject ) {
// inject is :any because flow is not smart enough to figure out cached
const result = Object . create ( null ) ;
const keys = hasSymbol ? Reflect . ownKeys ( inject ) : Object . keys ( inject ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
const key = keys [ i ] ;
// #6574 in case the inject object is observed...
if ( key === '__ob__' )
continue ;
const provideKey = inject [ key ] . from ;
if ( provideKey in vm . _provided ) {
result [ key ] = vm . _provided [ provideKey ] ;
}
else if ( 'default' in inject [ key ] ) {
const provideDefault = inject [ key ] . default ;
result [ key ] = isFunction ( provideDefault )
? provideDefault . call ( vm )
: provideDefault ;
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$2 ( ` Injection " ${ key } " not found ` , vm ) ;
}
}
return result ;
}
}
function resolveConstructorOptions ( Ctor ) {
let options = Ctor . options ;
if ( Ctor . super ) {
const superOptions = resolveConstructorOptions ( Ctor . super ) ;
const cachedSuperOptions = Ctor . superOptions ;
if ( superOptions !== cachedSuperOptions ) {
// super option changed,
// need to resolve new options.
Ctor . superOptions = superOptions ;
// check if there are any late-modified/attached options (#4976)
const modifiedOptions = resolveModifiedOptions ( Ctor ) ;
// update base extend options
if ( modifiedOptions ) {
extend ( Ctor . extendOptions , modifiedOptions ) ;
}
options = Ctor . options = mergeOptions ( superOptions , Ctor . extendOptions ) ;
if ( options . name ) {
options . components [ options . name ] = Ctor ;
}
}
}
return options ;
}
function resolveModifiedOptions ( Ctor ) {
let modified ;
const latest = Ctor . options ;
const sealed = Ctor . sealedOptions ;
for ( const key in latest ) {
if ( latest [ key ] !== sealed [ key ] ) {
if ( ! modified )
modified = { } ;
modified [ key ] = latest [ key ] ;
}
}
return modified ;
}
function FunctionalRenderContext ( data , props , children , parent , Ctor ) {
const options = Ctor . options ;
// ensure the createElement function in functional components
// gets a unique context - this is necessary for correct named slot check
let contextVm ;
if ( hasOwn ( parent , '_uid' ) ) {
contextVm = Object . create ( parent ) ;
contextVm . _original = parent ;
}
else {
// the context vm passed in is a functional context as well.
// in this case we want to make sure we are able to get a hold to the
// real context instance.
contextVm = parent ;
// @ts-ignore
parent = parent . _original ;
}
const isCompiled = isTrue ( options . _compiled ) ;
const needNormalization = ! isCompiled ;
this . data = data ;
this . props = props ;
this . children = children ;
this . parent = parent ;
this . listeners = data . on || emptyObject ;
this . injections = resolveInject ( options . inject , parent ) ;
this . slots = ( ) => {
if ( ! this . $slots ) {
normalizeScopedSlots ( parent , data . scopedSlots , ( this . $slots = resolveSlots ( children , parent ) ) ) ;
}
return this . $slots ;
} ;
Object . defineProperty ( this , 'scopedSlots' , {
enumerable : true ,
get ( ) {
return normalizeScopedSlots ( parent , data . scopedSlots , this . slots ( ) ) ;
}
} ) ;
// support for compiled functional template
if ( isCompiled ) {
// exposing $options for renderStatic()
this . $options = options ;
// pre-resolve slots for renderSlot()
this . $slots = this . slots ( ) ;
this . $scopedSlots = normalizeScopedSlots ( parent , data . scopedSlots , this . $slots ) ;
}
if ( options . _scopeId ) {
this . _c = ( a , b , c , d ) => {
const vnode = createElement ( contextVm , a , b , c , d , needNormalization ) ;
if ( vnode && ! isArray ( vnode ) ) {
vnode . fnScopeId = options . _scopeId ;
vnode . fnContext = parent ;
}
return vnode ;
} ;
}
else {
this . _c = ( a , b , c , d ) => createElement ( contextVm , a , b , c , d , needNormalization ) ;
}
}
installRenderHelpers ( FunctionalRenderContext . prototype ) ;
function createFunctionalComponent ( Ctor , propsData , data , contextVm , children ) {
const options = Ctor . options ;
const props = { } ;
const propOptions = options . props ;
if ( isDef ( propOptions ) ) {
for ( const key in propOptions ) {
props [ key ] = validateProp ( key , propOptions , propsData || emptyObject ) ;
}
}
else {
if ( isDef ( data . attrs ) )
mergeProps ( props , data . attrs ) ;
if ( isDef ( data . props ) )
mergeProps ( props , data . props ) ;
}
const renderContext = new FunctionalRenderContext ( data , props , children , contextVm , Ctor ) ;
const vnode = options . render . call ( null , renderContext . _c , renderContext ) ;
if ( vnode instanceof VNode ) {
return cloneAndMarkFunctionalResult ( vnode , data , renderContext . parent , options , renderContext ) ;
}
else if ( isArray ( vnode ) ) {
const vnodes = normalizeChildren ( vnode ) || [ ] ;
const res = new Array ( vnodes . length ) ;
for ( let i = 0 ; i < vnodes . length ; i ++ ) {
res [ i ] = cloneAndMarkFunctionalResult ( vnodes [ i ] , data , renderContext . parent , options , renderContext ) ;
}
return res ;
}
}
function cloneAndMarkFunctionalResult ( vnode , data , contextVm , options , renderContext ) {
// #7817 clone node before setting fnContext, otherwise if the node is reused
// (e.g. it was from a cached normal slot) the fnContext causes named slots
// that should not be matched to match.
const clone = cloneVNode ( vnode ) ;
clone . fnContext = contextVm ;
clone . fnOptions = options ;
if ( process . env . NODE _ENV !== 'production' ) {
( clone . devtoolsMeta = clone . devtoolsMeta || { } ) . renderContext =
renderContext ;
}
if ( data . slot ) {
( clone . data || ( clone . data = { } ) ) . slot = data . slot ;
}
return clone ;
}
function mergeProps ( to , from ) {
for ( const key in from ) {
to [ camelize ( key ) ] = from [ key ] ;
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
function getComponentName ( options ) {
return options . name || options . _ _name || options . _componentTag ;
}
// inline hooks to be invoked on component VNodes during patch
const componentVNodeHooks = {
init ( vnode , hydrating ) {
if ( vnode . componentInstance &&
! vnode . componentInstance . _isDestroyed &&
vnode . data . keepAlive ) {
// kept-alive components, treat as a patch
const mountedNode = vnode ; // work around flow
componentVNodeHooks . prepatch ( mountedNode , mountedNode ) ;
}
else {
const child = ( vnode . componentInstance = createComponentInstanceForVnode ( vnode , activeInstance ) ) ;
child . $mount ( hydrating ? vnode . elm : undefined , hydrating ) ;
}
} ,
prepatch ( oldVnode , vnode ) {
const options = vnode . componentOptions ;
const child = ( vnode . componentInstance = oldVnode . componentInstance ) ;
updateChildComponent ( child , options . propsData , // updated props
options . listeners , // updated listeners
vnode , // new parent vnode
options . children // new children
) ;
} ,
insert ( vnode ) {
const { context , componentInstance } = vnode ;
if ( ! componentInstance . _isMounted ) {
componentInstance . _isMounted = true ;
callHook ( componentInstance , 'mounted' ) ;
}
if ( vnode . data . keepAlive ) {
if ( context . _isMounted ) {
// vue-router#1212
// During updates, a kept-alive component's child components may
// change, so directly walking the tree here may call activated hooks
// on incorrect children. Instead we push them into a queue which will
// be processed after the whole patch process ended.
queueActivatedComponent ( componentInstance ) ;
}
else {
activateChildComponent ( componentInstance , true /* direct */ ) ;
}
}
} ,
destroy ( vnode ) {
const { componentInstance } = vnode ;
if ( ! componentInstance . _isDestroyed ) {
if ( ! vnode . data . keepAlive ) {
componentInstance . $destroy ( ) ;
}
else {
deactivateChildComponent ( componentInstance , true /* direct */ ) ;
}
}
}
} ;
const hooksToMerge = Object . keys ( componentVNodeHooks ) ;
function createComponent ( Ctor , data , context , children , tag ) {
if ( isUndef ( Ctor ) ) {
return ;
}
const baseCtor = context . $options . _base ;
// plain options object: turn it into a constructor
if ( isObject ( Ctor ) ) {
Ctor = baseCtor . extend ( Ctor ) ;
}
// if at this stage it's not a constructor or an async component factory,
// reject.
if ( typeof Ctor !== 'function' ) {
if ( process . env . NODE _ENV !== 'production' ) {
warn$2 ( ` Invalid Component definition: ${ String ( Ctor ) } ` , context ) ;
}
return ;
}
// async component
let asyncFactory ;
// @ts-expect-error
if ( isUndef ( Ctor . cid ) ) {
asyncFactory = Ctor ;
Ctor = resolveAsyncComponent ( asyncFactory ) ;
if ( Ctor === undefined ) {
// return a placeholder node for async component, which is rendered
// as a comment node but preserves all the raw information for the node.
// the information will be used for async server-rendering and hydration.
return createAsyncPlaceholder ( asyncFactory , data , context , children , tag ) ;
}
}
data = data || { } ;
// resolve constructor options in case global mixins are applied after
// component constructor creation
resolveConstructorOptions ( Ctor ) ;
// transform component v-model data into props & events
if ( isDef ( data . model ) ) {
// @ts-expect-error
transformModel ( Ctor . options , data ) ;
}
// extract props
// @ts-expect-error
const propsData = extractPropsFromVNodeData ( data , Ctor , tag ) ;
// functional component
// @ts-expect-error
if ( isTrue ( Ctor . options . functional ) ) {
return createFunctionalComponent ( Ctor , propsData , data , context , children ) ;
}
// extract listeners, since these needs to be treated as
// child component listeners instead of DOM listeners
const listeners = data . on ;
// replace with listeners with .native modifier
// so it gets processed during parent component patch.
data . on = data . nativeOn ;
// @ts-expect-error
if ( isTrue ( Ctor . options . abstract ) ) {
// abstract components do not keep anything
// other than props & listeners & slot
// work around flow
const slot = data . slot ;
data = { } ;
if ( slot ) {
data . slot = slot ;
}
}
// install component management hooks onto the placeholder node
installComponentHooks ( data ) ;
// return a placeholder vnode
// @ts-expect-error
const name = getComponentName ( Ctor . options ) || tag ;
const vnode = new VNode (
// @ts-expect-error
` vue-component- ${ Ctor . cid } ${ name ? ` - ${ name } ` : '' } ` , data , undefined , undefined , undefined , context ,
// @ts-expect-error
{ Ctor , propsData , listeners , tag , children } , asyncFactory ) ;
return vnode ;
}
function createComponentInstanceForVnode (
// we know it's MountedComponentVNode but flow doesn't
vnode ,
// activeInstance in lifecycle state
parent ) {
const options = {
_isComponent : true ,
_parentVnode : vnode ,
parent
} ;
// check inline-template render functions
const inlineTemplate = vnode . data . inlineTemplate ;
if ( isDef ( inlineTemplate ) ) {
options . render = inlineTemplate . render ;
options . staticRenderFns = inlineTemplate . staticRenderFns ;
}
return new vnode . componentOptions . Ctor ( options ) ;
}
function installComponentHooks ( data ) {
const hooks = data . hook || ( data . hook = { } ) ;
for ( let i = 0 ; i < hooksToMerge . length ; i ++ ) {
const key = hooksToMerge [ i ] ;
const existing = hooks [ key ] ;
const toMerge = componentVNodeHooks [ key ] ;
// @ts-expect-error
if ( existing !== toMerge && ! ( existing && existing . _merged ) ) {
hooks [ key ] = existing ? mergeHook ( toMerge , existing ) : toMerge ;
}
}
}
function mergeHook ( f1 , f2 ) {
const merged = ( a , b ) => {
// flow complains about extra args which is why we use any
f1 ( a , b ) ;
f2 ( a , b ) ;
} ;
merged . _merged = true ;
return merged ;
}
// transform component v-model info (value and callback) into
// prop and event handler respectively.
function transformModel ( options , data ) {
const prop = ( options . model && options . model . prop ) || 'value' ;
const event = ( options . model && options . model . event ) || 'input' ;
( data . attrs || ( data . attrs = { } ) ) [ prop ] = data . model . value ;
const on = data . on || ( data . on = { } ) ;
const existing = on [ event ] ;
const callback = data . model . callback ;
if ( isDef ( existing ) ) {
if ( isArray ( existing )
? existing . indexOf ( callback ) === - 1
: existing !== callback ) {
on [ event ] = [ callback ] . concat ( existing ) ;
}
}
else {
on [ event ] = callback ;
}
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let warn$2 = noop ;
let tip = noop ;
let generateComponentTrace ; // work around flow check
let formatComponentName ;
if ( process . env . NODE _ENV !== 'production' ) {
const hasConsole = typeof console !== 'undefined' ;
const classifyRE = /(?:^|[-_])(\w)/g ;
const classify = str => str . replace ( classifyRE , c => c . toUpperCase ( ) ) . replace ( /[-_]/g , '' ) ;
warn$2 = ( msg , vm = currentInstance ) => {
const trace = vm ? generateComponentTrace ( vm ) : '' ;
if ( hasConsole && ! config . silent ) {
console . error ( ` [Vue warn]: ${ msg } ${ trace } ` ) ;
}
} ;
tip = ( msg , vm ) => {
if ( hasConsole && ! config . silent ) {
console . warn ( ` [Vue tip]: ${ msg } ` + ( vm ? generateComponentTrace ( vm ) : '' ) ) ;
}
} ;
formatComponentName = ( vm , includeFile ) => {
if ( vm . $root === vm ) {
return '<Root>' ;
}
const options = isFunction ( vm ) && vm . cid != null
? vm . options
: vm . _isVue
? vm . $options || vm . constructor . options
: vm ;
let name = getComponentName ( options ) ;
const file = options . _ _file ;
if ( ! name && file ) {
const match = file . match ( /([^/\\]+)\.vue$/ ) ;
name = match && match [ 1 ] ;
}
return ( ( name ? ` < ${ classify ( name ) } > ` : ` <Anonymous> ` ) +
( file && includeFile !== false ? ` at ${ file } ` : '' ) ) ;
} ;
const repeat = ( str , n ) => {
let res = '' ;
while ( n ) {
if ( n % 2 === 1 )
res += str ;
if ( n > 1 )
str += str ;
n >>= 1 ;
}
return res ;
} ;
generateComponentTrace = ( vm ) => {
if ( vm . _isVue && vm . $parent ) {
const tree = [ ] ;
let currentRecursiveSequence = 0 ;
while ( vm ) {
if ( tree . length > 0 ) {
const last = tree [ tree . length - 1 ] ;
if ( last . constructor === vm . constructor ) {
currentRecursiveSequence ++ ;
vm = vm . $parent ;
continue ;
}
else if ( currentRecursiveSequence > 0 ) {
tree [ tree . length - 1 ] = [ last , currentRecursiveSequence ] ;
currentRecursiveSequence = 0 ;
}
}
tree . push ( vm ) ;
vm = vm . $parent ;
}
return ( '\n\nfound in\n\n' +
tree
. map ( ( vm , i ) => ` ${ i === 0 ? '---> ' : repeat ( ' ' , 5 + i * 2 ) } ${ isArray ( vm )
? ` ${ formatComponentName ( vm [ 0 ] ) } ... ( ${ vm [ 1 ] } recursive calls) `
: formatComponentName ( vm ) } ` )
. join ( '\n' ) ) ;
}
else {
return ` \n \n (found in ${ formatComponentName ( vm ) } ) ` ;
}
} ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
/ * *
* Option overwriting strategies are functions that handle
* how to merge a parent option value and a child option
* value into the final value .
* /
const strats = config . optionMergeStrategies ;
/ * *
* Options with restrictions
* /
if ( process . env . NODE _ENV !== 'production' ) {
strats . el = strats . propsData = function ( parent , child , vm , key ) {
if ( ! vm ) {
warn$2 ( ` option " ${ key } " can only be used during instance ` +
'creation with the `new` keyword.' ) ;
}
return defaultStrat ( parent , child ) ;
} ;
}
/ * *
* Helper that recursively merges two data objects together .
* /
function mergeData ( to , from , recursive = true ) {
if ( ! from )
return to ;
let key , toVal , fromVal ;
const keys = hasSymbol
? Reflect . ownKeys ( from )
: Object . keys ( from ) ;
for ( let i = 0 ; i < keys . length ; i ++ ) {
key = keys [ i ] ;
// in case the object is already observed...
if ( key === '__ob__' )
continue ;
toVal = to [ key ] ;
fromVal = from [ key ] ;
if ( ! recursive || ! hasOwn ( to , key ) ) {
set ( to , key , fromVal ) ;
}
else if ( toVal !== fromVal &&
isPlainObject ( toVal ) &&
isPlainObject ( fromVal ) ) {
mergeData ( toVal , fromVal ) ;
}
}
return to ;
}
/ * *
* Data
* /
function mergeDataOrFn ( parentVal , childVal , vm ) {
if ( ! vm ) {
// in a Vue.extend merge, both should be functions
if ( ! childVal ) {
return parentVal ;
}
if ( ! parentVal ) {
return childVal ;
}
// when parentVal & childVal are both present,
// we need to return a function that returns the
// merged result of both functions... no need to
// check if parentVal is a function here because
// it has to be a function to pass previous merges.
return function mergedDataFn ( ) {
return mergeData ( isFunction ( childVal ) ? childVal . call ( this , this ) : childVal , isFunction ( parentVal ) ? parentVal . call ( this , this ) : parentVal ) ;
} ;
}
else {
return function mergedInstanceDataFn ( ) {
// instance merge
const instanceData = isFunction ( childVal )
? childVal . call ( vm , vm )
: childVal ;
const defaultData = isFunction ( parentVal )
? parentVal . call ( vm , vm )
: parentVal ;
if ( instanceData ) {
return mergeData ( instanceData , defaultData ) ;
}
else {
return defaultData ;
}
} ;
}
}
strats . data = function ( parentVal , childVal , vm ) {
if ( ! vm ) {
if ( childVal && typeof childVal !== 'function' ) {
process . env . NODE _ENV !== 'production' &&
warn$2 ( 'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.' , vm ) ;
return parentVal ;
}
return mergeDataOrFn ( parentVal , childVal ) ;
}
return mergeDataOrFn ( parentVal , childVal , vm ) ;
} ;
/ * *
* Hooks and props are merged as arrays .
* /
function mergeLifecycleHook ( parentVal , childVal ) {
const res = childVal
? parentVal
? parentVal . concat ( childVal )
: isArray ( childVal )
? childVal
: [ childVal ]
: parentVal ;
return res ? dedupeHooks ( res ) : res ;
}
function dedupeHooks ( hooks ) {
const res = [ ] ;
for ( let i = 0 ; i < hooks . length ; i ++ ) {
if ( res . indexOf ( hooks [ i ] ) === - 1 ) {
res . push ( hooks [ i ] ) ;
}
}
return res ;
}
LIFECYCLE _HOOKS . forEach ( hook => {
strats [ hook ] = mergeLifecycleHook ;
} ) ;
/ * *
* Assets
*
* When a vm is present ( instance creation ) , we need to do
* a three - way merge between constructor options , instance
* options and parent options .
* /
function mergeAssets ( parentVal , childVal , vm , key ) {
const res = Object . create ( parentVal || null ) ;
if ( childVal ) {
process . env . NODE _ENV !== 'production' && assertObjectType ( key , childVal , vm ) ;
return extend ( res , childVal ) ;
}
else {
return res ;
}
}
ASSET _TYPES . forEach ( function ( type ) {
strats [ type + 's' ] = mergeAssets ;
} ) ;
/ * *
* Watchers .
*
* Watchers hashes should not overwrite one
* another , so we merge them as arrays .
* /
strats . watch = function ( parentVal , childVal , vm , key ) {
// work around Firefox's Object.prototype.watch...
//@ts-expect-error work around
if ( parentVal === nativeWatch )
parentVal = undefined ;
//@ts-expect-error work around
if ( childVal === nativeWatch )
childVal = undefined ;
/* istanbul ignore if */
if ( ! childVal )
return Object . create ( parentVal || null ) ;
if ( process . env . NODE _ENV !== 'production' ) {
assertObjectType ( key , childVal , vm ) ;
}
if ( ! parentVal )
return childVal ;
const ret = { } ;
extend ( ret , parentVal ) ;
for ( const key in childVal ) {
let parent = ret [ key ] ;
const child = childVal [ key ] ;
if ( parent && ! isArray ( parent ) ) {
parent = [ parent ] ;
}
ret [ key ] = parent ? parent . concat ( child ) : isArray ( child ) ? child : [ child ] ;
}
return ret ;
} ;
/ * *
* Other object hashes .
* /
strats . props =
strats . methods =
strats . inject =
strats . computed =
function ( parentVal , childVal , vm , key ) {
if ( childVal && process . env . NODE _ENV !== 'production' ) {
assertObjectType ( key , childVal , vm ) ;
}
if ( ! parentVal )
return childVal ;
const ret = Object . create ( null ) ;
extend ( ret , parentVal ) ;
if ( childVal )
extend ( ret , childVal ) ;
return ret ;
} ;
strats . provide = function ( parentVal , childVal ) {
if ( ! parentVal )
return childVal ;
return function ( ) {
const ret = Object . create ( null ) ;
mergeData ( ret , isFunction ( parentVal ) ? parentVal . call ( this ) : parentVal ) ;
if ( childVal ) {
mergeData ( ret , isFunction ( childVal ) ? childVal . call ( this ) : childVal , false // non-recursive
) ;
}
return ret ;
} ;
} ;
/ * *
* Default strategy .
* /
const defaultStrat = function ( parentVal , childVal ) {
return childVal === undefined ? parentVal : childVal ;
} ;
/ * *
* Validate component names
* /
function checkComponents ( options ) {
for ( const key in options . components ) {
validateComponentName ( key ) ;
}
}
function validateComponentName ( name ) {
if ( ! new RegExp ( ` ^[a-zA-Z][ \\ - \\ .0-9_ ${ unicodeRegExp . source } ]* $ ` ) . test ( name ) ) {
warn$2 ( 'Invalid component name: "' +
name +
'". Component names ' +
'should conform to valid custom element name in html5 specification.' ) ;
}
if ( isBuiltInTag ( name ) || config . isReservedTag ( name ) ) {
warn$2 ( 'Do not use built-in or reserved HTML elements as component ' +
'id: ' +
name ) ;
}
}
/ * *
* Ensure all props option syntax are normalized into the
* Object - based format .
* /
function normalizeProps ( options , vm ) {
const props = options . props ;
if ( ! props )
return ;
const res = { } ;
let i , val , name ;
if ( isArray ( props ) ) {
i = props . length ;
while ( i -- ) {
val = props [ i ] ;
if ( typeof val === 'string' ) {
name = camelize ( val ) ;
res [ name ] = { type : null } ;
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$2 ( 'props must be strings when using array syntax.' ) ;
}
}
}
else if ( isPlainObject ( props ) ) {
for ( const key in props ) {
val = props [ key ] ;
name = camelize ( key ) ;
res [ name ] = isPlainObject ( val ) ? val : { type : val } ;
}
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$2 ( ` Invalid value for option "props": expected an Array or an Object, ` +
` but got ${ toRawType ( props ) } . ` , vm ) ;
}
options . props = res ;
}
/ * *
* Normalize all injections into Object - based format
* /
function normalizeInject ( options , vm ) {
const inject = options . inject ;
if ( ! inject )
return ;
const normalized = ( options . inject = { } ) ;
if ( isArray ( inject ) ) {
for ( let i = 0 ; i < inject . length ; i ++ ) {
normalized [ inject [ i ] ] = { from : inject [ i ] } ;
}
}
else if ( isPlainObject ( inject ) ) {
for ( const key in inject ) {
const val = inject [ key ] ;
normalized [ key ] = isPlainObject ( val )
? extend ( { from : key } , val )
: { from : val } ;
}
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$2 ( ` Invalid value for option "inject": expected an Array or an Object, ` +
` but got ${ toRawType ( inject ) } . ` , vm ) ;
}
}
/ * *
* Normalize raw function directives into object format .
* /
function normalizeDirectives ( options ) {
const dirs = options . directives ;
if ( dirs ) {
for ( const key in dirs ) {
const def = dirs [ key ] ;
if ( isFunction ( def ) ) {
dirs [ key ] = { bind : def , update : def } ;
}
}
}
}
function assertObjectType ( name , value , vm ) {
if ( ! isPlainObject ( value ) ) {
warn$2 ( ` Invalid value for option " ${ name } ": expected an Object, ` +
` but got ${ toRawType ( value ) } . ` , vm ) ;
}
}
/ * *
* Merge two option objects into a new one .
* Core utility used in both instantiation and inheritance .
* /
function mergeOptions ( parent , child , vm ) {
if ( process . env . NODE _ENV !== 'production' ) {
checkComponents ( child ) ;
}
if ( isFunction ( child ) ) {
// @ts-expect-error
child = child . options ;
}
normalizeProps ( child , vm ) ;
normalizeInject ( child , vm ) ;
normalizeDirectives ( child ) ;
// Apply extends and mixins on the child options,
// but only if it is a raw options object that isn't
// the result of another mergeOptions call.
// Only merged options has the _base property.
if ( ! child . _base ) {
if ( child . extends ) {
parent = mergeOptions ( parent , child . extends , vm ) ;
}
if ( child . mixins ) {
for ( let i = 0 , l = child . mixins . length ; i < l ; i ++ ) {
parent = mergeOptions ( parent , child . mixins [ i ] , vm ) ;
}
}
}
const options = { } ;
let key ;
for ( key in parent ) {
mergeField ( key ) ;
}
for ( key in child ) {
if ( ! hasOwn ( parent , key ) ) {
mergeField ( key ) ;
}
}
function mergeField ( key ) {
const strat = strats [ key ] || defaultStrat ;
options [ key ] = strat ( parent [ key ] , child [ key ] , vm , key ) ;
}
return options ;
}
/ * *
* Resolve an asset .
* This function is used because child instances need access
* to assets defined in its ancestor chain .
* /
function resolveAsset ( options , type , id , warnMissing ) {
/* istanbul ignore if */
if ( typeof id !== 'string' ) {
return ;
}
const assets = options [ type ] ;
// check local registration variations first
if ( hasOwn ( assets , id ) )
return assets [ id ] ;
const camelizedId = camelize ( id ) ;
if ( hasOwn ( assets , camelizedId ) )
return assets [ camelizedId ] ;
const PascalCaseId = capitalize ( camelizedId ) ;
if ( hasOwn ( assets , PascalCaseId ) )
return assets [ PascalCaseId ] ;
// fallback to prototype chain
const res = assets [ id ] || assets [ camelizedId ] || assets [ PascalCaseId ] ;
if ( process . env . NODE _ENV !== 'production' && warnMissing && ! res ) {
warn$2 ( 'Failed to resolve ' + type . slice ( 0 , - 1 ) + ': ' + id ) ;
}
return res ;
}
function validateProp ( key , propOptions , propsData , vm ) {
const prop = propOptions [ key ] ;
const absent = ! hasOwn ( propsData , key ) ;
let value = propsData [ key ] ;
// boolean casting
const booleanIndex = getTypeIndex ( Boolean , prop . type ) ;
if ( booleanIndex > - 1 ) {
if ( absent && ! hasOwn ( prop , 'default' ) ) {
value = false ;
}
else if ( value === '' || value === hyphenate ( key ) ) {
// only cast empty string / same name to boolean if
// boolean has higher priority
const stringIndex = getTypeIndex ( String , prop . type ) ;
if ( stringIndex < 0 || booleanIndex < stringIndex ) {
value = true ;
}
}
}
// check default value
if ( value === undefined ) {
value = getPropDefaultValue ( vm , prop , key ) ;
// since the default value is a fresh copy,
// make sure to observe it.
const prevShouldObserve = shouldObserve ;
toggleObserving ( true ) ;
observe ( value ) ;
toggleObserving ( prevShouldObserve ) ;
}
if ( process . env . NODE _ENV !== 'production' ) {
assertProp ( prop , key , value , vm , absent ) ;
}
return value ;
}
/ * *
* Get the default value of a prop .
* /
function getPropDefaultValue ( vm , prop , key ) {
// no default, return undefined
if ( ! hasOwn ( prop , 'default' ) ) {
return undefined ;
}
const def = prop . default ;
// warn against non-factory defaults for Object & Array
if ( process . env . NODE _ENV !== 'production' && isObject ( def ) ) {
warn$2 ( 'Invalid default value for prop "' +
key +
'": ' +
'Props with type Object/Array must use a factory function ' +
'to return the default value.' , vm ) ;
}
// the raw prop value was also undefined from previous render,
// return previous default value to avoid unnecessary watcher trigger
if ( vm &&
vm . $options . propsData &&
vm . $options . propsData [ key ] === undefined &&
vm . _props [ key ] !== undefined ) {
return vm . _props [ key ] ;
}
// call factory function for non-Function types
// a value is Function if its prototype is function even across different execution context
return isFunction ( def ) && getType ( prop . type ) !== 'Function'
? def . call ( vm )
: def ;
}
/ * *
* Assert whether a prop is valid .
* /
function assertProp ( prop , name , value , vm , absent ) {
if ( prop . required && absent ) {
warn$2 ( 'Missing required prop: "' + name + '"' , vm ) ;
return ;
}
if ( value == null && ! prop . required ) {
return ;
}
let type = prop . type ;
let valid = ! type || type === true ;
const expectedTypes = [ ] ;
if ( type ) {
if ( ! isArray ( type ) ) {
type = [ type ] ;
}
for ( let i = 0 ; i < type . length && ! valid ; i ++ ) {
const assertedType = assertType ( value , type [ i ] , vm ) ;
expectedTypes . push ( assertedType . expectedType || '' ) ;
valid = assertedType . valid ;
}
}
const haveExpectedTypes = expectedTypes . some ( t => t ) ;
if ( ! valid && haveExpectedTypes ) {
warn$2 ( getInvalidTypeMessage ( name , value , expectedTypes ) , vm ) ;
return ;
}
const validator = prop . validator ;
if ( validator ) {
if ( ! validator ( value ) ) {
warn$2 ( 'Invalid prop: custom validator check failed for prop "' + name + '".' , vm ) ;
}
}
}
const simpleCheckRE = /^(String|Number|Boolean|Function|Symbol|BigInt)$/ ;
function assertType ( value , type , vm ) {
let valid ;
const expectedType = getType ( type ) ;
if ( simpleCheckRE . test ( expectedType ) ) {
const t = typeof value ;
valid = t === expectedType . toLowerCase ( ) ;
// for primitive wrapper objects
if ( ! valid && t === 'object' ) {
valid = value instanceof type ;
}
}
else if ( expectedType === 'Object' ) {
valid = isPlainObject ( value ) ;
}
else if ( expectedType === 'Array' ) {
valid = isArray ( value ) ;
}
else {
try {
valid = value instanceof type ;
}
catch ( e ) {
warn$2 ( 'Invalid prop type: "' + String ( type ) + '" is not a constructor' , vm ) ;
valid = false ;
}
}
return {
valid ,
expectedType
} ;
}
const functionTypeCheckRE = /^\s*function (\w+)/ ;
/ * *
* Use function string name to check built - in types ,
* because a simple equality check will fail when running
* across different vms / iframes .
* /
function getType ( fn ) {
const match = fn && fn . toString ( ) . match ( functionTypeCheckRE ) ;
return match ? match [ 1 ] : '' ;
}
function isSameType ( a , b ) {
return getType ( a ) === getType ( b ) ;
}
function getTypeIndex ( type , expectedTypes ) {
if ( ! isArray ( expectedTypes ) ) {
return isSameType ( expectedTypes , type ) ? 0 : - 1 ;
}
for ( let i = 0 , len = expectedTypes . length ; i < len ; i ++ ) {
if ( isSameType ( expectedTypes [ i ] , type ) ) {
return i ;
}
}
return - 1 ;
}
function getInvalidTypeMessage ( name , value , expectedTypes ) {
let message = ` Invalid prop: type check failed for prop " ${ name } ". ` +
` Expected ${ expectedTypes . map ( capitalize ) . join ( ', ' ) } ` ;
const expectedType = expectedTypes [ 0 ] ;
const receivedType = toRawType ( value ) ;
// check if we need to specify expected value
if ( expectedTypes . length === 1 &&
isExplicable ( expectedType ) &&
isExplicable ( typeof value ) &&
! isBoolean ( expectedType , receivedType ) ) {
message += ` with value ${ styleValue ( value , expectedType ) } ` ;
}
message += ` , got ${ receivedType } ` ;
// check if we need to specify received value
if ( isExplicable ( receivedType ) ) {
message += ` with value ${ styleValue ( value , receivedType ) } . ` ;
}
return message ;
}
function styleValue ( value , type ) {
if ( type === 'String' ) {
return ` " ${ value } " ` ;
}
else if ( type === 'Number' ) {
return ` ${ Number ( value ) } ` ;
}
else {
return ` ${ value } ` ;
}
}
const EXPLICABLE _TYPES = [ 'string' , 'number' , 'boolean' ] ;
function isExplicable ( value ) {
return EXPLICABLE _TYPES . some ( elem => value . toLowerCase ( ) === elem ) ;
}
function isBoolean ( ... args ) {
return args . some ( elem => elem . toLowerCase ( ) === 'boolean' ) ;
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
// these are reserved for web because they are directly compiled away
// during template compilation
makeMap ( 'style,class' ) ;
// attributes that should be using props for binding
const acceptValue = makeMap ( 'input,textarea,option,select,progress' ) ;
const mustUseProp = ( tag , type , attr ) => {
return ( ( attr === 'value' && acceptValue ( tag ) && type !== 'button' ) ||
( attr === 'selected' && tag === 'option' ) ||
( attr === 'checked' && tag === 'input' ) ||
( attr === 'muted' && tag === 'video' ) ) ;
} ;
const isEnumeratedAttr = makeMap ( 'contenteditable,draggable,spellcheck' ) ;
makeMap ( 'events,caret,typing,plaintext-only' ) ;
const isBooleanAttr = makeMap ( 'allowfullscreen,async,autofocus,autoplay,checked,compact,controls,declare,' +
'default,defaultchecked,defaultmuted,defaultselected,defer,disabled,' +
'enabled,formnovalidate,hidden,indeterminate,inert,ismap,itemscope,loop,multiple,' +
'muted,nohref,noresize,noshade,novalidate,nowrap,open,pauseonexit,readonly,' +
'required,reversed,scoped,seamless,selected,sortable,' +
'truespeed,typemustmatch,visible' ) ;
const isHTMLTag = makeMap ( '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' ) ;
2023-12-18 13:12:25 +08:00
// this map is intentionally selective, only covering SVG elements that may
// contain child elements.
2024-01-16 21:26:16 +08:00
const isSVG = makeMap ( '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' , true ) ;
const isPreTag = ( tag ) => tag === 'pre' ;
const isReservedTag = ( tag ) => {
return isHTMLTag ( tag ) || isSVG ( tag ) ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function getTagNamespace ( tag ) {
if ( isSVG ( tag ) ) {
return 'svg' ;
}
// basic support for MathML
// note it doesn't support other MathML elements being component roots
if ( tag === 'math' ) {
return 'math' ;
}
}
makeMap ( 'text,number,password,search,email,tel,url' ) ;
const validDivisionCharRE = /[\w).+\-_$\]]/ ;
function parseFilters ( exp ) {
let inSingle = false ;
let inDouble = false ;
let inTemplateString = false ;
let inRegex = false ;
let curly = 0 ;
let square = 0 ;
let paren = 0 ;
let lastFilterIndex = 0 ;
let c , prev , i , expression , filters ;
for ( i = 0 ; i < exp . length ; i ++ ) {
prev = c ;
c = exp . charCodeAt ( i ) ;
if ( inSingle ) {
if ( c === 0x27 && prev !== 0x5c )
inSingle = false ;
}
else if ( inDouble ) {
if ( c === 0x22 && prev !== 0x5c )
inDouble = false ;
}
else if ( inTemplateString ) {
if ( c === 0x60 && prev !== 0x5c )
inTemplateString = false ;
}
else if ( inRegex ) {
if ( c === 0x2f && prev !== 0x5c )
inRegex = false ;
}
else if ( c === 0x7c && // pipe
exp . charCodeAt ( i + 1 ) !== 0x7c &&
exp . charCodeAt ( i - 1 ) !== 0x7c &&
! curly &&
! square &&
! paren ) {
if ( expression === undefined ) {
// first filter, end of expression
lastFilterIndex = i + 1 ;
expression = exp . slice ( 0 , i ) . trim ( ) ;
}
else {
pushFilter ( ) ;
}
}
else {
switch ( c ) {
case 0x22 :
inDouble = true ;
break ; // "
case 0x27 :
inSingle = true ;
break ; // '
case 0x60 :
inTemplateString = true ;
break ; // `
case 0x28 :
paren ++ ;
break ; // (
case 0x29 :
paren -- ;
break ; // )
case 0x5b :
square ++ ;
break ; // [
case 0x5d :
square -- ;
break ; // ]
case 0x7b :
curly ++ ;
break ; // {
case 0x7d :
curly -- ;
break ; // }
}
if ( c === 0x2f ) {
// /
let j = i - 1 ;
let p ;
// find first non-whitespace prev char
for ( ; j >= 0 ; j -- ) {
p = exp . charAt ( j ) ;
if ( p !== ' ' )
break ;
}
if ( ! p || ! validDivisionCharRE . test ( p ) ) {
inRegex = true ;
}
}
}
}
if ( expression === undefined ) {
2023-12-18 13:12:25 +08:00
expression = exp . slice ( 0 , i ) . trim ( ) ;
2024-01-16 21:26:16 +08:00
}
else if ( lastFilterIndex !== 0 ) {
2023-12-18 13:12:25 +08:00
pushFilter ( ) ;
}
2024-01-16 21:26:16 +08:00
function pushFilter ( ) {
( filters || ( filters = [ ] ) ) . push ( exp . slice ( lastFilterIndex , i ) . trim ( ) ) ;
lastFilterIndex = i + 1 ;
}
if ( filters ) {
for ( i = 0 ; i < filters . length ; i ++ ) {
expression = wrapFilter ( expression , filters [ i ] ) ;
}
}
return expression ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function wrapFilter ( exp , filter ) {
const i = filter . indexOf ( '(' ) ;
if ( i < 0 ) {
// _f: resolveFilter
return ` _f(" ${ filter } ")( ${ exp } ) ` ;
}
else {
const name = filter . slice ( 0 , i ) ;
const args = filter . slice ( i + 1 ) ;
return ` _f(" ${ name } ")( ${ exp } ${ args !== ')' ? ',' + args : args } ` ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const defaultTagRE = /\{\{((?:.|\r?\n)+?)\}\}/g ;
const regexEscapeRE = /[-.*+?^${}()|[\]\/\\]/g ;
const buildRegex = cached ( delimiters => {
const open = delimiters [ 0 ] . replace ( regexEscapeRE , '\\$&' ) ;
const close = delimiters [ 1 ] . replace ( regexEscapeRE , '\\$&' ) ;
return new RegExp ( open + '((?:.|\\n)+?)' + close , 'g' ) ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
function parseText ( text , delimiters ) {
//@ts-expect-error
const tagRE = delimiters ? buildRegex ( delimiters ) : defaultTagRE ;
if ( ! tagRE . test ( text ) ) {
return ;
}
const tokens = [ ] ;
const rawTokens = [ ] ;
let lastIndex = ( tagRE . lastIndex = 0 ) ;
let match , index , tokenValue ;
while ( ( match = tagRE . exec ( text ) ) ) {
index = match . index ;
// push text token
if ( index > lastIndex ) {
rawTokens . push ( ( tokenValue = text . slice ( lastIndex , index ) ) ) ;
tokens . push ( JSON . stringify ( tokenValue ) ) ;
}
// tag token
const exp = parseFilters ( match [ 1 ] . trim ( ) ) ;
tokens . push ( ` _s( ${ exp } ) ` ) ;
rawTokens . push ( { '@binding' : exp } ) ;
lastIndex = index + match [ 0 ] . length ;
}
if ( lastIndex < text . length ) {
rawTokens . push ( ( tokenValue = text . slice ( lastIndex ) ) ) ;
tokens . push ( JSON . stringify ( tokenValue ) ) ;
}
return {
expression : tokens . join ( '+' ) ,
tokens : rawTokens
} ;
2023-12-18 13:12:25 +08:00
}
/* eslint-disable no-unused-vars */
2024-01-16 21:26:16 +08:00
function baseWarn ( msg , range ) {
console . error ( ` [Vue compiler]: ${ msg } ` ) ;
2023-12-18 13:12:25 +08:00
}
/* eslint-enable no-unused-vars */
2024-01-16 21:26:16 +08:00
function pluckModuleFunction ( modules , key ) {
return modules ? modules . map ( m => m [ key ] ) . filter ( _ => _ ) : [ ] ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function addProp ( el , name , value , range , dynamic ) {
( el . props || ( el . props = [ ] ) ) . push ( rangeSetItem ( { name , value , dynamic } , range ) ) ;
el . plain = false ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function addAttr ( el , name , value , range , dynamic ) {
const attrs = dynamic
? el . dynamicAttrs || ( el . dynamicAttrs = [ ] )
: el . attrs || ( el . attrs = [ ] ) ;
attrs . push ( rangeSetItem ( { name , value , dynamic } , range ) ) ;
el . plain = false ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// add a raw attr (use this in preTransforms)
function addRawAttr ( el , name , value , range ) {
el . attrsMap [ name ] = value ;
el . attrsList . push ( rangeSetItem ( { name , value } , range ) ) ;
}
function addDirective ( el , name , rawName , value , arg , isDynamicArg , modifiers , range ) {
( el . directives || ( el . directives = [ ] ) ) . push ( rangeSetItem ( {
name ,
rawName ,
value ,
arg ,
isDynamicArg ,
modifiers
} , range ) ) ;
el . plain = false ;
}
function prependModifierMarker ( symbol , name , dynamic ) {
return dynamic ? ` _p( ${ name } ," ${ symbol } ") ` : symbol + name ; // mark the event as captured
}
function addHandler ( el , name , value , modifiers , important , warn , range , dynamic ) {
modifiers = modifiers || emptyObject ;
// warn prevent and passive modifier
/* istanbul ignore if */
if ( process . env . NODE _ENV !== 'production' && warn && modifiers . prevent && modifiers . passive ) {
warn ( "passive and prevent can't be used together. " +
"Passive handler can't prevent default event." , range ) ;
}
// normalize click.right and click.middle since they don't actually fire
// this is technically browser-specific, but at least for now browsers are
// the only target envs that have right/middle clicks.
if ( modifiers . right ) {
if ( dynamic ) {
name = ` ( ${ name } )==='click'?'contextmenu':( ${ name } ) ` ;
}
else if ( name === 'click' ) {
name = 'contextmenu' ;
delete modifiers . right ;
}
}
else if ( modifiers . middle ) {
if ( dynamic ) {
name = ` ( ${ name } )==='click'?'mouseup':( ${ name } ) ` ;
}
else if ( name === 'click' ) {
name = 'mouseup' ;
}
}
// check capture modifier
if ( modifiers . capture ) {
delete modifiers . capture ;
name = prependModifierMarker ( '!' , name , dynamic ) ;
}
if ( modifiers . once ) {
delete modifiers . once ;
name = prependModifierMarker ( '~' , name , dynamic ) ;
}
/* istanbul ignore if */
if ( modifiers . passive ) {
delete modifiers . passive ;
name = prependModifierMarker ( '&' , name , dynamic ) ;
}
let events ;
if ( modifiers . native ) {
delete modifiers . native ;
events = el . nativeEvents || ( el . nativeEvents = { } ) ;
}
else {
events = el . events || ( el . events = { } ) ;
}
const newHandler = rangeSetItem ( { value : value . trim ( ) , dynamic } , range ) ;
if ( modifiers !== emptyObject ) {
newHandler . modifiers = modifiers ;
}
const handlers = events [ name ] ;
/* istanbul ignore if */
if ( Array . isArray ( handlers ) ) {
important ? handlers . unshift ( newHandler ) : handlers . push ( newHandler ) ;
}
else if ( handlers ) {
events [ name ] = important ? [ newHandler , handlers ] : [ handlers , newHandler ] ;
}
else {
events [ name ] = newHandler ;
}
el . plain = false ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getRawBindingAttr ( el , name ) {
return ( el . rawAttrsMap [ ':' + name ] ||
el . rawAttrsMap [ 'v-bind:' + name ] ||
el . rawAttrsMap [ name ] ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getBindingAttr ( el , name , getStatic ) {
const dynamicValue = getAndRemoveAttr ( el , ':' + name ) || getAndRemoveAttr ( el , 'v-bind:' + name ) ;
if ( dynamicValue != null ) {
return parseFilters ( dynamicValue ) ;
}
else if ( getStatic !== false ) {
const staticValue = getAndRemoveAttr ( el , name ) ;
if ( staticValue != null ) {
return JSON . stringify ( staticValue ) ;
}
}
2023-12-18 13:12:25 +08:00
}
// note: this only removes the attr from the Array (attrsList) so that it
// doesn't get processed by processAttrs.
// By default it does NOT remove it from the map (attrsMap) because the map is
// needed during codegen.
2024-01-16 21:26:16 +08:00
function getAndRemoveAttr ( el , name , removeFromMap ) {
let val ;
if ( ( val = el . attrsMap [ name ] ) != null ) {
const list = el . attrsList ;
for ( let i = 0 , l = list . length ; i < l ; i ++ ) {
if ( list [ i ] . name === name ) {
list . splice ( i , 1 ) ;
break ;
}
}
}
if ( removeFromMap ) {
delete el . attrsMap [ name ] ;
}
return val ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function getAndRemoveAttrByRegex ( el , name ) {
const list = el . attrsList ;
for ( let i = 0 , l = list . length ; i < l ; i ++ ) {
const attr = list [ i ] ;
if ( name . test ( attr . name ) ) {
list . splice ( i , 1 ) ;
return attr ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
}
function rangeSetItem ( item , range ) {
if ( range ) {
if ( range . start != null ) {
item . start = range . start ;
}
if ( range . end != null ) {
item . end = range . end ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return item ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function transformNode$1 ( el , options ) {
const warn = options . warn || baseWarn ;
const staticClass = getAndRemoveAttr ( el , 'class' ) ;
if ( process . env . NODE _ENV !== 'production' && staticClass ) {
const res = parseText ( staticClass , options . delimiters ) ;
if ( res ) {
warn ( ` class=" ${ staticClass } ": ` +
'Interpolation inside attributes has been removed. ' +
'Use v-bind or the colon shorthand instead. For example, ' +
'instead of <div class="{{ val }}">, use <div :class="val">.' , el . rawAttrsMap [ 'class' ] ) ;
}
}
if ( staticClass ) {
el . staticClass = JSON . stringify ( staticClass . replace ( /\s+/g , ' ' ) . trim ( ) ) ;
}
const classBinding = getBindingAttr ( el , 'class' , false /* getStatic */ ) ;
if ( classBinding ) {
el . classBinding = classBinding ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genData$2 ( el ) {
let data = '' ;
if ( el . staticClass ) {
data += ` staticClass: ${ el . staticClass } , ` ;
}
if ( el . classBinding ) {
data += ` class: ${ el . classBinding } , ` ;
}
return data ;
2023-12-18 13:12:25 +08:00
}
var klass = {
2024-01-16 21:26:16 +08:00
staticKeys : [ 'staticClass' ] ,
transformNode : transformNode$1 ,
genData : genData$2
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const parseStyleText = cached ( function ( cssText ) {
const res = { } ;
const listDelimiter = /;(?![^(]*\))/g ;
const propertyDelimiter = /:(.+)/ ;
cssText . split ( listDelimiter ) . forEach ( function ( item ) {
if ( item ) {
const tmp = item . split ( propertyDelimiter ) ;
tmp . length > 1 && ( res [ tmp [ 0 ] . trim ( ) ] = tmp [ 1 ] . trim ( ) ) ;
}
} ) ;
return res ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
function transformNode ( el , options ) {
const warn = options . warn || baseWarn ;
const staticStyle = getAndRemoveAttr ( el , 'style' ) ;
if ( staticStyle ) {
/* istanbul ignore if */
if ( process . env . NODE _ENV !== 'production' ) {
const res = parseText ( staticStyle , options . delimiters ) ;
if ( res ) {
warn ( ` style=" ${ staticStyle } ": ` +
'Interpolation inside attributes has been removed. ' +
'Use v-bind or the colon shorthand instead. For example, ' +
'instead of <div style="{{ val }}">, use <div :style="val">.' , el . rawAttrsMap [ 'style' ] ) ;
}
}
el . staticStyle = JSON . stringify ( parseStyleText ( staticStyle ) ) ;
}
const styleBinding = getBindingAttr ( el , 'style' , false /* getStatic */ ) ;
if ( styleBinding ) {
el . styleBinding = styleBinding ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function genData$1 ( el ) {
let data = '' ;
if ( el . staticStyle ) {
data += ` staticStyle: ${ el . staticStyle } , ` ;
}
if ( el . styleBinding ) {
data += ` style:( ${ el . styleBinding } ), ` ;
}
return data ;
2023-12-18 13:12:25 +08:00
}
var style = {
2024-01-16 21:26:16 +08:00
staticKeys : [ 'staticStyle' ] ,
transformNode ,
genData : genData$1
2023-12-18 13:12:25 +08:00
} ;
/ * *
* Cross - platform code generation for component v - model
* /
2024-01-16 21:26:16 +08:00
function genComponentModel ( el , value , modifiers ) {
const { number , trim } = modifiers || { } ;
const baseValueExpression = '$$v' ;
let valueExpression = baseValueExpression ;
if ( trim ) {
valueExpression =
` (typeof ${ baseValueExpression } === 'string' ` +
` ? ${ baseValueExpression } .trim() ` +
` : ${ baseValueExpression } ) ` ;
}
if ( number ) {
valueExpression = ` _n( ${ valueExpression } ) ` ;
}
const assignment = genAssignmentCode ( value , valueExpression ) ;
el . model = {
value : ` ( ${ value } ) ` ,
expression : JSON . stringify ( value ) ,
callback : ` function ( ${ baseValueExpression } ) { ${ assignment } } `
} ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Cross - platform codegen helper for generating v - model value assignment code .
* /
2024-01-16 21:26:16 +08:00
function genAssignmentCode ( value , assignment ) {
const res = parseModel ( value ) ;
if ( res . key === null ) {
return ` ${ value } = ${ assignment } ` ;
}
else {
return ` $ set( ${ res . exp } , ${ res . key } , ${ assignment } ) ` ;
}
2023-12-18 13:12:25 +08:00
}
/ * *
* Parse a v - model expression into a base path and a final key segment .
* Handles both dot - path and possible square brackets .
*
* Possible cases :
*
* - test
* - test [ key ]
* - test [ test1 [ key ] ]
* - test [ "a" ] [ key ]
* - xxx . test [ a [ a ] . test1 [ key ] ]
* - test . xxx . a [ "asa" ] [ test1 [ key ] ]
*
* /
2024-01-16 21:26:16 +08:00
let len , str , chr , index , expressionPos , expressionEndPos ;
function parseModel ( val ) {
// Fix https://github.com/vuejs/vue/pull/7730
// allow v-model="obj.val " (trailing whitespace)
val = val . trim ( ) ;
len = val . length ;
if ( val . indexOf ( '[' ) < 0 || val . lastIndexOf ( ']' ) < len - 1 ) {
index = val . lastIndexOf ( '.' ) ;
if ( index > - 1 ) {
return {
exp : val . slice ( 0 , index ) ,
key : '"' + val . slice ( index + 1 ) + '"'
} ;
}
else {
return {
exp : val ,
key : null
} ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
str = val ;
index = expressionPos = expressionEndPos = 0 ;
while ( ! eof ( ) ) {
chr = next ( ) ;
/* istanbul ignore if */
if ( isStringStart ( chr ) ) {
parseString ( chr ) ;
}
else if ( chr === 0x5b ) {
parseBracket ( chr ) ;
}
}
return {
exp : val . slice ( 0 , expressionPos ) ,
key : val . slice ( expressionPos + 1 , expressionEndPos )
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function next ( ) {
return str . charCodeAt ( ++ index ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function eof ( ) {
return index >= len ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isStringStart ( chr ) {
return chr === 0x22 || chr === 0x27 ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function parseBracket ( chr ) {
let inBracket = 1 ;
expressionPos = index ;
while ( ! eof ( ) ) {
chr = next ( ) ;
if ( isStringStart ( chr ) ) {
parseString ( chr ) ;
continue ;
}
if ( chr === 0x5b )
inBracket ++ ;
if ( chr === 0x5d )
inBracket -- ;
if ( inBracket === 0 ) {
expressionEndPos = index ;
break ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function parseString ( chr ) {
const stringQuote = chr ;
while ( ! eof ( ) ) {
chr = next ( ) ;
if ( chr === stringQuote ) {
break ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
const onRE = /^@|^v-on:/ ;
const dirRE = /^v-|^@|^:|^#/ ;
const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/ ;
const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/ ;
const stripParensRE = /^\(|\)$/g ;
const dynamicArgRE = /^\[.*\]$/ ;
const argRE = /:(.*)$/ ;
const bindRE = /^:|^\.|^v-bind:/ ;
const modifierRE = /\.[^.\]]+(?=[^\]]*$)/g ;
const slotRE = /^v-slot(:|$)|^#/ ;
const lineBreakRE = /[\r\n]/ ;
const whitespaceRE = /[ \f\t\r\n]+/g ;
const invalidAttributeRE = /[\s"'<>\/=]/ ;
const decodeHTMLCached = cached ( he _ _default [ "default" ] . decode ) ;
const emptySlotScopeToken = ` _empty_ ` ;
2023-12-18 13:12:25 +08:00
// configurable state
2024-01-16 21:26:16 +08:00
let warn$1 ;
let delimiters ;
let transforms ;
let preTransforms ;
let postTransforms ;
let platformIsPreTag ;
let platformMustUseProp ;
let platformGetTagNamespace ;
let maybeComponent ;
function createASTElement ( tag , attrs , parent ) {
return {
type : 1 ,
tag ,
attrsList : attrs ,
attrsMap : makeAttrsMap ( attrs ) ,
rawAttrsMap : { } ,
parent ,
children : [ ]
} ;
2023-12-18 13:12:25 +08:00
}
/ * *
* Convert HTML string to AST .
* /
2024-01-16 21:26:16 +08:00
function parse ( template , options ) {
warn$1 = options . warn || baseWarn ;
platformIsPreTag = options . isPreTag || no ;
platformMustUseProp = options . mustUseProp || no ;
platformGetTagNamespace = options . getTagNamespace || no ;
const isReservedTag = options . isReservedTag || no ;
maybeComponent = ( el ) => ! ! ( el . component ||
el . attrsMap [ ':is' ] ||
el . attrsMap [ 'v-bind:is' ] ||
! ( el . attrsMap . is ? isReservedTag ( el . attrsMap . is ) : isReservedTag ( el . tag ) ) ) ;
transforms = pluckModuleFunction ( options . modules , 'transformNode' ) ;
preTransforms = pluckModuleFunction ( options . modules , 'preTransformNode' ) ;
postTransforms = pluckModuleFunction ( options . modules , 'postTransformNode' ) ;
delimiters = options . delimiters ;
const stack = [ ] ;
const preserveWhitespace = options . preserveWhitespace !== false ;
const whitespaceOption = options . whitespace ;
let root ;
let currentParent ;
let inVPre = false ;
let inPre = false ;
let warned = false ;
function warnOnce ( msg , range ) {
if ( ! warned ) {
warned = true ;
warn$1 ( msg , range ) ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function closeElement ( element ) {
trimEndingWhitespace ( element ) ;
if ( ! inVPre && ! element . processed ) {
element = processElement ( element , options ) ;
}
// tree management
if ( ! stack . length && element !== root ) {
// allow root elements with v-if, v-else-if and v-else
if ( root . if && ( element . elseif || element . else ) ) {
if ( process . env . NODE _ENV !== 'production' ) {
checkRootConstraints ( element ) ;
}
addIfCondition ( root , {
exp : element . elseif ,
block : element
} ) ;
}
else if ( process . env . NODE _ENV !== 'production' ) {
warnOnce ( ` Component template should contain exactly one root element. ` +
` If you are using v-if on multiple elements, ` +
` use v-else-if to chain them instead. ` , { start : element . start } ) ;
}
}
if ( currentParent && ! element . forbidden ) {
if ( element . elseif || element . else ) {
processIfConditions ( element , currentParent ) ;
}
else {
if ( element . slotScope ) {
// scoped slot
// keep it in the children list so that v-else(-if) conditions can
// find it as the prev node.
const name = element . slotTarget || '"default"' ;
( currentParent . scopedSlots || ( currentParent . scopedSlots = { } ) ) [ name ] = element ;
}
currentParent . children . push ( element ) ;
element . parent = currentParent ;
}
}
// final children cleanup
// filter out scoped slots
element . children = element . children . filter ( c => ! c . slotScope ) ;
// remove trailing whitespace node again
trimEndingWhitespace ( element ) ;
// check pre state
if ( element . pre ) {
inVPre = false ;
}
if ( platformIsPreTag ( element . tag ) ) {
inPre = false ;
}
// apply post-transforms
for ( let i = 0 ; i < postTransforms . length ; i ++ ) {
postTransforms [ i ] ( element , options ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function trimEndingWhitespace ( el ) {
// remove trailing whitespace node
if ( ! inPre ) {
let lastNode ;
while ( ( lastNode = el . children [ el . children . length - 1 ] ) &&
lastNode . type === 3 &&
lastNode . text === ' ' ) {
el . children . pop ( ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkRootConstraints ( el ) {
if ( el . tag === 'slot' || el . tag === 'template' ) {
warnOnce ( ` Cannot use < ${ el . tag } > as component root element because it may ` +
'contain multiple nodes.' , { start : el . start } ) ;
}
if ( el . attrsMap . hasOwnProperty ( 'v-for' ) ) {
warnOnce ( 'Cannot use v-for on stateful component root element because ' +
'it renders multiple elements.' , el . rawAttrsMap [ 'v-for' ] ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
parseHTML ( template , {
warn : warn$1 ,
expectHTML : options . expectHTML ,
isUnaryTag : options . isUnaryTag ,
canBeLeftOpenTag : options . canBeLeftOpenTag ,
shouldDecodeNewlines : options . shouldDecodeNewlines ,
shouldDecodeNewlinesForHref : options . shouldDecodeNewlinesForHref ,
shouldKeepComment : options . comments ,
outputSourceRange : options . outputSourceRange ,
start ( tag , attrs , unary , start , end ) {
// check namespace.
// inherit parent ns if there is one
const ns = ( currentParent && currentParent . ns ) || platformGetTagNamespace ( tag ) ;
// handle IE svg bug
/* istanbul ignore if */
if ( isIE && ns === 'svg' ) {
attrs = guardIESVGBug ( attrs ) ;
}
let element = createASTElement ( tag , attrs , currentParent ) ;
if ( ns ) {
element . ns = ns ;
}
if ( process . env . NODE _ENV !== 'production' ) {
if ( options . outputSourceRange ) {
element . start = start ;
element . end = end ;
element . rawAttrsMap = element . attrsList . reduce ( ( cumulated , attr ) => {
cumulated [ attr . name ] = attr ;
return cumulated ;
} , { } ) ;
}
attrs . forEach ( attr => {
if ( invalidAttributeRE . test ( attr . name ) ) {
warn$1 ( ` Invalid dynamic argument expression: attribute names cannot contain ` +
` spaces, quotes, <, >, / or =. ` , options . outputSourceRange
? {
start : attr . start + attr . name . indexOf ( ` [ ` ) ,
end : attr . start + attr . name . length
}
: undefined ) ;
}
} ) ;
}
if ( isForbiddenTag ( element ) && ! isServerRendering ( ) ) {
element . forbidden = true ;
process . env . NODE _ENV !== 'production' &&
warn$1 ( 'Templates should only be responsible for mapping the state to the ' +
'UI. Avoid placing tags with side-effects in your templates, such as ' +
` < ${ tag } > ` +
', as they will not be parsed.' , { start : element . start } ) ;
}
// apply pre-transforms
for ( let i = 0 ; i < preTransforms . length ; i ++ ) {
element = preTransforms [ i ] ( element , options ) || element ;
}
if ( ! inVPre ) {
processPre ( element ) ;
if ( element . pre ) {
inVPre = true ;
}
}
if ( platformIsPreTag ( element . tag ) ) {
inPre = true ;
}
if ( inVPre ) {
processRawAttrs ( element ) ;
}
else if ( ! element . processed ) {
// structural directives
processFor ( element ) ;
processIf ( element ) ;
processOnce ( element ) ;
}
if ( ! root ) {
root = element ;
if ( process . env . NODE _ENV !== 'production' ) {
checkRootConstraints ( root ) ;
}
}
if ( ! unary ) {
currentParent = element ;
stack . push ( element ) ;
}
else {
closeElement ( element ) ;
}
} ,
end ( tag , start , end ) {
const element = stack [ stack . length - 1 ] ;
// pop stack
stack . length -= 1 ;
currentParent = stack [ stack . length - 1 ] ;
if ( process . env . NODE _ENV !== 'production' && options . outputSourceRange ) {
element . end = end ;
}
closeElement ( element ) ;
} ,
chars ( text , start , end ) {
if ( ! currentParent ) {
if ( process . env . NODE _ENV !== 'production' ) {
if ( text === template ) {
warnOnce ( 'Component template requires a root element, rather than just text.' , { start } ) ;
}
else if ( ( text = text . trim ( ) ) ) {
warnOnce ( ` text " ${ text } " outside root element will be ignored. ` , {
start
} ) ;
}
}
return ;
}
// IE textarea placeholder bug
/* istanbul ignore if */
if ( isIE &&
currentParent . tag === 'textarea' &&
currentParent . attrsMap . placeholder === text ) {
return ;
}
const children = currentParent . children ;
if ( inPre || text . trim ( ) ) {
text = isTextTag ( currentParent )
? text
: decodeHTMLCached ( text ) ;
}
else if ( ! children . length ) {
// remove the whitespace-only node right after an opening tag
text = '' ;
}
else if ( whitespaceOption ) {
if ( whitespaceOption === 'condense' ) {
// in condense mode, remove the whitespace node if it contains
// line break, otherwise condense to a single space
text = lineBreakRE . test ( text ) ? '' : ' ' ;
}
else {
text = ' ' ;
}
}
else {
text = preserveWhitespace ? ' ' : '' ;
}
if ( text ) {
if ( ! inPre && whitespaceOption === 'condense' ) {
// condense consecutive whitespaces into single space
text = text . replace ( whitespaceRE , ' ' ) ;
}
let res ;
let child ;
if ( ! inVPre && text !== ' ' && ( res = parseText ( text , delimiters ) ) ) {
child = {
type : 2 ,
expression : res . expression ,
tokens : res . tokens ,
text
} ;
}
else if ( text !== ' ' ||
! children . length ||
children [ children . length - 1 ] . text !== ' ' ) {
child = {
type : 3 ,
text
} ;
}
if ( child ) {
if ( process . env . NODE _ENV !== 'production' && options . outputSourceRange ) {
child . start = start ;
child . end = end ;
}
children . push ( child ) ;
}
}
} ,
comment ( text , start , end ) {
// adding anything as a sibling to the root node is forbidden
// comments should still be allowed, but ignored
if ( currentParent ) {
const child = {
type : 3 ,
text ,
isComment : true
} ;
if ( process . env . NODE _ENV !== 'production' && options . outputSourceRange ) {
child . start = start ;
child . end = end ;
}
currentParent . children . push ( child ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
} ) ;
return root ;
}
function processPre ( el ) {
if ( getAndRemoveAttr ( el , 'v-pre' ) != null ) {
el . pre = true ;
}
}
function processRawAttrs ( el ) {
const list = el . attrsList ;
const len = list . length ;
if ( len ) {
const attrs = ( el . attrs = new Array ( len ) ) ;
for ( let i = 0 ; i < len ; i ++ ) {
attrs [ i ] = {
name : list [ i ] . name ,
value : JSON . stringify ( list [ i ] . value )
} ;
if ( list [ i ] . start != null ) {
attrs [ i ] . start = list [ i ] . start ;
attrs [ i ] . end = list [ i ] . end ;
}
}
}
else if ( ! el . pre ) {
// non root node in pre blocks with no attributes
el . plain = true ;
}
}
function processElement ( element , options ) {
processKey ( element ) ;
// determine whether this is a plain element after
// removing structural attributes
element . plain =
! element . key && ! element . scopedSlots && ! element . attrsList . length ;
processRef ( element ) ;
processSlotContent ( element ) ;
processSlotOutlet ( element ) ;
processComponent ( element ) ;
for ( let i = 0 ; i < transforms . length ; i ++ ) {
element = transforms [ i ] ( element , options ) || element ;
}
processAttrs ( element ) ;
return element ;
}
function processKey ( el ) {
const exp = getBindingAttr ( el , 'key' ) ;
if ( exp ) {
2023-12-18 13:12:25 +08:00
if ( process . env . NODE _ENV !== 'production' ) {
2024-01-16 21:26:16 +08:00
if ( el . tag === 'template' ) {
warn$1 ( ` <template> cannot be keyed. Place the key on real elements instead. ` , getRawBindingAttr ( el , 'key' ) ) ;
}
if ( el . for ) {
const iterator = el . iterator2 || el . iterator1 ;
const parent = el . parent ;
if ( iterator &&
iterator === exp &&
parent &&
parent . tag === 'transition-group' ) {
warn$1 ( ` Do not use v-for index as key on <transition-group> children, ` +
` this is the same as not using keys. ` , getRawBindingAttr ( el , 'key' ) , true /* tip */ ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
el . key = exp ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function processRef ( el ) {
const ref = getBindingAttr ( el , 'ref' ) ;
if ( ref ) {
el . ref = ref ;
el . refInFor = checkInFor ( el ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function processFor ( el ) {
let exp ;
if ( ( exp = getAndRemoveAttr ( el , 'v-for' ) ) ) {
const res = parseFor ( exp ) ;
if ( res ) {
extend ( el , res ) ;
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$1 ( ` Invalid v-for expression: ${ exp } ` , el . rawAttrsMap [ 'v-for' ] ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function parseFor ( exp ) {
const inMatch = exp . match ( forAliasRE ) ;
if ( ! inMatch )
return ;
const res = { } ;
res . for = inMatch [ 2 ] . trim ( ) ;
const alias = inMatch [ 1 ] . trim ( ) . replace ( stripParensRE , '' ) ;
const iteratorMatch = alias . match ( forIteratorRE ) ;
if ( iteratorMatch ) {
res . alias = alias . replace ( forIteratorRE , '' ) . trim ( ) ;
res . iterator1 = iteratorMatch [ 1 ] . trim ( ) ;
if ( iteratorMatch [ 2 ] ) {
res . iterator2 = iteratorMatch [ 2 ] . trim ( ) ;
}
}
else {
res . alias = alias ;
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function processIf ( el ) {
const exp = getAndRemoveAttr ( el , 'v-if' ) ;
if ( exp ) {
el . if = exp ;
addIfCondition ( el , {
exp : exp ,
block : el
} ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
if ( getAndRemoveAttr ( el , 'v-else' ) != null ) {
el . else = true ;
}
const elseif = getAndRemoveAttr ( el , 'v-else-if' ) ;
if ( elseif ) {
el . elseif = elseif ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function processIfConditions ( el , parent ) {
const prev = findPrevElement ( parent . children ) ;
if ( prev && prev . if ) {
addIfCondition ( prev , {
exp : el . elseif ,
block : el
} ) ;
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$1 ( ` v- ${ el . elseif ? 'else-if="' + el . elseif + '"' : 'else' } ` +
` used on element < ${ el . tag } > without corresponding v-if. ` , el . rawAttrsMap [ el . elseif ? 'v-else-if' : 'v-else' ] ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function findPrevElement ( children ) {
let i = children . length ;
while ( i -- ) {
if ( children [ i ] . type === 1 ) {
return children [ i ] ;
}
else {
if ( process . env . NODE _ENV !== 'production' && children [ i ] . text !== ' ' ) {
warn$1 ( ` text " ${ children [ i ] . text . trim ( ) } " between v-if and v-else(-if) ` +
` will be ignored. ` , children [ i ] ) ;
}
children . pop ( ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function addIfCondition ( el , condition ) {
if ( ! el . ifConditions ) {
el . ifConditions = [ ] ;
}
el . ifConditions . push ( condition ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function processOnce ( el ) {
const once = getAndRemoveAttr ( el , 'v-once' ) ;
if ( once != null ) {
el . once = true ;
}
2023-12-18 13:12:25 +08:00
}
// handle content being passed to a component as slot,
// e.g. <template slot="xxx">, <div slot-scope="xxx">
2024-01-16 21:26:16 +08:00
function processSlotContent ( el ) {
let slotScope ;
2023-12-18 13:12:25 +08:00
if ( el . tag === 'template' ) {
2024-01-16 21:26:16 +08:00
slotScope = getAndRemoveAttr ( el , 'scope' ) ;
/* istanbul ignore if */
if ( process . env . NODE _ENV !== 'production' && slotScope ) {
warn$1 ( ` the "scope" attribute for scoped slots have been deprecated and ` +
` replaced by "slot-scope" since 2.5. The new "slot-scope" attribute ` +
` can also be used on plain elements in addition to <template> to ` +
` denote scoped slots. ` , el . rawAttrsMap [ 'scope' ] , true ) ;
}
el . slotScope = slotScope || getAndRemoveAttr ( el , 'slot-scope' ) ;
}
else if ( ( slotScope = getAndRemoveAttr ( el , 'slot-scope' ) ) ) {
/* istanbul ignore if */
if ( process . env . NODE _ENV !== 'production' && el . attrsMap [ 'v-for' ] ) {
warn$1 ( ` Ambiguous combined usage of slot-scope and v-for on < ${ el . tag } > ` +
` (v-for takes higher priority). Use a wrapper <template> for the ` +
` scoped slot to make it clearer. ` , el . rawAttrsMap [ 'slot-scope' ] , true ) ;
}
el . slotScope = slotScope ;
}
// slot="xxx"
const slotTarget = getBindingAttr ( el , 'slot' ) ;
if ( slotTarget ) {
el . slotTarget = slotTarget === '""' ? '"default"' : slotTarget ;
el . slotTargetDynamic = ! ! ( el . attrsMap [ ':slot' ] || el . attrsMap [ 'v-bind:slot' ] ) ;
// preserve slot as an attribute for native shadow DOM compat
// only for non-scoped slots.
if ( el . tag !== 'template' && ! el . slotScope ) {
addAttr ( el , 'slot' , slotTarget , getRawBindingAttr ( el , 'slot' ) ) ;
}
}
// 2.6 v-slot syntax
{
if ( el . tag === 'template' ) {
// v-slot on <template>
const slotBinding = getAndRemoveAttrByRegex ( el , slotRE ) ;
if ( slotBinding ) {
if ( process . env . NODE _ENV !== 'production' ) {
if ( el . slotTarget || el . slotScope ) {
warn$1 ( ` Unexpected mixed usage of different slot syntaxes. ` , el ) ;
}
if ( el . parent && ! maybeComponent ( el . parent ) ) {
warn$1 ( ` <template v-slot> can only appear at the root level inside ` +
` the receiving component ` , el ) ;
}
}
const { name , dynamic } = getSlotName ( slotBinding ) ;
el . slotTarget = name ;
el . slotTargetDynamic = dynamic ;
el . slotScope = slotBinding . value || emptySlotScopeToken ; // force it into a scoped slot for perf
}
}
else {
// v-slot on component, denotes default slot
const slotBinding = getAndRemoveAttrByRegex ( el , slotRE ) ;
if ( slotBinding ) {
if ( process . env . NODE _ENV !== 'production' ) {
if ( ! maybeComponent ( el ) ) {
warn$1 ( ` v-slot can only be used on components or <template>. ` , slotBinding ) ;
}
if ( el . slotScope || el . slotTarget ) {
warn$1 ( ` Unexpected mixed usage of different slot syntaxes. ` , el ) ;
}
if ( el . scopedSlots ) {
warn$1 ( ` To avoid scope ambiguity, the default slot should also use ` +
` <template> syntax when there are other named slots. ` , slotBinding ) ;
}
}
// add the component's children to its default slot
const slots = el . scopedSlots || ( el . scopedSlots = { } ) ;
const { name , dynamic } = getSlotName ( slotBinding ) ;
const slotContainer = ( slots [ name ] = createASTElement ( 'template' , [ ] , el ) ) ;
slotContainer . slotTarget = name ;
slotContainer . slotTargetDynamic = dynamic ;
slotContainer . children = el . children . filter ( ( c ) => {
if ( ! c . slotScope ) {
c . parent = slotContainer ;
return true ;
}
} ) ;
slotContainer . slotScope = slotBinding . value || emptySlotScopeToken ;
// remove children as they are returned from scopedSlots now
el . children = [ ] ;
// mark el non-plain so data gets generated
el . plain = false ;
}
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function getSlotName ( binding ) {
let name = binding . name . replace ( slotRE , '' ) ;
if ( ! name ) {
if ( binding . name [ 0 ] !== '#' ) {
name = 'default' ;
}
else if ( process . env . NODE _ENV !== 'production' ) {
warn$1 ( ` v-slot shorthand syntax requires a slot name. ` , binding ) ;
}
}
return dynamicArgRE . test ( name )
? // dynamic [name]
{ name : name . slice ( 1 , - 1 ) , dynamic : true }
: // static name
{ name : ` " ${ name } " ` , dynamic : false } ;
2023-12-18 13:12:25 +08:00
}
// handle <slot/> outlets
2024-01-16 21:26:16 +08:00
function processSlotOutlet ( el ) {
if ( el . tag === 'slot' ) {
el . slotName = getBindingAttr ( el , 'name' ) ;
if ( process . env . NODE _ENV !== 'production' && el . key ) {
warn$1 ( ` \` key \` does not work on <slot> because slots are abstract outlets ` +
` and can possibly expand into multiple elements. ` +
` Use the key on a wrapping element instead. ` , getRawBindingAttr ( el , 'key' ) ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function processComponent ( el ) {
let binding ;
if ( ( binding = getBindingAttr ( el , 'is' ) ) ) {
el . component = binding ;
}
if ( getAndRemoveAttr ( el , 'inline-template' ) != null ) {
el . inlineTemplate = true ;
}
}
function processAttrs ( el ) {
const list = el . attrsList ;
let i , l , name , rawName , value , modifiers , syncGen , isDynamic ;
for ( i = 0 , l = list . length ; i < l ; i ++ ) {
name = rawName = list [ i ] . name ;
value = list [ i ] . value ;
if ( dirRE . test ( name ) ) {
// mark element as dynamic
el . hasBindings = true ;
// modifiers
modifiers = parseModifiers ( name . replace ( dirRE , '' ) ) ;
// support .foo shorthand syntax for the .prop modifier
if ( modifiers ) {
name = name . replace ( modifierRE , '' ) ;
}
if ( bindRE . test ( name ) ) {
// v-bind
name = name . replace ( bindRE , '' ) ;
value = parseFilters ( value ) ;
isDynamic = dynamicArgRE . test ( name ) ;
if ( isDynamic ) {
name = name . slice ( 1 , - 1 ) ;
}
if ( process . env . NODE _ENV !== 'production' && value . trim ( ) . length === 0 ) {
warn$1 ( ` The value for a v-bind expression cannot be empty. Found in "v-bind: ${ name } " ` ) ;
}
if ( modifiers ) {
if ( modifiers . prop && ! isDynamic ) {
name = camelize ( name ) ;
if ( name === 'innerHtml' )
name = 'innerHTML' ;
}
if ( modifiers . camel && ! isDynamic ) {
name = camelize ( name ) ;
}
if ( modifiers . sync ) {
syncGen = genAssignmentCode ( value , ` $ event ` ) ;
if ( ! isDynamic ) {
addHandler ( el , ` update: ${ camelize ( name ) } ` , syncGen , null , false , warn$1 , list [ i ] ) ;
if ( hyphenate ( name ) !== camelize ( name ) ) {
addHandler ( el , ` update: ${ hyphenate ( name ) } ` , syncGen , null , false , warn$1 , list [ i ] ) ;
}
}
else {
// handler w/ dynamic event name
addHandler ( el , ` "update:"+( ${ name } ) ` , syncGen , null , false , warn$1 , list [ i ] , true // dynamic
) ;
}
}
}
if ( ( modifiers && modifiers . prop ) ||
( ! el . component && platformMustUseProp ( el . tag , el . attrsMap . type , name ) ) ) {
addProp ( el , name , value , list [ i ] , isDynamic ) ;
}
else {
addAttr ( el , name , value , list [ i ] , isDynamic ) ;
}
}
else if ( onRE . test ( name ) ) {
// v-on
name = name . replace ( onRE , '' ) ;
isDynamic = dynamicArgRE . test ( name ) ;
if ( isDynamic ) {
name = name . slice ( 1 , - 1 ) ;
}
addHandler ( el , name , value , modifiers , false , warn$1 , list [ i ] , isDynamic ) ;
}
else {
// normal directives
name = name . replace ( dirRE , '' ) ;
// parse arg
const argMatch = name . match ( argRE ) ;
let arg = argMatch && argMatch [ 1 ] ;
isDynamic = false ;
if ( arg ) {
name = name . slice ( 0 , - ( arg . length + 1 ) ) ;
if ( dynamicArgRE . test ( arg ) ) {
arg = arg . slice ( 1 , - 1 ) ;
isDynamic = true ;
}
}
addDirective ( el , name , rawName , value , arg , isDynamic , modifiers , list [ i ] ) ;
if ( process . env . NODE _ENV !== 'production' && name === 'model' ) {
checkForAliasModel ( el , value ) ;
}
}
}
else {
// literal attribute
if ( process . env . NODE _ENV !== 'production' ) {
const res = parseText ( value , delimiters ) ;
if ( res ) {
warn$1 ( ` ${ name } =" ${ value } ": ` +
'Interpolation inside attributes has been removed. ' +
'Use v-bind or the colon shorthand instead. For example, ' +
'instead of <div id="{{ val }}">, use <div :id="val">.' , list [ i ] ) ;
}
}
addAttr ( el , name , JSON . stringify ( value ) , list [ i ] ) ;
// #6887 firefox doesn't update muted state if set via attribute
// even immediately after element creation
if ( ! el . component &&
name === 'muted' &&
platformMustUseProp ( el . tag , el . attrsMap . type , name ) ) {
addProp ( el , name , 'true' , list [ i ] ) ;
}
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkInFor ( el ) {
let parent = el ;
while ( parent ) {
if ( parent . for !== undefined ) {
return true ;
}
parent = parent . parent ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return false ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function parseModifiers ( name ) {
const match = name . match ( modifierRE ) ;
if ( match ) {
const ret = { } ;
match . forEach ( m => {
ret [ m . slice ( 1 ) ] = true ;
} ) ;
return ret ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function makeAttrsMap ( attrs ) {
const map = { } ;
for ( let i = 0 , l = attrs . length ; i < l ; i ++ ) {
if ( process . env . NODE _ENV !== 'production' && map [ attrs [ i ] . name ] && ! isIE && ! isEdge ) {
warn$1 ( 'duplicate attribute: ' + attrs [ i ] . name , attrs [ i ] ) ;
}
map [ attrs [ i ] . name ] = attrs [ i ] . value ;
}
return map ;
2023-12-18 13:12:25 +08:00
}
// for script (e.g. type="x/template") or style, do not decode content
2024-01-16 21:26:16 +08:00
function isTextTag ( el ) {
return el . tag === 'script' || el . tag === 'style' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isForbiddenTag ( el ) {
return ( el . tag === 'style' ||
( el . tag === 'script' &&
( ! el . attrsMap . type || el . attrsMap . type === 'text/javascript' ) ) ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const ieNSBug = /^xmlns:NS\d+/ ;
const ieNSPrefix = /^NS\d+:/ ;
2023-12-18 13:12:25 +08:00
/* istanbul ignore next */
2024-01-16 21:26:16 +08:00
function guardIESVGBug ( attrs ) {
const res = [ ] ;
for ( let i = 0 ; i < attrs . length ; i ++ ) {
const attr = attrs [ i ] ;
if ( ! ieNSBug . test ( attr . name ) ) {
attr . name = attr . name . replace ( ieNSPrefix , '' ) ;
res . push ( attr ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return res ;
}
function checkForAliasModel ( el , value ) {
let _el = el ;
while ( _el ) {
if ( _el . for && _el . alias === value ) {
warn$1 ( ` < ${ el . tag } v-model=" ${ value } ">: ` +
` You are binding v-model directly to a v-for iteration alias. ` +
` This will not be able to modify the v-for source array because ` +
` writing to the alias is like modifying a function local variable. ` +
` Consider using an array of objects and use v-model on an object property instead. ` , el . rawAttrsMap [ 'v-model' ] ) ;
}
_el = _el . parent ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
}
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
/ * *
* Expand input [ v - model ] with dynamic type bindings into v - if - else chains
* Turn this :
* < input v - model = "data[type]" : type = "type" >
* into this :
* < input v - if = "type === 'checkbox'" type = "checkbox" v - model = "data[type]" >
* < input v - else - if = "type === 'radio'" type = "radio" v - model = "data[type]" >
* < input v - else : type = "type" v - model = "data[type]" >
* /
function preTransformNode ( el , options ) {
if ( el . tag === 'input' ) {
const map = el . attrsMap ;
if ( ! map [ 'v-model' ] ) {
return ;
}
let typeBinding ;
if ( map [ ':type' ] || map [ 'v-bind:type' ] ) {
typeBinding = getBindingAttr ( el , 'type' ) ;
}
if ( ! map . type && ! typeBinding && map [ 'v-bind' ] ) {
typeBinding = ` ( ${ map [ 'v-bind' ] } ).type ` ;
}
if ( typeBinding ) {
const ifCondition = getAndRemoveAttr ( el , 'v-if' , true ) ;
const ifConditionExtra = ifCondition ? ` &&( ${ ifCondition } ) ` : ` ` ;
const hasElse = getAndRemoveAttr ( el , 'v-else' , true ) != null ;
const elseIfCondition = getAndRemoveAttr ( el , 'v-else-if' , true ) ;
// 1. checkbox
const branch0 = cloneASTElement ( el ) ;
// process for on the main node
processFor ( branch0 ) ;
addRawAttr ( branch0 , 'type' , 'checkbox' ) ;
processElement ( branch0 , options ) ;
branch0 . processed = true ; // prevent it from double-processed
branch0 . if = ` ( ${ typeBinding } )==='checkbox' ` + ifConditionExtra ;
addIfCondition ( branch0 , {
exp : branch0 . if ,
block : branch0
} ) ;
// 2. add radio else-if condition
const branch1 = cloneASTElement ( el ) ;
getAndRemoveAttr ( branch1 , 'v-for' , true ) ;
addRawAttr ( branch1 , 'type' , 'radio' ) ;
processElement ( branch1 , options ) ;
addIfCondition ( branch0 , {
exp : ` ( ${ typeBinding } )==='radio' ` + ifConditionExtra ,
block : branch1
} ) ;
// 3. other
const branch2 = cloneASTElement ( el ) ;
getAndRemoveAttr ( branch2 , 'v-for' , true ) ;
addRawAttr ( branch2 , ':type' , typeBinding ) ;
processElement ( branch2 , options ) ;
addIfCondition ( branch0 , {
exp : ifCondition ,
block : branch2
} ) ;
if ( hasElse ) {
branch0 . else = true ;
}
else if ( elseIfCondition ) {
branch0 . elseif = elseIfCondition ;
}
return branch0 ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function cloneASTElement ( el ) {
return createASTElement ( el . tag , el . attrsList . slice ( ) , el . parent ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
var model$1 = {
preTransformNode
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
var modules = [ klass , style , model$1 ] ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
let warn ;
2023-12-18 13:12:25 +08:00
// in some cases, the event used has to be determined at runtime
// so we used some reserved tokens during compile.
2024-01-16 21:26:16 +08:00
const RANGE _TOKEN = '__r' ;
function model ( el , dir , _warn ) {
warn = _warn ;
const value = dir . value ;
const modifiers = dir . modifiers ;
const tag = el . tag ;
const type = el . attrsMap . type ;
if ( process . env . NODE _ENV !== 'production' ) {
// inputs with type="file" are read only and setting the input's
// value will throw an error.
if ( tag === 'input' && type === 'file' ) {
warn ( ` < ${ el . tag } v-model=" ${ value } " type="file">: \n ` +
` File inputs are read only. Use a v-on:change listener instead. ` , el . rawAttrsMap [ 'v-model' ] ) ;
}
}
if ( el . component ) {
genComponentModel ( el , value , modifiers ) ;
// component v-model doesn't need extra runtime
return false ;
}
else if ( tag === 'select' ) {
genSelect ( el , value , modifiers ) ;
}
else if ( tag === 'input' && type === 'checkbox' ) {
genCheckboxModel ( el , value , modifiers ) ;
}
else if ( tag === 'input' && type === 'radio' ) {
genRadioModel ( el , value , modifiers ) ;
}
else if ( tag === 'input' || tag === 'textarea' ) {
genDefaultModel ( el , value , modifiers ) ;
}
else {
genComponentModel ( el , value , modifiers ) ;
// component v-model doesn't need extra runtime
return false ;
}
// ensure runtime directive metadata
return true ;
}
function genCheckboxModel ( el , value , modifiers ) {
const number = modifiers && modifiers . number ;
const valueBinding = getBindingAttr ( el , 'value' ) || 'null' ;
const trueValueBinding = getBindingAttr ( el , 'true-value' ) || 'true' ;
const falseValueBinding = getBindingAttr ( el , 'false-value' ) || 'false' ;
addProp ( el , 'checked' , ` Array.isArray( ${ value } ) ` +
` ?_i( ${ value } , ${ valueBinding } )>-1 ` +
( trueValueBinding === 'true'
? ` :( ${ value } ) `
: ` :_q( ${ value } , ${ trueValueBinding } ) ` ) ) ;
addHandler ( el , 'change' , ` var $ $ a= ${ value } , ` +
2023-12-18 13:12:25 +08:00
'$$el=$event.target,' +
2024-01-16 21:26:16 +08:00
` $ $ c= $ $ el.checked?( ${ trueValueBinding } ):( ${ falseValueBinding } ); ` +
'if(Array.isArray($$a)){' +
` var $ $ v= ${ number ? '_n(' + valueBinding + ')' : valueBinding } , ` +
'$$i=_i($$a,$$v);' +
` if( $ $ el.checked){ $ $ i<0&&( ${ genAssignmentCode ( value , '$$a.concat([$$v])' ) } )} ` +
` else{ $ $ i>-1&&( ${ genAssignmentCode ( value , '$$a.slice(0,$$i).concat($$a.slice($$i+1))' ) } )} ` +
` }else{ ${ genAssignmentCode ( value , '$$c' ) } } ` , null , true ) ;
}
function genRadioModel ( el , value , modifiers ) {
const number = modifiers && modifiers . number ;
let valueBinding = getBindingAttr ( el , 'value' ) || 'null' ;
valueBinding = number ? ` _n( ${ valueBinding } ) ` : valueBinding ;
addProp ( el , 'checked' , ` _q( ${ value } , ${ valueBinding } ) ` ) ;
addHandler ( el , 'change' , genAssignmentCode ( value , valueBinding ) , null , true ) ;
}
function genSelect ( el , value , modifiers ) {
const number = modifiers && modifiers . number ;
const selectedVal = ` Array.prototype.filter ` +
` .call( $ event.target.options,function(o){return o.selected}) ` +
` .map(function(o){var val = "_value" in o ? o._value : o.value; ` +
` return ${ number ? '_n(val)' : 'val' } }) ` ;
const assignment = '$event.target.multiple ? $$selectedVal : $$selectedVal[0]' ;
let code = ` var $ $ selectedVal = ${ selectedVal } ; ` ;
code = ` ${ code } ${ genAssignmentCode ( value , assignment ) } ` ;
addHandler ( el , 'change' , code , null , true ) ;
}
function genDefaultModel ( el , value , modifiers ) {
const type = el . attrsMap . type ;
// warn if v-bind:value conflicts with v-model
// except for inputs with v-bind:type
if ( process . env . NODE _ENV !== 'production' ) {
const value = el . attrsMap [ 'v-bind:value' ] || el . attrsMap [ ':value' ] ;
const typeBinding = el . attrsMap [ 'v-bind:type' ] || el . attrsMap [ ':type' ] ;
if ( value && ! typeBinding ) {
const binding = el . attrsMap [ 'v-bind:value' ] ? 'v-bind:value' : ':value' ;
warn ( ` ${ binding } =" ${ value } " conflicts with v-model on the same element ` +
'because the latter already expands to a value binding internally' , el . rawAttrsMap [ binding ] ) ;
}
}
const { lazy , number , trim } = modifiers || { } ;
const needCompositionGuard = ! lazy && type !== 'range' ;
const event = lazy ? 'change' : type === 'range' ? RANGE _TOKEN : 'input' ;
let valueExpression = '$event.target.value' ;
if ( trim ) {
valueExpression = ` $ event.target.value.trim() ` ;
}
if ( number ) {
valueExpression = ` _n( ${ valueExpression } ) ` ;
}
let code = genAssignmentCode ( value , valueExpression ) ;
if ( needCompositionGuard ) {
code = ` if( $ event.target.composing)return; ${ code } ` ;
}
addProp ( el , 'value' , ` ( ${ value } ) ` ) ;
addHandler ( el , event , code , null , true ) ;
if ( trim || number ) {
addHandler ( el , 'blur' , '$forceUpdate()' ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function text ( el , dir ) {
if ( dir . value ) {
addProp ( el , 'textContent' , ` _s( ${ dir . value } ) ` , dir ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function html ( el , dir ) {
if ( dir . value ) {
addProp ( el , 'innerHTML' , ` _s( ${ dir . value } ) ` , dir ) ;
}
2023-12-18 13:12:25 +08:00
}
var directives = {
2024-01-16 21:26:16 +08:00
model ,
text ,
html
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const baseOptions = {
expectHTML : true ,
modules ,
directives ,
isPreTag ,
isUnaryTag ,
mustUseProp ,
canBeLeftOpenTag ,
isReservedTag ,
getTagNamespace ,
staticKeys : genStaticKeys$1 ( modules )
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
let isStaticKey ;
let isPlatformReservedTag$1 ;
const genStaticKeysCached = cached ( genStaticKeys ) ;
2023-12-18 13:12:25 +08:00
/ * *
* Goal of the optimizer : walk the generated template AST tree
* and detect sub - trees that are purely static , i . e . parts of
* the DOM that never needs to change .
*
* Once we detect these sub - trees , we can :
*
* 1. Hoist them into constants , so that we no longer need to
* create fresh nodes for them on each re - render ;
* 2. Completely skip them in the patching process .
* /
2024-01-16 21:26:16 +08:00
function optimize$1 ( root , options ) {
if ( ! root )
return ;
isStaticKey = genStaticKeysCached ( options . staticKeys || '' ) ;
isPlatformReservedTag$1 = options . isReservedTag || no ;
// first pass: mark all non-static nodes.
markStatic ( root ) ;
// second pass: mark static roots.
markStaticRoots ( root , false ) ;
}
function genStaticKeys ( keys ) {
return makeMap ( 'type,tag,attrsList,attrsMap,plain,parent,children,attrs,start,end,rawAttrsMap' +
( keys ? ',' + keys : '' ) ) ;
}
function markStatic ( node ) {
node . static = isStatic ( node ) ;
if ( node . type === 1 ) {
// do not make component slot content static. this avoids
// 1. components not able to mutate slot nodes
// 2. static slot content fails for hot-reloading
if ( ! isPlatformReservedTag$1 ( node . tag ) &&
node . tag !== 'slot' &&
node . attrsMap [ 'inline-template' ] == null ) {
return ;
}
for ( let i = 0 , l = node . children . length ; i < l ; i ++ ) {
const child = node . children [ i ] ;
markStatic ( child ) ;
if ( ! child . static ) {
node . static = false ;
}
}
if ( node . ifConditions ) {
for ( let i = 1 , l = node . ifConditions . length ; i < l ; i ++ ) {
const block = node . ifConditions [ i ] . block ;
markStatic ( block ) ;
if ( ! block . static ) {
node . static = false ;
}
}
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function markStaticRoots ( node , isInFor ) {
if ( node . type === 1 ) {
if ( node . static || node . once ) {
node . staticInFor = isInFor ;
}
// For a node to qualify as a static root, it should have children that
// are not just static text. Otherwise the cost of hoisting out will
// outweigh the benefits and it's better off to just always render it fresh.
if ( node . static &&
node . children . length &&
! ( node . children . length === 1 && node . children [ 0 ] . type === 3 ) ) {
node . staticRoot = true ;
return ;
}
else {
node . staticRoot = false ;
}
if ( node . children ) {
for ( let i = 0 , l = node . children . length ; i < l ; i ++ ) {
markStaticRoots ( node . children [ i ] , isInFor || ! ! node . for ) ;
}
}
if ( node . ifConditions ) {
for ( let i = 1 , l = node . ifConditions . length ; i < l ; i ++ ) {
markStaticRoots ( node . ifConditions [ i ] . block , isInFor ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
}
function isStatic ( node ) {
if ( node . type === 2 ) {
// expression
return false ;
}
if ( node . type === 3 ) {
// text
return true ;
}
return ! ! ( node . pre ||
( ! node . hasBindings && // no dynamic bindings
! node . if &&
! node . for && // not v-if or v-for or v-else
! isBuiltInTag ( node . tag ) && // not a built-in
isPlatformReservedTag$1 ( node . tag ) && // not a component
! isDirectChildOfTemplateFor ( node ) &&
Object . keys ( node ) . every ( isStaticKey ) ) ) ;
}
function isDirectChildOfTemplateFor ( node ) {
while ( node . parent ) {
node = node . parent ;
if ( node . tag !== 'template' ) {
return false ;
}
if ( node . for ) {
return true ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return false ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function(?:\s+[\w$]+)?\s*\(/ ;
const fnInvokeRE = /\([^)]*?\);*$/ ;
const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/ ;
2023-12-18 13:12:25 +08:00
// KeyboardEvent.keyCode aliases
2024-01-16 21:26:16 +08:00
const keyCodes = {
esc : 27 ,
tab : 9 ,
enter : 13 ,
space : 32 ,
up : 38 ,
left : 37 ,
right : 39 ,
down : 40 ,
delete : [ 8 , 46 ]
2023-12-18 13:12:25 +08:00
} ;
// KeyboardEvent.key aliases
2024-01-16 21:26:16 +08:00
const keyNames = {
// #7880: IE11 and Edge use `Esc` for Escape key name.
esc : [ 'Esc' , 'Escape' ] ,
tab : 'Tab' ,
enter : 'Enter' ,
// #9112: IE11 uses `Spacebar` for Space key name.
space : [ ' ' , 'Spacebar' ] ,
// #7806: IE11 uses key names without `Arrow` prefix for arrow keys.
up : [ 'Up' , 'ArrowUp' ] ,
left : [ 'Left' , 'ArrowLeft' ] ,
right : [ 'Right' , 'ArrowRight' ] ,
down : [ 'Down' , 'ArrowDown' ] ,
// #9112: IE11 uses `Del` for Delete key name.
delete : [ 'Backspace' , 'Delete' , 'Del' ]
2023-12-18 13:12:25 +08:00
} ;
// #4868: modifiers that prevent the execution of the listener
// need to explicitly return null so that we can determine whether to remove
// the listener for .once
2024-01-16 21:26:16 +08:00
const genGuard = condition => ` if( ${ condition } )return null; ` ;
const modifierCode = {
stop : '$event.stopPropagation();' ,
prevent : '$event.preventDefault();' ,
self : genGuard ( ` $ event.target !== $ event.currentTarget ` ) ,
ctrl : genGuard ( ` ! $ event.ctrlKey ` ) ,
shift : genGuard ( ` ! $ event.shiftKey ` ) ,
alt : genGuard ( ` ! $ event.altKey ` ) ,
meta : genGuard ( ` ! $ event.metaKey ` ) ,
left : genGuard ( ` 'button' in $ event && $ event.button !== 0 ` ) ,
middle : genGuard ( ` 'button' in $ event && $ event.button !== 1 ` ) ,
right : genGuard ( ` 'button' in $ event && $ event.button !== 2 ` )
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function genHandlers ( events , isNative ) {
const prefix = isNative ? 'nativeOn:' : 'on:' ;
let staticHandlers = ` ` ;
let dynamicHandlers = ` ` ;
for ( const name in events ) {
const handlerCode = genHandler ( events [ name ] ) ;
//@ts-expect-error
if ( events [ name ] && events [ name ] . dynamic ) {
dynamicHandlers += ` ${ name } , ${ handlerCode } , ` ;
}
else {
staticHandlers += ` " ${ name } ": ${ handlerCode } , ` ;
}
}
staticHandlers = ` { ${ staticHandlers . slice ( 0 , - 1 ) } } ` ;
if ( dynamicHandlers ) {
return prefix + ` _d( ${ staticHandlers } ,[ ${ dynamicHandlers . slice ( 0 , - 1 ) } ]) ` ;
}
else {
return prefix + staticHandlers ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genHandler ( handler ) {
if ( ! handler ) {
return 'function(){}' ;
}
if ( Array . isArray ( handler ) ) {
return ` [ ${ handler . map ( handler => genHandler ( handler ) ) . join ( ',' ) } ] ` ;
}
const isMethodPath = simplePathRE . test ( handler . value ) ;
const isFunctionExpression = fnExpRE . test ( handler . value ) ;
const isFunctionInvocation = simplePathRE . test ( handler . value . replace ( fnInvokeRE , '' ) ) ;
if ( ! handler . modifiers ) {
if ( isMethodPath || isFunctionExpression ) {
return handler . value ;
}
return ` function( $ event){ ${ isFunctionInvocation ? ` return ${ handler . value } ` : handler . value } } ` ; // inline statement
}
else {
let code = '' ;
let genModifierCode = '' ;
const keys = [ ] ;
for ( const key in handler . modifiers ) {
if ( modifierCode [ key ] ) {
genModifierCode += modifierCode [ key ] ;
// left/right
if ( keyCodes [ key ] ) {
keys . push ( key ) ;
}
}
else if ( key === 'exact' ) {
const modifiers = handler . modifiers ;
genModifierCode += genGuard ( [ 'ctrl' , 'shift' , 'alt' , 'meta' ]
. filter ( keyModifier => ! modifiers [ keyModifier ] )
. map ( keyModifier => ` $ event. ${ keyModifier } Key ` )
. join ( '||' ) ) ;
}
else {
keys . push ( key ) ;
}
}
if ( keys . length ) {
code += genKeyFilter ( keys ) ;
}
// Make sure modifiers like prevent and stop get executed after key filtering
if ( genModifierCode ) {
code += genModifierCode ;
}
const handlerCode = isMethodPath
? ` return ${ handler . value } .apply(null, arguments) `
: isFunctionExpression
? ` return ( ${ handler . value } ).apply(null, arguments) `
: isFunctionInvocation
? ` return ${ handler . value } `
: handler . value ;
return ` function( $ event){ ${ code } ${ handlerCode } } ` ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genKeyFilter ( keys ) {
return (
2023-12-18 13:12:25 +08:00
// make sure the key filters only apply to KeyboardEvents
// #9441: can't use 'keyCode' in $event because Chrome autofill fires fake
// key events that do not have keyCode property...
2024-01-16 21:26:16 +08:00
` if(! $ event.type.indexOf('key')&& ` +
` ${ keys . map ( genFilterCode ) . join ( '&&' ) } )return null; ` ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genFilterCode ( key ) {
const keyVal = parseInt ( key , 10 ) ;
if ( keyVal ) {
return ` $ event.keyCode!== ${ keyVal } ` ;
}
const keyCode = keyCodes [ key ] ;
const keyName = keyNames [ key ] ;
return ( ` _k( $ event.keyCode, ` +
` ${ JSON . stringify ( key ) } , ` +
` ${ JSON . stringify ( keyCode ) } , ` +
` $ event.key, ` +
` ${ JSON . stringify ( keyName ) } ` +
` ) ` ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function on ( el , dir ) {
if ( process . env . NODE _ENV !== 'production' && dir . modifiers ) {
warn$2 ( ` v-on without argument does not support modifiers. ` ) ;
}
el . wrapListeners = ( code ) => ` _g( ${ code } , ${ dir . value } ) ` ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function bind ( el , dir ) {
el . wrapData = ( code ) => {
return ` _b( ${ code } ,' ${ el . tag } ', ${ dir . value } , ${ dir . modifiers && dir . modifiers . prop ? 'true' : 'false' } ${ dir . modifiers && dir . modifiers . sync ? ',true' : '' } ) ` ;
} ;
2023-12-18 13:12:25 +08:00
}
var baseDirectives = {
2024-01-16 21:26:16 +08:00
on ,
bind ,
cloak : noop
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
class CodegenState {
constructor ( options ) {
this . options = options ;
this . warn = options . warn || baseWarn ;
this . transforms = pluckModuleFunction ( options . modules , 'transformCode' ) ;
this . dataGenFns = pluckModuleFunction ( options . modules , 'genData' ) ;
this . directives = extend ( extend ( { } , baseDirectives ) , options . directives ) ;
const isReservedTag = options . isReservedTag || no ;
this . maybeComponent = ( el ) => ! ! el . component || ! isReservedTag ( el . tag ) ;
this . onceId = 0 ;
this . staticRenderFns = [ ] ;
this . pre = false ;
}
}
function generate$1 ( ast , options ) {
const state = new CodegenState ( options ) ;
// fix #11483, Root level <script> tags should not be rendered.
const code = ast
? ast . tag === 'script'
? 'null'
: genElement ( ast , state )
: '_c("div")' ;
return {
render : ` with(this){return ${ code } } ` ,
staticRenderFns : state . staticRenderFns
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genElement ( el , state ) {
if ( el . parent ) {
el . pre = el . pre || el . parent . pre ;
}
if ( el . staticRoot && ! el . staticProcessed ) {
return genStatic ( el , state ) ;
}
else if ( el . once && ! el . onceProcessed ) {
return genOnce ( el , state ) ;
}
else if ( el . for && ! el . forProcessed ) {
return genFor ( el , state ) ;
}
else if ( el . if && ! el . ifProcessed ) {
return genIf ( el , state ) ;
}
else if ( el . tag === 'template' && ! el . slotTarget && ! state . pre ) {
return genChildren ( el , state ) || 'void 0' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else if ( el . tag === 'slot' ) {
return genSlot ( el , state ) ;
}
else {
// component or element
let code ;
if ( el . component ) {
code = genComponent ( el . component , el , state ) ;
}
else {
let data ;
const maybeComponent = state . maybeComponent ( el ) ;
if ( ! el . plain || ( el . pre && maybeComponent ) ) {
data = genData ( el , state ) ;
}
let tag ;
// check if this is a component in <script setup>
const bindings = state . options . bindings ;
if ( maybeComponent && bindings && bindings . _ _isScriptSetup !== false ) {
tag = checkBindingType ( bindings , el . tag ) ;
}
if ( ! tag )
tag = ` ' ${ el . tag } ' ` ;
const children = el . inlineTemplate ? null : genChildren ( el , state , true ) ;
code = ` _c( ${ tag } ${ data ? ` , ${ data } ` : '' // data
} $ { children ? ` , ${ children } ` : '' // children
} ) ` ;
}
// module transforms
for ( let i = 0 ; i < state . transforms . length ; i ++ ) {
code = state . transforms [ i ] ( el , code ) ;
}
return code ;
}
}
function checkBindingType ( bindings , key ) {
const camelName = camelize ( key ) ;
const PascalName = capitalize ( camelName ) ;
const checkType = ( type ) => {
if ( bindings [ key ] === type ) {
return key ;
}
if ( bindings [ camelName ] === type ) {
return camelName ;
}
if ( bindings [ PascalName ] === type ) {
return PascalName ;
}
} ;
const fromConst = checkType ( "setup-const" /* BindingTypes.SETUP_CONST */ ) ||
checkType ( "setup-reactive-const" /* BindingTypes.SETUP_REACTIVE_CONST */ ) ;
if ( fromConst ) {
return fromConst ;
}
const fromMaybeRef = checkType ( "setup-let" /* BindingTypes.SETUP_LET */ ) ||
checkType ( "setup-ref" /* BindingTypes.SETUP_REF */ ) ||
checkType ( "setup-maybe-ref" /* BindingTypes.SETUP_MAYBE_REF */ ) ;
if ( fromMaybeRef ) {
return fromMaybeRef ;
2023-12-18 13:12:25 +08:00
}
}
// hoist static sub-trees out
2024-01-16 21:26:16 +08:00
function genStatic ( el , state ) {
el . staticProcessed = true ;
// Some elements (templates) need to behave differently inside of a v-pre
// node. All pre nodes are static roots, so we can use this as a location to
// wrap a state change and reset it upon exiting the pre node.
const originalPreState = state . pre ;
if ( el . pre ) {
state . pre = el . pre ;
}
state . staticRenderFns . push ( ` with(this){return ${ genElement ( el , state ) } } ` ) ;
state . pre = originalPreState ;
return ` _m( ${ state . staticRenderFns . length - 1 } ${ el . staticInFor ? ',true' : '' } ) ` ;
2023-12-18 13:12:25 +08:00
}
// v-once
2024-01-16 21:26:16 +08:00
function genOnce ( el , state ) {
el . onceProcessed = true ;
if ( el . if && ! el . ifProcessed ) {
return genIf ( el , state ) ;
}
else if ( el . staticInFor ) {
let key = '' ;
let parent = el . parent ;
while ( parent ) {
if ( parent . for ) {
key = parent . key ;
break ;
}
parent = parent . parent ;
}
if ( ! key ) {
process . env . NODE _ENV !== 'production' &&
state . warn ( ` v-once can only be used inside v-for that is keyed. ` , el . rawAttrsMap [ 'v-once' ] ) ;
return genElement ( el , state ) ;
}
return ` _o( ${ genElement ( el , state ) } , ${ state . onceId ++ } , ${ key } ) ` ;
}
else {
return genStatic ( el , state ) ;
}
}
function genIf ( el , state , altGen , altEmpty ) {
el . ifProcessed = true ; // avoid recursion
return genIfConditions ( el . ifConditions . slice ( ) , state , altGen , altEmpty ) ;
}
function genIfConditions ( conditions , state , altGen , altEmpty ) {
if ( ! conditions . length ) {
return altEmpty || '_e()' ;
}
const condition = conditions . shift ( ) ;
if ( condition . exp ) {
return ` ( ${ condition . exp } )? ${ genTernaryExp ( condition . block ) } : ${ genIfConditions ( conditions , state , altGen , altEmpty ) } ` ;
}
else {
return ` ${ genTernaryExp ( condition . block ) } ` ;
}
// v-if with v-once should generate code like (a)?_m(0):_m(1)
function genTernaryExp ( el ) {
return altGen
? altGen ( el , state )
: el . once
? genOnce ( el , state )
: genElement ( el , state ) ;
}
}
function genFor ( el , state , altGen , altHelper ) {
const exp = el . for ;
const alias = el . alias ;
const iterator1 = el . iterator1 ? ` , ${ el . iterator1 } ` : '' ;
const iterator2 = el . iterator2 ? ` , ${ el . iterator2 } ` : '' ;
if ( process . env . NODE _ENV !== 'production' &&
state . maybeComponent ( el ) &&
el . tag !== 'slot' &&
el . tag !== 'template' &&
! el . key ) {
state . warn ( ` < ${ el . tag } v-for=" ${ alias } in ${ exp } ">: component lists rendered with ` +
` v-for should have explicit keys. ` +
` See https://v2.vuejs.org/v2/guide/list.html#key for more info. ` , el . rawAttrsMap [ 'v-for' ] , true /* tip */ ) ;
}
el . forProcessed = true ; // avoid recursion
return ( ` ${ altHelper || '_l' } (( ${ exp } ), ` +
` function( ${ alias } ${ iterator1 } ${ iterator2 } ){ ` +
` return ${ ( altGen || genElement ) ( el , state ) } ` +
'})' ) ;
}
function genData ( el , state ) {
let data = '{' ;
// directives first.
// directives may mutate the el's other properties before they are generated.
const dirs = genDirectives ( el , state ) ;
if ( dirs )
data += dirs + ',' ;
// key
if ( el . key ) {
data += ` key: ${ el . key } , ` ;
}
// ref
if ( el . ref ) {
data += ` ref: ${ el . ref } , ` ;
}
if ( el . refInFor ) {
data += ` refInFor:true, ` ;
}
// pre
if ( el . pre ) {
data += ` pre:true, ` ;
}
// record original tag name for components using "is" attribute
if ( el . component ) {
data += ` tag:" ${ el . tag } ", ` ;
}
// module data generation functions
for ( let i = 0 ; i < state . dataGenFns . length ; i ++ ) {
data += state . dataGenFns [ i ] ( el ) ;
}
// attributes
if ( el . attrs ) {
data += ` attrs: ${ genProps ( el . attrs ) } , ` ;
}
// DOM props
if ( el . props ) {
data += ` domProps: ${ genProps ( el . props ) } , ` ;
}
// event handlers
if ( el . events ) {
data += ` ${ genHandlers ( el . events , false ) } , ` ;
}
if ( el . nativeEvents ) {
data += ` ${ genHandlers ( el . nativeEvents , true ) } , ` ;
}
// slot target
// only for non-scoped slots
if ( el . slotTarget && ! el . slotScope ) {
data += ` slot: ${ el . slotTarget } , ` ;
}
// scoped slots
if ( el . scopedSlots ) {
data += ` ${ genScopedSlots ( el , el . scopedSlots , state ) } , ` ;
}
// component v-model
if ( el . model ) {
data += ` model:{value: ${ el . model . value } ,callback: ${ el . model . callback } ,expression: ${ el . model . expression } }, ` ;
}
// inline-template
if ( el . inlineTemplate ) {
const inlineTemplate = genInlineTemplate ( el , state ) ;
if ( inlineTemplate ) {
data += ` ${ inlineTemplate } , ` ;
}
}
data = data . replace ( /,$/ , '' ) + '}' ;
// v-bind dynamic argument wrap
// v-bind with dynamic arguments must be applied using the same v-bind object
// merge helper so that class/style/mustUseProp attrs are handled correctly.
if ( el . dynamicAttrs ) {
data = ` _b( ${ data } ," ${ el . tag } ", ${ genProps ( el . dynamicAttrs ) } ) ` ;
}
// v-bind data wrap
if ( el . wrapData ) {
data = el . wrapData ( data ) ;
}
// v-on data wrap
if ( el . wrapListeners ) {
data = el . wrapListeners ( data ) ;
}
return data ;
}
function genDirectives ( el , state ) {
const dirs = el . directives ;
if ( ! dirs )
return ;
let res = 'directives:[' ;
let hasRuntime = false ;
let i , l , dir , needRuntime ;
for ( i = 0 , l = dirs . length ; i < l ; i ++ ) {
dir = dirs [ i ] ;
needRuntime = true ;
const gen = state . directives [ dir . name ] ;
if ( gen ) {
// compile-time directive that manipulates AST.
// returns true if it also needs a runtime counterpart.
needRuntime = ! ! gen ( el , dir , state . warn ) ;
}
if ( needRuntime ) {
hasRuntime = true ;
res += ` {name:" ${ dir . name } ",rawName:" ${ dir . rawName } " ${ dir . value
? ` ,value:( ${ dir . value } ),expression: ${ JSON . stringify ( dir . value ) } `
: '' } $ { dir . arg ? ` ,arg: ${ dir . isDynamicArg ? dir . arg : ` " ${ dir . arg } " ` } ` : '' } $ { dir . modifiers ? ` ,modifiers: ${ JSON . stringify ( dir . modifiers ) } ` : '' } } , ` ;
}
}
if ( hasRuntime ) {
return res . slice ( 0 , - 1 ) + ']' ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genInlineTemplate ( el , state ) {
const ast = el . children [ 0 ] ;
if ( process . env . NODE _ENV !== 'production' && ( el . children . length !== 1 || ast . type !== 1 ) ) {
state . warn ( 'Inline-template components must have exactly one child element.' , { start : el . start } ) ;
}
if ( ast && ast . type === 1 ) {
const inlineRenderFns = generate$1 ( ast , state . options ) ;
return ` inlineTemplate:{render:function(){ ${ inlineRenderFns . render } },staticRenderFns:[ ${ inlineRenderFns . staticRenderFns
. map ( code => ` function(){ ${ code } } ` )
. join ( ',' ) } ] } ` ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genScopedSlots ( el , slots , state ) {
// by default scoped slots are considered "stable", this allows child
// components with only scoped slots to skip forced updates from parent.
// but in some cases we have to bail-out of this optimization
// for example if the slot contains dynamic names, has v-if or v-for on them...
let needsForceUpdate = el . for ||
Object . keys ( slots ) . some ( key => {
const slot = slots [ key ] ;
return ( slot . slotTargetDynamic || slot . if || slot . for || containsSlotChild ( slot ) // is passing down slot from parent which may be dynamic
) ;
} ) ;
// #9534: if a component with scoped slots is inside a conditional branch,
// it's possible for the same component to be reused but with different
// compiled slot content. To avoid that, we generate a unique key based on
// the generated code of all the slot contents.
let needsKey = ! ! el . if ;
// OR when it is inside another scoped slot or v-for (the reactivity may be
// disconnected due to the intermediate scope variable)
// #9438, #9506
// TODO: this can be further optimized by properly analyzing in-scope bindings
// and skip force updating ones that do not actually use scope variables.
if ( ! needsForceUpdate ) {
let parent = el . parent ;
while ( parent ) {
if ( ( parent . slotScope && parent . slotScope !== emptySlotScopeToken ) ||
parent . for ) {
needsForceUpdate = true ;
break ;
}
if ( parent . if ) {
needsKey = true ;
}
parent = parent . parent ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const generatedSlots = Object . keys ( slots )
. map ( key => genScopedSlot ( slots [ key ] , state ) )
. join ( ',' ) ;
return ` scopedSlots:_u([ ${ generatedSlots } ] ${ needsForceUpdate ? ` ,null,true ` : ` ` } ${ ! needsForceUpdate && needsKey ? ` ,null,false, ${ hash ( generatedSlots ) } ` : ` ` } ) ` ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function hash ( str ) {
let hash = 5381 ;
let i = str . length ;
while ( i ) {
hash = ( hash * 33 ) ^ str . charCodeAt ( -- i ) ;
}
return hash >>> 0 ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function containsSlotChild ( el ) {
if ( el . type === 1 ) {
if ( el . tag === 'slot' ) {
return true ;
}
return el . children . some ( containsSlotChild ) ;
}
return false ;
}
function genScopedSlot ( el , state ) {
const isLegacySyntax = el . attrsMap [ 'slot-scope' ] ;
if ( el . if && ! el . ifProcessed && ! isLegacySyntax ) {
return genIf ( el , state , genScopedSlot , ` null ` ) ;
}
if ( el . for && ! el . forProcessed ) {
return genFor ( el , state , genScopedSlot ) ;
}
const slotScope = el . slotScope === emptySlotScopeToken ? ` ` : String ( el . slotScope ) ;
const fn = ` function( ${ slotScope } ){ ` +
` return ${ el . tag === 'template'
? el . if && isLegacySyntax
? ` ( ${ el . if } )? ${ genChildren ( el , state ) || 'undefined' } :undefined `
: genChildren ( el , state ) || 'undefined'
: genElement ( el , state ) } } ` ;
// reverse proxy v-slot without scope on this.$slots
const reverseProxy = slotScope ? ` ` : ` ,proxy:true ` ;
return ` {key: ${ el . slotTarget || ` "default" ` } ,fn: ${ fn } ${ reverseProxy } } ` ;
}
function genChildren ( el , state , checkSkip , altGenElement , altGenNode ) {
const children = el . children ;
if ( children . length ) {
const el = children [ 0 ] ;
// optimize single v-for
if ( children . length === 1 &&
el . for &&
el . tag !== 'template' &&
el . tag !== 'slot' ) {
const normalizationType = checkSkip
? state . maybeComponent ( el )
? ` ,1 `
: ` ,0 `
: ` ` ;
return ` ${ ( altGenElement || genElement ) ( el , state ) } ${ normalizationType } ` ;
}
const normalizationType = checkSkip
? getNormalizationType ( children , state . maybeComponent )
: 0 ;
const gen = altGenNode || genNode ;
return ` [ ${ children . map ( c => gen ( c , state ) ) . join ( ',' ) } ] ${ normalizationType ? ` , ${ normalizationType } ` : '' } ` ;
}
2023-12-18 13:12:25 +08:00
}
// determine the normalization needed for the children array.
// 0: no normalization needed
// 1: simple normalization needed (possible 1-level deep nested array)
// 2: full normalization needed
2024-01-16 21:26:16 +08:00
function getNormalizationType ( children , maybeComponent ) {
let res = 0 ;
for ( let i = 0 ; i < children . length ; i ++ ) {
const el = children [ i ] ;
if ( el . type !== 1 ) {
continue ;
}
if ( needsNormalization ( el ) ||
( el . ifConditions &&
el . ifConditions . some ( c => needsNormalization ( c . block ) ) ) ) {
res = 2 ;
break ;
}
if ( maybeComponent ( el ) ||
( el . ifConditions && el . ifConditions . some ( c => maybeComponent ( c . block ) ) ) ) {
res = 1 ;
}
}
return res ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function needsNormalization ( el ) {
return el . for !== undefined || el . tag === 'template' || el . tag === 'slot' ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genNode ( node , state ) {
if ( node . type === 1 ) {
return genElement ( node , state ) ;
}
else if ( node . type === 3 && node . isComment ) {
return genComment ( node ) ;
}
else {
return genText ( node ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genText ( text ) {
return ` _v( ${ text . type === 2
? text . expression // no need for () because already wrapped in _s()
: transformSpecialNewlines ( JSON . stringify ( text . text ) ) } ) ` ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genComment ( comment ) {
return ` _e( ${ JSON . stringify ( comment . text ) } ) ` ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genSlot ( el , state ) {
const slotName = el . slotName || '"default"' ;
const children = genChildren ( el , state ) ;
let res = ` _t( ${ slotName } ${ children ? ` ,function(){return ${ children } } ` : '' } ` ;
const attrs = el . attrs || el . dynamicAttrs
? genProps ( ( el . attrs || [ ] ) . concat ( el . dynamicAttrs || [ ] ) . map ( attr => ( {
// slot props are camelized
name : camelize ( attr . name ) ,
value : attr . value ,
dynamic : attr . dynamic
} ) ) )
: null ;
const bind = el . attrsMap [ 'v-bind' ] ;
if ( ( attrs || bind ) && ! children ) {
res += ` ,null ` ;
}
if ( attrs ) {
res += ` , ${ attrs } ` ;
}
if ( bind ) {
res += ` ${ attrs ? '' : ',null' } , ${ bind } ` ;
}
return res + ')' ;
2023-12-18 13:12:25 +08:00
}
// componentName is el.component, take it as argument to shun flow's pessimistic refinement
2024-01-16 21:26:16 +08:00
function genComponent ( componentName , el , state ) {
const children = el . inlineTemplate ? null : genChildren ( el , state , true ) ;
return ` _c( ${ componentName } , ${ genData ( el , state ) } ${ children ? ` , ${ children } ` : '' } ) ` ;
}
function genProps ( props ) {
let staticProps = ` ` ;
let dynamicProps = ` ` ;
for ( let i = 0 ; i < props . length ; i ++ ) {
const prop = props [ i ] ;
const value = transformSpecialNewlines ( prop . value ) ;
if ( prop . dynamic ) {
dynamicProps += ` ${ prop . name } , ${ value } , ` ;
}
else {
staticProps += ` " ${ prop . name } ": ${ value } , ` ;
}
}
staticProps = ` { ${ staticProps . slice ( 0 , - 1 ) } } ` ;
if ( dynamicProps ) {
return ` _d( ${ staticProps } ,[ ${ dynamicProps . slice ( 0 , - 1 ) } ]) ` ;
}
else {
return staticProps ;
}
2023-12-18 13:12:25 +08:00
}
// #3895, #4268
2024-01-16 21:26:16 +08:00
function transformSpecialNewlines ( text ) {
return text . replace ( /\u2028/g , '\\u2028' ) . replace ( /\u2029/g , '\\u2029' ) ;
2023-12-18 13:12:25 +08:00
}
// these keywords should not appear inside expressions, but operators like
// typeof, instanceof and in are allowed
2024-01-16 21:26:16 +08:00
const prohibitedKeywordRE = new RegExp ( '\\b' +
( 'do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +
'super,throw,while,yield,delete,export,import,return,switch,default,' +
'extends,finally,continue,debugger,function,arguments' )
. split ( ',' )
. join ( '\\b|\\b' ) +
'\\b' ) ;
2023-12-18 13:12:25 +08:00
// these unary operators should not be used as property/method names
2024-01-16 21:26:16 +08:00
const unaryOperatorsRE = new RegExp ( '\\b' +
'delete,typeof,void' . split ( ',' ) . join ( '\\s*\\([^\\)]*\\)|\\b' ) +
'\\s*\\([^\\)]*\\)' ) ;
2023-12-18 13:12:25 +08:00
// strip strings in expressions
2024-01-16 21:26:16 +08:00
const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g ;
2023-12-18 13:12:25 +08:00
// detect problematic expressions in a template
2024-01-16 21:26:16 +08:00
function detectErrors ( ast , warn ) {
if ( ast ) {
checkNode ( ast , warn ) ;
}
}
function checkNode ( node , warn ) {
if ( node . type === 1 ) {
for ( const name in node . attrsMap ) {
if ( dirRE . test ( name ) ) {
const value = node . attrsMap [ name ] ;
if ( value ) {
const range = node . rawAttrsMap [ name ] ;
if ( name === 'v-for' ) {
checkFor ( node , ` v-for=" ${ value } " ` , warn , range ) ;
}
else if ( name === 'v-slot' || name [ 0 ] === '#' ) {
checkFunctionParameterExpression ( value , ` ${ name } =" ${ value } " ` , warn , range ) ;
}
else if ( onRE . test ( name ) ) {
checkEvent ( value , ` ${ name } =" ${ value } " ` , warn , range ) ;
}
else {
checkExpression ( value , ` ${ name } =" ${ value } " ` , warn , range ) ;
}
}
}
}
if ( node . children ) {
for ( let i = 0 ; i < node . children . length ; i ++ ) {
checkNode ( node . children [ i ] , warn ) ;
}
}
}
else if ( node . type === 2 ) {
checkExpression ( node . expression , node . text , warn , node ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkEvent ( exp , text , warn , range ) {
const stripped = exp . replace ( stripStringRE , '' ) ;
const keywordMatch = stripped . match ( unaryOperatorsRE ) ;
if ( keywordMatch && stripped . charAt ( keywordMatch . index - 1 ) !== '$' ) {
warn ( ` avoid using JavaScript unary operator as property name: ` +
` " ${ keywordMatch [ 0 ] } " in expression ${ text . trim ( ) } ` , range ) ;
}
checkExpression ( exp , text , warn , range ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkFor ( node , text , warn , range ) {
checkExpression ( node . for || '' , text , warn , range ) ;
checkIdentifier ( node . alias , 'v-for alias' , text , warn , range ) ;
checkIdentifier ( node . iterator1 , 'v-for iterator' , text , warn , range ) ;
checkIdentifier ( node . iterator2 , 'v-for iterator' , text , warn , range ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkIdentifier ( ident , type , text , warn , range ) {
if ( typeof ident === 'string' ) {
try {
new Function ( ` var ${ ident } =_ ` ) ;
}
catch ( e ) {
warn ( ` invalid ${ type } " ${ ident } " in expression: ${ text . trim ( ) } ` , range ) ;
}
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function checkExpression ( exp , text , warn , range ) {
2023-12-18 13:12:25 +08:00
try {
2024-01-16 21:26:16 +08:00
new Function ( ` return ${ exp } ` ) ;
}
catch ( e ) {
const keywordMatch = exp
. replace ( stripStringRE , '' )
. match ( prohibitedKeywordRE ) ;
if ( keywordMatch ) {
warn ( ` avoid using JavaScript keyword as property name: ` +
` " ${ keywordMatch [ 0 ] } " \n Raw expression: ${ text . trim ( ) } ` , range ) ;
}
else {
warn ( ` invalid expression: ${ e . message } in \n \n ` +
` ${ exp } \n \n ` +
` Raw expression: ${ text . trim ( ) } \n ` , range ) ;
}
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function checkFunctionParameterExpression ( exp , text , warn , range ) {
try {
new Function ( exp , '' ) ;
}
catch ( e ) {
warn ( ` invalid function parameter expression: ${ e . message } in \n \n ` +
` ${ exp } \n \n ` +
` Raw expression: ${ text . trim ( ) } \n ` , range ) ;
}
}
const range = 2 ;
function generateCodeFrame ( source , start = 0 , end = source . length ) {
const lines = source . split ( /\r?\n/ ) ;
let count = 0 ;
const res = [ ] ;
for ( let i = 0 ; i < lines . length ; i ++ ) {
count += lines [ i ] . length + 1 ;
if ( count >= start ) {
for ( let j = i - range ; j <= i + range || end > count ; j ++ ) {
if ( j < 0 || j >= lines . length )
continue ;
res . push ( ` ${ j + 1 } ${ repeat ( ` ` , 3 - String ( j + 1 ) . length ) } | ${ lines [ j ] } ` ) ;
const lineLength = lines [ j ] . length ;
if ( j === i ) {
// push underline
const pad = start - ( count - lineLength ) + 1 ;
const length = end > count ? lineLength - pad : end - start ;
res . push ( ` | ` + repeat ( ` ` , pad ) + repeat ( ` ^ ` , length ) ) ;
}
else if ( j > i ) {
if ( end > count ) {
const length = Math . min ( end - count , lineLength ) ;
res . push ( ` | ` + repeat ( ` ^ ` , length ) ) ;
}
count += lineLength + 1 ;
}
}
break ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return res . join ( '\n' ) ;
}
function repeat ( str , n ) {
let result = '' ;
if ( n > 0 ) {
// eslint-disable-next-line no-constant-condition
while ( true ) {
// eslint-disable-line
if ( n & 1 )
result += str ;
n >>>= 1 ;
if ( n <= 0 )
break ;
str += str ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
return result ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createFunction ( code , errors ) {
try {
return new Function ( code ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
catch ( err ) {
errors . push ( { err , code } ) ;
return noop ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
}
function createCompileToFunctionFn ( compile ) {
const cache = Object . create ( null ) ;
return function compileToFunctions ( template , options , vm ) {
options = extend ( { } , options ) ;
const warn = options . warn || warn$2 ;
delete options . warn ;
/* istanbul ignore if */
if ( process . env . NODE _ENV !== 'production' ) {
// detect possible CSP restriction
try {
new Function ( 'return 1' ) ;
}
catch ( e ) {
if ( e . toString ( ) . match ( /unsafe-eval|CSP/ ) ) {
warn ( 'It seems you are using the standalone build of Vue.js in an ' +
'environment with Content Security Policy that prohibits unsafe-eval. ' +
'The template compiler cannot work in this environment. Consider ' +
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
'templates into render functions.' ) ;
}
}
}
// check cache
const key = options . delimiters
? String ( options . delimiters ) + template
: template ;
if ( cache [ key ] ) {
return cache [ key ] ;
}
// compile
const compiled = compile ( template , options ) ;
// check compilation errors/tips
if ( process . env . NODE _ENV !== 'production' ) {
if ( compiled . errors && compiled . errors . length ) {
if ( options . outputSourceRange ) {
compiled . errors . forEach ( e => {
warn ( ` Error compiling template: \n \n ${ e . msg } \n \n ` +
generateCodeFrame ( template , e . start , e . end ) , vm ) ;
} ) ;
}
else {
warn ( ` Error compiling template: \n \n ${ template } \n \n ` +
compiled . errors . map ( e => ` - ${ e } ` ) . join ( '\n' ) +
'\n' , vm ) ;
}
}
if ( compiled . tips && compiled . tips . length ) {
if ( options . outputSourceRange ) {
compiled . tips . forEach ( e => tip ( e . msg , vm ) ) ;
}
else {
compiled . tips . forEach ( msg => tip ( msg , vm ) ) ;
}
}
}
// turn code into functions
const res = { } ;
const fnGenErrors = [ ] ;
res . render = createFunction ( compiled . render , fnGenErrors ) ;
res . staticRenderFns = compiled . staticRenderFns . map ( code => {
return createFunction ( code , fnGenErrors ) ;
} ) ;
// check function generation errors.
// this should only happen if there is a bug in the compiler itself.
// mostly for codegen development use
/* istanbul ignore if */
if ( process . env . NODE _ENV !== 'production' ) {
if ( ( ! compiled . errors || ! compiled . errors . length ) && fnGenErrors . length ) {
warn ( ` Failed to generate render function: \n \n ` +
fnGenErrors
. map ( ( { err , code } ) => ` ${ err . toString ( ) } in \n \n ${ code } \n ` )
. join ( '\n' ) , vm ) ;
}
}
return ( cache [ key ] = res ) ;
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function createCompilerCreator ( baseCompile ) {
return function createCompiler ( baseOptions ) {
function compile ( template , options ) {
const finalOptions = Object . create ( baseOptions ) ;
const errors = [ ] ;
const tips = [ ] ;
let warn = ( msg , range , tip ) => {
( tip ? tips : errors ) . push ( msg ) ;
} ;
if ( options ) {
if ( process . env . NODE _ENV !== 'production' && options . outputSourceRange ) {
// $flow-disable-line
const leadingSpaceLength = template . match ( /^\s*/ ) [ 0 ] . length ;
warn = ( msg , range , tip ) => {
const data = typeof msg === 'string' ? { msg } : msg ;
if ( range ) {
if ( range . start != null ) {
data . start = range . start + leadingSpaceLength ;
}
if ( range . end != null ) {
data . end = range . end + leadingSpaceLength ;
}
}
( tip ? tips : errors ) . push ( data ) ;
} ;
}
// merge custom modules
if ( options . modules ) {
finalOptions . modules = ( baseOptions . modules || [ ] ) . concat ( options . modules ) ;
}
// merge custom directives
if ( options . directives ) {
finalOptions . directives = extend ( Object . create ( baseOptions . directives || null ) , options . directives ) ;
}
// copy other options
for ( const key in options ) {
if ( key !== 'modules' && key !== 'directives' ) {
finalOptions [ key ] = options [ key ] ;
}
}
}
finalOptions . warn = warn ;
const compiled = baseCompile ( template . trim ( ) , finalOptions ) ;
if ( process . env . NODE _ENV !== 'production' ) {
detectErrors ( compiled . ast , warn ) ;
}
compiled . errors = errors ;
compiled . tips = tips ;
return compiled ;
}
return {
compile ,
compileToFunctions : createCompileToFunctionFn ( compile )
} ;
} ;
}
2023-12-18 13:12:25 +08:00
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
2024-01-16 21:26:16 +08:00
const createCompiler$1 = createCompilerCreator ( function baseCompile ( template , options ) {
const ast = parse ( template . trim ( ) , options ) ;
if ( options . optimize !== false ) {
optimize$1 ( ast , options ) ;
}
const code = generate$1 ( ast , options ) ;
return {
ast ,
render : code . render ,
staticRenderFns : code . staticRenderFns
} ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
const { compile : compile$1 , compileToFunctions : compileToFunctions$1 } = createCompiler$1 ( baseOptions ) ;
const isAttr = makeMap ( 'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,' +
'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,' +
'checked,cite,class,code,codebase,color,cols,colspan,content,' +
'contenteditable,contextmenu,controls,coords,data,datetime,default,' +
'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,for,' +
'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,' +
'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,' +
'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,' +
'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,' +
'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,' +
'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,' +
'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,' +
'target,title,usemap,value,width,wrap' ) ;
2023-12-18 13:12:25 +08:00
/* istanbul ignore next */
2024-01-16 21:26:16 +08:00
const isRenderableAttr = ( name ) => {
return ( isAttr ( name ) || name . indexOf ( 'data-' ) === 0 || name . indexOf ( 'aria-' ) === 0 ) ;
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const propsToAttrMap = {
acceptCharset : 'accept-charset' ,
className : 'class' ,
htmlFor : 'for' ,
httpEquiv : 'http-equiv'
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
const ESC = {
'<' : '<' ,
'>' : '>' ,
'"' : '"' ,
'&' : '&'
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
function escape ( s ) {
return s . replace ( /[<>"&]/g , escapeChar ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function escapeChar ( a ) {
return ESC [ a ] || a ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const plainStringRE = /^"(?:[^"\\]|\\.)*"$|^'(?:[^'\\]|\\.)*'$/ ;
2023-12-18 13:12:25 +08:00
// let the model AST transform translate v-model into appropriate
// props bindings
2024-01-16 21:26:16 +08:00
function applyModelTransform ( el , state ) {
if ( el . directives ) {
for ( let i = 0 ; i < el . directives . length ; i ++ ) {
const dir = el . directives [ i ] ;
if ( dir . name === 'model' ) {
state . directives . model ( el , dir , state . warn ) ;
// remove value for textarea as its converted to text
if ( el . tag === 'textarea' && el . props ) {
el . props = el . props . filter ( p => p . name !== 'value' ) ;
}
break ;
}
2023-12-18 13:12:25 +08:00
}
}
}
2024-01-16 21:26:16 +08:00
function genAttrSegments ( attrs ) {
return attrs . map ( ( { name , value } ) => genAttrSegment ( name , value ) ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genDOMPropSegments ( props , attrs ) {
const segments = [ ] ;
props . forEach ( ( { name , value } ) => {
name = propsToAttrMap [ name ] || name . toLowerCase ( ) ;
if ( isRenderableAttr ( name ) &&
! ( attrs && attrs . some ( a => a . name === name ) ) ) {
segments . push ( genAttrSegment ( name , value ) ) ;
}
} ) ;
return segments ;
}
function genAttrSegment ( name , value ) {
if ( plainStringRE . test ( value ) ) {
// force double quote
value = value . replace ( /^'|'$/g , '"' ) ;
// force enumerated attr to "true"
if ( isEnumeratedAttr ( name ) && value !== ` "false" ` ) {
value = ` "true" ` ;
}
return {
type : RAW ,
value : isBooleanAttr ( name )
? ` ${ name } =" ${ name } " `
: value === '""'
? ` ${ name } `
: ` ${ name } =" ${ JSON . parse ( value ) } " `
} ;
}
else {
return {
type : EXPRESSION ,
value : ` _ssrAttr( ${ JSON . stringify ( name ) } , ${ value } ) `
} ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function genClassSegments ( staticClass , classBinding ) {
if ( staticClass && ! classBinding ) {
return [ { type : RAW , value : ` class=" ${ JSON . parse ( staticClass ) } " ` } ] ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
return [
{
type : EXPRESSION ,
value : ` _ssrClass( ${ staticClass || 'null' } , ${ classBinding || 'null' } ) `
}
] ;
2023-12-18 13:12:25 +08:00
}
}
2024-01-16 21:26:16 +08:00
function genStyleSegments ( staticStyle , parsedStaticStyle , styleBinding , vShowExpression ) {
if ( staticStyle && ! styleBinding && ! vShowExpression ) {
return [ { type : RAW , value : ` style= ${ JSON . stringify ( staticStyle ) } ` } ] ;
}
else {
return [
{
type : EXPRESSION ,
value : ` _ssrStyle( ${ parsedStaticStyle || 'null' } , ${ styleBinding || 'null' } , ${ vShowExpression
? ` { display: ( ${ vShowExpression } ) ? '' : 'none' } `
: 'null' } ) `
}
] ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
/ * *
* In SSR , the vdom tree is generated only once and never patched , so
* we can optimize most element / trees into plain string render functions .
* The SSR optimizer walks the AST tree to detect optimizable elements and trees .
*
* The criteria for SSR optimizability is quite a bit looser than static tree
* detection ( which is designed for client re - render ) . In SSR we bail only for
* components / slots / custom directives .
* /
2023-12-18 13:12:25 +08:00
// optimizability constants
2024-01-16 21:26:16 +08:00
const optimizability = {
FALSE : 0 ,
FULL : 1 ,
SELF : 2 ,
CHILDREN : 3 ,
PARTIAL : 4 // self un-optimizable with some un-optimizable children
2023-12-18 13:12:25 +08:00
} ;
2024-01-16 21:26:16 +08:00
let isPlatformReservedTag ;
function optimize ( root , options ) {
if ( ! root )
return ;
isPlatformReservedTag = options . isReservedTag || no ;
walk ( root , true ) ;
}
function walk ( node , isRoot ) {
if ( isUnOptimizableTree ( node ) ) {
node . ssrOptimizability = optimizability . FALSE ;
return ;
}
// root node or nodes with custom directives should always be a VNode
const selfUnoptimizable = isRoot || hasCustomDirective ( node ) ;
const check = child => {
if ( child . ssrOptimizability !== optimizability . FULL ) {
node . ssrOptimizability = selfUnoptimizable
? optimizability . PARTIAL
: optimizability . SELF ;
}
} ;
if ( selfUnoptimizable ) {
node . ssrOptimizability = optimizability . CHILDREN ;
}
if ( node . type === 1 ) {
for ( let i = 0 , l = node . children . length ; i < l ; i ++ ) {
const child = node . children [ i ] ;
walk ( child ) ;
check ( child ) ;
}
if ( node . ifConditions ) {
for ( let i = 1 , l = node . ifConditions . length ; i < l ; i ++ ) {
const block = node . ifConditions [ i ] . block ;
walk ( block , isRoot ) ;
check ( block ) ;
}
}
if ( node . ssrOptimizability == null ||
( ! isRoot && ( node . attrsMap [ 'v-html' ] || node . attrsMap [ 'v-text' ] ) ) ) {
node . ssrOptimizability = optimizability . FULL ;
}
else {
node . children = optimizeSiblings ( node ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
else {
node . ssrOptimizability = optimizability . FULL ;
}
}
function optimizeSiblings ( el ) {
const children = el . children ;
const optimizedChildren = [ ] ;
let currentOptimizableGroup = [ ] ;
const pushGroup = ( ) => {
if ( currentOptimizableGroup . length ) {
optimizedChildren . push ( {
type : 1 ,
parent : el ,
tag : 'template' ,
attrsList : [ ] ,
attrsMap : { } ,
rawAttrsMap : { } ,
children : currentOptimizableGroup ,
ssrOptimizability : optimizability . FULL
} ) ;
}
currentOptimizableGroup = [ ] ;
} ;
for ( let i = 0 ; i < children . length ; i ++ ) {
const c = children [ i ] ;
if ( c . ssrOptimizability === optimizability . FULL ) {
currentOptimizableGroup . push ( c ) ;
}
else {
// wrap fully-optimizable adjacent siblings inside a template tag
// so that they can be optimized into a single ssrNode by codegen
pushGroup ( ) ;
optimizedChildren . push ( c ) ;
}
}
pushGroup ( ) ;
return optimizedChildren ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function isUnOptimizableTree ( node ) {
if ( node . type === 2 || node . type === 3 ) {
// text or expression
return false ;
}
return ( isBuiltInTag ( node . tag ) || // built-in (slot, component)
! isPlatformReservedTag ( node . tag ) || // custom component
! ! node . component || // "is" component
isSelectWithModel ( node ) // <select v-model> requires runtime inspection
) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const isBuiltInDir = makeMap ( 'text,html,show,on,bind,model,pre,cloak,once' ) ;
function hasCustomDirective ( node ) {
return ( node . type === 1 &&
node . directives &&
node . directives . some ( d => ! isBuiltInDir ( d . name ) ) ) ;
2023-12-18 13:12:25 +08:00
}
// <select v-model> cannot be optimized because it requires a runtime check
// to determine proper selected option
2024-01-16 21:26:16 +08:00
function isSelectWithModel ( node ) {
return ( node . type === 1 &&
node . tag === 'select' &&
node . directives != null &&
node . directives . some ( d => d . name === 'model' ) ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
// The SSR codegen is essentially extending the default codegen to handle
2023-12-18 13:12:25 +08:00
// segment types
2024-01-16 21:26:16 +08:00
const RAW = 0 ;
const INTERPOLATION = 1 ;
const EXPRESSION = 2 ;
function generate ( ast , options ) {
const state = new CodegenState ( options ) ;
const code = ast ? genSSRElement ( ast , state ) : '_c("div")' ;
return {
render : ` with(this){return ${ code } } ` ,
staticRenderFns : state . staticRenderFns
} ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function genSSRElement ( el , state ) {
if ( el . for && ! el . forProcessed ) {
return genFor ( el , state , genSSRElement ) ;
}
else if ( el . if && ! el . ifProcessed ) {
return genIf ( el , state , genSSRElement ) ;
}
else if ( el . tag === 'template' && ! el . slotTarget ) {
return el . ssrOptimizability === optimizability . FULL
? genChildrenAsStringNode ( el , state )
: genSSRChildren ( el , state ) || 'void 0' ;
}
switch ( el . ssrOptimizability ) {
case optimizability . FULL :
// stringify whole tree
return genStringElement ( el , state ) ;
case optimizability . SELF :
// stringify self and check children
return genStringElementWithChildren ( el , state ) ;
case optimizability . CHILDREN :
// generate self as VNode and stringify children
return genNormalElement ( el , state , true ) ;
case optimizability . PARTIAL :
// generate self as VNode and check children
return genNormalElement ( el , state , false ) ;
default :
// bail whole tree
return genElement ( el , state ) ;
}
}
function genNormalElement ( el , state , stringifyChildren ) {
const data = el . plain ? undefined : genData ( el , state ) ;
const children = stringifyChildren
? ` [ ${ genChildrenAsStringNode ( el , state ) } ] `
: genSSRChildren ( el , state , true ) ;
return ` _c(' ${ el . tag } ' ${ data ? ` , ${ data } ` : '' } ${ children ? ` , ${ children } ` : '' } ) ` ;
}
function genSSRChildren ( el , state , checkSkip ) {
return genChildren ( el , state , checkSkip , genSSRElement , genSSRNode ) ;
}
function genSSRNode ( el , state ) {
return el . type === 1 ? genSSRElement ( el , state ) : genText ( el ) ;
}
function genChildrenAsStringNode ( el , state ) {
return el . children . length
? ` _ssrNode( ${ flattenSegments ( childrenToSegments ( el , state ) ) } ) `
: '' ;
}
function genStringElement ( el , state ) {
return ` _ssrNode( ${ elementToString ( el , state ) } ) ` ;
}
function genStringElementWithChildren ( el , state ) {
const children = genSSRChildren ( el , state , true ) ;
return ` _ssrNode( ${ flattenSegments ( elementToOpenTagSegments ( el , state ) ) } ,"</ ${ el . tag } >" ${ children ? ` , ${ children } ` : '' } ) ` ;
}
function elementToString ( el , state ) {
return ` ( ${ flattenSegments ( elementToSegments ( el , state ) ) } ) ` ;
}
function elementToSegments ( el , state ) {
// v-for / v-if
if ( el . for && ! el . forProcessed ) {
el . forProcessed = true ;
return [
{
type : EXPRESSION ,
value : genFor ( el , state , elementToString , '_ssrList' )
}
] ;
}
else if ( el . if && ! el . ifProcessed ) {
el . ifProcessed = true ;
return [
{
type : EXPRESSION ,
value : genIf ( el , state , elementToString , '"<!---->"' )
}
] ;
}
else if ( el . tag === 'template' ) {
return childrenToSegments ( el , state ) ;
}
const openSegments = elementToOpenTagSegments ( el , state ) ;
const childrenSegments = childrenToSegments ( el , state ) ;
const { isUnaryTag } = state . options ;
const close = isUnaryTag && isUnaryTag ( el . tag )
? [ ]
: [ { type : RAW , value : ` </ ${ el . tag } > ` } ] ;
return openSegments . concat ( childrenSegments , close ) ;
}
function elementToOpenTagSegments ( el , state ) {
applyModelTransform ( el , state ) ;
let binding ;
const segments = [ { type : RAW , value : ` < ${ el . tag } ` } ] ;
// attrs
if ( el . attrs ) {
segments . push . apply ( segments , genAttrSegments ( el . attrs ) ) ;
}
// domProps
if ( el . props ) {
segments . push . apply ( segments , genDOMPropSegments ( el . props , el . attrs ) ) ;
}
// v-bind="object"
if ( ( binding = el . attrsMap [ 'v-bind' ] ) ) {
segments . push ( { type : EXPRESSION , value : ` _ssrAttrs( ${ binding } ) ` } ) ;
}
// v-bind.prop="object"
if ( ( binding = el . attrsMap [ 'v-bind.prop' ] ) ) {
segments . push ( { type : EXPRESSION , value : ` _ssrDOMProps( ${ binding } ) ` } ) ;
}
// class
if ( el . staticClass || el . classBinding ) {
segments . push . apply ( segments , genClassSegments ( el . staticClass , el . classBinding ) ) ;
}
// style & v-show
if ( el . staticStyle || el . styleBinding || el . attrsMap [ 'v-show' ] ) {
segments . push . apply ( segments , genStyleSegments ( el . attrsMap . style , el . staticStyle , el . styleBinding , el . attrsMap [ 'v-show' ] ) ) ;
}
// _scopedId
if ( state . options . scopeId ) {
segments . push ( { type : RAW , value : ` ${ state . options . scopeId } ` } ) ;
}
segments . push ( { type : RAW , value : ` > ` } ) ;
return segments ;
}
function childrenToSegments ( el , state ) {
let binding ;
if ( ( binding = el . attrsMap [ 'v-html' ] ) ) {
return [ { type : EXPRESSION , value : ` _s( ${ binding } ) ` } ] ;
}
if ( ( binding = el . attrsMap [ 'v-text' ] ) ) {
return [ { type : INTERPOLATION , value : ` _s( ${ binding } ) ` } ] ;
}
if ( el . tag === 'textarea' && ( binding = el . attrsMap [ 'v-model' ] ) ) {
return [ { type : INTERPOLATION , value : ` _s( ${ binding } ) ` } ] ;
}
return el . children ? nodesToSegments ( el . children , state ) : [ ] ;
}
function nodesToSegments ( children , state ) {
const segments = [ ] ;
for ( let i = 0 ; i < children . length ; i ++ ) {
const c = children [ i ] ;
if ( c . type === 1 ) {
segments . push . apply ( segments , elementToSegments ( c , state ) ) ;
}
else if ( c . type === 2 ) {
segments . push ( { type : INTERPOLATION , value : c . expression } ) ;
}
else if ( c . type === 3 ) {
let text = escape ( c . text ) ;
if ( c . isComment ) {
text = '<!--' + text + '-->' ;
}
segments . push ( { type : RAW , value : text } ) ;
}
}
return segments ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
function flattenSegments ( segments ) {
const mergedSegments = [ ] ;
let textBuffer = '' ;
const pushBuffer = ( ) => {
if ( textBuffer ) {
mergedSegments . push ( JSON . stringify ( textBuffer ) ) ;
textBuffer = '' ;
}
} ;
for ( let i = 0 ; i < segments . length ; i ++ ) {
const s = segments [ i ] ;
if ( s . type === RAW ) {
textBuffer += s . value ;
}
else if ( s . type === INTERPOLATION ) {
pushBuffer ( ) ;
mergedSegments . push ( ` _ssrEscape( ${ s . value } ) ` ) ;
}
else if ( s . type === EXPRESSION ) {
pushBuffer ( ) ;
mergedSegments . push ( ` ( ${ s . value } ) ` ) ;
}
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
pushBuffer ( ) ;
return mergedSegments . join ( '+' ) ;
2023-12-18 13:12:25 +08:00
}
2024-01-16 21:26:16 +08:00
const createCompiler = createCompilerCreator ( function baseCompile ( template , options ) {
const ast = parse ( template . trim ( ) , options ) ;
optimize ( ast , options ) ;
const code = generate ( ast , options ) ;
return {
ast ,
render : code . render ,
staticRenderFns : code . staticRenderFns
} ;
2023-12-18 13:12:25 +08:00
} ) ;
2024-01-16 21:26:16 +08:00
const { compile , compileToFunctions } = createCompiler ( baseOptions ) ;
2023-12-18 13:12:25 +08:00
2024-01-16 21:26:16 +08:00
exports . compile = compile$1 ;
exports . compileToFunctions = compileToFunctions$1 ;
2023-12-18 13:12:25 +08:00
exports . generateCodeFrame = generateCodeFrame ;
2024-01-16 21:26:16 +08:00
exports . parseComponent = parseComponent ;
exports . ssrCompile = compile ;
exports . ssrCompileToFunctions = compileToFunctions ;