From e7cf1e05802a61bda9cbe619ed86a491ba067d04 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Fri, 6 Dec 2019 13:41:15 +0100 Subject: [PATCH] feat(docs-infra): add the ability to expose globals (#34237) Adds the ability to expose global symbols in the API docs via the `@globalApi` tag. Also supports optionally setting a namespace which will be added to the name automatically (e.g. `foo` will be renamed to `ng.foo`). Relevant APIs should also be exported through the `global.ts` file which will show up under `core/global`. PR Close #34237 --- .../transforms/angular-api-package/index.js | 3 ++ .../processors/addGlobalApiData.js | 28 ++++++++++ .../processors/addGlobalApiData.spec.js | 51 +++++++++++++++++++ .../processors/updateGlobalApiPath.js | 26 ++++++++++ .../processors/updateGlobalApiPath.spec.js | 37 ++++++++++++++ .../angular-api-package/tag-defs/globalApi.js | 3 ++ .../templates/api/base.template.html | 1 + packages/core/global.ts | 7 +++ 8 files changed, 156 insertions(+) create mode 100644 aio/tools/transforms/angular-api-package/processors/addGlobalApiData.js create mode 100644 aio/tools/transforms/angular-api-package/processors/addGlobalApiData.spec.js create mode 100644 aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.js create mode 100644 aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.spec.js create mode 100644 aio/tools/transforms/angular-api-package/tag-defs/globalApi.js create mode 100644 packages/core/global.ts diff --git a/aio/tools/transforms/angular-api-package/index.js b/aio/tools/transforms/angular-api-package/index.js index a8d731505d..3931a8b897 100644 --- a/aio/tools/transforms/angular-api-package/index.js +++ b/aio/tools/transforms/angular-api-package/index.js @@ -24,6 +24,8 @@ module.exports = .processor(require('./processors/extractPipeParams')) .processor(require('./processors/matchUpDirectiveDecorators')) .processor(require('./processors/addMetadataAliases')) + .processor(require('./processors/addGlobalApiData')) + .processor(require('./processors/updateGlobalApiPath')) .processor(require('./processors/computeApiBreadCrumbs')) .processor(require('./processors/filterContainedDocs')) .processor(require('./processors/processClassLikeMembers')) @@ -95,6 +97,7 @@ module.exports = 'common/testing/index.ts', 'common/upgrade/index.ts', 'core/index.ts', + 'core/global.ts', 'core/testing/index.ts', 'elements/index.ts', 'forms/index.ts', diff --git a/aio/tools/transforms/angular-api-package/processors/addGlobalApiData.js b/aio/tools/transforms/angular-api-package/processors/addGlobalApiData.js new file mode 100644 index 0000000000..8043650dec --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/addGlobalApiData.js @@ -0,0 +1,28 @@ +/** + * @dgProcessor addGlobalApiData + * + * Marks APIs tagged with `@globalApi` as globals and + * prefixes them with the namespace, if there is one. + */ +module.exports = function addGlobalApiDataProcessor() { + return { + $runBefore: ['computing-ids'], + $process: function(docs) { + docs.forEach(doc => { + const globalApiTag = doc.globalApi && doc.globalApi.trim(); + + if (globalApiTag != null) { + doc.global = true; + + if (globalApiTag.length > 0) { + // Prefix the symbol name with the global namespace, + // if we have one (e.g. `foo` becomes `ng.foo`). + doc.unprefixedName = doc.name; + doc.name = `${globalApiTag}.${doc.name}`; + doc.globalNamespace = globalApiTag; + } + } + }); + } + }; +}; diff --git a/aio/tools/transforms/angular-api-package/processors/addGlobalApiData.spec.js b/aio/tools/transforms/angular-api-package/processors/addGlobalApiData.spec.js new file mode 100644 index 0000000000..e4d117a372 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/addGlobalApiData.spec.js @@ -0,0 +1,51 @@ +const testPackage = require('../../helpers/test-package'); +const processorFactory = require('./addGlobalApiData'); +const Dgeni = require('dgeni'); + +describe('addGlobalApiData processor', () => { + it('should be available on the injector', () => { + const dgeni = new Dgeni([testPackage('angular-api-package')]); + const injector = dgeni.configureInjector(); + const processor = injector.get('addGlobalApiDataProcessor'); + expect(processor.$process).toBeDefined(); + }); + + it('should run before the correct processor', () => { + const processor = processorFactory(); + expect(processor.$runBefore).toEqual(['computing-ids']); + }); + + it('should mark global APIs correctly', () => { + const processor = processorFactory(); + const docs = [ + { docType: 'function', name: 'noNamespace', globalApi: '' }, + { docType: 'function', name: 'withNamespace', globalApi: 'ng' }, + { docType: 'function', name: 'notGlobal' }, + ]; + processor.$process(docs); + expect(docs[0].global).toBe(true); + expect(docs[1].global).toBe(true); + expect(docs[2].global).toBeUndefined(); + }); + + it('should prefix global APIs with the namespace, if one is defined', () => { + const processor = processorFactory(); + const docs = [ + { docType: 'function', name: 'noNamespace', globalApi: '' }, + { docType: 'function', name: 'withNamespace', globalApi: 'ng' }, + { docType: 'function', name: 'notGlobal' }, + ]; + processor.$process(docs); + expect(docs[0].name).toBe('noNamespace'); + expect(docs[1].name).toBe('ng.withNamespace'); + expect(docs[2].name).toBe('notGlobal'); + + expect(docs[0].unprefixedName).toBeUndefined(); + expect(docs[1].unprefixedName).toBe('withNamespace'); + expect(docs[2].unprefixedName).toBeUndefined(); + + expect(docs[0].globalNamespace).toBeUndefined(); + expect(docs[1].globalNamespace).toBe('ng'); + expect(docs[2].globalNamespace).toBeUndefined(); + }); +}); diff --git a/aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.js b/aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.js new file mode 100644 index 0000000000..4219a68f8f --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.js @@ -0,0 +1,26 @@ +/** + * @dgProcessor updateGlobalApiPath + * + * If a global API has a namespace, its name will contain a dot which will cause its + * URL to look like a file path. This processor updates it so it's less ambiguous. + */ +module.exports = function updateGlobalApiPathProcessor() { + return { + $runAfter: ['computePathsProcessor'], + $runBefore: ['processNgModuleDocs'], + $process: function(docs) { + docs.forEach(doc => { + if (doc.global && doc.globalNamespace) { + // We need to change the path to camel case, because having a dot + // in the URL will make it look like a file path. + const name = doc.unprefixedName; + const fileName = doc.globalNamespace + name[0].toUpperCase() + name.slice(1); + + doc.path = `${doc.moduleDoc.moduleFolder}/${fileName}`; + doc.outputPath = + `${doc.moduleDoc.moduleFolder}/${fileName}.json`; + } + }); + } + }; +}; diff --git a/aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.spec.js b/aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.spec.js new file mode 100644 index 0000000000..556dc1a221 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/processors/updateGlobalApiPath.spec.js @@ -0,0 +1,37 @@ +const testPackage = require('../../helpers/test-package'); +const processorFactory = require('./updateGlobalApiPath'); +const Dgeni = require('dgeni'); + +describe('updateGlobalApiPath processor', () => { + it('should be available on the injector', () => { + const dgeni = new Dgeni([testPackage('angular-api-package')]); + const injector = dgeni.configureInjector(); + const processor = injector.get('updateGlobalApiPathProcessor'); + expect(processor.$process).toBeDefined(); + }); + + it('should run before the correct processor', () => { + const processor = processorFactory(); + expect(processor.$runBefore).toEqual(['processNgModuleDocs']); + }); + + it('should run after the correct processor', () => { + const processor = processorFactory(); + expect(processor.$runAfter).toEqual(['computePathsProcessor']); + }); + + it('should update the paths of namespaced global APIs', () => { + const processor = processorFactory(); + const docs = [{ + docType: 'function', + moduleDoc: { moduleFolder: 'folder' }, + name: 'ng.withNamespace', + globalNamespace: 'ng', + unprefixedName: 'withNamespace', + global: true + }]; + processor.$process(docs); + expect(docs[0].path).toBe('folder/ngWithNamespace'); + expect(docs[0].outputPath).toBe('folder/ngWithNamespace.json'); + }); +}); diff --git a/aio/tools/transforms/angular-api-package/tag-defs/globalApi.js b/aio/tools/transforms/angular-api-package/tag-defs/globalApi.js new file mode 100644 index 0000000000..15edd42bd7 --- /dev/null +++ b/aio/tools/transforms/angular-api-package/tag-defs/globalApi.js @@ -0,0 +1,3 @@ +module.exports = function() { + return {name: 'globalApi'}; +}; diff --git a/aio/tools/transforms/templates/api/base.template.html b/aio/tools/transforms/templates/api/base.template.html index b910986525..a30f8c3862 100644 --- a/aio/tools/transforms/templates/api/base.template.html +++ b/aio/tools/transforms/templates/api/base.template.html @@ -21,6 +21,7 @@ {% block header %}

{$ doc.name $}

+ {% if doc.global %}{% endif %} {% if doc.deprecated !== undefined %}{% endif %} {% if doc.security !== undefined %}{% endif %} diff --git a/packages/core/global.ts b/packages/core/global.ts new file mode 100644 index 0000000000..c91a05e544 --- /dev/null +++ b/packages/core/global.ts @@ -0,0 +1,7 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */