'use strict'; var language = require('@codemirror/language'); var langHtml = require('@codemirror/lang-html'); var highlight = require('@lezer/highlight'); var common = require('@lezer/common'); var lr = require('@lezer/lr'); var state = require('@codemirror/state'); var view = require('@codemirror/view'); // This file was generated by lezer-generator. You probably shouldn't edit it. const interpolationStart = 1, tagStart = 2, endTagStart = 3, text = 180, endrawTagStart = 4, rawText = 181, endcommentTagStart = 5, commentText = 182; function wordChar(code) { return code >= 65 && code <= 90 || code >= 97 && code <= 122; } const base = new lr.ExternalTokenizer(input => { let start = input.pos; for (;;) { let { next } = input; if (next < 0) break; if (next == 123 /* Ch.BraceL */) { let after = input.peek(1); if (after == 123 /* Ch.BraceL */) { if (input.pos > start) break; input.acceptToken(interpolationStart, 2); return; } else if (after == 37 /* Ch.Percent */) { if (input.pos > start) break; let scan = 2, size = 2; for (;;) { let next = input.peek(scan); if (next == 32 /* Ch.Space */ || next == 10 /* Ch.Newline */) { ++scan; } else if (next == 35 /* Ch.Hash */) { ++scan; for (;;) { let comment = input.peek(scan); if (comment < 0 || comment == 10 /* Ch.Newline */) break; scan++; } } else if (next == 45 /* Ch.Dash */ && size == 2) { size = ++scan; } else { let end = next == 101 /* Ch.e */ && input.peek(scan + 1) == 110 /* Ch.n */ && input.peek(scan + 2) == 100 /* Ch.d */; input.acceptToken(end ? endTagStart : tagStart, size); return; } } } } input.advance(); if (next == 10 /* Ch.Newline */) break; } if (input.pos > start) input.acceptToken(text); }); function rawTokenizer(endTag, text, tagStart) { return new lr.ExternalTokenizer(input => { let start = input.pos; for (;;) { let { next } = input; if (next == 123 /* Ch.BraceL */ && input.peek(1) == 37 /* Ch.Percent */) { let scan = 2; for (;; scan++) { let ch = input.peek(scan); if (ch != 32 /* Ch.Space */ && ch != 10 /* Ch.Newline */) break; } let word = ""; for (;; scan++) { let next = input.peek(scan); if (!wordChar(next)) break; word += String.fromCharCode(next); } if (word == endTag) { if (input.pos > start) break; input.acceptToken(tagStart, 2); break; } } else if (next < 0) { break; } input.advance(); if (next == 10 /* Ch.Newline */) break; } if (input.pos > start) input.acceptToken(text); }); } const comment = rawTokenizer("endcomment", commentText, endcommentTagStart); const raw = rawTokenizer("endraw", rawText, endrawTagStart); // This file was generated by lezer-generator. You probably shouldn't edit it. const spec_identifier = {__proto__:null,contains:32, or:36, and:36, true:50, false:50, empty:52, forloop:54, tablerowloop:56, continue:58, in:128, with:194, for:196, as:198, if:234, endif:238, unless:244, endunless:248, elsif:252, else:256, case:262, endcase:266, when:270, endfor:278, tablerow:284, endtablerow:288, break:292, cycle:298, echo:302, render:306, include:312, assign:316, capture:322, endcapture:326, increment:330, decrement:334}; const spec_TagName = {__proto__:null,if:82, endif:86, elsif:90, else:94, unless:100, endunless:104, case:110, endcase:114, when:118, for:126, endfor:136, tablerow:142, endtablerow:146, break:150, continue:154, cycle:158, comment:164, endcomment:170, raw:176, endraw:182, echo:186, render:190, include:202, assign:206, capture:212, endcapture:216, increment:220, decrement:224, liquid:228}; const parser = lr.LRParser.deserialize({ version: 14, states: "HOQYOPOOOOOP'#F{'#F{OeOXO'#CdOsQWO'#CfO!bQ`O'#DQO#{OPO'#DTO$ZOPO'#D^O$iOPO'#DcO$wOPO'#DkO%VOPO'#DsO%eOSO'#EOO%jOQO'#EUO%oOPO'#EhOOOP'#G`'#G`OOOP'#G]'#G]OOOP'#Fz'#FzQYOPOOOOOP-E9y-E9yOOQO'#Cg'#CgO&`QpO,59QO&gQpO'#G^OsQWO'#CsOOQO'#G^'#G^OOOP,59l,59lO)PQWO,59lOsQWO,59pOsQWO,59tO)ZQWO,59vOsQWO,59yOsQWO,5:OOsQWO,5:SO!]QWO,5:WO!]QWO,5:`O)`QWO,5:dO)eQWO,5:fO)jQWO,5:hO)oQWO,5:kO)tQWO,5:qOsQWO,5:vOsQWO,5:xOsQWO,5;OOsQWO,5;QOsQWO,5;TOsQWO,5;XOsQWO,5;ZO+TQWO,5;]O+[OPO'#CdOOOP,59o,59oO#{OPO,59oO+jQ`O'#DWOOOP,59x,59xO$ZOPO,59xO+oQ`O'#DaOOOP,59},59}O$iOPO,59}O+tQ`O'#DfOOOP,5:V,5:VO$wOPO,5:VO+yQ`O'#DqOOOP,5:_,5:_O%VOPO,5:_O,OQ`O'#DvOOOS'#GQ'#GQO,TOSO'#ERO,]OSO,5:jOOOQ'#GR'#GRO,bOQO'#EXO,jOQO,5:pOOOP,5;S,5;SO%oOPO,5;SO,oQ`O'#EkOOOP-E9x-E9xO,tQ!bO,59SOsQWO,59VOsQWO,59VO,yQWO'#C|OOQO'#F|'#F|O-OQWO1G.lOOOP1G.l1G.lOsQWO,59VOsQWO,59ZO-WQpO,59_O-iQpO1G/WO-pQWO1G/WOOOP1G/W1G/WO-xQpO1G/[O.ZQpO1G/`OOOP1G/b1G/bO.lQpO1G/eO.}QpO1G/jO/qQpO1G/nO/xQWO1G/rO/}QWO1G/zOOOP1G0O1G0OOOOP1G0Q1G0QO0SQWO1G0SOOOS1G0V1G0VOOOQ1G0]1G0]O0_QpO1G0bO0fQpO1G0dO1QQpO1G0jO1cQpO1G0lO1jQpO1G0oO1{QpO1G0sO2^QpO1G0uO2oQWO'#EsO2vQWO'#ExO2}QWO'#FRO3UQWO'#FYO3]QWO'#F^O3dQWO'#FqOOQO'#Ga'#GaOOQO'#GT'#GTO3kQWO1G0wOsQWO'#EtOsQWO'#EyOsQWO'#E}OOQO'#FP'#FPOsQWO'#FSOsQWO'#FWO!]QWO'#FZO!]QWO'#F_OOQO'#Fc'#FcOOQO'#Fe'#FeO3rQWO'#FfOsQWO'#FhOsQWO'#FjOsQWO'#FmOsQWO'#FoOsQWO'#FrOsQWO'#FvOsQWO'#FxOOOP1G0w1G0wOOOP1G/Z1G/ZO3wQWO,59rOOOP1G/d1G/dO3|QWO,59{OOOP1G/i1G/iO4RQWO,5:QOOOP1G/q1G/qO4WQWO,5:]OOOP1G/y1G/yO4]QWO,5:bOOOS-E:O-E:OOOOP1G0U1G0UO4bQ`O'#ESOOOQ-E:P-E:POOOP1G0[1G0[O4gQ`O'#EYOOOP1G0n1G0nO4lQWO,5;VOOQO1G.n1G.nOOQO1G.q1G.qO7QQpO1G.qOOQO'#DO'#DOO7[QWO,59hOOQO-E9z-E9zOOOP7+$W7+$WO9UQpO1G.qO9`QpO1G.uOsQWO1G.yO;uQWO7+$rOOOP7+$r7+$rOOOP7+$v7+$vOOOP7+$z7+$zOOOP7+%P7+%POOOP7+%U7+%UOsQWO'#F}O;}QWO7+%YOOOP7+%Y7+%YOsQWO7+%^OsQWO7+%fOrQpO,5;eO@]QpO,5;iOBYQpO,5;nOCsQpO,5;rOEfQWO,5;uOEkQWO,5;yOEpQWO,5dOOOPAN>dAN>dO!7QQWOAN>lOOOPAN>lAN>lO!7YQWOAN>tOOOPAN>tAN>tOsQWO1G0fO!]QWO1G0fO!7bQpO7+&{O!8qQpO7+'PO!:QQWO7+'WO!;tQWO,5 spec_identifier[value] || -1},{term: 37, get: (value) => spec_TagName[value] || -1}], tokenPrec: 0 }); function completions(words, type) { return words.split(" ").map(label => ({ label, type })); } const Filters = completions("abs append at_least at_most capitalize ceil compact concat date default " + "divided_by downcase escape escape_once first floor join last lstrip map minus modulo " + "newline_to_br plus prepend remove remove_first replace replace_first reverse round rstrip " + "size slice sort sort_natural split strip strip_html strip_newlines sum times truncate " + "truncatewords uniq upcase url_decode url_encode where", "function"); const Tags = completions("cycle comment endcomment raw endraw echo increment decrement liquid if elsif " + "else endif unless endunless case endcase for endfor tablerow endtablerow break continue " + "assign capture endcapture render include", "keyword"); const Expressions = completions("empty forloop tablerowloop in with as contains", "keyword"); const forloop = completions("first index index0 last length rindex", "property"); const tablerowloop = completions("col col0 col_first col_last first index index0 last length rindex rindex0 row", "property"); function findContext(context) { var _a; let { state, pos } = context; let node = language.syntaxTree(state).resolveInner(pos, -1).enterUnfinishedNodesBefore(pos); let before = ((_a = node.childBefore(pos)) === null || _a === void 0 ? void 0 : _a.name) || node.name; if (node.name == "FilterName") return { type: "filter", node }; if (context.explicit && before == "|") return { type: "filter" }; if (node.name == "TagName") return { type: "tag", node }; if (context.explicit && before == "{%") return { type: "tag" }; if (node.name == "PropertyName" && node.parent.name == "MemberExpression") return { type: "property", node, target: node.parent }; if (node.name == "." && node.parent.name == "MemberExpression") return { type: "property", target: node.parent }; if (node.name == "MemberExpression" && before == ".") return { type: "property", target: node }; if (node.name == "VariableName") return { type: "expression", from: node.from }; let word = context.matchBefore(/[\w\u00c0-\uffff]+$/); if (word) return { type: "expression", from: word.from }; if (context.explicit && node.name != "CommentText" && node.name != "StringLiteral" && node.name != "NumberLiteral" && node.name != "InlineComment") return { type: "expression" }; return null; } function resolveProperties(state, node, context, properties) { let path = []; for (;;) { let obj = node.getChild("Expression"); if (!obj) return []; if (obj.name == "forloop") { return path.length ? [] : forloop; } else if (obj.name == "tablerowloop") { return path.length ? [] : tablerowloop; } else if (obj.name == "VariableName") { path.unshift(state.sliceDoc(obj.from, obj.to)); break; } else if (obj.name == "MemberExpression") { let name = obj.getChild("PropertyName"); if (name) path.unshift(state.sliceDoc(name.from, name.to)); node = obj; } else { return []; } } return properties ? properties(path, state, context) : []; } /** Returns a completion source for liquid templates. Optionally takes a configuration that adds additional custom completions. */ function liquidCompletionSource(config = {}) { let filters = config.filters ? config.filters.concat(Filters) : Filters; let tags = config.tags ? config.tags.concat(Tags) : Tags; let exprs = config.variables ? config.variables.concat(Expressions) : Expressions; let { properties } = config; return (context) => { var _a; let cx = findContext(context); if (!cx) return null; let from = (_a = cx.from) !== null && _a !== void 0 ? _a : (cx.node ? cx.node.from : context.pos); let options; if (cx.type == "filter") options = filters; else if (cx.type == "tag") options = tags; else if (cx.type == "expression") options = exprs; else /* property */ options = resolveProperties(context.state, cx.target, context, properties); return options.length ? { options, from, validFor: /^[\w\u00c0-\uffff]*$/ } : null; }; } /** This extension will, when the user types a `%` between two matching braces, insert two percent signs instead and put the cursor between them. */ const closePercentBrace = view.EditorView.inputHandler.of((view, from, to, text) => { if (text != "%" || from != to || view.state.doc.sliceString(from - 1, to + 1) != "{}") return false; view.dispatch(view.state.changeByRange(range => ({ changes: { from: range.from, to: range.to, insert: "%%" }, range: state.EditorSelection.cursor(range.from + 1) })), { scrollIntoView: true, userEvent: "input.type" }); return true; }); function directiveIndent(except) { return (context) => { let back = except.test(context.textAfter); return context.lineIndent(context.node.from) + (back ? 0 : context.unit); }; } const tagLanguage = language.LRLanguage.define({ name: "liquid", parser: parser.configure({ props: [ highlight.styleTags({ "cycle comment endcomment raw endraw echo increment decrement liquid in with as": highlight.tags.keyword, "empty forloop tablerowloop": highlight.tags.atom, "if elsif else endif unless endunless case endcase for endfor tablerow endtablerow break continue": highlight.tags.controlKeyword, "assign capture endcapture": highlight.tags.definitionKeyword, "contains": highlight.tags.operatorKeyword, "render include": highlight.tags.moduleKeyword, VariableName: highlight.tags.variableName, TagName: highlight.tags.tagName, FilterName: highlight.tags.function(highlight.tags.variableName), PropertyName: highlight.tags.propertyName, CompareOp: highlight.tags.compareOperator, AssignOp: highlight.tags.definitionOperator, LogicOp: highlight.tags.logicOperator, NumberLiteral: highlight.tags.number, StringLiteral: highlight.tags.string, BooleanLiteral: highlight.tags.bool, InlineComment: highlight.tags.lineComment, CommentText: highlight.tags.blockComment, "{% %} {{ }}": highlight.tags.brace, "( )": highlight.tags.paren, ".": highlight.tags.derefOperator, ", .. : |": highlight.tags.punctuation }), language.indentNodeProp.add({ Tag: language.delimitedIndent({ closing: "%}" }), "UnlessDirective ForDirective TablerowDirective CaptureDirective": directiveIndent(/^\s*(\{%-?\s*)?end\w/), IfDirective: directiveIndent(/^\s*(\{%-?\s*)?(endif|else|elsif)\b/), CaseDirective: directiveIndent(/^\s*(\{%-?\s*)?(endcase|when)\b/), }), language.foldNodeProp.add({ "UnlessDirective ForDirective TablerowDirective CaptureDirective IfDirective CaseDirective RawDirective Comment"(tree) { let first = tree.firstChild, last = tree.lastChild; if (!first || first.name != "Tag") return null; return { from: first.to, to: last.name == "EndTag" ? last.from : tree.to }; } }) ] }), languageData: { commentTokens: { line: "#" }, indentOnInput: /^\s*{%-?\s*(?:end|elsif|else|when|)$/ } }); const baseHTML = langHtml.html(); function makeLiquid(base) { return tagLanguage.configure({ wrap: common.parseMixed(node => node.type.isTop ? { parser: base.parser, overlay: n => n.name == "Text" || n.name == "RawText" } : null) }, "liquid"); } /** A language provider for Liquid templates. */ const liquidLanguage = makeLiquid(baseHTML.language); /** Liquid template support. */ function liquid(config = {}) { let base = config.base || baseHTML; let lang = base.language == baseHTML.language ? liquidLanguage : makeLiquid(base.language); return new language.LanguageSupport(lang, [ base.support, lang.data.of({ autocomplete: liquidCompletionSource(config) }), base.language.data.of({ closeBrackets: { brackets: ["{"] } }), closePercentBrace ]); } exports.closePercentBrace = closePercentBrace; exports.liquid = liquid; exports.liquidCompletionSource = liquidCompletionSource; exports.liquidLanguage = liquidLanguage;