Skip to content

Commit d68a02e

Browse files
committed
feat: allow to disable variable checks
1 parent 43334ad commit d68a02e

File tree

4 files changed

+111
-31
lines changed

4 files changed

+111
-31
lines changed

src/Preview.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,13 @@ export default {
6767
type: Object,
6868
default: () => {},
6969
},
70+
/**
71+
* Avoid checking variables for availability it template
72+
*/
73+
checkVariableAvailability: {
74+
type: Boolean,
75+
default: true,
76+
},
7077
},
7178
data() {
7279
return {
@@ -156,7 +163,7 @@ export default {
156163
}
157164
158165
try {
159-
checkTemplate(options);
166+
checkTemplate(options, this.checkVariableAvailability);
160167
} catch (e) {
161168
this.handleError(e);
162169
return;

src/VueLive.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
:requires="requires"
3535
:jsx="jsx"
3636
:data-scope="dataScope"
37+
:check-variable-availability="checkVariableAvailability"
3738
/>
3839
</template>
3940
</component>
@@ -128,6 +129,15 @@ export default {
128129
type: Object,
129130
default: () => {},
130131
},
132+
/**
133+
* Set if checking variables for availability
134+
* when used in template
135+
* NOTE: if this is not checked, undefined vars will yield a blank output
136+
*/
137+
checkVariableAvailability: {
138+
type: Boolean,
139+
default: true,
140+
},
131141
},
132142
data() {
133143
return {

src/utils/__tests__/checkTemplate.js

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import checkTemplate from "../checkTemplate";
1+
import checkTemplateDummy from "../checkTemplate";
2+
3+
const checkTemplate = (opts) => checkTemplateDummy(opts, true);
24

35
test("parse valid template without error with a function", () => {
46
expect(() =>
57
checkTemplate({ template: '<div><a :href="foo()">hello</a></div>' })
68
).not.toThrow();
79
});
810

9-
test("parse valid template without error with a value", () => {
11+
test("parse valid template without error with a value in data", () => {
1012
expect(() =>
1113
checkTemplate({
1214
template: '<div><compo :value="today">hello</compo></div>',
@@ -19,6 +21,43 @@ test("parse valid template without error with a value", () => {
1921
).not.toThrow();
2022
});
2123

24+
test("parse valid template without error with a value in props", () => {
25+
expect(() =>
26+
checkTemplate({
27+
template: '<div><compo :value="today">hello</compo></div>',
28+
props: {
29+
today: { type: String },
30+
},
31+
})
32+
).not.toThrow();
33+
});
34+
35+
test("parse valid template without error with a value in computed", () => {
36+
expect(() =>
37+
checkTemplate({
38+
template: '<div><compo :value="today">hello</compo></div>',
39+
computed: {
40+
today() {
41+
return "bonjour";
42+
},
43+
},
44+
})
45+
).not.toThrow();
46+
});
47+
48+
test("parse valid template without error with a value in methods", () => {
49+
expect(() =>
50+
checkTemplate({
51+
template: '<div><compo :value="today">hello</compo></div>',
52+
methods: {
53+
today() {
54+
return "bonjour";
55+
},
56+
},
57+
})
58+
).not.toThrow();
59+
});
60+
2261
test("parse false value as a valid value", () => {
2362
expect(() =>
2463
checkTemplate({
@@ -171,3 +210,18 @@ test("parse v-slot-scope deconstructed array expressions without issues", () =>
171210
})
172211
).not.toThrow();
173212
});
213+
214+
test("parse v-for nested expressions and add their vars to available data", () => {
215+
expect(() =>
216+
checkTemplate({
217+
template: `<div v-for="hello in [1,2]">
218+
<div v-for="other in [1,2]">
219+
<CustomSelect @event="
220+
test();
221+
callFunction(hello);
222+
" />
223+
</div>
224+
</div>`,
225+
})
226+
).not.toThrow();
227+
});

src/utils/checkTemplate.js

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const ELEMENT = 1;
77
const SIMPLE_EXPRESSION = 4;
88
const INTERPOLATION = 5;
99

10-
export default function($options) {
10+
export default function($options, checkVariableAvailability) {
1111
if (!$options.template) {
1212
return;
1313
}
@@ -18,8 +18,33 @@ export default function($options) {
1818
throw createCompilerError(e.code);
1919
}
2020

21+
if (!checkVariableAvailability) {
22+
return;
23+
}
24+
25+
const propNamesArray = $options.props
26+
? Array.isArray($options.props)
27+
? $options.props
28+
: Object.keys($options.props)
29+
: [];
30+
31+
const dataArray =
32+
typeof $options.data === "function" ? Object.keys($options.data()) : [];
33+
34+
const computedArray = $options.computed ? Object.keys($options.computed) : [];
35+
36+
const methodsArray =
37+
$options && $options.methods ? Object.keys($options.methods) : [];
38+
39+
const scriptVars = [
40+
...propNamesArray,
41+
...dataArray,
42+
...computedArray,
43+
...methodsArray,
44+
];
45+
2146
traverse(ast, [
22-
(templateAst, availableVarNames) => {
47+
(templateAst, parentTemplateVars) => {
2348
const templateVars = [];
2449
if (templateAst.type === ELEMENT) {
2550
templateAst.props.forEach((attr) => {
@@ -65,8 +90,8 @@ export default function($options) {
6590
}
6691
} else {
6792
try {
68-
checkExpression(exp, $options, [
69-
...availableVarNames,
93+
checkExpression(exp, scriptVars, [
94+
...parentTemplateVars,
7095
...templateVars,
7196
]);
7297
} catch (e) {
@@ -79,8 +104,8 @@ export default function($options) {
79104
if (templateAst.content) {
80105
checkExpression(
81106
templateAst.content.content,
82-
$options,
83-
availableVarNames
107+
scriptVars,
108+
parentTemplateVars
84109
);
85110
}
86111
} catch (e) {
@@ -96,29 +121,13 @@ export default function($options) {
96121
]);
97122
}
98123

99-
export function checkExpression(expression, $options, templateVars) {
124+
export function checkExpression(expression, availableVars, templateVars) {
100125
// try and parse the expression
101126
const ast = parseEs(`(function(){return ${expression}})()`);
102127

103-
const propNamesArray =
104-
$options && $options.props
105-
? Array.isArray($options.props)
106-
? $options.props
107-
: Object.keys($options.props)
108-
: [];
109-
110-
const dataArray =
111-
$options && typeof $options.data === "function"
112-
? Object.keys($options.data())
113-
: [];
114-
115-
const availableIdentifiers = [
116-
...propNamesArray,
117-
...dataArray,
118-
...templateVars,
119-
];
120-
121-
// identify all variables that would be undefined because not in the data object
128+
// identify all variables that would be undefined because
129+
// - not in the options object
130+
// - not defined in the template
122131
visit(ast, {
123132
visitIdentifier(identifier) {
124133
const varName = identifier.value.name;
@@ -128,8 +137,8 @@ export function checkExpression(expression, $options, templateVars) {
128137
identifier.parentPath.name === "arguments"
129138
) {
130139
if (
131-
!availableIdentifiers ||
132-
availableIdentifiers.indexOf(varName) === -1
140+
availableVars.indexOf(varName) === -1 &&
141+
templateVars.indexOf(varName) === -1
133142
) {
134143
throw new VueLiveUndefinedVariableError(
135144
`Variable "${varName}" is not defined.`,

0 commit comments

Comments
 (0)