UNPKG

gherkin

Version:
246 lines (216 loc) 7.44 kB
var AstNode = require('./ast_node'); var Errors = require('./errors'); module.exports = function AstBuilder () { var stack = [new AstNode('None')]; var comments = []; this.reset = function () { stack = [new AstNode('None')]; comments = []; }; this.startRule = function (ruleType) { stack.push(new AstNode(ruleType)); }; this.endRule = function (ruleType) { var node = stack.pop(); var transformedNode = transformNode(node); currentNode().add(node.ruleType, transformedNode); }; this.build = function (token) { if(token.matchedType === 'Comment') { comments.push({ type: 'Comment', location: getLocation(token), text: token.matchedText }); } else { currentNode().add(token.matchedType, token); } }; this.getResult = function () { return currentNode().getSingle('Feature'); }; function currentNode () { return stack[stack.length - 1]; } function getLocation (token, column) { return !column ? token.location : {line: token.location.line, column: column}; } function getTags (node) { var tags = []; var tagsNode = node.getSingle('Tags'); if (!tagsNode) return tags; tagsNode.getTokens('TagLine').forEach(function (token) { token.matchedItems.forEach(function (tagItem) { tags.push({ type: 'Tag', location: getLocation(token, tagItem.column), name: tagItem.text }); }); }); return tags; } function getCells(tableRowToken) { return tableRowToken.matchedItems.map(function (cellItem) { return { type: 'TableCell', location: getLocation(tableRowToken, cellItem.column), value: cellItem.text } }); } function getDescription (node) { return node.getSingle('Description'); } function getSteps (node) { return node.getItems('Step'); } function getTableRows(node) { var rows = node.getTokens('TableRow').map(function (token) { return { type: 'TableRow', location: getLocation(token), cells: getCells(token) }; }); ensureCellCount(rows); return rows; } function ensureCellCount(rows) { if(rows.length == 0) return; var cellCount = rows[0].cells.length; rows.forEach(function (row) { if (row.cells.length != cellCount) { throw Errors.AstBuilderException.create("inconsistent cell count within the table", row.location); } }); } function transformNode(node) { switch(node.ruleType) { case 'Step': var stepLine = node.getToken('StepLine'); var stepArgument = node.getSingle('DataTable') || node.getSingle('DocString') || undefined; return { type: node.ruleType, location: getLocation(stepLine), keyword: stepLine.matchedKeyword, text: stepLine.matchedText, argument: stepArgument } case 'DocString': var separatorToken = node.getTokens('DocStringSeparator')[0]; var contentType = separatorToken.matchedText; var lineTokens = node.getTokens('Other'); var content = lineTokens.map(function (t) {return t.matchedText}).join("\n"); return { type: node.ruleType, location: getLocation(separatorToken), contentType: contentType, content: content }; case 'DataTable': var rows = getTableRows(node); return { type: node.ruleType, location: rows[0].location, rows: rows, } case 'Background': var backgroundLine = node.getToken('BackgroundLine'); var description = getDescription(node); var steps = getSteps(node); return { type: node.ruleType, location: getLocation(backgroundLine), keyword: backgroundLine.matchedKeyword, name: backgroundLine.matchedText, description: description, steps: steps }; case 'Scenario_Definition': var tags = getTags(node); var scenarioNode = node.getSingle('Scenario'); if(scenarioNode) { var scenarioLine = scenarioNode.getToken('ScenarioLine'); var description = getDescription(scenarioNode); var steps = getSteps(scenarioNode); return { type: scenarioNode.ruleType, tags: tags, location: getLocation(scenarioLine), keyword: scenarioLine.matchedKeyword, name: scenarioLine.matchedText, description: description, steps: steps }; } else { var scenarioOutlineNode = node.getSingle('ScenarioOutline'); if(!scenarioOutlineNode) throw new Error('Internal grammar error'); var scenarioOutlineLine = scenarioOutlineNode.getToken('ScenarioOutlineLine'); var description = getDescription(scenarioOutlineNode); var steps = getSteps(scenarioOutlineNode); var examples = scenarioOutlineNode.getItems('Examples_Definition'); return { type: scenarioOutlineNode.ruleType, tags: tags, location: getLocation(scenarioOutlineLine), keyword: scenarioOutlineLine.matchedKeyword, name: scenarioOutlineLine.matchedText, description: description, steps: steps, examples: examples }; } case 'Examples_Definition': var tags = getTags(node); var examplesNode = node.getSingle('Examples'); var examplesLine = examplesNode.getToken('ExamplesLine'); var description = getDescription(examplesNode); var rows = getTableRows(examplesNode) return { type: examplesNode.ruleType, tags: tags, location: getLocation(examplesLine), keyword: examplesLine.matchedKeyword, name: examplesLine.matchedText, description: description, tableHeader: rows[0], tableBody: rows.slice(1) }; case 'Description': var lineTokens = node.getTokens('Other'); // Trim trailing empty lines var end = lineTokens.length; while (end > 0 && lineTokens[end-1].line.trimmedLineText === '') { end--; } lineTokens = lineTokens.slice(0, end); var description = lineTokens.map(function (token) { return token.matchedText}).join("\n"); return description; case 'Feature': var header = node.getSingle('Feature_Header'); if(!header) return null; var tags = getTags(header); var featureLine = header.getToken('FeatureLine'); if(!featureLine) return null; var background = node.getSingle('Background'); var scenariodefinitions = node.getItems('Scenario_Definition'); var description = getDescription(header); var language = featureLine.matchedGherkinDialect; return { type: node.ruleType, tags: tags, location: getLocation(featureLine), language: language, keyword: featureLine.matchedKeyword, name: featureLine.matchedText, description: description, background: background, scenarioDefinitions: scenariodefinitions, comments: comments }; default: return node; } } };