@shopify/theme-language-server-common
Version:
<h1 align="center" style="position: relative;" > <br> <img src="https://github.com/Shopify/theme-check-vscode/blob/main/images/shopify_glyph.png?raw=true" alt="logo" width="141" height="160"> <br> Theme Language Server </h1>
88 lines • 2.82 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.findCurrentNode = exports.forEachChildNodes = exports.visit = void 0;
function isNode(x) {
return x !== null && typeof x === 'object' && typeof x.type === 'string';
}
/**
* @example
*
* const links = visit<'LiquidHTML', DocumentLink>(liquidAST, {
* 'LiquidTag': (node, ancestors) => {
* if (node.name === 'render' || node.name === 'include') {
* return DocumentLink.create(...);
* }
* },
* })
*
* Note: this is the ChatGPT-rewritten version of the recursive method.
* If you want to refactor it, just ask it to do it for you :P
*/
function visit(node, visitor) {
const results = [];
const stack = [{ node, lineage: [] }];
const pushStack = (node, lineage) => stack.push({ node, lineage });
while (stack.length > 0) {
// Visit current node
const { node, lineage } = stack.pop();
const visitNode = visitor[node.type];
const result = visitNode ? visitNode(node, lineage) : undefined;
if (Array.isArray(result)) {
results.push(...result);
}
else if (result !== undefined) {
results.push(result);
}
// Enqueue child nodes
forEachChildNodes(node, lineage.concat(node), pushStack);
}
return results;
}
exports.visit = visit;
function forEachChildNodes(node, lineage, execute) {
for (const value of Object.values(node)) {
if (Array.isArray(value)) {
for (let i = value.length - 1; i >= 0; i--) {
execute(value[i], lineage);
}
}
else if (isNode(value)) {
execute(value, lineage);
}
}
}
exports.forEachChildNodes = forEachChildNodes;
function findCurrentNode(ast, cursorPosition) {
let prev;
let current = ast;
let ancestors = [];
while (current !== prev) {
prev = current;
forEachChildNodes(current, ancestors.concat(current), (child, lineage) => {
if (isUnclosed(child) ||
(isCovered(child, cursorPosition) && size(child) <= size(current))) {
current = child;
ancestors = lineage;
}
});
}
return [current, ancestors];
}
exports.findCurrentNode = findCurrentNode;
function isCovered(node, offset) {
return node.position.start < offset && offset <= node.position.end;
}
function size(node) {
return node.position.end - node.position.start;
}
function isUnclosed(node) {
var _a;
if ('blockEndPosition' in node) {
return ((_a = node.blockEndPosition) === null || _a === void 0 ? void 0 : _a.end) === -1;
}
else if ('children' in node) {
return node.children.length > 0;
}
return false;
}
//# sourceMappingURL=visitor.js.map
;