UNPKG

volar-service-pug

Version:
276 lines 10.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.baseParse = baseParse; const muggle_string_1 = require("muggle-string"); const pugLex = require("pug-lexer"); const vscode_languageserver_textdocument_1 = require("vscode-languageserver-textdocument"); const buildMappings_1 = require("./buildMappings"); const pugParser = require('pug-parser'); function baseParse(pugCode) { const fileName = 'foo.pug'; const pugTextDocument = vscode_languageserver_textdocument_1.TextDocument.create('file:///a.pug', 'jade', 0, pugCode); const codes = []; let error; let emptyLineEnds = []; let attrsBlocks; let ast; try { const tokens = pugLex(pugCode, { filename: fileName }); emptyLineEnds = collectEmptyLineEnds(tokens); attrsBlocks = collectAttrsBlocks(tokens); ast = pugParser(tokens, { filename: fileName, src: pugCode }); visitNode(ast, undefined, undefined); codes.push([ '', undefined, pugCode.trimEnd().length, ]); } catch (e) { const _error = e; error = { ..._error, line: _error.line - 1, column: _error.column - 1, }; } ; return { htmlCode: (0, muggle_string_1.toString)(codes), mappings: (0, buildMappings_1.buildMappings)(codes), pugTextDocument, error, ast, emptyLineEnds, }; function visitNode(node, next, parent) { if (node.type === 'Block') { for (let i = 0; i < node.nodes.length; i++) { visitNode(node.nodes[i], node.nodes[i + 1], node); } } else if (node.type === 'Mixin') { if (node.block) { visitNode(node.block, undefined, node); } } else if (node.type === 'Tag') { const pugTagRange = getDocRange(node.line, node.column, node.name.length); codes.push([ '', undefined, pugTagRange.start, ]); const selfClosing = node.block.nodes.length === 0; addStartTag(node, selfClosing); if (!selfClosing) { visitNode(node.block, next, parent); addEndTag(node, next, parent); } codes.push([ '', undefined, pugTagRange.start, ]); } else if (node.type === 'Text') { codes.push([ node.val, undefined, getDocOffset(node.line, node.column), ]); } } function addStartTag(node, selfClosing) { codes.push([ '', undefined, getDocOffset(node.line, node.column), ]); codes.push('<'); const tagRange = getDocRange(node.line, node.column, node.name.length); if (pugCode.substring(tagRange.start, tagRange.end) === node.name) { codes.push([ node.name, undefined, tagRange.start, ]); } else { codes.push(node.name); } const noTitleAttrs = node.attrs.filter(attr => !attr.mustEscape && attr.name !== 'class'); const noTitleClassAttrs = node.attrs.filter(attr => !attr.mustEscape && attr.name === 'class'); const attrsBlock = attrsBlocks.get(getDocOffset(node.line, node.column)); // support attr auto-complete in spaces const hasClassAttr = attrsBlock && attrsBlock.text.match(/\bclass\b\s*=/i); if (!hasClassAttr) { addClassesOrStyles(noTitleClassAttrs, 'class'); } for (const attr of noTitleAttrs) { codes.push(' '); codes.push(attr.name); if (typeof attr.val !== 'boolean') { codes.push('='); codes.push([ attr.val, undefined, getDocOffset(attr.line, attr.column), ]); } } if (attrsBlock) { codes.push(' '); codes.push([ attrsBlock.text, undefined, attrsBlock.offset, ]); } if (selfClosing) { codes.push(' />'); } else { codes.push('>'); } } function addEndTag(node, next, parent) { let nextStart; if (next) { if (next.type === 'Block') { nextStart = getDocOffset(next.line, 1); } else { nextStart = getDocOffset(next.line, next.column); } } else if (!parent) { nextStart = pugCode.length; } if (nextStart !== undefined) { codes.push([ '', undefined, nextStart, ]); } codes.push(`</${node.name}>`); } function addClassesOrStyles(attrs, attrName) { if (!attrs.length) { return; } codes.push(' '); codes.push(attrName); codes.push('='); codes.push('"'); for (const attr of attrs) { if (typeof attr.val !== 'boolean') { codes.push(' '); codes.push([ attr.val.slice(1, -1), // remove " undefined, getDocOffset(attr.line, attr.column + 1), ]); } } codes.push('"'); } function collectEmptyLineEnds(tokens) { const ends = []; for (const token of tokens) { if (token.type === 'newline' || token.type === 'outdent') { let currentLine = token.loc.start.line - 2; let prevLine = getLineText(pugTextDocument, currentLine); while (prevLine.trim() === '') { ends.push(pugTextDocument.offsetAt({ line: currentLine + 1, character: 0 }) - 1); if (currentLine <= 0) { break; } currentLine--; prevLine = getLineText(pugTextDocument, currentLine); } } } return ends.sort((a, b) => a - b); } function collectAttrsBlocks(tokens) { const blocks = new Map(); for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; if (token.type === 'start-attributes') { let tagStart = token; for (let j = i - 1; j >= 0; j--) { const prevToken = tokens[j]; if (prevToken.type === 'newline' || prevToken.type === 'indent' || prevToken.type === 'outdent' || prevToken.type === ':') { break; } tagStart = prevToken; if (prevToken.type === 'tag') { break; } } let prevToken = token; let text = ''; for (i++; i < tokens.length; i++) { const attrToken = tokens[i]; addPrevSpace(attrToken); if (attrToken.type === 'attribute') { let attrText = pugCode.substring(getDocOffset(attrToken.loc.start.line, attrToken.loc.start.column), getDocOffset(attrToken.loc.end.line, attrToken.loc.end.column)); if (typeof attrToken.val === 'string' && attrText.indexOf('=') >= 0) { let valText = attrToken.val; if (valText.startsWith('`') && valText.endsWith('`')) { if (valText.indexOf('"') === -1) { valText = `"${valText.slice(1, -1)}"`; } else { valText = `'${valText.slice(1, -1)}'`; } } valText = valText.replace(/ \\\n/g, '//\n'); text += attrText.substring(0, attrText.lastIndexOf(attrToken.val)) + valText; } else { text += attrText; } } else if (attrToken.type === 'end-attributes') { blocks.set(getDocOffset(tagStart.loc.start.line, tagStart.loc.start.column), { offset: getDocOffset(token.loc.end.line, token.loc.end.column), text, }); break; } prevToken = attrToken; } function addPrevSpace(currentToken) { text += pugCode.substring(getDocOffset(prevToken.loc.end.line, prevToken.loc.end.column), getDocOffset(currentToken.loc.start.line, currentToken.loc.start.column)).replace(/,/g, '\n'); } } } return blocks; } function getDocOffset(pugLine, pugColumn) { return pugTextDocument.offsetAt({ line: pugLine - 1, character: pugColumn - 1 }); } function getDocRange(pugLine, pugColumn, length) { const start = getDocOffset(pugLine, pugColumn); const end = start + length; return { start, end, }; } } function getLineText(document, line) { const endOffset = document.offsetAt({ line: line + 1, character: 0 }); const end = document.positionAt(endOffset); const text = document.getText({ start: { line: line, character: 0 }, end: end.line === line ? end : document.positionAt(endOffset - 1), }); return text; } //# sourceMappingURL=baseParse.js.map