Skip to content

Commit

Permalink
test(html) Bring test coverage back up for HTML transform - Smarter w…
Browse files Browse the repository at this point in the history
…hitespace rule

Signed-off-by: Jerome Simeon <[email protected]>
  • Loading branch information
jeromesimeon committed Jun 30, 2020
1 parent 8969b03 commit f0ea257
Show file tree
Hide file tree
Showing 38 changed files with 1,006 additions and 9,927 deletions.
110 changes: 55 additions & 55 deletions packages/markdown-html/src/HtmlTransformer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,17 @@ const HtmlTransformer = require('./HtmlTransformer');
let htmlTransformer = null;
let ciceroTransformer = null;

/**
* Prepare the text for parsing (normalizes new lines, etc)
* @param {string} input - the text for the clause
* @return {string} - the normalized text for the clause
*/
function normalizeNLs(input) {
// we replace all \r and \n with \n
let text = input.replace(/\r/gm,'');
return text;
}

// @ts-ignore
beforeAll(() => {
htmlTransformer = new HtmlTransformer();
Expand All @@ -35,63 +46,19 @@ beforeAll(() => {
*/
function getMarkdownFiles() {
const result = [];
const files = fs.readdirSync(__dirname + '/../test/data');
const files = fs.readdirSync(__dirname + '/../test/data/markdown');

files.forEach(function(file) {
if(file.endsWith('.md')) {
let contents = fs.readFileSync(__dirname + '/../test/data/' + file, 'utf8');
let contents = fs.readFileSync(__dirname + '/../test/data/markdown/' + file, 'utf8');
result.push([file, contents]);
}
});

return result;
}

/**
* Get the name and contents of all markdown snippets
* used in a commonmark spec file
* @returns {*} an array of name/contents tuples
*/
function getMarkdownSpecFiles() {
const result = [];
const specExamples = extractSpecTests(__dirname + '/../test/data/spec.txt');
specExamples.forEach(function(example) {
result.push([`${example.section}-${example.number}`, example.markdown]);
});

return result;
}

/**
* Extracts all the test md snippets from a commonmark spec file
* @param {string} testfile the file to use
* @return {*} the examples
*/
function extractSpecTests(testfile) {
let data = fs.readFileSync(testfile, 'utf8');
let examples = [];
let current_section = '';
let example_number = 0;
let tests = data
.replace(/\r\n?/g, '\n') // Normalize newlines for platform independence
.replace(/^<!-- END TESTS -->(.|[\n])*/m, '');

tests.replace(/^`{32} example\n([\s\S]*?)^\.\n([\s\S]*?)^`{32}$|^#{1,6} *(.*)$/gm,
function(_, markdownSubmatch, htmlSubmatch, sectionSubmatch){
if (sectionSubmatch) {
current_section = sectionSubmatch;
} else {
example_number++;
examples.push({markdown: markdownSubmatch,
html: htmlSubmatch,
section: current_section,
number: example_number});
}
});
return examples;
}

describe.only('html', () => {
describe('markdown <-> html', () => {
getMarkdownFiles().forEach(([file, markdownText], i) => {
it(`converts ${file} to html`, () => {
const json = ciceroTransformer.fromMarkdown(markdownText, 'json');
Expand All @@ -111,13 +78,46 @@ describe.only('html', () => {
});
});

describe('markdown-spec', () => {
getMarkdownSpecFiles().forEach( ([file, markdownText]) => {
it(`converts ${file} to concerto JSON`, () => {
const json = ciceroTransformer.fromMarkdown(markdownText, 'json');
expect(json).toMatchSnapshot(); // (1)
const html = htmlTransformer.toHtml(json);
expect(html).toMatchSnapshot(); // (2)
/**
* Get the name and contents of all ciceromark test files
* @returns {*} an array of name/contents tuples
*/
function getCiceroMarkFiles() {
const result = [];
const files = fs.readdirSync(__dirname + '/../test/data/ciceromark');

files.forEach(function(file) {
if(file.endsWith('.json')) {
let contents = normalizeNLs(fs.readFileSync(__dirname + '/../test/data/ciceromark/' + file, 'utf8'));
result.push([file, contents]);
}
});

return result;
}

describe('ciceromark <-> html', () => {
getCiceroMarkFiles().forEach( ([file, jsonText], index) => {
it(`converts ${file} to and from CiceroMark`, () => {
const value = JSON.parse(jsonText);
const html = htmlTransformer.toHtml(value);

// check no changes to html
expect(html).toMatchSnapshot(); // (1)

// load expected html
const expectedHtml = normalizeNLs(fs.readFileSync(__dirname + '/../test/data/ciceromark/' + file.replace(/.json$/,'.html'), 'utf8'));
expect(expectedHtml).toMatchSnapshot(); // (2)

// convert the expected html and compare
const expectedCiceroMarkValue = htmlTransformer.toCiceroMark(expectedHtml);
expect(expectedCiceroMarkValue).toMatchSnapshot(); // (3)

// check that html created from ciceromark and from the expected html is the same
expect(html).toEqual(expectedHtml);

// check roundtrip
expect(expectedCiceroMarkValue).toEqual(value);
});
});
});
});
20 changes: 11 additions & 9 deletions packages/markdown-html/src/ToCiceroMarkVisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,27 @@ class ToCiceroMarkVisitor {
* Deserialize a DOM element.
*
* @param {Object} element DOM element
* @param {boolean} ignoreSpace override
* @return {Any} node
*/
deserializeElement(element) {
deserializeElement(element, ignoreSpace) {
let node;

//console.log('tagName', element.tagName);
if (!element.tagName) {
element.tagName = '';
}

const next = elements => {
const next = (elements, ignoreSpace) => {
if (Object.prototype.toString.call(elements) === '[object NodeList]') {
elements = Array.from(elements);
}

switch (typeOf(elements)) {
case 'array':
return this.deserializeElements(elements);
return this.deserializeElements(elements, ignoreSpace);
case 'object':
return this.deserializeElement(elements);
return this.deserializeElement(elements, ignoreSpace);
case 'null':
case 'undefined':
return;
Expand All @@ -83,7 +84,7 @@ class ToCiceroMarkVisitor {

for (const rule of this.rules) {
if (!rule.deserialize) {continue;}
const ret = rule.deserialize(element, next);
const ret = rule.deserialize(element, next, ignoreSpace);
const type = typeOf(ret);

if (
Expand Down Expand Up @@ -118,21 +119,22 @@ class ToCiceroMarkVisitor {
break;
}

return node || next(element.childNodes);
return node || next(element.childNodes, ignoreSpace);
}

/**
* Deserialize an array of DOM elements.
*
* @param {Array} elements DOM elements
* @param {boolean} ignoreSpace override
* @return {Array} array of nodes
*/
deserializeElements(elements = []) {
deserializeElements(elements = [], ignoreSpace) {
let nodes = [];

elements.filter(this.cruftNewline).forEach(element => {
// console.log('element -- ', element);
const node = this.deserializeElement(element);
const node = this.deserializeElement(element, ignoreSpace);
// console.log('node -- ', node);

switch (typeOf(node)) {
Expand Down Expand Up @@ -166,7 +168,7 @@ class ToCiceroMarkVisitor {
}
const children = Array.from(fragment.childNodes);
// console.log('children -- ', children);
const nodes = this.deserializeElements(children);
const nodes = this.deserializeElements(children, true);
// console.log('nodes', nodes);
return {
'$class': `${NS_PREFIX_CommonMarkModel}${'Document'}`,
Expand Down
81 changes: 44 additions & 37 deletions packages/markdown-html/src/ToHtmlStringVisitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,32 +54,6 @@ class ToHtmlStringVisitor {
return parameters.result;
}

/**
* Set parameters for inner node
* @param {*} parametersOut - the current parameters
* @return {*} the new parameters with first set to true
*/
static mkParametersIn(parametersOut) {
let parameters = {};
parameters.result = '';
parameters.first = true;
parameters.indent = parametersOut.indent; // Same indentation
return parameters;
}

/**
* Set parameters for inner list
* @param {*} parametersOut - the current parameters
* @return {*} the new parameters with first set to true
*/
static mkParametersInList(parametersOut) {
let parameters = {};
parameters.result = '';
parameters.first = true;
parameters.indent = parametersOut.indent+1; // Increases indentation
return parameters;
}

/**
* Visit a node
* @param {*} thing the object being visited
Expand All @@ -88,31 +62,64 @@ class ToHtmlStringVisitor {
visit(thing, parameters) {

switch(thing.getType()) {
case 'Clause':
// {
// const ciceroMarkTransformer = new CiceroMarkTransformer();
// console.log(JSON.stringify(ciceroMarkTransformer.getSerializer().toJSON(thing), null, 4));
// }
parameters.result += `<div class="clause" name="${thing.name}" src="${thing.src}">\n${ToHtmlStringVisitor.visitChildren(this, thing)}</div>\n`;
case 'Clause': {
let attributes = `class="clause" name="${thing.name}"`;
if (thing.elementType) {
attributes += ` elementType="${thing.elementType}"`;
}
if (thing.src) {
attributes += ` src="${thing.src}"`;
}
parameters.result += `<div ${attributes}>\n${ToHtmlStringVisitor.visitChildren(this, thing)}</div>\n`;
}
break;
case 'Variable': {
parameters.result += `<span class="variable" name="${thing.name}">${thing.value}</span>`;
let attributes = `class="variable" name="${thing.name}"`;
if (thing.elementType) {
attributes += ` elementType="${thing.elementType}"`;
}
if (thing.identifiedBy) {
attributes += ` identifiedBy="${thing.identifiedBy}"`;
}
parameters.result += `<span ${attributes}>${thing.value}</span>`;
}
break;
case 'FormattedVariable': {
parameters.result += `<span class="variable" name="${thing.name}" format="${thing.format}">${thing.value}</span>`;
let attributes = `class="variable" name="${thing.name}" format="${thing.format}"`;
if (thing.elementType) {
attributes += ` elementType="${thing.elementType}"`;
}
if (thing.identifiedBy) {
attributes += ` identifiedBy="${thing.identifiedBy}"`;
}
parameters.result += `<span ${attributes}>${thing.value}</span>`;
}
break;
case 'EnumVariable': {
const enumValues = encodeURIComponent(JSON.stringify(thing.enumValues));
parameters.result += `<span class="variable" name="${thing.name}" enumValues="${enumValues}">${thing.value}</span>`;
let attributes = `class="variable" name="${thing.name}" enumValues="${enumValues}"`;
if (thing.elementType) {
attributes += ` elementType="${thing.elementType}"`;
}
if (thing.identifiedBy) {
attributes += ` identifiedBy="${thing.identifiedBy}"`;
}
parameters.result += `<span ${attributes}>${thing.value}</span>`;
}
break;
case 'Conditional':
parameters.result += `<span class="conditional" name="${thing.name}" whenTrue="${thing.whenTrue[0] ? thing.whenTrue[0].text : ''}" whenFalse="${thing.whenFalse[0] ? thing.whenFalse[0].text : ''}">${thing.nodes[0].text}</span>`;
break;
case 'Formula':
parameters.result += `<span class="formula" name="${thing.name}">${thing.value}</span>`;
case 'Formula': {
let attributes = `class="formula" name="${thing.name}"`;
if (thing.code) {
attributes += ` code="${encodeURIComponent(thing.code)}"`;
}
if (thing.dependencies) {
attributes += ` dependencies="${encodeURIComponent(JSON.stringify(thing.dependencies))}"`;
}
parameters.result += `<span ${attributes}>${thing.value}</span>`;
}
break;
case 'CodeBlock': {
const info = thing.info;
Expand Down
Loading

0 comments on commit f0ea257

Please sign in to comment.