diff --git a/aio/package.json b/aio/package.json index 6a953e7104..463c8be4af 100644 --- a/aio/package.json +++ b/aio/package.json @@ -73,6 +73,7 @@ "fs-extra": "^2.1.2", "globby": "^6.1.0", "hast-util-is-element": "^1.0.0", + "hast-util-to-string": "^1.0.0", "html": "^1.0.0", "http-server": "^0.9.0", "image-size": "^0.5.1", diff --git a/aio/src/styles/2-modules/_code.scss b/aio/src/styles/2-modules/_code.scss index 0fa10ce522..4015777436 100644 --- a/aio/src/styles/2-modules/_code.scss +++ b/aio/src/styles/2-modules/_code.scss @@ -235,3 +235,8 @@ code-tabs md-tab-group *.mat-ripple-element, code-tabs md-tab-group *.mat-tab-bo [role="tabpanel"] { transition: none; } + +.sidenav-content code a { + color: inherit; + font-size: inherit; +} \ No newline at end of file diff --git a/aio/tools/transforms/angular-api-package/index.js b/aio/tools/transforms/angular-api-package/index.js index 4bc8db59c8..783b263e54 100644 --- a/aio/tools/transforms/angular-api-package/index.js +++ b/aio/tools/transforms/angular-api-package/index.js @@ -114,10 +114,11 @@ module.exports = new Package('angular-api', [basePackage, typeScriptPackage]) }) - .config(function(convertToJsonProcessor, postProcessHtml, EXPORT_DOC_TYPES) { + .config(function(convertToJsonProcessor, postProcessHtml, EXPORT_DOC_TYPES, autoLinkCode) { const DOCS_TO_CONVERT = EXPORT_DOC_TYPES.concat([ 'decorator', 'directive', 'pipe', 'module' ]); convertToJsonProcessor.docTypes = convertToJsonProcessor.docTypes.concat(DOCS_TO_CONVERT); postProcessHtml.docTypes = convertToJsonProcessor.docTypes.concat(DOCS_TO_CONVERT); + autoLinkCode.docTypes = DOCS_TO_CONVERT; }); diff --git a/aio/tools/transforms/angular-base-package/index.js b/aio/tools/transforms/angular-base-package/index.js index 83d1fd84df..ab05c4e976 100644 --- a/aio/tools/transforms/angular-base-package/index.js +++ b/aio/tools/transforms/angular-base-package/index.js @@ -37,6 +37,7 @@ module.exports = new Package('angular-base', [ .factory(require('./services/getImageDimensions')) .factory(require('./post-processors/add-image-dimensions')) + .factory(require('./post-processors/auto-link-code')) .config(function(checkAnchorLinksProcessor) { // This is disabled here to prevent false negatives for the `docs-watch` task. @@ -123,12 +124,13 @@ module.exports = new Package('angular-base', [ }) - .config(function(postProcessHtml, addImageDimensions) { + .config(function(postProcessHtml, addImageDimensions, autoLinkCode) { addImageDimensions.basePath = path.resolve(AIO_PATH, 'src'); postProcessHtml.plugins = [ require('./post-processors/autolink-headings'), addImageDimensions, require('./post-processors/h1-checker'), + autoLinkCode, ]; }) diff --git a/aio/tools/transforms/angular-base-package/post-processors/auto-link-code.js b/aio/tools/transforms/angular-base-package/post-processors/auto-link-code.js new file mode 100644 index 0000000000..cb6e115d04 --- /dev/null +++ b/aio/tools/transforms/angular-base-package/post-processors/auto-link-code.js @@ -0,0 +1,36 @@ +const visit = require('unist-util-visit'); +const is = require('hast-util-is-element'); +const textContent = require('hast-util-to-string'); + +/** + * Automatically add in a link to the relevant document for simple + * code blocks, e.g. `MyClass` becomes + * `MyClass` + * + * @property docTypes an array of strings. Only docs that have one of these docTypes + * will be linked to. + * Usually set to the API exported docTypes, e.g. "class", "function", "directive", etc. + */ +module.exports = function autoLinkCode(getDocFromAlias) { + autoLinkCodeImpl.docTypes = []; + return autoLinkCodeImpl; + + function autoLinkCodeImpl() { + return (ast) => { + visit(ast, node => { + if (is(node, 'code')) { + const docs = getDocFromAlias(textContent(node)); + if (docs.length === 1 && autoLinkCodeImpl.docTypes.indexOf(docs[0].docType) !== -1) { + const link = { + type: 'element', + tagName: 'a', + properties: { href: docs[0].path }, + children: node.children + }; + node.children = [link]; + } + } + }); + }; + } +}; diff --git a/aio/tools/transforms/angular-base-package/post-processors/auto-link-code.spec.js b/aio/tools/transforms/angular-base-package/post-processors/auto-link-code.spec.js new file mode 100644 index 0000000000..9ddd36a3e0 --- /dev/null +++ b/aio/tools/transforms/angular-base-package/post-processors/auto-link-code.spec.js @@ -0,0 +1,39 @@ +var createTestPackage = require('../../helpers/test-package'); +var Dgeni = require('dgeni'); + +describe('autoLinkCode post-processor', () => { + let processor, autoLinkCode, aliasMap; + + beforeEach(() => { + const testPackage = createTestPackage('angular-base-package'); + const dgeni = new Dgeni([testPackage]); + const injector = dgeni.configureInjector(); + autoLinkCode = injector.get('autoLinkCode'); + autoLinkCode.docTypes = ['class', 'pipe']; + aliasMap = injector.get('aliasMap'); + processor = injector.get('postProcessHtml'); + processor.docTypes = ['test-doc']; + processor.plugins = [autoLinkCode]; + }); + + it('should insert an anchor into every code item that matches the id of an API doc', () => { + aliasMap.addDoc({ docType: 'class', id: 'MyClass', aliases: ['MyClass'], path: 'a/b/myclass' }); + const doc = { docType: 'test-doc', renderedContent: 'MyClass' }; + processor.$process([doc]); + expect(doc.renderedContent).toEqual('MyClass'); + }); + + it('should insert an anchor into every code item that matches an alias of an API doc', () => { + aliasMap.addDoc({ docType: 'class', id: 'MyClass', aliases: ['MyClass', 'foo.MyClass'], path: 'a/b/myclass' }); + const doc = { docType: 'test-doc', renderedContent: 'foo.MyClass' }; + processor.$process([doc]); + expect(doc.renderedContent).toEqual('foo.MyClass'); + }); + + it('should ignore code items that do not match a link to an API doc', () => { + aliasMap.addDoc({ docType: 'guide', id: 'MyClass', aliases: ['MyClass'], path: 'a/b/myclass' }); + const doc = { docType: 'test-doc', renderedContent: 'MyClass' }; + processor.$process([doc]); + expect(doc.renderedContent).toEqual('MyClass'); + }); +});