vue
Version:
Reactive, component-oriented view layer for modern web interfaces.
134 lines (118 loc) • 2.85 kB
JavaScript
/* @flow */
/**
* Cross-platform code generation for component v-model
*/
export function genComponentModel (
el: ASTElement,
value: string,
modifiers: ?ASTModifiers
): ?boolean {
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: `"${value}"`,
callback: `function (${baseValueExpression}) {${assignment}}`
}
}
/**
* Cross-platform codegen helper for generating v-model value assignment code.
*/
export function genAssignmentCode (
value: string,
assignment: string
): string {
const modelRs = parseModel(value)
if (modelRs.idx === null) {
return `${value}=${assignment}`
} else {
return `var $$exp = ${modelRs.exp}, $$idx = ${modelRs.idx};` +
`if (!Array.isArray($$exp)){` +
`${value}=${assignment}}` +
`else{$$exp.splice($$idx, 1, ${assignment})}`
}
}
/**
* parse directive model to do the array update transform. a[idx] = val => $$a.splice($$idx, 1, val)
*
* for loop possible cases:
*
* - test
* - test[idx]
* - test[test1[idx]]
* - test["a"][idx]
* - xxx.test[a[a].test1[idx]]
* - test.xxx.a["asa"][test1[idx]]
*
*/
let len, str, chr, index, expressionPos, expressionEndPos
export function parseModel (val: string): Object {
str = val
len = str.length
index = expressionPos = expressionEndPos = 0
if (val.indexOf('[') < 0 || val.lastIndexOf(']') < len - 1) {
return {
exp: val,
idx: null
}
}
while (!eof()) {
chr = next()
/* istanbul ignore if */
if (isStringStart(chr)) {
parseString(chr)
} else if (chr === 0x5B) {
parseBracket(chr)
}
}
return {
exp: val.substring(0, expressionPos),
idx: val.substring(expressionPos + 1, expressionEndPos)
}
}
function next (): number {
return str.charCodeAt(++index)
}
function eof (): boolean {
return index >= len
}
function isStringStart (chr: number): boolean {
return chr === 0x22 || chr === 0x27
}
function parseBracket (chr: number): void {
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
}
}
}
function parseString (chr: number): void {
const stringQuote = chr
while (!eof()) {
chr = next()
if (chr === stringQuote) {
break
}
}
}