提交 5314c12c 编写于 作者: B Bogdan Chadkin

Convert element children to xast

Ref https://github.com/syntax-tree/xast

Renamed content to children to match xast spec.
上级 b9a68244
......@@ -189,8 +189,8 @@ function csstreeToStyleDeclaration(declaration) {
* @return {string} CSS string or empty array if no styles are set
*/
function getCssStr(elem) {
if (elem.content[0].type === 'text' || elem.content[0].type === 'cdata') {
return elem.content[0].value;
if (elem.children[0].type === 'text' || elem.children[0].type === 'cdata') {
return elem.children[0].value;
}
return '';
}
......@@ -203,9 +203,9 @@ function getCssStr(elem) {
* @return {string} reference to field with CSS
*/
function setCssStr(elem, css) {
if (elem.content[0].type === 'text' || elem.content[0].type === 'cdata') {
elem.content[0].value = css;
return elem.content[0].value;
if (elem.children[0].type === 'text' || elem.children[0].type === 'cdata') {
elem.children[0].value = css;
return elem.children[0].value;
}
return css;
}
......
......@@ -151,7 +151,7 @@ const computeStyle = (node) => {
styleNode.attributes.type === '' ||
styleNode.attributes.type === 'text/css'
) {
const children = styleNode.content || [];
const children = styleNode.children;
for (const child of children) {
if (child.type === 'text' || child.type === 'cdata') {
stylesheet.push(...parseStylesheet(child.value, dynamic));
......
......@@ -23,7 +23,7 @@ const getAttributeValue = (elem, name) => {
};
const getChildren = (node) => {
return node.content || [];
return node.children || [];
};
const getName = (elemAst) => {
......@@ -40,8 +40,8 @@ const getSiblings = (elem) => {
};
const getText = (node) => {
if (node.content[0].type === 'text' && node.content[0].type === 'cdata') {
return node.content[0].value;
if (node.children[0].type === 'text' && node.children[0].type === 'cdata') {
return node.children[0].value;
}
return '';
};
......
......@@ -93,29 +93,27 @@ function encodeEntity(char) {
JS2SVG.prototype.convert = function (data) {
var svg = '';
if (data.content) {
this.indentLevel++;
this.indentLevel++;
data.content.forEach(function (item) {
if (item.type === 'element') {
svg += this.createElem(item);
}
if (item.type === 'text') {
svg += this.createText(item);
}
if (item.type === 'doctype') {
svg += this.createDoctype(item);
}
if (item.type === 'instruction') {
svg += this.createProcInst(item);
}
if (item.type === 'comment') {
svg += this.createComment(item);
}
if (item.type === 'cdata') {
svg += this.createCDATA(item);
}
}, this);
for (const item of data.children) {
if (item.type === 'element') {
svg += this.createElem(item);
}
if (item.type === 'text') {
svg += this.createText(item);
}
if (item.type === 'doctype') {
svg += this.createDoctype(item);
}
if (item.type === 'instruction') {
svg += this.createProcInst(item);
}
if (item.type === 'comment') {
svg += this.createComment(item);
}
if (item.type === 'cdata') {
svg += this.createCDATA(item);
}
}
this.indentLevel--;
......@@ -211,7 +209,7 @@ JS2SVG.prototype.createElem = function (data) {
}
// empty element and short tag
if (data.isEmpty()) {
if (data.children.length === 0) {
if (this.config.useShortTags) {
return (
this.createIndent() +
......
......@@ -30,7 +30,7 @@ JSAPI.prototype.clone = function () {
var nodeData = {};
Object.keys(node).forEach(function (key) {
if (key !== 'class' && key !== 'style' && key !== 'content') {
if (key !== 'class' && key !== 'style' && key !== 'children') {
nodeData[key] = node[key];
}
});
......@@ -49,8 +49,8 @@ JSAPI.prototype.clone = function () {
if (node.style) {
clonedNode.style = node.style.clone(clonedNode);
}
if (node.content) {
clonedNode.content = node.content.map(function (childNode) {
if (node.children) {
clonedNode.children = node.children.map(function (childNode) {
var clonedChild = childNode.clone();
clonedChild.parentNode = clonedNode;
return clonedChild;
......@@ -98,7 +98,7 @@ JSAPI.prototype.renameElem = function (name) {
* @return {Boolean}
*/
JSAPI.prototype.isEmpty = function () {
return !this.content || !this.content.length;
return !this.children || !this.children.length;
};
/**
......@@ -116,11 +116,11 @@ JSAPI.prototype.closestElem = function (elemName) {
};
/**
* Changes content by removing elements and/or adding new elements.
* Changes children by removing elements and/or adding new elements.
*
* @param {Number} start Index at which to start changing the content.
* @param {Number} start Index at which to start changing the children.
* @param {Number} n Number of elements to remove.
* @param {Array|Object} [insertion] Elements to add to the content.
* @param {Array|Object} [insertion] Elements to add to the children.
* @return {Array} Removed elements.
*/
JSAPI.prototype.spliceContent = function (start, n, insertion) {
......@@ -133,7 +133,10 @@ JSAPI.prototype.spliceContent = function (start, n, insertion) {
inner.parentNode = this;
}, this);
return this.content.splice.apply(this.content, [start, n].concat(insertion));
return this.children.splice.apply(
this.children,
[start, n].concat(insertion)
);
};
/**
......
......@@ -50,9 +50,9 @@ module.exports = function (data, info, plugins) {
*/
function perItem(data, info, plugins, reverse) {
function monkeys(items) {
items.content = items.content.filter(function (item) {
items.children = items.children.filter(function (item) {
// reverse pass
if (reverse && item.content) {
if (reverse && item.children) {
monkeys(item);
}
......@@ -68,7 +68,7 @@ function perItem(data, info, plugins, reverse) {
}
// direct pass
if (!reverse && item.content) {
if (!reverse && item.children) {
monkeys(item);
}
......
......@@ -23,13 +23,13 @@ var config = {
*/
module.exports = function (data) {
var sax = SAX.parser(config.strict, config),
root = new JSAPI({ type: 'root', content: [] }),
root = new JSAPI({ type: 'root', children: [] }),
current = root,
stack = [root];
function pushToContent(content) {
const wrapped = new JSAPI(content, current);
current.content.push(wrapped);
function pushToContent(node) {
const wrapped = new JSAPI(node, current);
current.children.push(wrapped);
return wrapped;
}
......@@ -128,7 +128,7 @@ module.exports = function (data) {
}
element.attributes = newAttributes;
},
content: [],
children: [],
};
element.class = new CSSClassList(element);
......
......@@ -57,7 +57,7 @@ exports.fn = function (data, params) {
}
var attributes = params.attributes || [params.attribute],
svg = data.content[0];
svg = data.children[0];
if (svg.isElem('svg')) {
attributes.forEach(function (attribute) {
......
......@@ -45,7 +45,7 @@ exports.fn = function (data, params) {
}
var classNames = params.classNames || [params.className],
svg = data.content[0];
svg = data.children[0];
if (svg.isElem('svg')) {
svg.class.add.apply(svg.class, classNames);
......
......@@ -60,10 +60,10 @@ exports.fn = function (data) {
}
function monkeys(items, fn) {
items.content.forEach(function (item) {
items.children.forEach(function (item) {
fn(item);
if (item.content) {
if (item.children) {
monkeys(item, fn);
}
});
......
......@@ -117,13 +117,12 @@ exports.fn = function (data, params) {
* @return {Array} output items
*/
function monkeys(items) {
for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
var item = items.content[i];
for (var i = 0; i < items.children.length && !hasStyleOrScript; i++) {
var item = items.children[i];
// quit if <style> or <script> present ('force' param prevents quitting)
if (!params.force) {
var isNotEmpty = item.isEmpty() === false;
if (item.isElem(styleOrScript) && isNotEmpty) {
if (item.isElem(styleOrScript) && item.children.length !== 0) {
hasStyleOrScript = true;
continue;
}
......@@ -132,8 +131,8 @@ exports.fn = function (data, params) {
if (item.isElem('svg')) {
var hasDefsOnly = true;
for (var j = 0; j < item.content.length; j++) {
if (!item.content[j].isElem('defs')) {
for (var j = 0; j < item.children.length; j++) {
if (!item.children[j].isElem('defs')) {
hasDefsOnly = false;
break;
}
......@@ -181,7 +180,7 @@ exports.fn = function (data, params) {
});
}
// go deeper
if (item.content) {
if (item.children) {
monkeys(item);
}
}
......
......@@ -13,7 +13,9 @@ var collections = require('./_collections'),
function hasAnimatedAttr(item) {
return (
(item.isElem(animationElems) && item.hasAttr('attributeName', this)) ||
(!item.isEmpty() && item.content.some(hasAnimatedAttr, this))
(item.type === 'element' &&
item.children.length !== 0 &&
item.children.some(hasAnimatedAttr, this))
);
}
......@@ -42,13 +44,17 @@ function hasAnimatedAttr(item) {
*/
exports.fn = function (item) {
// non-empty elements
if (item.type === 'element' && !item.isElem('switch') && !item.isEmpty()) {
item.content.forEach(function (g, i) {
if (
item.type === 'element' &&
!item.isElem('switch') &&
item.children.length !== 0
) {
item.children.forEach(function (g, i) {
// non-empty groups
if (g.isElem('g') && !g.isEmpty()) {
// move group attibutes to the single content element
if (g.hasAttr() && g.content.length === 1) {
var inner = g.content[0];
if (g.isElem('g') && g.children.length !== 0) {
// move group attibutes to the single child element
if (g.hasAttr() && g.children.length === 1) {
var inner = g.children[0];
if (
inner.type === 'element' &&
......@@ -61,7 +67,7 @@ exports.fn = function (item) {
!inner.hasAttr('transform')))
) {
g.eachAttr(function (attr) {
if (g.content.some(hasAnimatedAttr, attr.name)) return;
if (g.children.some(hasAnimatedAttr, attr.name)) return;
if (!inner.hasAttr(attr.name)) {
inner.addAttr(attr);
......@@ -85,11 +91,11 @@ exports.fn = function (item) {
// collapse groups without attributes
if (
!g.hasAttr() &&
!g.content.some(function (item) {
!g.children.some(function (item) {
return item.isElem(animationElems);
})
) {
item.spliceContent(i, 1, g.content);
item.spliceContent(i, 1, g.children);
}
}
});
......
......@@ -62,7 +62,7 @@ exports.fn = function (document, opts) {
continue;
}
// skip empty <style/>s or <foreignObject> content.
if (styleEl.isEmpty() || styleEl.closestElem('foreignObject')) {
if (styleEl.children.length === 0 || styleEl.closestElem('foreignObject')) {
continue;
}
......@@ -244,15 +244,18 @@ exports.fn = function (document, opts) {
// clean up now emtpy <style/>s
var styleParentEl = style.styleEl.parentNode;
styleParentEl.spliceContent(
styleParentEl.content.indexOf(style.styleEl),
styleParentEl.children.indexOf(style.styleEl),
1
);
if (styleParentEl.name === 'defs' && styleParentEl.content.length === 0) {
if (
styleParentEl.name === 'defs' &&
styleParentEl.children.length === 0
) {
// also clean up now empty <def/>s
var defsParentEl = styleParentEl.parentNode;
defsParentEl.spliceContent(
defsParentEl.content.indexOf(styleParentEl),
defsParentEl.children.indexOf(styleParentEl),
1
);
}
......
......@@ -26,19 +26,19 @@ exports.params = {
* @author Kir Belevich, Lev Solntsev
*/
exports.fn = function (item, params) {
if (item.type !== 'element' || item.isEmpty()) return;
if (item.type !== 'element' || item.children.length === 0) return;
var prevContentItem = null,
prevContentItemKeys = null;
item.content = item.content.filter(function (contentItem) {
item.children = item.children.filter(function (contentItem) {
if (
prevContentItem &&
prevContentItem.isElem('path') &&
prevContentItem.isEmpty() &&
prevContentItem.children.length === 0 &&
prevContentItem.hasAttr('d') &&
contentItem.isElem('path') &&
contentItem.isEmpty() &&
contentItem.children.length === 0 &&
contentItem.hasAttr('d')
) {
const computedStyle = computeStyle(contentItem);
......
......@@ -38,17 +38,20 @@ exports.fn = function (ast, options) {
elems.forEach(function (elem) {
if (elem.isElem('style')) {
if (elem.content[0].type === 'text' || elem.content[0].type === 'cdata') {
const styleCss = elem.content[0].value;
if (
elem.children[0].type === 'text' ||
elem.children[0].type === 'cdata'
) {
const styleCss = elem.children[0].value;
const minified = csso.minify(styleCss, minifyOptionsForStylesheet).css;
// preserve cdata if necessary
// TODO split cdata -> text optimisation into separate plugin
if (styleCss.indexOf('>') >= 0 || styleCss.indexOf('<') >= 0) {
elem.content[0].type = 'cdata';
elem.content[0].value = minified;
elem.children[0].type = 'cdata';
elem.children[0].value = minified;
} else {
elem.content[0].type = 'text';
elem.content[0].value = minified;
elem.children[0].type = 'text';
elem.children[0].value = minified;
}
}
} else {
......@@ -71,15 +74,15 @@ function cloneObject(obj) {
function findStyleElems(ast) {
function walk(items, styles) {
for (var i = 0; i < items.content.length; i++) {
var item = items.content[i];
for (var i = 0; i < items.children.length; i++) {
var item = items.children[i];
// go deeper
if (item.content) {
if (item.children) {
walk(item, styles);
}
if (item.isElem('style') && !item.isEmpty()) {
if (item.isElem('style') && item.children.length !== 0) {
styles.push(item);
} else if (item.type === 'element' && item.hasAttr('style')) {
styles.push(item);
......@@ -106,11 +109,11 @@ function shouldFilter(options, name) {
function collectUsageData(ast, options) {
function walk(items, usageData) {
for (var i = 0; i < items.content.length; i++) {
var item = items.content[i];
for (var i = 0; i < items.children.length; i++) {
var item = items.children[i];
// go deeper
if (item.content) {
if (item.children) {
walk(item, usageData);
}
......
......@@ -34,11 +34,11 @@ var inheritableAttrs = require('./_collections').inheritableAttrs,
* @author Kir Belevich
*/
exports.fn = function (item) {
if (item.isElem('g') && !item.isEmpty() && item.content.length > 1) {
if (item.isElem('g') && item.children.length > 1) {
var intersection = {},
hasTransform = false,
hasClip = item.hasAttr('clip-path') || item.hasAttr('mask'),
intersected = item.content.every(function (inner) {
intersected = item.children.every(function (inner) {
if (inner.type === 'element' && inner.hasAttr()) {
// don't mess with possible styles (hack until CSS parsing is implemented)
if (inner.hasAttr('class')) return false;
......@@ -56,12 +56,12 @@ exports.fn = function (item) {
return true;
}
}),
allPath = item.content.every(function (inner) {
allPath = item.children.every(function (inner) {
return inner.isElem(pathElems);
});
if (intersected) {
item.content.forEach(function (g) {
item.children.forEach(function (g) {
for (const [name, value] of Object.entries(intersection)) {
if ((!allPath && !hasClip) || name !== 'transform') {
g.removeAttr(name);
......
......@@ -33,16 +33,16 @@ exports.fn = function (item) {
// move group transform attr to content's pathElems
if (
item.isElem('g') &&
item.children.length !== 0 &&
item.hasAttr('transform') &&
!item.isEmpty() &&
!item.someAttr(function (attr) {
return ~referencesProps.indexOf(attr.name) && ~attr.value.indexOf('url(');
}) &&
item.content.every(function (inner) {
item.children.every(function (inner) {
return inner.isElem(pathElems) && !inner.hasAttr('id');
})
) {
item.content.forEach(function (inner) {
item.children.forEach(function (inner) {
var attr = item.attr('transform');
if (inner.hasAttr('transform')) {
inner.attr('transform').value =
......
......@@ -197,15 +197,15 @@ exports.fn = function (node, opts, extra) {
// <style/> property values
if (node.name === 'style') {
if (node.isEmpty()) {
if (node.type === 'element' && node.name === 'style') {
if (node.children.length === 0) {
// skip empty <style/>s
return node;
}
var cssStr = '';
if (node.content[0].type === 'text' || node.content[0].type === 'cdata') {
cssStr = node.content[0].value;
if (node.children[0].type === 'text' || node.children[0].type === 'cdata') {
cssStr = node.children[0].value;
}
var cssAst = {};
......@@ -249,7 +249,7 @@ exports.fn = function (node, opts, extra) {
});
// update <style>s
node.content[0].value = csstree.generate(cssAst);
node.children[0].value = csstree.generate(cssAst);
return node;
}
......
......@@ -29,9 +29,9 @@ exports.fn = function (item, params) {
!item.isElem('desc') ||
!(
params.removeAny ||
item.isEmpty() ||
(item.content[0].type === 'text' &&
standardDescs.test(item.content[0].value))
item.children.length === 0 ||
(item.children[0].type === 'text' &&
standardDescs.test(item.children[0].value))
)
);
};
......@@ -27,7 +27,7 @@ var container = require('./_collections').elemsGroups.container;
exports.fn = function (item) {
return (
item.isElem(container) === false ||
item.isEmpty() === false ||
(item.type === 'element' && item.children.length !== 0) ||
item.isElem('svg') ||
// empty patterns may contain reusable configuration
(item.isElem('pattern') && Object.keys(item.attrs).length !== 0) ||
......
......@@ -35,12 +35,17 @@ exports.params = {
*/
exports.fn = function (item, params) {
// Remove empty text element
if (params.text && item.isElem('text') && item.isEmpty()) return false;
if (params.text && item.isElem('text') && item.children.length === 0) {
return false;
}
// Remove empty tspan element
if (params.tspan && item.isElem('tspan') && item.isEmpty()) return false;
if (params.tspan && item.isElem('tspan') && item.children.length === 0) {
return false;
}
// Remove tref with empty xlink:href attribute
if (params.tref && item.isElem('tref') && !item.hasAttrLocal('href'))
if (params.tref && item.isElem('tref') && !item.hasAttrLocal('href')) {
return false;
}
};
......@@ -102,7 +102,7 @@ exports.fn = function (item, params) {
if (
params.circleR0 &&
item.isElem('circle') &&
item.isEmpty() &&
item.children.length === 0 &&
item.hasAttr('r', '0')
) {
return false;
......@@ -117,7 +117,7 @@ exports.fn = function (item, params) {
if (
params.ellipseRX0 &&
item.isElem('ellipse') &&
item.isEmpty() &&
item.children.length === 0 &&
item.hasAttr('rx', '0')
) {
return false;
......@@ -132,7 +132,7 @@ exports.fn = function (item, params) {
if (
params.ellipseRY0 &&
item.isElem('ellipse') &&