From 0355142737237e2729fe8f414c2e20f4f58dfa18 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Mon, 23 Oct 2017 17:58:49 +0100 Subject: [PATCH] build(aio): fail doc-gen if a code-example is badly formatted. This will catch the problem that was missed in https://github.com/angular/angular/pull/19845#issuecomment-338626662 --- .../processors/render-examples.js | 47 +++++++++++++++---- .../processors/render-examples.spec.js | 13 ++++- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/aio/tools/transforms/examples-package/processors/render-examples.js b/aio/tools/transforms/examples-package/processors/render-examples.js index 9ff0ce19e8..ac777cf9d0 100644 --- a/aio/tools/transforms/examples-package/processors/render-examples.js +++ b/aio/tools/transforms/examples-package/processors/render-examples.js @@ -12,16 +12,43 @@ module.exports = function renderExamples(getExampleRegion) { docs.forEach(doc => { if (doc.renderedContent) { // We match either `code-example` or `code-pane` elements that have a path attribute - doc.renderedContent = doc.renderedContent.replace(/<(code-example|code-pane)([^>]*)>[^<]*<\/\1>/g, (original, element, attributes) => { - const attrMap = parseAttributes(attributes); - if (attrMap.path) { - // We found a path attribute so look up the example and rebuild the HTML - const exampleContent = getExampleRegion(doc, attrMap.path, attrMap.region); - return `<${element}${renderAttributes(attrMap)}>\n${exampleContent}\n`; - } - // No path attribute so just ignore this one - return original; - }); + doc.renderedContent = doc.renderedContent.replace( + /<(code-example|code-pane)([^>]*)>[^<]*<\/([^>]+)>/g, + (original, openingTag, attributes, closingTag) => { + const attrMap = parseAttributes(attributes); + if (attrMap.path) { + if (closingTag !== openingTag) { + // The markdown renderer will wrap what it thinks is a paragraph in `

` and `

` tags. + // If you do not leave a blank line between a paragraph of text and a `` then + // the markdown renderer may add a paragraph marker "in-between" the opening and closing + // tags of the code-example. For example: + // + // ``` + // Some paragraph + // + // + // + // ``` + // + // will be rendered as: + // + // ``` + //

Some paragraph + // + //

+ //
+ // ``` + throw new Error( + 'Badly formed example: ' + original + ' - closing tag does not match opening tag.\n' + + ' - Perhaps you forgot to put a blank line before the example?'); + } + // We found a path attribute so look up the example and rebuild the HTML + const exampleContent = getExampleRegion(doc, attrMap.path, attrMap.region); + return `<${openingTag}${renderAttributes(attrMap)}>\n${exampleContent}\n`; + } + // No path attribute so just ignore this one + return original; + }); } }); } diff --git a/aio/tools/transforms/examples-package/processors/render-examples.spec.js b/aio/tools/transforms/examples-package/processors/render-examples.spec.js index c0e1f90a1f..362d8406f5 100644 --- a/aio/tools/transforms/examples-package/processors/render-examples.spec.js +++ b/aio/tools/transforms/examples-package/processors/render-examples.spec.js @@ -34,10 +34,10 @@ describe('renderExamples processor', () => { describe(CODE_TAG, () => { it(`should ignore a <${CODE_TAG}> tags with no path attribute`, () => { const docs = [ - { renderedContent: `Some text\n<${CODE_TAG}>Some code\n<${CODE_TAG} class="anti-pattern" title="Bad Code">do not do this` } + { renderedContent: `Some text\n<${CODE_TAG}>Some code\n<${CODE_TAG} class="anti-pattern" title="Bad Code">do not do this` } ]; processor.$process(docs); - expect(docs[0].renderedContent).toEqual(`Some text\n<${CODE_TAG}>Some code\n<${CODE_TAG} class="anti-pattern" title="Bad Code">do not do this`); + expect(docs[0].renderedContent).toEqual(`Some text\n<${CODE_TAG}>Some code\n<${CODE_TAG} class="anti-pattern" title="Bad Code">do not do this`); }); it(`should replace the content of the <${CODE_TAG}> tag with the whole contents from an example file if a path is provided`, () => { @@ -88,6 +88,15 @@ describe('renderExamples processor', () => { processor.$process(docs); expect(docs[0].renderedContent).toEqual(`<${CODE_TAG} title="a "quoted" value" path="test/url">\nwhole file\n`); }); + + it('should throw an exception if the code-example tag is not closed correctly', () => { + const docs = [ + { renderedContent: `<${CODE_TAG} path="test/url">

`} + ]; + expect(() => processor.$process(docs)).toThrowError( + 'Badly formed example: <' + CODE_TAG + ' path="test/url">

- closing tag does not match opening tag.\n' + + ' - Perhaps you forgot to put a blank line before the example?'); + }); }) ); });