From bcbee13e26a482c72a9c938261b01298a66f18b1 Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Wed, 10 May 2017 10:59:50 +0100 Subject: [PATCH] build(aio): fail build if more than h1 is found in a doc Closes #16193 --- .../transforms/angular-base-package/index.js | 3 +- .../post-processors/h1-checker.js | 18 +++++++ .../post-processors/h1-checker.spec.js | 49 +++++++++++++++++++ .../processors/post-process-html.js | 21 ++++---- .../processors/post-process-html.spec.js | 6 ++- 5 files changed, 84 insertions(+), 13 deletions(-) create mode 100644 aio/tools/transforms/angular-base-package/post-processors/h1-checker.js create mode 100644 aio/tools/transforms/angular-base-package/post-processors/h1-checker.spec.js diff --git a/aio/tools/transforms/angular-base-package/index.js b/aio/tools/transforms/angular-base-package/index.js index 58580d02bb..83d1fd84df 100644 --- a/aio/tools/transforms/angular-base-package/index.js +++ b/aio/tools/transforms/angular-base-package/index.js @@ -127,7 +127,8 @@ module.exports = new Package('angular-base', [ addImageDimensions.basePath = path.resolve(AIO_PATH, 'src'); postProcessHtml.plugins = [ require('./post-processors/autolink-headings'), - addImageDimensions + addImageDimensions, + require('./post-processors/h1-checker'), ]; }) diff --git a/aio/tools/transforms/angular-base-package/post-processors/h1-checker.js b/aio/tools/transforms/angular-base-package/post-processors/h1-checker.js new file mode 100644 index 0000000000..74a7c16f26 --- /dev/null +++ b/aio/tools/transforms/angular-base-package/post-processors/h1-checker.js @@ -0,0 +1,18 @@ +const visit = require('unist-util-visit'); +const is = require('hast-util-is-element'); +const source = require('unist-util-source'); + +module.exports = function h1CheckerPostProcessor() { + return (ast, file) => { + let h1s = []; + visit(ast, node => { + if (is(node, 'h1')) { + h1s.push(node); + } + }); + if (h1s.length > 1) { + const h1Src = h1s.map(node => source(node, file)).join(', '); + file.fail(`More than one h1 found [${h1Src}]`); + } + }; +}; diff --git a/aio/tools/transforms/angular-base-package/post-processors/h1-checker.spec.js b/aio/tools/transforms/angular-base-package/post-processors/h1-checker.spec.js new file mode 100644 index 0000000000..a23f1b007d --- /dev/null +++ b/aio/tools/transforms/angular-base-package/post-processors/h1-checker.spec.js @@ -0,0 +1,49 @@ +var testPackage = require('../../helpers/test-package'); +var Dgeni = require('dgeni'); +const plugin = require('./h1-checker'); + +describe('h1Checker postprocessor', () => { + let processor, createDocMessage; + + beforeEach(() => { + const dgeni = new Dgeni([testPackage('angular-base-package')]); + const injector = dgeni.configureInjector(); + createDocMessage = injector.get('createDocMessage'); + processor = injector.get('postProcessHtml'); + processor.docTypes = ['a']; + processor.plugins = [plugin]; + }); + + it('should complain if there is more than one h1 in a document', () => { + const doc = { + docType: 'a', + renderedContent: ` +

Heading 1

+

Heading 2

+

Heading 1a

+ ` + }; + expect(() => processor.$process([doc])).toThrowError(createDocMessage('More than one h1 found [

Heading 1,

Heading 1a

]', doc)); + }); + + it('should not complain if there is exactly one h1 in a document', () => { + const doc = { + docType: 'a', + renderedContent: ` +

Heading 1

+

Heading 2

+ ` + }; + expect(() => processor.$process([doc])).not.toThrow(); + }); + + it('should not complain if there are no h1s in a document', () => { + const doc = { + docType: 'a', + renderedContent: ` +

Heading 2

+ ` + }; + expect(() => processor.$process([doc])).not.toThrow(); + }); +}); \ No newline at end of file diff --git a/aio/tools/transforms/post-process-package/processors/post-process-html.js b/aio/tools/transforms/post-process-package/processors/post-process-html.js index 8ec02f0477..9517c63e4e 100644 --- a/aio/tools/transforms/post-process-package/processors/post-process-html.js +++ b/aio/tools/transforms/post-process-package/processors/post-process-html.js @@ -28,19 +28,20 @@ module.exports = function postProcessHtml(log, createDocMessage) { .data('settings', { fragment: true }); this.plugins.forEach(plugin => engine.use(plugin)); + let vFile; + docs .filter(doc => this.docTypes.indexOf(doc.docType) !== -1) .forEach(doc => { - const vFile = engine.processSync(doc.renderedContent); - vFile.messages.forEach(m => { - const message = createDocMessage(m.message, doc); - if (m.fatal) { - throw new Error(message); - } else { - log.warn(message); - } - }); - doc.renderedContent = vFile.contents; + try { + vFile = engine.processSync(doc.renderedContent); + doc.renderedContent = vFile.contents; + vFile.messages.forEach(m => { + log.warn(createDocMessage(m.message, doc)); + }); + } catch(e) { + throw new Error(createDocMessage(e.message, doc)); + } }); } }; diff --git a/aio/tools/transforms/post-process-package/processors/post-process-html.spec.js b/aio/tools/transforms/post-process-package/processors/post-process-html.spec.js index 33c8173855..9516f0714d 100644 --- a/aio/tools/transforms/post-process-package/processors/post-process-html.spec.js +++ b/aio/tools/transforms/post-process-package/processors/post-process-html.spec.js @@ -2,11 +2,12 @@ const testPackage = require('../../helpers/test-package'); const Dgeni = require('dgeni'); describe('postProcessHtml', function() { - let dgeni, injector, processor; + let dgeni, injector, processor, createDocMessage; beforeEach(function() { dgeni = new Dgeni([testPackage('post-process-package', true)]); injector = dgeni.configureInjector(); + createDocMessage = injector.get('createDocMessage'); processor = injector.get('postProcessHtml'); processor.docTypes = ['a', 'b']; }); @@ -75,8 +76,9 @@ describe('postProcessHtml', function() { const addError = (ast, file) => { file.fail('There was an error'); }; + const doc = { docType: 'a', renderedContent: '' }; processor.plugins = [() => addError]; - expect(() => processor.$process([{ docType: 'a', renderedContent: '' }])).toThrow(); + expect(() => processor.$process([doc])).toThrowError(createDocMessage('There was an error', doc)); expect(log.error).not.toHaveBeenCalled(); }); });