Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | 1x 1x 1x 217x 217x 217x 217x 217x 194x 194x 23x 23x 217x 217x 217x 217x 217x 217x 10x 10x 97x 13x 13x 13x 108x 24x 217x 217x 217x 217x 13x 13x 217x 13x 13x 19x 19x 19x 19x 19x 19x 19x 19x 12x 19x 7x 7x 7x 17x 12x 12x 12x 12x 19x 13x 9x 9x 9x 9x 9x 9x 13x 23x 23x 23x 23x 23x 217x 217x 217x 217x 217x 217x 217x 217x 217x 217x 217x 217x 217x 10x 13x 217x 217x 217x 1x 197x 13x 13x 13x 13x 13x 22x 22x 22x 22x 12x 12x 12x 12x 1x 1x 1x 1x 1x 12x 4x 4x 4x 12x 5x 8x 3x 12x 22x 22x 3x 3x 22x 6x 19x 9x 13x 4x 4x 22x 22x 22x 22x 22x 22x 13x 13x | import type { LVal, Node, TSType } from '@babel/types' import type { ScriptCompileContext } from './context' import { inferRuntimeType } from './resolveType' import { UNKNOWN_TYPE, isCallOf, toRuntimeTypeString } from './utils' import { BindingTypes, unwrapTSNode } from '@vue/compiler-dom' export const DEFINE_MODEL = 'defineModel' export interface ModelDecl { type: TSType | undefined options: string | undefined identifier: string | undefined runtimeOptionNodes: Node[] } export function processDefineModel( ctx: ScriptCompileContext, node: Node, declId?: LVal, ): boolean { if (!isCallOf(node, DEFINE_MODEL)) { return false } ctx.hasDefineModelCall = true const type = (node.typeParameters && node.typeParameters.params[0]) || undefined let modelName: string let options: Node | undefined const arg0 = node.arguments[0] && unwrapTSNode(node.arguments[0]) const hasName = arg0 && arg0.type === 'StringLiteral' if (hasName) { modelName = arg0.value options = node.arguments[1] } else { modelName = 'modelValue' options = arg0 } if (ctx.modelDecls[modelName]) { ctx.error(`duplicate model name ${JSON.stringify(modelName)}`, node) } let optionsString = options && ctx.getString(options) let optionsRemoved = !options const runtimeOptionNodes: Node[] = [] if ( options && options.type === 'ObjectExpression' && !options.properties.some(p => p.type === 'SpreadElement' || p.computed) ) { let removed = 0 for (let i = options.properties.length - 1; i >= 0; i--) { const p = options.properties[i] const next = options.properties[i + 1] const start = p.start! const end = next ? next.start! : options.end! - 1 if ( (p.type === 'ObjectProperty' || p.type === 'ObjectMethod') && ((p.key.type === 'Identifier' && (p.key.name === 'get' || p.key.name === 'set')) || (p.key.type === 'StringLiteral' && (p.key.value === 'get' || p.key.value === 'set'))) ) { // remove runtime-only options from prop options to avoid duplicates optionsString = optionsString.slice(0, start - options.start!) + optionsString.slice(end - options.start!) } else { // remove prop options from runtime options removed++ ctx.s.remove(ctx.startOffset! + start, ctx.startOffset! + end) // record prop options for invalid scope var reference check runtimeOptionNodes.push(p) } } if (removed === options.properties.length) { optionsRemoved = true ctx.s.remove( ctx.startOffset! + (hasName ? arg0.end! : options.start!), ctx.startOffset! + options.end!, ) } } ctx.modelDecls[modelName] = { type, options: optionsString, runtimeOptionNodes, identifier: declId && declId.type === 'Identifier' ? declId.name : undefined, } // register binding type ctx.bindingMetadata[modelName] = BindingTypes.PROPS // defineModel -> useModel ctx.s.overwrite( ctx.startOffset! + node.callee.start!, ctx.startOffset! + node.callee.end!, ctx.helper('useModel'), ) // inject arguments ctx.s.appendLeft( ctx.startOffset! + (node.arguments.length ? node.arguments[0].start! : node.end! - 1), `__props, ` + (hasName ? `` : `${JSON.stringify(modelName)}${optionsRemoved ? `` : `, `}`), ) return true } export function genModelProps(ctx: ScriptCompileContext) { if (!ctx.hasDefineModelCall) return const isProd = !!ctx.options.isProd let modelPropsDecl = '' for (const [name, { type, options: runtimeOptions }] of Object.entries( ctx.modelDecls, )) { let skipCheck = false let codegenOptions = `` let runtimeTypes = type && inferRuntimeType(ctx, type) if (runtimeTypes) { const hasBoolean = runtimeTypes.includes('Boolean') const hasFunction = runtimeTypes.includes('Function') const hasUnknownType = runtimeTypes.includes(UNKNOWN_TYPE) if (hasUnknownType) { if (hasBoolean || hasFunction) { runtimeTypes = runtimeTypes.filter(t => t !== UNKNOWN_TYPE) skipCheck = true } else { runtimeTypes = ['null'] } } if (!isProd) { codegenOptions = `type: ${toRuntimeTypeString(runtimeTypes)}` + (skipCheck ? ', skipCheck: true' : '') } else if (hasBoolean || (runtimeOptions && hasFunction)) { // preserve types if contains boolean, or // function w/ runtime options that may contain default codegenOptions = `type: ${toRuntimeTypeString(runtimeTypes)}` } else { // able to drop types in production } } let decl: string if (codegenOptions && runtimeOptions) { decl = ctx.isTS ? `{ ${codegenOptions}, ...${runtimeOptions} }` : `Object.assign({ ${codegenOptions} }, ${runtimeOptions})` } else if (codegenOptions) { decl = `{ ${codegenOptions} }` } else if (runtimeOptions) { decl = runtimeOptions } else { decl = `{}` } modelPropsDecl += `\n ${JSON.stringify(name)}: ${decl},` // also generate modifiers prop const modifierPropName = JSON.stringify( name === 'modelValue' ? `modelModifiers` : `${name}Modifiers`, ) modelPropsDecl += `\n ${modifierPropName}: {},` } return `{${modelPropsDecl}\n }` } |