UNPKG

@udraft/cursor

Version:

uDraft Cursor enables you to declarative write code generators!

296 lines 10.4 kB
"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