/* @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: JSON.stringify(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 res = parseModel(value) if (res.key === null) { return `${value}=${assignment}` } else { return `$set(${res.exp}, ${res.key}, ${assignment})` } } /** * 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]] * */ let len, str, chr, index, expressionPos, expressionEndPos type ModelParseResult = { exp: string, key: string | null } export function parseModel (val: string): ModelParseResult { // 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 } } } 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) } } 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 } } }