Skip to content

Commit 1f35496

Browse files
mgdodgeMichael Dodge
and
Michael Dodge
authored
feat: create allow list for camelCased SVG attributes (#67)
Co-authored-by: Michael Dodge <[email protected]>
1 parent 5f8501f commit 1f35496

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

src/utils/__tests__/checkTemplate.js

+11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import checkTemplateDummy from "../checkTemplate";
2+
import defaultAttrAllowList from "../defaultAttrAllowList";
23

34
const checkTemplate = (opts) => checkTemplateDummy(opts, true);
45

@@ -293,6 +294,16 @@ test("throw error when mixed case attributes", () => {
293294
).toThrowError("[VueLive] Invalid attribute name: aA");
294295
});
295296

297+
test.each(defaultAttrAllowList)("don't throw error for allowed SVG attribute %s", (attr) => {
298+
expect(() =>
299+
checkTemplate({
300+
template: `<svg ${attr}="as">
301+
<g/>
302+
</svg>`,
303+
})
304+
).not.toThrowError(`[VueLive] Invalid attribute name: ${attr}`);
305+
});
306+
296307
test("throw error when invalid character attributes", () => {
297308
expect(() =>
298309
checkTemplate({

src/utils/checkTemplate.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { parse as parseVue } from "@vue/compiler-dom";
33
import { createCompilerError } from "@vue/compiler-core/dist/compiler-core.cjs";
44
import { parse as parseEs } from "acorn";
55
import { ancestor, simple } from "acorn-walk";
6+
import defaultAttrAllowList from "./defaultAttrAllowList";
67

78
const ELEMENT = 1;
89
const SIMPLE_EXPRESSION = 4;
@@ -44,12 +45,16 @@ export default function($options, checkVariableAvailability) {
4445
...methodsArray,
4546
];
4647

48+
// Define list of attributes for which name check will be skipped. Defaults to known camelCased SVG attributes.
49+
// Allow future enhancement via $options.attrAllowList
50+
const attrAllowList = $options.attrAllowList || defaultAttrAllowList;
51+
4752
traverse(ast, [
4853
(templateAst, parentTemplateVars) => {
4954
const templateVars = [];
5055
if (templateAst.type === ELEMENT) {
5156
templateAst.props.forEach((attr) => {
52-
if (!/^[a-z-:]+$/g.test(attr.name)) {
57+
if (!attrAllowList.includes(attr.name) && !/^[a-z-:]+$/g.test(attr.name)) {
5358
throw new VueLiveParseTemplateAttrError(
5459
"[VueLive] Invalid attribute name: " + attr.name,
5560
attr.loc

src/utils/defaultAttrAllowList.js

+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Default list of allowed camelCase attributes (based on SVG attributes)
2+
const defaultAttrAllowList = [
3+
"attributeName",
4+
"attributeType",
5+
"baseFrequency",
6+
"baseProfile",
7+
"calcMode",
8+
"clipPathUnits",
9+
"contentScriptType",
10+
"contentStyleType",
11+
"diffuseConstant",
12+
"edgeMode",
13+
"filterRes",
14+
"filterUnits",
15+
"glyphRef",
16+
"gradientTransform",
17+
"gradientUnits",
18+
"kernelMatrix",
19+
"kernelUnitLength",
20+
"kerning",
21+
"keyPoints",
22+
"keySplines",
23+
"keyTimes",
24+
"lengthAdjust",
25+
"limitingConeAngle",
26+
"markerHeight",
27+
"markerUnits",
28+
"markerWidth",
29+
"maskContentUnits",
30+
"maskUnits",
31+
"numOctaves",
32+
"pathLength",
33+
"patternContentUnits",
34+
"patternTransform",
35+
"patternUnits",
36+
"pointsAtX",
37+
"pointsAtY",
38+
"pointsAtZ",
39+
"preserveAlpha",
40+
"preserveAspectRatio",
41+
"primitiveUnits",
42+
"referrerPolicy",
43+
"refX",
44+
"refY",
45+
"repeatCount",
46+
"repeatDur",
47+
"requiredExtensions",
48+
"requiredFeatures",
49+
"specularConstant",
50+
"specularExponent",
51+
"spreadMethod",
52+
"startOffset",
53+
"stdDeviation",
54+
"stitchTiles",
55+
"surfaceScale",
56+
"systemLanguage",
57+
"tableValues",
58+
"targetX",
59+
"targetY",
60+
"textLength",
61+
"viewBox",
62+
"viewTarget",
63+
"xChannelSelector",
64+
"yChannelSelector",
65+
"zoomAndPan",
66+
];
67+
68+
export default defaultAttrAllowList;

0 commit comments

Comments
 (0)