Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@cucumber/gherkin-utils

Package Overview
Dependencies
Maintainers
2
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cucumber/gherkin-utils - npm Package Compare versions

Comparing version 6.0.0 to 7.0.0

bin/gherkin-utils

2

dist/src/index.d.ts

@@ -0,1 +1,3 @@

export * from './walkGherkinDocument';
export * from './GherkinDocumentHandlers';
import pretty from './pretty';

@@ -2,0 +4,0 @@ import Query from './Query';

@@ -14,2 +14,5 @@ "use strict";

});
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importStar = (this && this.__importStar) || function (mod) {

@@ -27,2 +30,4 @@ if (mod && mod.__esModule) return mod;

exports.rejectAllFilters = exports.GherkinDocumentWalker = exports.Query = exports.pretty = void 0;
__exportStar(require("./walkGherkinDocument"), exports);
__exportStar(require("./GherkinDocumentHandlers"), exports);
const pretty_1 = __importDefault(require("./pretty"));

@@ -29,0 +34,0 @@ exports.pretty = pretty_1.default;

4

dist/src/pretty.d.ts
import * as messages from '@cucumber/messages';
export default function pretty(gherkinDocument: messages.GherkinDocument): string;
export declare type Syntax = 'markdown' | 'gherkin';
export default function pretty(gherkinDocument: messages.GherkinDocument, syntax?: Syntax): string;
export declare function escapeCell(s: string): string;
//# sourceMappingURL=pretty.d.ts.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function pretty(gherkinDocument) {
const feature = gherkinDocument.feature;
let s = prettyTags(feature.tags);
s += feature.keyword + ': ' + feature.name + '\n';
if (feature.description) {
s += feature.description + '\n';
}
for (const child of feature.children) {
if (child.background) {
s += prettyStepContainer(child.background, ' ');
}
else if (child.scenario) {
s += prettyStepContainer(child.scenario, ' ');
}
else if (child.rule) {
s += `\n ${child.rule.keyword}: ${child.rule.name}\n`;
if (child.rule.description) {
s += child.rule.description + '\n';
}
for (const ruleChild of child.rule.children) {
if (ruleChild.background) {
s += prettyStepContainer(ruleChild.background, ' ');
exports.escapeCell = void 0;
const walkGherkinDocument_1 = require("./walkGherkinDocument");
function pretty(gherkinDocument, syntax = 'gherkin') {
let scenarioLevel = 1;
return (0, walkGherkinDocument_1.walkGherkinDocument)(gherkinDocument, '', {
feature(feature, content) {
return content
.concat(prettyLanguageHeader(feature.language))
.concat(prettyKeywordContainer(feature, syntax, 0));
},
rule(rule, content) {
scenarioLevel = 2;
return content.concat(prettyKeywordContainer(rule, syntax, 1));
},
background(background, content) {
return content.concat(prettyKeywordContainer(background, syntax, scenarioLevel));
},
scenario(scenario, content) {
return content.concat(prettyKeywordContainer(scenario, syntax, scenarioLevel));
},
examples(examples, content) {
const tableRows = examples.tableHeader ? [examples.tableHeader, ...examples.tableBody] : [];
return content
.concat(prettyKeywordContainer(examples, syntax, scenarioLevel + 1))
.concat(prettyTableRows(tableRows, syntax, scenarioLevel + 2));
},
step(step, content) {
return content
.concat(stepPrefix(scenarioLevel + 1, syntax))
.concat(step.keyword)
.concat(step.text)
.concat('\n');
},
dataTable(dataTable, content) {
const level = syntax === 'markdown' ? 1 : scenarioLevel + 2;
return content.concat(prettyTableRows(dataTable.rows || [], syntax, level));
},
docString(docString, content) {
const delimiter = makeDocStringDelimiter(syntax, docString);
const level = syntax === 'markdown' ? 1 : scenarioLevel + 2;
const indent = spaces(level);
let docStringContent = docString.content.replace(/^/gm, indent);
if (syntax === 'gherkin') {
if (docString.delimiter === '"""') {
docStringContent = docStringContent.replace(/"""/gm, '\\"\\"\\"');
}
if (ruleChild.scenario) {
s += prettyStepContainer(ruleChild.scenario, ' ');
else {
docStringContent = docStringContent.replace(/```/gm, '\\`\\`\\`');
}
}
}
}
return s;
return content
.concat(indent)
.concat(delimiter)
.concat(docString.mediaType || '')
.concat('\n')
.concat(docStringContent)
.concat('\n')
.concat(indent)
.concat(delimiter)
.concat('\n');
},
});
}
exports.default = pretty;
function prettyStepContainer(stepContainer, indent) {
const scenario = 'tags' in stepContainer ? stepContainer : null;
const tags = (scenario === null || scenario === void 0 ? void 0 : scenario.tags) || [];
let s = `\n${prettyTags(tags, indent)}${indent}${stepContainer.keyword}: ${stepContainer.name}\n`;
if (stepContainer.description) {
s += stepContainer.description + '\n\n';
function prettyLanguageHeader(language) {
return language === 'en' ? '' : `# language: ${language}\n`;
}
function prettyKeywordContainer(stepContainer, syntax, level) {
const tags = 'tags' in stepContainer ? stepContainer.tags : [];
const stepCount = 'steps' in stepContainer ? stepContainer.steps.length : 0;
const description = prettyDescription(stepContainer.description, syntax);
return ''
.concat(level === 0 ? '' : '\n')
.concat(prettyTags(tags, syntax, level))
.concat(keywordPrefix(level, syntax))
.concat(stepContainer.keyword)
.concat(': ')
.concat(stepContainer.name)
.concat('\n')
.concat(description)
.concat(description && stepCount > 0 ? '\n' : '');
}
function prettyDescription(description, syntax) {
if (!description)
return '';
if (syntax === 'gherkin')
return description + '\n';
else
return description.replace(/^\s*/gm, '') + '\n';
}
function prettyTags(tags, syntax, level) {
if (tags === undefined || tags.length == 0) {
return '';
}
for (const step of stepContainer.steps) {
s += `${indent} ${step.keyword}${step.text}\n`;
const prefix = syntax === 'gherkin' ? spaces(level) : '';
const tagQuote = syntax === 'gherkin' ? '' : '`';
return prefix + tags.map((tag) => `${tagQuote}${tag.name}${tagQuote}`).join(' ') + '\n';
}
function keywordPrefix(level, syntax) {
if (syntax === 'markdown') {
return new Array(level + 2).join('#') + ' ';
}
if (scenario) {
for (const example of scenario.examples) {
s += prettyExample(example, `${indent} `);
}
else {
return spaces(level);
}
return s;
}
function prettyExample(example, indent) {
let s = `\n${indent}Examples: ${example.name}\n`;
s += prettyTableRow(example.tableHeader, `${indent} `);
for (const row of example.tableBody) {
s += prettyTableRow(row, `${indent} `);
function stepPrefix(level, syntax) {
if (syntax === 'markdown') {
return '* ';
}
return s;
else {
return new Array(level + 1).join(' ');
}
}
function prettyTableRow(row, indent) {
return `${indent}| ${row.cells.map((cell) => cell.value).join(' | ')} |\n`;
function spaces(level) {
return new Array(level + 1).join(' ');
}
function prettyTags(tags, indent = '') {
if (tags === undefined || tags.length == 0) {
function makeDocStringDelimiter(syntax, docString) {
if (syntax === 'gherkin') {
return docString.delimiter.substring(0, 3);
}
// The length of the fenced code block delimiter is three backticks when the content inside doesn't have backticks.
// If the content inside has three or more backticks, the number of backticks in the delimiter must be at least one more
// https://github.github.com/gfm/#fenced-code-blocks
const threeOrMoreBackticks = /(```+)/g;
let maxContentBackTickCount = 2;
let match;
do {
match = threeOrMoreBackticks.exec(docString.content);
if (match) {
maxContentBackTickCount = Math.max(maxContentBackTickCount, match[1].length);
}
} while (match);
// Return a delimiter with one more backtick than the max number of backticks in the contents (3 ny default)
return new Array(maxContentBackTickCount + 2).join('`');
}
function prettyTableRows(tableRows, syntax, level) {
if (tableRows.length === 0)
return '';
const maxWidths = new Array(tableRows[0].cells.length).fill(0);
tableRows.forEach((tableRow) => {
tableRow.cells.forEach((tableCell, j) => {
maxWidths[j] = Math.max(maxWidths[j], escapeCell(tableCell.value).length);
});
});
let n = 0;
let s = '';
for (const row of tableRows) {
s += prettyTableRow(row, level, maxWidths, syntax);
if (n === 0 && syntax === 'markdown') {
const separatorRow = {
location: row.location,
id: row.id + '-separator',
cells: row.cells.map((cell, j) => ({
location: cell.location,
value: new Array(maxWidths[j] + 1).join('-'),
})),
};
s += prettyTableRow(separatorRow, level, maxWidths, syntax);
}
n++;
}
return indent + tags.map((tag) => tag.name).join(' ') + '\n';
return s;
}
function prettyTableRow(row, level, maxWidths, syntax) {
const actualLevel = syntax === 'markdown' ? 1 : level;
return `${spaces(actualLevel)}| ${row.cells
.map((cell, j) => {
const escapedCellValue = escapeCell(cell.value);
const spaceCount = maxWidths[j] - escapedCellValue.length;
const spaces = new Array(spaceCount + 1).join(' ');
return isNumeric(escapedCellValue) ? spaces + escapedCellValue : escapedCellValue + spaces;
})
.join(' | ')} |\n`;
}
function escapeCell(s) {
let e = '';
const characters = s.split('');
for (const c of characters) {
switch (c) {
case '\\':
e += '\\\\';
break;
case '\n':
e += '\\n';
break;
case '|':
e += '\\|';
break;
default:
e += c;
}
}
return e;
}
exports.escapeCell = escapeCell;
function isNumeric(s) {
return !isNaN(parseFloat(s));
}
//# sourceMappingURL=pretty.js.map

@@ -39,3 +39,3 @@ "use strict";

it('returns a deep copy', () => {
const gherkinDocument = parse_1.default(`@featureTag
const gherkinDocument = (0, parse_1.default)(`@featureTag
Feature: hello

@@ -70,3 +70,3 @@ This feature has a description

it('filters one scenario', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -81,3 +81,3 @@ Scenario: Saturn

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -91,3 +91,3 @@

it('keeps scenario with search hit in step', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -102,3 +102,3 @@ Scenario: Saturn

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -112,3 +112,3 @@

it('does not leave null object as a feature child', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -126,3 +126,3 @@ Scenario: Saturn

it('keeps a hit scenario even when no steps match', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -137,3 +137,3 @@ Scenario: Saturn

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -148,3 +148,3 @@

xit('keeps a hit background', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -166,3 +166,3 @@ Background: Space

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -181,3 +181,3 @@

it('keeps a hit in background step', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -197,3 +197,3 @@ Background: Space

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -218,3 +218,3 @@

xit('keeps scenario in rule', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -234,3 +234,3 @@ Rule: Galaxy

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -249,3 +249,3 @@

it('keeps scenario and background in rule', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -265,3 +265,3 @@ Rule: Galaxy

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -283,3 +283,3 @@

it('only keeps rule and its content', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -296,3 +296,3 @@ Scenario: Milky Way

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -308,3 +308,3 @@

it('return a feature and keep scenario', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -319,3 +319,3 @@ Scenario: Saturn

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument);
const newSource = pretty_1.default(newGherkinDocument);
const newSource = (0, pretty_1.default)(newGherkinDocument, 'gherkin');
const expectedNewSource = `Feature: Solar System

@@ -332,3 +332,3 @@

it('returns null when no hit found', () => {
const gherkinDocument = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -349,3 +349,3 @@ Scenario: Saturn

it('is called for each steps', () => {
const source = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -359,3 +359,3 @@ Scenario: Earth

});
astWalker.walkGherkinDocument(source);
astWalker.walkGherkinDocument(gherkinDocument);
assert_1.default.deepEqual(stepText, ['it is a planet']);

@@ -366,3 +366,3 @@ });

it('is called for each scenarios', () => {
const source = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -379,3 +379,3 @@ Scenario: Earth

});
astWalker.walkGherkinDocument(source);
astWalker.walkGherkinDocument(gherkinDocument);
assert_1.default.deepEqual(scenarioName, ['Earth', 'Saturn']);

@@ -386,3 +386,3 @@ });

it('is called for each backgrounds', () => {
const source = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -397,3 +397,3 @@ Background: Milky Way

});
astWalker.walkGherkinDocument(source);
astWalker.walkGherkinDocument(gherkinDocument);
assert_1.default.deepEqual(backgroundName, ['Milky Way']);

@@ -404,3 +404,3 @@ });

it('is called for each rules', () => {
const source = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -419,3 +419,3 @@ Rule: On a planet

});
astWalker.walkGherkinDocument(source);
astWalker.walkGherkinDocument(gherkinDocument);
assert_1.default.deepEqual(ruleName, ['On a planet', 'On an exoplanet']);

@@ -426,3 +426,3 @@ });

it('is called for each features', () => {
const source = parse_1.default(`Feature: Solar System
const gherkinDocument = (0, parse_1.default)(`Feature: Solar System

@@ -441,3 +441,3 @@ Rule: On a planet

});
astWalker.walkGherkinDocument(source);
astWalker.walkGherkinDocument(gherkinDocument);
assert_1.default.deepEqual(featureName, ['Solar System']);

@@ -449,5 +449,5 @@ });

it('does not fail with empty/commented documents', () => {
const source = parse_1.default('# Feature: Solar System');
const gherkinDocument = (0, parse_1.default)('# Feature: Solar System');
const astWalker = new GherkinDocumentWalker_1.default();
astWalker.walkGherkinDocument(source);
astWalker.walkGherkinDocument(gherkinDocument);
});

@@ -454,0 +454,0 @@ });

@@ -19,8 +19,8 @@ "use strict";

const fs_1 = __importDefault(require("fs"));
const glob_1 = __importDefault(require("glob"));
const fast_glob_1 = __importDefault(require("fast-glob"));
const util_1 = require("util");
const asyncPipeline = util_1.promisify(stream_1.pipeline);
const asyncPipeline = (0, util_1.promisify)(stream_1.pipeline);
describe('Walking with messages', () => {
const localMessageFiles = glob_1.default.sync(`${__dirname}/messages/**/*.ndjson`);
const tckMessageFiles = glob_1.default.sync(`${__dirname}/../../../compatibility-kit/javascript/features/**/*.ndjson`);
const localMessageFiles = fast_glob_1.default.sync(`${__dirname}/messages/**/*.ndjson`);
const tckMessageFiles = fast_glob_1.default.sync(`${__dirname}/../../../compatibility-kit/javascript/features/**/*.ndjson`);
const messageFiles = [].concat(localMessageFiles, tckMessageFiles);

@@ -27,0 +27,0 @@ for (const messageFile of messageFiles) {

import * as messages from '@cucumber/messages';
export default function parse(source: string): messages.GherkinDocument;
import { GherkinClassicTokenMatcher, GherkinInMarkdownTokenMatcher } from '@cucumber/gherkin';
export default function parse(source: string, tokenMatcher?: GherkinClassicTokenMatcher | GherkinInMarkdownTokenMatcher): messages.GherkinDocument;
//# sourceMappingURL=parse.d.ts.map

@@ -24,10 +24,16 @@ "use strict";

const gherkin_1 = require("@cucumber/gherkin");
function parse(source) {
function parse(source, tokenMatcher = new gherkin_1.GherkinClassicTokenMatcher()) {
const newId = messages.IdGenerator.uuid();
const parser = new gherkin_1.Parser(new gherkin_1.AstBuilder(newId), new gherkin_1.GherkinClassicTokenMatcher());
const gherkinDocument = parser.parse(source);
gherkinDocument.uri = '';
return gherkinDocument;
const parser = new gherkin_1.Parser(new gherkin_1.AstBuilder(newId), tokenMatcher);
try {
const gherkinDocument = parser.parse(source);
gherkinDocument.uri = '';
return gherkinDocument;
}
catch (err) {
err.message += `\n${source}`;
throw err;
}
}
exports.default = parse;
//# sourceMappingURL=parse.js.map
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {

@@ -7,10 +26,27 @@ return (mod && mod.__esModule) ? mod : { "default": mod };

const assert_1 = __importDefault(require("assert"));
const path_1 = __importDefault(require("path"));
const parse_1 = __importDefault(require("./parse"));
const pretty_1 = __importDefault(require("../src/pretty"));
describe('PrettyFormatter', () => {
it('renders a feature with no scenarios', () => {
assertPrettyIdentical('Feature: hello\n');
const pretty_1 = __importStar(require("../src/pretty"));
const gherkin_1 = require("@cucumber/gherkin");
const fast_glob_1 = __importDefault(require("fast-glob"));
const fs_1 = __importDefault(require("fs"));
describe('pretty', () => {
it('renders an empty file', () => {
checkGherkinToAstToMarkdownToAstToGherkin('');
});
it('renders the language header if it is not "en"', () => {
checkGherkinToAstToGherkin(`# language: no
Egenskap: hallo
`);
});
it('renders a feature with empty scenarios', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Scenario: Two
`);
});
it('renders a feature with two scenarios', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -25,3 +61,3 @@ Scenario: one

it('renders a feature with two scenarios in a rule', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -38,3 +74,3 @@ Rule: ok

it('renders a feature with background and scenario', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -49,3 +85,3 @@ Background: bbb

it('renders a rule with background and scenario', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -62,3 +98,3 @@ Rule: machin

it('renders tags when set', () => {
assertPrettyIdentical(`@featureTag
checkGherkinToAstToMarkdownToAstToGherkin(`@featureTag
Feature: hello

@@ -76,4 +112,73 @@

});
it('renders examples tables', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a a <text> and a <number>
Examples: some data
| text | number |
| a | 1 |
| ab | 10 |
| abc | 100 |
`);
});
it('renders data tables', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a data table:
| text | numbers |
| a | 1 |
| ab | 10 |
| abc | 100 |
`);
});
describe('DocString', () => {
it('is rendered with type', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a doc string:
\`\`\`json
{
"foo": "bar"
}
\`\`\`
`);
});
it('escapes DocString separators', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a doc string:
\`\`\`
2
\`\`
3
\\\`\\\`\\\`
4
\\\`\\\`\\\`\`
5
\\\`\\\`\\\`\`\`
\`\`\`
`);
});
});
xit('renders comments', () => {
checkGherkinToAstToGherkin(`# one
Feature: hello
Scenario: one
# two
Given a doc string:
"""
a
\\"\\"\\"
b
"""
`);
});
it('renders descriptions when set', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToGherkin(`Feature: hello
So this is a feature

@@ -95,7 +200,66 @@

});
const featureFiles = fast_glob_1.default.sync(`${__dirname}/../../../gherkin/testdata/good/*.feature`);
for (const featureFile of featureFiles) {
const relativePath = path_1.default.relative(__dirname, featureFile);
it(`renders ${relativePath}`, () => {
var _a;
const gherkinSource = fs_1.default.readFileSync(featureFile, 'utf-8');
const gherkinDocument = (0, parse_1.default)(gherkinSource, new gherkin_1.GherkinClassicTokenMatcher());
const formattedGherkinSource = (0, pretty_1.default)(gherkinDocument, 'gherkin');
const language = ((_a = gherkinDocument.feature) === null || _a === void 0 ? void 0 : _a.language) || 'en';
const newGherkinDocument = checkGherkinToAstToGherkin(formattedGherkinSource, language);
(0, assert_1.default)(newGherkinDocument);
// TODO: comments
if (gherkinDocument.comments.length === 0) {
assert_1.default.deepStrictEqual(neutralize(newGherkinDocument), neutralize(gherkinDocument));
}
});
}
describe('escapeCell', () => {
it('escapes nothing', () => {
assert_1.default.strictEqual((0, pretty_1.escapeCell)('hello'), 'hello');
});
it('escapes newline', () => {
assert_1.default.strictEqual((0, pretty_1.escapeCell)('\n'), '\\n');
});
it('escapes pipe', () => {
assert_1.default.strictEqual((0, pretty_1.escapeCell)('|'), '\\|');
});
it('escapes backslash', () => {
assert_1.default.strictEqual((0, pretty_1.escapeCell)('\\'), '\\\\');
});
});
});
function assertPrettyIdentical(source) {
const gherkinDocument = parse_1.default(source);
assert_1.default.strictEqual(pretty_1.default(gherkinDocument), source);
function checkGherkinToAstToMarkdownToAstToGherkin(gherkinSource) {
const gherkinDocument = (0, parse_1.default)(gherkinSource, new gherkin_1.GherkinClassicTokenMatcher());
// console.log({gherkinDocument})
const markdownSource = (0, pretty_1.default)(gherkinDocument, 'markdown');
// console.log(`<Markdown>${markdownSource}</Markdown>`)
const markdownGherkinDocument = (0, parse_1.default)(markdownSource, new gherkin_1.GherkinInMarkdownTokenMatcher());
// console.log({markdownGherkinDocument})
const newGherkinSource = (0, pretty_1.default)(markdownGherkinDocument, 'gherkin');
// console.log(`<Gherkin>${newGherkinSource}</Gherkin>`)
assert_1.default.strictEqual(newGherkinSource, gherkinSource);
}
function checkGherkinToAstToGherkin(gherkinSource, language = 'en') {
const gherkinDocument = (0, parse_1.default)(gherkinSource, new gherkin_1.GherkinClassicTokenMatcher(language));
const newGherkinSource = (0, pretty_1.default)(gherkinDocument, 'gherkin');
// console.log(`<Gherkin>${newGherkinSource}</Gherkin>`)
assert_1.default.strictEqual(newGherkinSource, gherkinSource);
return gherkinDocument;
}
function neutralize(gherkinDocument) {
const json = JSON.stringify(gherkinDocument, (key, value) => {
if ('id' === key) {
return 'id';
}
else if (['column', 'line'].includes(key)) {
return '0';
}
else {
return value;
}
}, 2);
return JSON.parse(json);
}
//# sourceMappingURL=prettyTest.js.map

@@ -40,3 +40,3 @@ "use strict";

const util_1 = require("util");
const pipelinePromise = util_1.promisify(stream_1.pipeline);
const pipelinePromise = (0, util_1.promisify)(stream_1.pipeline);
describe('Query', () => {

@@ -43,0 +43,0 @@ let gherkinQuery;

{
"name": "@cucumber/gherkin-utils",
"version": "6.0.0",
"version": "7.0.0",
"description": "Various Gherkin utilities",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"bin": {
"@cucumber/gherkin-utils": "bin/gherkin-utils"
},
"scripts": {

@@ -25,16 +28,16 @@ "test": "mocha",

"devDependencies": {
"@cucumber/gherkin": "^20.0.0",
"@cucumber/gherkin-streams": "^3.0.0",
"@cucumber/gherkin": "^21.0.0",
"@cucumber/gherkin-streams": "^4.0.0",
"@cucumber/message-streams": "^3.0.0",
"@types/glob": "7.1.4",
"@types/mocha": "8.2.3",
"@types/node": "14.17.5",
"glob": "7.1.7",
"mocha": "9.0.2",
"ts-node": "10.0.0",
"typescript": "4.3.5"
"@types/mocha": "9.0.0",
"@types/node": "14.17.14",
"fast-glob": "3.2.7",
"mocha": "9.1.1",
"ts-node": "10.2.1",
"typescript": "4.4.2"
},
"dependencies": {
"@cucumber/messages": "^17.0.0",
"@teppeis/multimaps": "2.0.0"
"@cucumber/messages": "^17.1.0",
"@teppeis/multimaps": "2.0.0",
"commander": "8.1.0"
},

@@ -41,0 +44,0 @@ "directories": {

@@ -0,1 +1,2 @@

// This file is DEPRECATED - use ./walkGherkinDocument instead
import * as messages from '@cucumber/messages'

@@ -2,0 +3,0 @@

@@ -0,1 +1,3 @@

export * from './walkGherkinDocument'
export * from './GherkinDocumentHandlers'
import pretty from './pretty'

@@ -2,0 +4,0 @@ import Query from './Query'

import * as messages from '@cucumber/messages'
import { walkGherkinDocument } from './walkGherkinDocument'
export default function pretty(gherkinDocument: messages.GherkinDocument): string {
const feature = gherkinDocument.feature
let s = prettyTags(feature.tags)
export type Syntax = 'markdown' | 'gherkin'
s += feature.keyword + ': ' + feature.name + '\n'
if (feature.description) {
s += feature.description + '\n'
}
for (const child of feature.children) {
if (child.background) {
s += prettyStepContainer(child.background, ' ')
} else if (child.scenario) {
s += prettyStepContainer(child.scenario, ' ')
} else if (child.rule) {
s += `\n ${child.rule.keyword}: ${child.rule.name}\n`
if (child.rule.description) {
s += child.rule.description + '\n'
}
for (const ruleChild of child.rule.children) {
if (ruleChild.background) {
s += prettyStepContainer(ruleChild.background, ' ')
export default function pretty(
gherkinDocument: messages.GherkinDocument,
syntax: Syntax = 'gherkin'
): string {
let scenarioLevel = 1
return walkGherkinDocument<string>(gherkinDocument, '', {
feature(feature, content) {
return content
.concat(prettyLanguageHeader(feature.language))
.concat(prettyKeywordContainer(feature, syntax, 0))
},
rule(rule, content) {
scenarioLevel = 2
return content.concat(prettyKeywordContainer(rule, syntax, 1))
},
background(background, content) {
return content.concat(prettyKeywordContainer(background, syntax, scenarioLevel))
},
scenario(scenario, content) {
return content.concat(prettyKeywordContainer(scenario, syntax, scenarioLevel))
},
examples(examples, content) {
const tableRows = examples.tableHeader ? [examples.tableHeader, ...examples.tableBody] : []
return content
.concat(prettyKeywordContainer(examples, syntax, scenarioLevel + 1))
.concat(prettyTableRows(tableRows, syntax, scenarioLevel + 2))
},
step(step, content) {
return content
.concat(stepPrefix(scenarioLevel + 1, syntax))
.concat(step.keyword)
.concat(step.text)
.concat('\n')
},
dataTable(dataTable, content) {
const level = syntax === 'markdown' ? 1 : scenarioLevel + 2
return content.concat(prettyTableRows(dataTable.rows || [], syntax, level))
},
docString(docString, content) {
const delimiter = makeDocStringDelimiter(syntax, docString)
const level = syntax === 'markdown' ? 1 : scenarioLevel + 2
const indent = spaces(level)
let docStringContent = docString.content.replace(/^/gm, indent)
if (syntax === 'gherkin') {
if (docString.delimiter === '"""') {
docStringContent = docStringContent.replace(/"""/gm, '\\"\\"\\"')
} else {
docStringContent = docStringContent.replace(/```/gm, '\\`\\`\\`')
}
if (ruleChild.scenario) {
s += prettyStepContainer(ruleChild.scenario, ' ')
}
}
}
}
return s
return content
.concat(indent)
.concat(delimiter)
.concat(docString.mediaType || '')
.concat('\n')
.concat(docStringContent)
.concat('\n')
.concat(indent)
.concat(delimiter)
.concat('\n')
},
})
}
function prettyStepContainer(
stepContainer: messages.Scenario | messages.Background,
indent: string
function prettyLanguageHeader(language: string | undefined): string {
return language === 'en' ? '' : `# language: ${language}\n`
}
function prettyKeywordContainer(
stepContainer:
| messages.Feature
| messages.Scenario
| messages.Rule
| messages.Examples
| messages.Background,
syntax: Syntax,
level: number
): string {
const scenario: messages.Scenario = 'tags' in stepContainer ? stepContainer : null
const tags: readonly messages.Tag[] = scenario?.tags || []
let s = `\n${prettyTags(tags, indent)}${indent}${stepContainer.keyword}: ${stepContainer.name}\n`
if (stepContainer.description) {
s += stepContainer.description + '\n\n'
const tags: readonly messages.Tag[] = 'tags' in stepContainer ? stepContainer.tags : []
const stepCount = 'steps' in stepContainer ? stepContainer.steps.length : 0
const description = prettyDescription(stepContainer.description, syntax)
return ''
.concat(level === 0 ? '' : '\n')
.concat(prettyTags(tags, syntax, level))
.concat(keywordPrefix(level, syntax))
.concat(stepContainer.keyword)
.concat(': ')
.concat(stepContainer.name)
.concat('\n')
.concat(description)
.concat(description && stepCount > 0 ? '\n' : '')
}
function prettyDescription(description: string, syntax: Syntax): string {
if (!description) return ''
if (syntax === 'gherkin') return description + '\n'
else return description.replace(/^\s*/gm, '') + '\n'
}
function prettyTags(tags: readonly messages.Tag[], syntax: Syntax, level: number): string {
if (tags === undefined || tags.length == 0) {
return ''
}
const prefix = syntax === 'gherkin' ? spaces(level) : ''
const tagQuote = syntax === 'gherkin' ? '' : '`'
return prefix + tags.map((tag) => `${tagQuote}${tag.name}${tagQuote}`).join(' ') + '\n'
}
for (const step of stepContainer.steps) {
s += `${indent} ${step.keyword}${step.text}\n`
function keywordPrefix(level: number, syntax: Syntax): string {
if (syntax === 'markdown') {
return new Array(level + 2).join('#') + ' '
} else {
return spaces(level)
}
}
if (scenario) {
for (const example of scenario.examples) {
s += prettyExample(example, `${indent} `)
}
function stepPrefix(level: number, syntax: Syntax): string {
if (syntax === 'markdown') {
return '* '
} else {
return new Array(level + 1).join(' ')
}
return s
}
function prettyExample(example: messages.Examples, indent: string): string {
let s = `\n${indent}Examples: ${example.name}\n`
function spaces(level: number): string {
return new Array(level + 1).join(' ')
}
s += prettyTableRow(example.tableHeader, `${indent} `)
for (const row of example.tableBody) {
s += prettyTableRow(row, `${indent} `)
function makeDocStringDelimiter(syntax: Syntax, docString: messages.DocString) {
if (syntax === 'gherkin') {
return docString.delimiter.substring(0, 3)
}
// The length of the fenced code block delimiter is three backticks when the content inside doesn't have backticks.
// If the content inside has three or more backticks, the number of backticks in the delimiter must be at least one more
// https://github.github.com/gfm/#fenced-code-blocks
const threeOrMoreBackticks = /(```+)/g
let maxContentBackTickCount = 2
let match
do {
match = threeOrMoreBackticks.exec(docString.content)
if (match) {
maxContentBackTickCount = Math.max(maxContentBackTickCount, match[1].length)
}
} while (match)
// Return a delimiter with one more backtick than the max number of backticks in the contents (3 ny default)
return new Array(maxContentBackTickCount + 2).join('`')
}
function prettyTableRows(
tableRows: readonly messages.TableRow[],
syntax: Syntax,
level: number
): string {
if (tableRows.length === 0) return ''
const maxWidths: number[] = new Array(tableRows[0].cells.length).fill(0)
tableRows.forEach((tableRow) => {
tableRow.cells.forEach((tableCell, j) => {
maxWidths[j] = Math.max(maxWidths[j], escapeCell(tableCell.value).length)
})
})
let n = 0
let s = ''
for (const row of tableRows) {
s += prettyTableRow(row, level, maxWidths, syntax)
if (n === 0 && syntax === 'markdown') {
const separatorRow: messages.TableRow = {
location: row.location,
id: row.id + '-separator',
cells: row.cells.map((cell, j) => ({
location: cell.location,
value: new Array(maxWidths[j] + 1).join('-'),
})),
}
s += prettyTableRow(separatorRow, level, maxWidths, syntax)
}
n++
}
return s
}
function prettyTableRow(row: messages.TableRow, indent: string): string {
return `${indent}| ${row.cells.map((cell) => cell.value).join(' | ')} |\n`
function prettyTableRow(
row: messages.TableRow,
level: number,
maxWidths: readonly number[],
syntax: Syntax
): string {
const actualLevel = syntax === 'markdown' ? 1 : level
return `${spaces(actualLevel)}| ${row.cells
.map((cell, j) => {
const escapedCellValue = escapeCell(cell.value)
const spaceCount = maxWidths[j] - escapedCellValue.length
const spaces = new Array(spaceCount + 1).join(' ')
return isNumeric(escapedCellValue) ? spaces + escapedCellValue : escapedCellValue + spaces
})
.join(' | ')} |\n`
}
function prettyTags(tags: readonly messages.Tag[], indent = ''): string {
if (tags === undefined || tags.length == 0) {
return ''
export function escapeCell(s: string) {
let e = ''
const characters = s.split('')
for (const c of characters) {
switch (c) {
case '\\':
e += '\\\\'
break
case '\n':
e += '\\n'
break
case '|':
e += '\\|'
break
default:
e += c
}
}
return e
}
return indent + tags.map((tag) => tag.name).join(' ') + '\n'
function isNumeric(s: string) {
return !isNaN(parseFloat(s))
}

@@ -80,3 +80,3 @@ import assert from 'assert'

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -105,3 +105,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -151,3 +151,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -184,3 +184,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -219,3 +219,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -260,3 +260,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -295,3 +295,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -330,3 +330,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -357,3 +357,3 @@

const newGherkinDocument = walker.walkGherkinDocument(gherkinDocument)
const newSource = pretty(newGherkinDocument)
const newSource = pretty(newGherkinDocument, 'gherkin')
const expectedNewSource = `Feature: Solar System

@@ -389,3 +389,3 @@

it('is called for each steps', () => {
const source = parse(`Feature: Solar System
const gherkinDocument = parse(`Feature: Solar System

@@ -403,3 +403,3 @@ Scenario: Earth

)
astWalker.walkGherkinDocument(source)
astWalker.walkGherkinDocument(gherkinDocument)

@@ -412,3 +412,3 @@ assert.deepEqual(stepText, ['it is a planet'])

it('is called for each scenarios', () => {
const source = parse(`Feature: Solar System
const gherkinDocument = parse(`Feature: Solar System

@@ -429,3 +429,3 @@ Scenario: Earth

)
astWalker.walkGherkinDocument(source)
astWalker.walkGherkinDocument(gherkinDocument)

@@ -438,3 +438,3 @@ assert.deepEqual(scenarioName, ['Earth', 'Saturn'])

it('is called for each backgrounds', () => {
const source = parse(`Feature: Solar System
const gherkinDocument = parse(`Feature: Solar System

@@ -453,3 +453,3 @@ Background: Milky Way

)
astWalker.walkGherkinDocument(source)
astWalker.walkGherkinDocument(gherkinDocument)

@@ -462,3 +462,3 @@ assert.deepEqual(backgroundName, ['Milky Way'])

it('is called for each rules', () => {
const source = parse(`Feature: Solar System
const gherkinDocument = parse(`Feature: Solar System

@@ -481,3 +481,3 @@ Rule: On a planet

)
astWalker.walkGherkinDocument(source)
astWalker.walkGherkinDocument(gherkinDocument)

@@ -490,3 +490,3 @@ assert.deepEqual(ruleName, ['On a planet', 'On an exoplanet'])

it('is called for each features', () => {
const source = parse(`Feature: Solar System
const gherkinDocument = parse(`Feature: Solar System

@@ -509,3 +509,3 @@ Rule: On a planet

)
astWalker.walkGherkinDocument(source)
astWalker.walkGherkinDocument(gherkinDocument)

@@ -519,8 +519,8 @@ assert.deepEqual(featureName, ['Solar System'])

it('does not fail with empty/commented documents', () => {
const source = parse('# Feature: Solar System')
const gherkinDocument = parse('# Feature: Solar System')
const astWalker = new GherkinDocumentWalker()
astWalker.walkGherkinDocument(source)
astWalker.walkGherkinDocument(gherkinDocument)
})
})
})

@@ -7,3 +7,3 @@ import * as messages from '@cucumber/messages'

import fs from 'fs'
import glob from 'glob'
import fg from 'fast-glob'
import { promisify } from 'util'

@@ -14,4 +14,4 @@

describe('Walking with messages', () => {
const localMessageFiles = glob.sync(`${__dirname}/messages/**/*.ndjson`)
const tckMessageFiles = glob.sync(
const localMessageFiles = fg.sync(`${__dirname}/messages/**/*.ndjson`)
const tckMessageFiles = fg.sync(
`${__dirname}/../../../compatibility-kit/javascript/features/**/*.ndjson`

@@ -18,0 +18,0 @@ )

import * as messages from '@cucumber/messages'
import { AstBuilder, Parser, GherkinClassicTokenMatcher } from '@cucumber/gherkin'
import {
AstBuilder,
Parser,
GherkinClassicTokenMatcher,
GherkinInMarkdownTokenMatcher,
} from '@cucumber/gherkin'
export default function parse(source: string): messages.GherkinDocument {
export default function parse(
source: string,
tokenMatcher:
| GherkinClassicTokenMatcher
| GherkinInMarkdownTokenMatcher = new GherkinClassicTokenMatcher()
): messages.GherkinDocument {
const newId = messages.IdGenerator.uuid()
const parser = new Parser(new AstBuilder(newId), new GherkinClassicTokenMatcher())
const gherkinDocument = parser.parse(source)
gherkinDocument.uri = ''
return gherkinDocument
const parser = new Parser(new AstBuilder(newId), tokenMatcher)
try {
const gherkinDocument = parser.parse(source)
gherkinDocument.uri = ''
return gherkinDocument
} catch (err) {
err.message += `\n${source}`
throw err
}
}
import assert from 'assert'
import path from 'path'
import parse from './parse'
import pretty from '../src/pretty'
import pretty, { escapeCell } from '../src/pretty'
import { GherkinClassicTokenMatcher, GherkinInMarkdownTokenMatcher } from '@cucumber/gherkin'
import fg from 'fast-glob'
import fs from 'fs'
import * as messages from '@cucumber/messages'
describe('PrettyFormatter', () => {
it('renders a feature with no scenarios', () => {
assertPrettyIdentical('Feature: hello\n')
describe('pretty', () => {
it('renders an empty file', () => {
checkGherkinToAstToMarkdownToAstToGherkin('')
})
it('renders the language header if it is not "en"', () => {
checkGherkinToAstToGherkin(`# language: no
Egenskap: hallo
`)
})
it('renders a feature with empty scenarios', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Scenario: Two
`)
})
it('renders a feature with two scenarios', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -22,3 +42,3 @@ Scenario: one

it('renders a feature with two scenarios in a rule', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -36,3 +56,3 @@ Rule: ok

it('renders a feature with background and scenario', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -48,3 +68,3 @@ Background: bbb

it('renders a rule with background and scenario', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello

@@ -62,3 +82,3 @@ Rule: machin

it('renders tags when set', () => {
assertPrettyIdentical(`@featureTag
checkGherkinToAstToMarkdownToAstToGherkin(`@featureTag
Feature: hello

@@ -77,4 +97,78 @@

it('renders examples tables', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a a <text> and a <number>
Examples: some data
| text | number |
| a | 1 |
| ab | 10 |
| abc | 100 |
`)
})
it('renders data tables', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a data table:
| text | numbers |
| a | 1 |
| ab | 10 |
| abc | 100 |
`)
})
describe('DocString', () => {
it('is rendered with type', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a doc string:
\`\`\`json
{
"foo": "bar"
}
\`\`\`
`)
})
it('escapes DocString separators', () => {
checkGherkinToAstToMarkdownToAstToGherkin(`Feature: hello
Scenario: one
Given a doc string:
\`\`\`
2
\`\`
3
\\\`\\\`\\\`
4
\\\`\\\`\\\`\`
5
\\\`\\\`\\\`\`\`
\`\`\`
`)
})
})
xit('renders comments', () => {
checkGherkinToAstToGherkin(`# one
Feature: hello
Scenario: one
# two
Given a doc string:
"""
a
\\"\\"\\"
b
"""
`)
})
it('renders descriptions when set', () => {
assertPrettyIdentical(`Feature: hello
checkGherkinToAstToGherkin(`Feature: hello
So this is a feature

@@ -96,7 +190,78 @@

})
const featureFiles = fg.sync(`${__dirname}/../../../gherkin/testdata/good/*.feature`)
for (const featureFile of featureFiles) {
const relativePath = path.relative(__dirname, featureFile)
it(`renders ${relativePath}`, () => {
const gherkinSource = fs.readFileSync(featureFile, 'utf-8')
const gherkinDocument = parse(gherkinSource, new GherkinClassicTokenMatcher())
const formattedGherkinSource = pretty(gherkinDocument, 'gherkin')
const language = gherkinDocument.feature?.language || 'en'
const newGherkinDocument = checkGherkinToAstToGherkin(formattedGherkinSource, language)
assert(newGherkinDocument)
// TODO: comments
if (gherkinDocument.comments.length === 0) {
assert.deepStrictEqual(neutralize(newGherkinDocument), neutralize(gherkinDocument))
}
})
}
describe('escapeCell', () => {
it('escapes nothing', () => {
assert.strictEqual(escapeCell('hello'), 'hello')
})
it('escapes newline', () => {
assert.strictEqual(escapeCell('\n'), '\\n')
})
it('escapes pipe', () => {
assert.strictEqual(escapeCell('|'), '\\|')
})
it('escapes backslash', () => {
assert.strictEqual(escapeCell('\\'), '\\\\')
})
})
})
function assertPrettyIdentical(source: string) {
const gherkinDocument = parse(source)
assert.strictEqual(pretty(gherkinDocument), source)
function checkGherkinToAstToMarkdownToAstToGherkin(gherkinSource: string) {
const gherkinDocument = parse(gherkinSource, new GherkinClassicTokenMatcher())
// console.log({gherkinDocument})
const markdownSource = pretty(gherkinDocument, 'markdown')
// console.log(`<Markdown>${markdownSource}</Markdown>`)
const markdownGherkinDocument = parse(markdownSource, new GherkinInMarkdownTokenMatcher())
// console.log({markdownGherkinDocument})
const newGherkinSource = pretty(markdownGherkinDocument, 'gherkin')
// console.log(`<Gherkin>${newGherkinSource}</Gherkin>`)
assert.strictEqual(newGherkinSource, gherkinSource)
}
function checkGherkinToAstToGherkin(
gherkinSource: string,
language = 'en'
): messages.GherkinDocument {
const gherkinDocument = parse(gherkinSource, new GherkinClassicTokenMatcher(language))
const newGherkinSource = pretty(gherkinDocument, 'gherkin')
// console.log(`<Gherkin>${newGherkinSource}</Gherkin>`)
assert.strictEqual(newGherkinSource, gherkinSource)
return gherkinDocument
}
function neutralize(gherkinDocument: messages.GherkinDocument): messages.GherkinDocument {
const json = JSON.stringify(
gherkinDocument,
(key, value) => {
if ('id' === key) {
return 'id'
} else if (['column', 'line'].includes(key)) {
return '0'
} else {
return value
}
},
2
)
return JSON.parse(json)
}

@@ -9,4 +9,5 @@ {

"src",
"test"
"test",
"package.json"
]
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc