Skip to content

Commit

Permalink
add support for declared namespaces – fixes #147
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Dec 10, 2016
1 parent 7f392e5 commit fbe1308
Show file tree
Hide file tree
Showing 17 changed files with 123 additions and 9 deletions.
11 changes: 10 additions & 1 deletion src/generate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import deindent from '../utils/deindent.js';
import isReference from '../utils/isReference.js';
import counter from './utils/counter.js';
import flattenReference from '../utils/flattenReference.js';
import namespaces from '../utils/namespaces.js';
import getIntro from './utils/getIntro.js';
import getOutro from './utils/getOutro.js';
import visitors from './visitors/index.js';
Expand Down Expand Up @@ -277,9 +278,17 @@ export default function generate ( parsed, source, options, names ) {
});
}

let namespace = null;
if ( templateProperties.namespace ) {
const ns = templateProperties.namespace.value;
namespace = namespaces[ ns ] || ns;

// TODO remove the namespace property from the generated code, it's unused past this point
}

generator.push({
name: 'renderMainFragment',
namespace: null,
namespace,
target: 'target',
elementDepth: 0,
localElementDepth: 0,
Expand Down
8 changes: 8 additions & 0 deletions src/utils/namespaces.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const html = 'http://www.w3.org/1999/xhtml';
export const mathml = 'http://www.w3.org/1998/Math/MathML';
export const svg = 'http://www.w3.org/2000/svg';
export const xlink = 'http://www.w3.org/1999/xlink';
export const xml = 'http://www.w3.org/XML/1998/namespace';
export const xmlns = 'http://www.w3.org/2000/xmlns';

export default { html, mathml, svg, xlink, xml, xmlns };
18 changes: 18 additions & 0 deletions src/validate/html/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,31 @@
import * as namespaces from '../../utils/namespaces.js';

const svg = /^(?:altGlyph|altGlyphDef|altGlyphItem|animate|animateColor|animateMotion|animateTransform|circle|clipPath|color-profile|cursor|defs|desc|discard|ellipse|feBlend|feColorMatrix|feComponentTransfer|feComposite|feConvolveMatrix|feDiffuseLighting|feDisplacementMap|feDistantLight|feDropShadow|feFlood|feFuncA|feFuncB|feFuncG|feFuncR|feGaussianBlur|feImage|feMerge|feMergeNode|feMorphology|feOffset|fePointLight|feSpecularLighting|feSpotLight|feTile|feTurbulence|filter|font|font-face|font-face-format|font-face-name|font-face-src|font-face-uri|foreignObject|g|glyph|glyphRef|hatch|hatchpath|hkern|image|line|linearGradient|marker|mask|mesh|meshgradient|meshpatch|meshrow|metadata|missing-glyph|mpath|path|pattern|polygon|polyline|radialGradient|rect|set|solidcolor|stop|switch|symbol|text|textPath|title|tref|tspan|unknown|use|view|vkern)$/;

export default function validateHtml ( validator, html ) {
let elementDepth = 0;

function visit ( node ) {
if ( node.type === 'EachBlock' ) {
if ( !~validator.names.indexOf( node.context ) ) validator.names.push( node.context );
if ( node.index && !~validator.names.indexOf( node.index ) ) validator.names.push( node.index );
}

if ( node.type === 'Element' ) {
if ( elementDepth === 0 && validator.namespace !== namespaces.svg && svg.test( node.name ) ) {
validator.warn( `<${node.name}> is an SVG element – did you forget to add { namespace: 'svg' } ?`, node.start );
}

elementDepth += 1;
}

if ( node.children ) {
node.children.forEach( visit );
}

if ( node.type === 'Element' ) {
elementDepth -= 1;
}
}

html.children.forEach( visit );
Expand Down
12 changes: 7 additions & 5 deletions src/validate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,19 @@ export default function validate ( parsed, source, options ) {

templateProperties: {},

names: []
};
names: [],

if ( parsed.html ) {
validateHtml( validator, parsed.html );
}
namespace: null
};

if ( parsed.js ) {
validateJs( validator, parsed.js );
}

if ( parsed.html ) {
validateHtml( validator, parsed.html );
}

return {
names: validator.names
};
Expand Down
8 changes: 7 additions & 1 deletion src/validate/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import propValidators from './propValidators/index.js';
import FuzzySet from './utils/FuzzySet.js';
import checkForDupes from './utils/checkForDupes.js';
import checkForComputedKeys from './utils/checkForComputedKeys.js';
import namespaces from '../../utils/namespaces.js';

const validPropList = Object.keys( propValidators );

Expand Down Expand Up @@ -29,7 +30,7 @@ export default function validateJs ( validator, js ) {
checkForDupes( validator, validator.defaultExport.declaration.properties );

validator.defaultExport.declaration.properties.forEach( prop => {
validator.templateProperties[ prop.key.value ] = prop;
validator.templateProperties[ prop.key.name ] = prop;
});

validator.defaultExport.declaration.properties.forEach( prop => {
Expand All @@ -48,5 +49,10 @@ export default function validateJs ( validator, js ) {
}
}
});

if ( validator.templateProperties.namespace ) {
const ns = validator.templateProperties.namespace.value.value;
validator.namespace = namespaces[ ns ] || ns;
}
}
}
4 changes: 3 additions & 1 deletion src/validate/js/propValidators/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import helpers from './helpers.js';
import methods from './methods.js';
import components from './components.js';
import events from './events.js';
import namespace from './namespace.js';

export default {
data,
Expand All @@ -15,5 +16,6 @@ export default {
helpers,
methods,
components,
events
events,
namespace
};
5 changes: 5 additions & 0 deletions src/validate/js/propValidators/namespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default function namespace ( validator, prop ) {
if ( prop.value.type !== 'Literal' || typeof prop.value.value !== 'string' ) {
validator.error( `The 'namespace' property must be a string literal representing a valid namespace`, prop.start );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>

<script>
export default {
namespace: 'svg'
};
</script>
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
export default {
skip: true,
data: {
x: 0,
y: 0,
width: 100,
height: 100
},

html: `<svg><rect x="0" y="0" width="100" height="100"></rect></svg>`,

test ( assert, component, target ) {
const svg = target.querySelector( 'svg' );
const rect = target.querySelector( 'rect' );
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<svg>
<Rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>
</svg>

<script>
import Rect from './Rect.html';

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>

<script>
export default {
namespace: 'http://www.w3.org/2000/svg'
};
</script>
21 changes: 21 additions & 0 deletions test/generator/svg-child-component-declared-namespace/_config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export default {
data: {
x: 0,
y: 0,
width: 100,
height: 100
},

html: `<svg><rect x="0" y="0" width="100" height="100"></rect></svg>`,

test ( assert, component, target ) {
const svg = target.querySelector( 'svg' );
const rect = target.querySelector( 'rect' );

assert.equal( svg.namespaceURI, 'http://www.w3.org/2000/svg' );
assert.equal( rect.namespaceURI, 'http://www.w3.org/2000/svg' );

component.set({ width: 150, height: 50 });
assert.equal( target.innerHTML, `<svg><rect x="0" y="0" width="150" height="50"></rect></svg>` );
}
};
11 changes: 11 additions & 0 deletions test/generator/svg-child-component-declared-namespace/main.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<svg>
<Rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>
</svg>

<script>
import Rect from './Rect.html';

export default {
components: { Rect }
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>

<script>
export default {
namespace: 'svg'
};
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[{
"message": "<rect> is an SVG element – did you forget to add { namespace: 'svg' } ?",
"loc": {
"line": 1,
"column": 0
},
"pos": 0
}]

0 comments on commit fbe1308

Please sign in to comment.