@effectful/transducers
Version:
JS syntax transformation framework for @effectful/js
574 lines (541 loc) • 16.2 kB
JavaScript
;
exports.__esModule = true;
exports.after = after;
exports.ancestors = ancestors;
exports.append = append;
exports.appendBlock = appendBlock;
exports.arr = arr;
exports.assign = assign;
exports.block = block;
exports.bool = bool;
exports.child = child;
exports.childArr = childArr;
exports.clone = clone;
exports.consume = consume;
exports.consumeRange = consumeRange;
exports.detach = detach;
exports.dft = dft;
exports.empty = empty;
exports.error = error;
exports.fromIterable = fromIterable;
exports.hier = hier;
exports.id = id;
exports.insertAfter = insertAfter;
exports.insertBefore = insertBefore;
exports.lookahead = lookahead;
exports.next = next;
exports.node = node;
exports.num = num;
exports.prepend = prepend;
exports.prev = prev;
exports.produce = produce;
exports.produceNode = produceNode;
exports.replace = replace;
exports.resetFieldInfo = resetFieldInfo;
exports.result = result;
exports.share = share;
exports.skip = skip;
exports.str = str;
exports.toArray = toArray;
exports.tok = tok;
var _types = require("./types");
var _config = require("./config");
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
* drafts for the next version
*
* V2 (unlike V1) doesn't have tokens wraps all information
* is stored directly in the Value, no entering and closing tokens
*
* # DOM-like AST representation
*
* type Value = {
* pos: Pos,
* type: Type,
* node: BabelNode,
* parent: Value | null,
* id: number,
* nextSibling: Value,
* prevSibling: Value,
* // .....
* }
*
*/
let valCount = 0;
function empty() {
const res = {
type: _types.Tag.Empty,
pos: _types.Tag.Empty,
id: valCount++,
level: 0,
node: null,
parent: null,
data: null
//pure: false
};
res.prevSibling = res;
res.nextSibling = res;
res.firstChild = null;
return res;
}
/**
* detaches `node` from the tree
*/
function detach(node) {
const {
nextSibling,
parent
} = node;
(nextSibling.prevSibling = node.prevSibling).nextSibling = nextSibling;
if (parent && parent.firstChild === node) {
if (nextSibling === node) parent.firstChild = null;else parent.firstChild = nextSibling;
}
node.nextSibling = node.prevSibling = node;
node.parent = null;
return node;
}
/** inserts sibling `node` after `pos` node */
function insertAfter(pos, node) {
const {
nextSibling
} = pos;
node.prevSibling = pos;
node.nextSibling = nextSibling;
nextSibling.prevSibling = pos.nextSibling = node;
node.parent = pos.parent;
return node;
}
/**
* inserts sibling `child` before `pos`
* - expects `last` of the both nodes
*/
function insertBefore(pos, node) {
const {
prevSibling
} = pos;
node.nextSibling = pos;
node.prevSibling = prevSibling;
prevSibling.nextSibling = pos.prevSibling = node;
const parent = pos.parent;
node.parent = parent;
if (parent.firstChild === pos) parent.firstChild = node;
return node;
}
/** makes `child` to be the last child of `parent` */
function append(parent, child) {
const old = parent.firstChild;
if (old) return insertAfter(old.prevSibling, child);
child.parent = parent;
return parent.firstChild = child;
}
/** makes `child` to be the first child of `parent` */
function prepend(parent, child) {
const old = parent.firstChild;
if (old) return insertBefore(old, child);
child.parent = parent;
parent.firstChild = child;
return child;
}
/**
* replaces node `from` by `to`
* - expects `last` of both
*/
function replace(from, to) {
insertAfter(from, to);
detach(from);
return to;
}
/** builds default DOM node */
function node(pos, type) {
return tok(pos, type, {
type: ""
});
}
/** builds DOM node for `=` assignments */
function assign(pos) {
return tok(pos, _types.Tag.AssignmentExpression, {
operator: "="
});
}
/** builds DOM node for an identifier with symbol */
function id(pos, sym) {
const res = node(pos, _types.Tag.Identifier);
res.sym = sym;
return res;
}
/** builds DOM node for array */
function arr(pos) {
return tok(pos, _types.Tag.Array, [], null);
}
function childArr(pos, par) {
const res = tok(pos, _types.Tag.Array, [], null);
append(par, res);
return res;
}
function block(pos, par) {
const res = node(pos, _types.Tag.BlockStatement);
append(res, arr(_types.Tag.body));
append(par, res);
return res;
}
function appendBlock(pos, par) {
const block = node(pos, _types.Tag.BlockStatement);
const res = childArr(_types.Tag.body, block);
append(par, block);
return res;
}
/** builds DOM node for a numeric constant */
function num(pos, value) {
return tok(pos, _types.Tag.NumericLiteral, {
value
});
}
/** builds DOM node for a string constant */
function str(pos, value) {
return tok(pos, _types.Tag.StringLiteral, {
value
});
}
/** builds DOM node for a boolean constant */
function bool(pos, value) {
return tok(pos, _types.Tag.BooleanLiteral, {
value
});
}
/** builds DOM node */
function tok(pos, type, node) {
const res = empty();
res.pos = pos;
res.type = type;
res.node = node;
return res;
}
/* same as `tok` but also sets `parent` */
function child(pos, type, node, parent) {
const res = tok(pos, type, node);
res.parent = parent;
return res;
}
function Share(inner) {
this.inner = inner[Symbol.iterator]();
}
Share.prototype[Symbol.iterator] = function () {
return this;
};
Share.prototype.next = function () {
return this.inner.next();
};
/** returns same iterable which ignores `return` method call */
function share(inner) {
return new Share(inner);
}
function* hierImpl(s) {
let last = null;
for (const i of s) {
const level = i.level = i.parent ? i.parent.level + 1 : 0;
if (last) for (let j = level, till = last.level; j <= till; ++j, last = last.parent) yield {
start: false,
value: last
};
last = i;
yield {
start: true,
value: i
};
}
for (; last && last.pos !== _types.Tag.root; last = last.parent) yield {
start: false,
value: last
};
}
/**
* converts each element of `s:Iterable<Value>` into two elements
* `{start:boolean,value:Value}` with `start:true` on entering the token
* and `start:false` on exit
*/
function hier(inner) {
return share(hierImpl(inner));
}
function Reset(inner) {
const iter = this.inner = inner[Symbol.iterator]();
const item = iter.next();
if (item.done) {
this.first = this.buf = null;
return;
}
const buf = item.value;
const first = buf.parent;
buf.prev = first;
first.next = buf;
first.level = 0;
this.buf = buf;
this.first = first;
this.levels = [first, null];
}
Reset.prototype[Symbol.iterator] = function () {
return this;
};
Reset.prototype.next = function () {
const value = this.step();
return value ? {
done: false,
value
} : {
done: true
};
};
Reset.prototype.step = function step() {
const cur = this.buf;
if (!cur) return null;
const nextItem = this.inner.next();
const levels = this.levels;
if (nextItem.done) {
const first = this.first;
cur.nextSibling = first;
this.buf = null;
return cur;
}
const next = nextItem.value;
const level = next.parent.level + 1;
const prevSibling = levels[level];
levels[level] = cur;
if (prevSibling) {
prevSibling.nextSibling = next;
next.prevSibling = prevSibling;
} else {
next.parent.firstChild = next;
next.prevSibling = next;
}
levels[level + 1] = null;
this.buf = next;
cur.nextSibling = next;
return cur;
};
/**
* takes an iterable of values and returns another iterable
* with same elements but all the DOM fields re-calculated
* this calculates only 1 token ahead
*/
function lookahead(s) {
return new Reset(s);
}
/**
* converts AST `node` into the AST representation with
*/
function produceNode(pos, babelNode) {
if (Array.isArray(babelNode)) {
const res = arr(pos);
for (const i of babelNode) append(res, i ? produceNode(_types.Tag.push, i) : tok(_types.Tag.push, _types.Tag.Null, null));
return res;
}
const type = babelNode.type;
const keys = _types.VISITOR_KEYS[type];
const res = tok(pos, _types.Tag[type], babelNode);
if (keys.length) {
for (const i of keys) {
const v = babelNode[i];
if (v != null) append(res, produceNode(_types.Tag[i], v));
}
}
return res;
}
/** next node strictly after `node` */
function after(node) {
for (let i = node;;) {
const {
parent,
nextSibling
} = i;
if (!parent) return nextSibling;
if (nextSibling !== parent.firstChild) return nextSibling;
i = parent;
}
}
/** next node in DFT order after `node` */
function next(node) {
return node.firstChild || after(node);
}
/** prev node in DFT order before `node` */
function prev(node) {
const {
parent
} = node;
if (parent && parent.firstChild === node) return parent;
for (let i = node.prevSibling;;) {
const {
firstChild
} = i;
if (!firstChild) return i;
i = firstChild.prevSibling;
}
}
/** traverses range [from,to) */
function* dft(from, to = from.nextSibling) {
let i = from;
do {
const n = next(i);
yield i;
i = n;
} while (i !== to);
}
/**
* like `produce` but wraps the resulting node with `Tag.root` element
*/
function produce(babelNode) {
const root = node(_types.Tag.root, _types.Tag.Root);
append(root, produceNode(_types.Tag.top, babelNode));
return root;
}
/**
* converts DOM root node into a babel AST node
*/
function consume(root) {
consumeRange(root.firstChild, root);
return root.firstChild.node;
}
/**
* resets babel AST properties in [from..to) range
*/
function consumeRange(from, to) {
for (const i of dft(from, to)) {
const {
parent,
node
} = i;
if (parent) {
if (i.pos === _types.Tag.push) {
parent.node.push(node);
} else parent.node[(0, _types.symName)(i.pos)] = node;
}
if (i.type === _types.Tag.Array) node.length = 0;else if (i.type === _types.Tag.Null) i.node = null;else {
const ti = (0, _types.symInfo)(i.type);
if (ti) {
if (ti.esType != null) i.node.type = ti.esType;
if (ti.fields) Object.assign(i.node, ti.fields);
}
}
}
}
/**
* Resets `fieldInfo` field in each `value`.
* The field descripts AST node context.
*/
function resetFieldInfo(root) {
root.typeInfo = (0, _types.typeInfo)(root);
let i = root;
do {
let f = i.parent && i.parent.typeInfo;
if (f && f.fieldsMap) f = i.fieldInfo = f.fieldsMap.get(i.pos);
let ti = f && f.ti || (0, _types.typeInfo)(i);
switch (i.type) {
case _types.Tag.Array:
ti = f;
break;
case _types.Tag.ArrayPattern:
ti = f && f.declVar ? _types.arrayPattern : _types.arrayAssignmentPattern;
break;
case _types.Tag.ObjectPattern:
ti = f && f.declVar ? _types.objectPattern : _types.objectAssignmentPattern;
break;
case _types.Tag.RestElement:
ti = f && f.declVar ? _types.restElement : _types.restElementAssignment;
break;
case _types.Tag.AssignmentExpression:
ti = i.node.operator === "=" ? _types.assignmentOpEq : _types.assignmentOpDefault;
break;
case _types.Tag.ObjectProperty:
if (i.node.computed) ti = ti.propAlt;else if (f && f.declVar) ti = _types.assignmentProperty;
break;
case _types.Tag.AssignmentPattern:
if (!f || !f.declVar) ti = (0, _types.symInfo)(_types.Tag.AssignmentExpression);
break;
case _types.Tag.MemberExpression:
case _types.Tag.ObjectMethod:
case _types.Tag.ClassProperty:
case _types.Tag.ClassMethod:
case _types.Tag.ClassPrivateMethod:
case _types.Tag.ClassPrivateProperty:
if (i.node.computed) ti = ti.propAlt;
break;
}
i.typeInfo = ti;
} while ((i = next(i)) !== root);
return root;
}
/** runs iterable `s` and ignores its output, returns its result */
function skip(s) {
const iter = s[Symbol.iterator]();
let item;
for (; !(item = iter.next()).done;) {}
return item.value;
}
function error(msg, doc) {
const file = _config.default.babelFile;
if (!file) return new SyntaxError(msg);
for (let i = doc; i; i = i.parent) {
if (i.node.loc || i.node._loc) return file.buildCodeFrameError(i.node, msg);
}
return file.buildCodeFrameError(doc.node, msg);
}
/** same as `Array.from` but outputs the array into `buf` and returns iterable result */
function result(s, buf) {
const iter = s[Symbol.iterator]();
let item;
while (!(item = iter.next()).done) buf.push(item.value);
return item.value;
}
/**
* same as `Array.from` but returns `s` if it is already `Array`
*/
function toArray(s) {
if (Array.isArray(s)) return s;
const res = [];
result(s, res);
return res;
}
/** converts stream to a fully calculated DOM node */
function fromIterable(s) {
const iter = lookahead(s);
while (iter.step()) {}
return iter.first;
}
/** returns all ancestors of `node` (until and including root) */
function* ancestors(value) {
for (let i = value.parent; i; i = i.parent) yield i;
}
function clone(doc) {
if (!doc) return doc;
let i = doc;
do {
const node = i.node;
i.data = _objectSpread(_objectSpread({}, i), {}, {
node: Array.isArray(node) ? _toConsumableArray(node) : _objectSpread({}, node),
id: valCount++
});
} while ((i = next(i)) !== doc);
i = doc;
do {
const {
data
} = i;
if (i.parent) data.parent = i.parent.data;
if (i.firstChild) data.firstChild = i.firstChild.data;
data.prevSibling = i.prevSibling.data;
data.nextSibling = i.nextSibling.data;
} while ((i = next(i)) !== doc);
const res = doc.data;
do {
i.data = null;
} while ((i = next(i)) !== doc);
res.prevSibling = res.nextSibling = res;
return res;
}