mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
Use attr helper and handle attribute escaping Also improved AST and added walking capability
125 lines
2.8 KiB
JavaScript
125 lines
2.8 KiB
JavaScript
'use strict';
|
|
var isArray = Array.isArray;
|
|
var Container = require('./ast/Container');
|
|
|
|
function noop() {}
|
|
|
|
class Walker {
|
|
constructor(options) {
|
|
this._enter = options.enter || noop;
|
|
this._exit = options.exit || noop;
|
|
this._stopped = false;
|
|
this._reset();
|
|
this._stack = [];
|
|
}
|
|
|
|
_reset() {
|
|
this._skipped = false;
|
|
this._replaced = null;
|
|
}
|
|
|
|
skip() {
|
|
this._skipped = true;
|
|
}
|
|
|
|
stop() {
|
|
this._stopped = true;
|
|
}
|
|
|
|
replace(newNode) {
|
|
this._replaced = newNode;
|
|
}
|
|
|
|
_walkArray(array) {
|
|
var hasRemoval = false;
|
|
|
|
array.forEach((node, i) => {
|
|
var transformed = this.walk(node);
|
|
if (transformed == null) {
|
|
array[i] = null;
|
|
hasRemoval = true;
|
|
} else if (transformed !== node) {
|
|
array[i] = transformed;
|
|
}
|
|
});
|
|
|
|
if (hasRemoval) {
|
|
for (let i=array.length-1; i>=0; i--) {
|
|
if (array[i] == null) {
|
|
array.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
_walkContainer(nodes) {
|
|
nodes.forEach((node) => {
|
|
var transformed = this.walk(node);
|
|
if (transformed == null) {
|
|
node.container.removeChild(node);
|
|
} else if (transformed !== node) {
|
|
node.container.replaceChild(transformed, node);
|
|
}
|
|
});
|
|
}
|
|
|
|
walk(node) {
|
|
if (!node || this._stopped || typeof node === 'string') {
|
|
return node;
|
|
}
|
|
|
|
this._reset();
|
|
|
|
var parent = this._stack.length ? this._stack[this._stack.length - 1] : undefined;
|
|
|
|
this._stack.push(node);
|
|
|
|
var replaced = this._enter(node, parent) || this._replaced;
|
|
if (replaced) {
|
|
this._stack.pop();
|
|
return replaced;
|
|
}
|
|
|
|
if (this._skipped || this._stopped) {
|
|
this._stack.pop();
|
|
return node;
|
|
}
|
|
|
|
if (isArray(node)) {
|
|
let array = node;
|
|
let newArray = this._walkArray(array);
|
|
this._stack.pop();
|
|
return newArray;
|
|
} else if (node instanceof Container) {
|
|
let container = node;
|
|
this._walkContainer(container);
|
|
this._stack.pop();
|
|
return container;
|
|
} else {
|
|
if (node.walk) {
|
|
node.walk(this);
|
|
}
|
|
}
|
|
|
|
if (this._stopped) {
|
|
this._stack.pop();
|
|
return node;
|
|
}
|
|
|
|
this._reset();
|
|
replaced = this._exit(node, parent) || this._replaced;
|
|
if (replaced) {
|
|
this._stack.pop();
|
|
return replaced;
|
|
}
|
|
|
|
this._stack.pop();
|
|
return node;
|
|
}
|
|
}
|
|
|
|
module.exports = Walker;
|
|
|