@udraft/cursor
Version:
uDraft Cursor enables you to declarative write code generators!
296 lines • 10.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UCursor = void 0;
class UCursor {
constructor() {
this._children = [];
this._identationSize = null;
this._identationChar = null;
this._block = null;
this._prefix = "";
this._suffix = "";
this._move = 0;
this._selector = null;
this._parent = null;
this._transformers = [];
this._template = "";
this._clearSelections = false;
this._eachJoin = "";
}
$children() {
return [...this._children];
}
$parent() {
return this._parent;
}
$blocks(root = false) {
let parent = this.$parent();
let blocks = 0;
if (!root && this._block)
blocks += 1;
if (parent)
blocks += parent.$blocks();
blocks += this._move;
if (blocks < 0)
blocks = 0;
return blocks;
}
$identationChar() {
let parent = this.$parent();
if (parent && this._identationChar === null)
return parent.$identationChar();
return this._identationChar;
}
$identationSize() {
let parent = this.$parent();
if (parent && this._identationSize === null)
return parent.$identationSize();
return this._identationSize;
}
$identation() {
let identationSize = this.$identationSize();
let identationChar = this.$identationChar();
return {
root: "".padStart(this.$blocks(true) * (identationSize !== null && identationSize !== void 0 ? identationSize : 0), identationChar !== null && identationChar !== void 0 ? identationChar : ""),
children: "".padStart(this.$blocks(false) * (identationSize !== null && identationSize !== void 0 ? identationSize : 0), identationChar !== null && identationChar !== void 0 ? identationChar : ""),
};
}
$seletion(input) {
if (!this._selector)
return [
{
params: [],
content: "",
pos: input.length,
},
];
return Array.from(input.matchAll(this._selector)).map((match) => ({
pos: match.index,
content: match[0],
params: match.slice(1),
}));
}
move(amount) {
this._move = amount;
return this;
}
block(start, end) {
this._block = [start, end];
return this;
}
template(template) {
this._template = template;
return this;
}
clean(clearSelections = true) {
this._clearSelections = clearSelections;
return this;
}
prefix(prefix) {
this._prefix = prefix;
return this;
}
suffix(suffix) {
this._suffix = suffix;
return this;
}
join(str) {
this._eachJoin = str;
return this;
}
select(selector) {
this._selector = selector;
return this;
}
noIdent() {
this._identationChar = "";
this._identationSize = 0;
return this;
}
ident({ size: identation, char }) {
if (identation)
this._identationSize = identation;
if (char)
this._identationChar = char;
return this;
}
parent(parent) {
this._parent = parent;
return this;
}
empty(write) {
const key = "_cursorWithEmptyData";
const nestedCursor = new UCursor();
nestedCursor.parent(this);
this._children.push({ key, cursor: nestedCursor, each: false });
nestedCursor._transformers.push({
key: "_cursorWithEmptyData",
transformer: write,
each: false,
});
return this;
}
linebreak(amount = 1) {
return this.empty(() => "".padStart(amount, "\n"));
}
expand(expanded) {
const expandedCursor = new UCursor();
expandedCursor.parent(this);
this._children.push({
key: "_expandedCursor",
cursor: expandedCursor,
each: false,
});
expanded(expandedCursor);
return this;
}
in(key, nested) {
const nestedCursor = new UCursor();
nestedCursor.parent(this);
this._children.push({ key, cursor: nestedCursor, each: false });
nested(nestedCursor);
return this;
}
each(key, nested) {
const nestedCursor = new UCursor();
nestedCursor.parent(this);
this._children.push({ key, cursor: nestedCursor, each: true });
nested(nestedCursor);
return this;
}
writeFrom(key, transformer) {
this._transformers.push({ key, transformer, each: false });
return this;
}
writeFromEach(key, transformer) {
this._transformers.push({
key,
transformer: transformer,
each: true,
});
return this;
}
write(transformer) {
this._transformers.push({
key: "_cursorRoot",
transformer: transformer,
each: false,
});
return this;
}
render(data, input, meta) {
input = input !== null && input !== void 0 ? input : this._template;
let output = input;
const selections = this.$seletion(input);
const identation = this.$identation();
let transformers = [];
const lastLineIsEmpty = (str) => str.split("\n").slice(-1)[0].length == 0;
const applyIdentation = (str, identation) => str
.split("\n")
.map((l) => (!!l ? identation + l : l))
.join("\n");
transformers.push(...this._transformers);
for (const { key, each, transformer } of transformers) {
if (!transformer)
continue;
const transformSelections = (transformerData, transformerMeta) => {
var _a, _b;
for (const selection of selections) {
if (selection.ignore)
continue;
let transformed = (lastLineIsEmpty(output) ? identation.root : "") +
transformer(transformerData, selection, transformerMeta);
const selectionInTransform = this._selector
? (_a = Array.from(transformed.matchAll(this._selector))[0]) !== null && _a !== void 0 ? _a : null
: null;
const extraLength = selectionInTransform
? transformed.length - selection.content.length
: transformed.length;
output =
output.slice(0, selection.pos) +
transformed +
output.slice(selection.pos + selection.content.length);
selections
.filter((s) => s != selection)
.forEach((s) => {
if (s.pos > selection.pos)
s.pos += extraLength;
});
if (selection.content && !selectionInTransform)
selection.ignore = true;
else {
const addToPos = selectionInTransform
? (_b = selectionInTransform.index) !== null && _b !== void 0 ? _b : 0
: transformed.length;
selection.pos += addToPos;
}
}
};
const root = key === "_cursorRoot";
const ignoreEmptyData = key === "_cursorWithEmptyData";
const dataSrc = root ? data : (data || [])[key];
if ((data === undefined || dataSrc === undefined) && !ignoreEmptyData)
continue;
if (each) {
const total = Object.keys(dataSrc || []).length;
for (const i in dataSrc) {
const index = parseInt(i + "");
transformSelections(dataSrc[i], {
index,
total,
isLast: index == total - 1,
});
}
}
else
transformSelections(dataSrc, {});
}
if (this._block)
output +=
(lastLineIsEmpty(output) ? identation.root : "") +
(this._block[0] + "\n");
for (const { key, each, cursor } of this._children) {
const cursorIdentation = cursor.$identation();
let cursorOutput = applyIdentation(cursor._prefix, cursorIdentation.root);
if (each) {
const total = Object.keys(data[key] || []).length;
for (const i in data[key]) {
const index = parseInt(i + "");
cursorOutput = cursor.render(data[key][i], cursorOutput, {
noFix: true,
});
if (total > 1 && index < total - 1)
cursorOutput += cursor._eachJoin;
}
}
else {
cursorOutput = cursor.render(key == "_expandedCursor" ? data : data[key], cursorOutput, { noFix: true });
}
if (cursor._suffix) {
const identedSuffix = applyIdentation(cursor._suffix, cursorIdentation.root);
cursorOutput += identedSuffix.slice(identedSuffix[0] == "\n" || lastLineIsEmpty(cursorOutput)
? 0
: cursorIdentation.root.length);
}
output += cursorOutput;
}
if (this._block)
output += "\n" + identation.root + this._block[1];
if (!(meta === null || meta === void 0 ? void 0 : meta.noFix))
output = this._prefix + output + this._suffix;
if (!this.$parent()) {
output = this._clean(output);
}
return output;
}
_clean(output) {
if (this._clearSelections && this._selector)
output = output.replace(this._selector, "");
this._children.forEach((child) => {
output = child.cursor._clean(output);
});
return output;
}
}
exports.UCursor = UCursor;
//# sourceMappingURL=cursor.js.map