|
|
@@ -0,0 +1,127 @@
|
|
|
+/* @flow */
|
|
|
+
|
|
|
+/**
|
|
|
+ * Cross-platform code generation for component v-model
|
|
|
+ */
|
|
|
+export function genComponentModel (
|
|
|
+ el: ASTElement,
|
|
|
+ value: string,
|
|
|
+ modifiers: ?ASTModifiers
|
|
|
+): ?boolean {
|
|
|
+ const { number, trim } = modifiers || {}
|
|
|
+
|
|
|
+ let valueExpression = 'value'
|
|
|
+ if (trim) {
|
|
|
+ valueExpression = `(typeof value === 'string' ? value.trim() : value)`
|
|
|
+ }
|
|
|
+ if (number) {
|
|
|
+ valueExpression = `_n(${valueExpression})`
|
|
|
+ }
|
|
|
+
|
|
|
+ el.model = {
|
|
|
+ value: `(${value})`,
|
|
|
+ callback: `function (value) {${genAssignmentCode(value, valueExpression)}}`
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|