Skip to content

Commit 5e38384

Browse files
committed
split props compilation into its own file
1 parent 12c82fe commit 5e38384

File tree

2 files changed

+149
-147
lines changed

2 files changed

+149
-147
lines changed

src/compiler/compile-props.js

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
var _ = require('../util')
2+
var textParser = require('../parsers/text')
3+
var propDef = require('../directives/prop')
4+
var propBindingModes = require('../config')._propBindingModes
5+
6+
// regexes
7+
var identRE = require('../parsers/path').identRE
8+
var dataAttrRE = /^data-/
9+
var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]+\])*$/
10+
var literalValueRE = /^(true|false)$|^\d.*/
11+
12+
/**
13+
* Compile param attributes on a root element and return
14+
* a props link function.
15+
*
16+
* @param {Element|DocumentFragment} el
17+
* @param {Array} propOptions
18+
* @return {Function} propsLinkFn
19+
*/
20+
21+
module.exports = function compileProps (el, propOptions) {
22+
var props = []
23+
var i = propOptions.length
24+
var options, name, value, path, prop, literal, single
25+
while (i--) {
26+
options = propOptions[i]
27+
name = options.name
28+
// props could contain dashes, which will be
29+
// interpreted as minus calculations by the parser
30+
// so we need to camelize the path here
31+
path = _.camelize(name.replace(dataAttrRE, ''))
32+
if (/[A-Z]/.test(name)) {
33+
_.warn(
34+
'You seem to be using camelCase for a component prop, ' +
35+
'but HTML doesn\'t differentiate between upper and ' +
36+
'lower case. You should use hyphen-delimited ' +
37+
'attribute names. For more info see ' +
38+
'http://vuejs.org/api/options.html#props'
39+
)
40+
}
41+
if (!identRE.test(path)) {
42+
_.warn(
43+
'Invalid prop key: "' + name + '". Prop keys ' +
44+
'must be valid identifiers.'
45+
)
46+
}
47+
value = el.getAttribute(name)
48+
// create a prop descriptor
49+
prop = {
50+
name: name,
51+
raw: value,
52+
path: path,
53+
options: options,
54+
mode: propBindingModes.ONE_WAY
55+
}
56+
if (value !== null) {
57+
// important so that this doesn't get compiled
58+
// again as a normal attribute binding
59+
el.removeAttribute(name)
60+
var tokens = textParser.parse(value)
61+
if (tokens) {
62+
if (el && el.nodeType === 1) {
63+
el.removeAttribute(name)
64+
}
65+
prop.dynamic = true
66+
prop.parentPath = textParser.tokensToExp(tokens)
67+
// check prop binding type.
68+
single = tokens.length === 1
69+
literal = literalValueRE.test(prop.parentPath)
70+
// one time: {{* prop}}
71+
if (literal || (single && tokens[0].oneTime)) {
72+
prop.mode = propBindingModes.ONE_TIME
73+
} else if (
74+
!literal &&
75+
(single && tokens[0].twoWay)
76+
) {
77+
if (settablePathRE.test(prop.parentPath)) {
78+
prop.mode = propBindingModes.TWO_WAY
79+
} else {
80+
_.warn(
81+
'Cannot bind two-way prop with non-settable ' +
82+
'parent path: ' + prop.parentPath
83+
)
84+
}
85+
}
86+
}
87+
} else if (options && options.required) {
88+
_.warn('Missing required prop: ' + name)
89+
}
90+
props.push(prop)
91+
}
92+
return makePropsLinkFn(props)
93+
}
94+
95+
/**
96+
* Build a function that applies props to a vm.
97+
*
98+
* @param {Array} props
99+
* @return {Function} propsLinkFn
100+
*/
101+
102+
function makePropsLinkFn (props) {
103+
return function propsLinkFn (vm, el) {
104+
var i = props.length
105+
var prop, path, options, value
106+
while (i--) {
107+
prop = props[i]
108+
path = prop.path
109+
options = prop.options
110+
if (prop.raw === null) {
111+
// initialize absent prop
112+
vm._data[path] = options.type === Boolean
113+
? false
114+
: options.hasOwnProperty('default')
115+
? options.default
116+
: undefined
117+
} else if (prop.dynamic) {
118+
// dynamic prop
119+
if (vm._context) {
120+
if (prop.mode === propBindingModes.ONE_TIME) {
121+
// one time binding
122+
value = vm._context.$get(prop.parentPath)
123+
if (_.assertProp(prop, value)) {
124+
vm[path] = vm._data[path] = value
125+
}
126+
} else {
127+
// dynamic binding
128+
vm._bindDir('prop', el, prop, propDef)
129+
}
130+
} else {
131+
_.warn(
132+
'Cannot bind dynamic prop on a root instance' +
133+
' with no parent: ' + prop.name + '="' +
134+
prop.raw + '"'
135+
)
136+
}
137+
} else {
138+
// literal, cast it and just set once
139+
value = options.type === Boolean && prop.raw === ''
140+
? true
141+
: _.toBoolean(_.toNumber(prop.raw))
142+
if (_.assertProp(prop, value)) {
143+
vm[path] = vm._data[path] = value
144+
}
145+
}
146+
}
147+
}
148+
}

src/compiler/compile.js

Lines changed: 1 addition & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
11
var _ = require('../util')
2+
var compileProps = require('./compile-props')
23
var config = require('../config')
34
var textParser = require('../parsers/text')
45
var dirParser = require('../parsers/directive')
56
var templateParser = require('../parsers/template')
67
var resolveAsset = _.resolveAsset
7-
var propBindingModes = config._propBindingModes
8-
9-
// internal directives
10-
var propDef = require('../directives/prop')
118
var componentDef = require('../directives/component')
129

1310
// terminal directives
@@ -410,149 +407,6 @@ function makeChildLinkFn (linkFns) {
410407
}
411408
}
412409

413-
/**
414-
* Compile param attributes on a root element and return
415-
* a props link function.
416-
*
417-
* @param {Element|DocumentFragment} el
418-
* @param {Array} propOptions
419-
* @return {Function} propsLinkFn
420-
*/
421-
422-
var dataAttrRE = /^data-/
423-
var settablePathRE = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*|\[[^\[\]]+\])*$/
424-
var literalValueRE = /^(true|false)$|^\d.*/
425-
var identRE = require('../parsers/path').identRE
426-
427-
function compileProps (el, propOptions) {
428-
var props = []
429-
var i = propOptions.length
430-
var options, name, value, path, prop, literal, single
431-
while (i--) {
432-
options = propOptions[i]
433-
name = options.name
434-
// props could contain dashes, which will be
435-
// interpreted as minus calculations by the parser
436-
// so we need to camelize the path here
437-
path = _.camelize(name.replace(dataAttrRE, ''))
438-
if (/[A-Z]/.test(name)) {
439-
_.warn(
440-
'You seem to be using camelCase for a component prop, ' +
441-
'but HTML doesn\'t differentiate between upper and ' +
442-
'lower case. You should use hyphen-delimited ' +
443-
'attribute names. For more info see ' +
444-
'http://vuejs.org/api/options.html#props'
445-
)
446-
}
447-
if (!identRE.test(path)) {
448-
_.warn(
449-
'Invalid prop key: "' + name + '". Prop keys ' +
450-
'must be valid identifiers.'
451-
)
452-
}
453-
value = el.getAttribute(name)
454-
// create a prop descriptor
455-
prop = {
456-
name: name,
457-
raw: value,
458-
path: path,
459-
options: options,
460-
mode: propBindingModes.ONE_WAY
461-
}
462-
if (value !== null) {
463-
// important so that this doesn't get compiled
464-
// again as a normal attribute binding
465-
el.removeAttribute(name)
466-
var tokens = textParser.parse(value)
467-
if (tokens) {
468-
if (el && el.nodeType === 1) {
469-
el.removeAttribute(name)
470-
}
471-
prop.dynamic = true
472-
prop.parentPath = textParser.tokensToExp(tokens)
473-
// check prop binding type.
474-
single = tokens.length === 1
475-
literal = literalValueRE.test(prop.parentPath)
476-
// one time: {{* prop}}
477-
if (literal || (single && tokens[0].oneTime)) {
478-
prop.mode = propBindingModes.ONE_TIME
479-
} else if (
480-
!literal &&
481-
(single && tokens[0].twoWay)
482-
) {
483-
if (settablePathRE.test(prop.parentPath)) {
484-
prop.mode = propBindingModes.TWO_WAY
485-
} else {
486-
_.warn(
487-
'Cannot bind two-way prop with non-settable ' +
488-
'parent path: ' + prop.parentPath
489-
)
490-
}
491-
}
492-
}
493-
} else if (options && options.required) {
494-
_.warn('Missing required prop: ' + name)
495-
}
496-
props.push(prop)
497-
}
498-
return makePropsLinkFn(props)
499-
}
500-
501-
/**
502-
* Build a function that applies props to a vm.
503-
*
504-
* @param {Array} props
505-
* @return {Function} propsLinkFn
506-
*/
507-
508-
function makePropsLinkFn (props) {
509-
return function propsLinkFn (vm, el) {
510-
var i = props.length
511-
var prop, path, options, value
512-
while (i--) {
513-
prop = props[i]
514-
path = prop.path
515-
options = prop.options
516-
if (prop.raw === null) {
517-
// initialize absent prop
518-
vm._data[path] = options.type === Boolean
519-
? false
520-
: options.hasOwnProperty('default')
521-
? options.default
522-
: undefined
523-
} else if (prop.dynamic) {
524-
// dynamic prop
525-
if (vm._context) {
526-
if (prop.mode === propBindingModes.ONE_TIME) {
527-
// one time binding
528-
value = vm._context.$get(prop.parentPath)
529-
if (_.assertProp(prop, value)) {
530-
vm[path] = vm._data[path] = value
531-
}
532-
} else {
533-
// dynamic binding
534-
vm._bindDir('prop', el, prop, propDef)
535-
}
536-
} else {
537-
_.warn(
538-
'Cannot bind dynamic prop on a root instance' +
539-
' with no parent: ' + prop.name + '="' +
540-
prop.raw + '"'
541-
)
542-
}
543-
} else {
544-
// literal, cast it and just set once
545-
value = options.type === Boolean && prop.raw === ''
546-
? true
547-
: _.toBoolean(_.toNumber(prop.raw))
548-
if (_.assertProp(prop, value)) {
549-
vm[path] = vm._data[path] = value
550-
}
551-
}
552-
}
553-
}
554-
}
555-
556410
/**
557411
* Check for element directives (custom elements that should
558412
* be resovled as terminal directives).

0 commit comments

Comments
 (0)