0
0
mirror of https://github.com/sveltejs/svelte.git synced 2024-12-01 17:30:59 +01:00

add support for declared namespaces – fixes #147

This commit is contained in:
Rich-Harris 2016-12-10 11:07:11 -05:00
parent 7f392e562b
commit fbe130835d
17 changed files with 123 additions and 9 deletions

View File

@ -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';
@ -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,

8
src/utils/namespaces.js Normal file
View File

@ -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 };

View File

@ -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 );

View File

@ -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
};

View File

@ -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 );
@ -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 => {
@ -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;
}
}
}

View File

@ -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,
@ -15,5 +16,6 @@ export default {
helpers,
methods,
components,
events
events,
namespace
};

View File

@ -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 );
}
}

View File

@ -0,0 +1,7 @@
<rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>
<script>
export default {
namespace: 'svg'
};
</script>

View File

@ -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' );

View File

@ -1,6 +1,7 @@
<svg>
<Rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>
</svg>
<script>
import Rect from './Rect.html';

Before

Width:  |  Height:  |  Size: 178 B

After

Width:  |  Height:  |  Size: 179 B

View File

@ -0,0 +1,7 @@
<rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>
<script>
export default {
namespace: 'http://www.w3.org/2000/svg'
};
</script>

View File

@ -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>` );
}
};

View File

@ -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>

After

Width:  |  Height:  |  Size: 179 B

View File

@ -0,0 +1,7 @@
<rect x='{{x}}' y='{{y}}' width='{{width}}' height='{{height}}'/>
<script>
export default {
namespace: 'svg'
};
</script>

View File

@ -0,0 +1,8 @@
[{
"message": "<rect> is an SVG element did you forget to add { namespace: 'svg' } ?",
"loc": {
"line": 1,
"column": 0
},
"pos": 0
}]