From 1ceb2f9c79cb9196b4a8ea2b342adda8ba3f956d Mon Sep 17 00:00:00 2001 From: Peter Bacon Darwin Date: Thu, 27 Apr 2017 10:17:15 +0100 Subject: [PATCH] build(aio): add new post-process dgeni package This package will allow us to do complex post-processing on the HTML that is rendered by Nunjucks. --- aio/package.json | 1 + .../transforms/angular-base-package/index.js | 3 +- .../transforms/post-process-package/index.js | 5 ++ .../processors/post-process-html.js | 37 +++++++++++ .../processors/post-process-html.spec.js | 62 +++++++++++++++++++ aio/yarn.lock | 55 +++++++++++++++- 6 files changed, 160 insertions(+), 3 deletions(-) create mode 100644 aio/tools/transforms/post-process-package/index.js create mode 100644 aio/tools/transforms/post-process-package/processors/post-process-html.js create mode 100644 aio/tools/transforms/post-process-package/processors/post-process-html.spec.js diff --git a/aio/package.json b/aio/package.json index 0d58b16fa6..4015a08465 100644 --- a/aio/package.json +++ b/aio/package.json @@ -82,6 +82,7 @@ "lighthouse": "^1.6.3", "lodash": "^4.17.4", "protractor": "~5.1.0", + "rehype": "^4.0.0", "remark": "^7.0.0", "remark-autolink-headings": "^4.0.0", "remark-html": "^6.0.0", diff --git a/aio/tools/transforms/angular-base-package/index.js b/aio/tools/transforms/angular-base-package/index.js index 6cd6b4b7fd..0ee75eb0ee 100644 --- a/aio/tools/transforms/angular-base-package/index.js +++ b/aio/tools/transforms/angular-base-package/index.js @@ -14,11 +14,12 @@ const linksPackage = require('../links-package'); const examplesPackage = require('../examples-package'); const targetPackage = require('../target-package'); const remarkPackage = require('../remark-package'); +const postProcessPackage = require('../post-process-package'); const { PROJECT_ROOT, DOCS_OUTPUT_PATH, TEMPLATES_PATH, requireFolder } = require('../config'); module.exports = new Package('angular-base', [ - jsdocPackage, nunjucksPackage, linksPackage, examplesPackage, targetPackage, remarkPackage + jsdocPackage, nunjucksPackage, linksPackage, examplesPackage, targetPackage, remarkPackage, postProcessPackage ]) // Register the processors diff --git a/aio/tools/transforms/post-process-package/index.js b/aio/tools/transforms/post-process-package/index.js new file mode 100644 index 0000000000..559bc57d55 --- /dev/null +++ b/aio/tools/transforms/post-process-package/index.js @@ -0,0 +1,5 @@ +var Package = require('dgeni').Package; +var base = require('dgeni-packages/base'); + +module.exports = new Package('post-process-package', [base]) + .processor(require('./processors/post-process-html')); 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 new file mode 100644 index 0000000000..ddd2387205 --- /dev/null +++ b/aio/tools/transforms/post-process-package/processors/post-process-html.js @@ -0,0 +1,37 @@ +const rehype = require('rehype'); + +/** + * @dgProcessor postProcessHtml + * + * @description + * Use the rehype processing engine to manipulate the + * `renderedContent` HTML via rehype "plugins" that work with HTML ASTs (HASTs). + * See https://github.com/wooorm/rehype + * + * Each plugin is a factory function that will be called with the "rehype" engine as `this`. + * The factory should return a function that takes a HAST and returns a `boolean` or `undefined`. + * The HAST can be mutated by the this function. + * If `false` is returned then the processing stops with that plugin. + * + * @property docTypes {string[]} the `docTypes` of docs that should be post-processed + * @property plugins {Function[]} the rehype plugins that will modify the HAST. + * + */ +module.exports = function postProcessHtml() { + return { + $runAfter: ['docs-rendered'], + $runBefore: ['writing-files'], + docTypes: [], + plugins: [], + $process(docs) { + const engine = rehype() + .data('settings', { fragment: true }); + this.plugins.forEach(plugin => engine.use(plugin)); + + docs + .filter(doc => this.docTypes.indexOf(doc.docType) !== -1) + .forEach(doc => + doc.renderedContent = engine.processSync(doc.renderedContent).contents); + } + }; +}; 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 new file mode 100644 index 0000000000..4ec2854198 --- /dev/null +++ b/aio/tools/transforms/post-process-package/processors/post-process-html.spec.js @@ -0,0 +1,62 @@ +const testPackage = require('../../helpers/test-package'); +const Dgeni = require('dgeni'); + +describe('postProcessHtml', function() { + let dgeni, injector, processor; + + beforeEach(function() { + dgeni = new Dgeni([testPackage('post-process-package', true)]); + injector = dgeni.configureInjector(); + processor = injector.get('postProcessHtml'); + processor.docTypes = ['a', 'b']; + }); + + it('should be available from the injector', () => { + expect(processor).toBeDefined(); + }); + + it('should only process docs that match the specified docTypes', () => { + const elements = []; + const captureFirstElement = ast => { + elements.push(ast.children[0].tagName); + }; + processor.plugins = [() => captureFirstElement]; + + const docs = [ + { docType: 'a', renderedContent: '' }, + { docType: 'b', renderedContent: '' }, + { docType: 'c', renderedContent: '' }, + { docType: 'd', renderedContent: '' }, + ]; + processor.$process(docs); + expect(elements).toEqual(['a', 'b']); + }); + + it('should run all the plugins on each doc', () => { + const capitalizeFirstElement = ast => { + ast.children[0].tagName = ast.children[0].tagName.toUpperCase(); + }; + const addOneToFirstElement = ast => { + ast.children[0].tagName = ast.children[0].tagName + '1'; + }; + const elements = []; + const captureFirstElement = ast => { + elements.push(ast.children[0].tagName); + }; + + const docs = [ + { docType: 'a', renderedContent: '' }, + { docType: 'b', renderedContent: '' }, + { docType: 'c', renderedContent: '' }, + { docType: 'd', renderedContent: '' }, + ]; + + processor.plugins = [ + () => capitalizeFirstElement, + () => addOneToFirstElement, + () => captureFirstElement + ]; + processor.$process(docs); + expect(elements).toEqual(['A1', 'B1']); + }); +}); diff --git a/aio/yarn.lock b/aio/yarn.lock index 4f6eac49fd..02e08830e9 100644 --- a/aio/yarn.lock +++ b/aio/yarn.lock @@ -1219,7 +1219,7 @@ combined-stream@^1.0.5, combined-stream@~1.0.5: dependencies: delayed-stream "~1.0.0" -comma-separated-tokens@^1.0.1: +comma-separated-tokens@^1.0.0, comma-separated-tokens@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.2.tgz#4b64717a2ee363af6dd39878336bd95e42d063e7" dependencies: @@ -3014,10 +3014,24 @@ hash.js@^1.0.0: dependencies: inherits "^2.0.1" +hast-util-from-parse5@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-1.1.0.tgz#359cc339dc8ccf1dfaca41915ad63fd546130acd" + dependencies: + camelcase "^3.0.0" + has "^1.0.1" + hastscript "^3.0.0" + property-information "^3.1.0" + vfile-location "^2.0.0" + hast-util-is-element@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-1.0.0.tgz#3f7216978b2ae14d98749878782675f33be3ce00" +hast-util-parse-selector@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.1.0.tgz#b55c0f4bb7bb2040c889c325ef87ab29c38102b4" + hast-util-sanitize@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hast-util-sanitize/-/hast-util-sanitize-1.1.0.tgz#9b4bc3731043fe92e1253a9a4ca7bcc4148d06f2" @@ -3046,6 +3060,16 @@ hast-util-whitespace@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-1.0.0.tgz#bd096919625d2936e1ff17bc4df7fd727f17ece9" +hastscript@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-3.0.1.tgz#9edfab8839e6d67bc6835297a0bf9ba6ad7a00a9" + dependencies: + camelcase "^3.0.0" + comma-separated-tokens "^1.0.0" + hast-util-parse-selector "^2.0.0" + property-information "^3.0.0" + space-separated-tokens "^1.0.0" + hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -4902,6 +4926,10 @@ parse5@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" +parse5@^2.1.5: + version "2.2.3" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-2.2.3.tgz#0c4fc41c1000c5e6b93d48b03f8083837834e9f6" + parse5@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/parse5/-/parse5-3.0.2.tgz#05eff57f0ef4577fb144a79f8b9a967a6cc44510" @@ -5324,7 +5352,7 @@ promise@^7.1.1: dependencies: asap "~2.0.3" -property-information@^3.1.0: +property-information@^3.0.0, property-information@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/property-information/-/property-information-3.1.0.tgz#1581bf8a445dfbfef759775a86700e8dda18b4a1" @@ -5623,6 +5651,29 @@ regjsparser@^0.1.4: dependencies: jsesc "~0.5.0" +rehype-parse@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-3.1.0.tgz#7f5227a597a3f39fc4b938646161539c444ee728" + dependencies: + hast-util-from-parse5 "^1.0.0" + parse5 "^2.1.5" + xtend "^4.0.1" + +rehype-stringify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/rehype-stringify/-/rehype-stringify-3.0.0.tgz#9fef0868213c2dce2f780b76f3d0488c85e819eb" + dependencies: + hast-util-to-html "^3.0.0" + xtend "^4.0.1" + +rehype@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/rehype/-/rehype-4.0.0.tgz#2ed92dd269bfa549f7108fd2c4f6f626d27c7be4" + dependencies: + rehype-parse "^3.0.0" + rehype-stringify "^3.0.0" + unified "^6.0.0" + relateurl@0.2.x: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"