From ef91702ed6b91388617dbd5dc66d106cd255116b Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Sat, 4 May 2019 00:03:26 -0700 Subject: [PATCH 01/19] Setup testing --- apps/api-documenter/.vscode/launch.json | 19 +++++++++++++++++++ .../config/generateSchema.js | 0 2 files changed, 19 insertions(+) create mode 100644 apps/api-documenter/.vscode/launch.json create mode 100644 build-tests/api-documenter-oufr/config/generateSchema.js diff --git a/apps/api-documenter/.vscode/launch.json b/apps/api-documenter/.vscode/launch.json new file mode 100644 index 00000000000..adee0b47e55 --- /dev/null +++ b/apps/api-documenter/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Example", + "program": "${workspaceFolder}/lib/start.js", + "cwd": "${workspaceFolder}/../../build-tests/api-documenter-oufr", + "args": [ + "yaml" + ], + "sourceMaps": true + }, + ] +} \ No newline at end of file diff --git a/build-tests/api-documenter-oufr/config/generateSchema.js b/build-tests/api-documenter-oufr/config/generateSchema.js new file mode 100644 index 00000000000..e69de29bb2d From 9f4a5e480f7bd99ac65b420ade622769576a3ffb Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Sat, 4 May 2019 01:16:40 -0700 Subject: [PATCH 02/19] Generate schema function --- .../config/apiTocConfig.json | 119 ++++++++++++ .../config/generateSchema.js | 174 ++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 build-tests/api-documenter-oufr/config/apiTocConfig.json diff --git a/build-tests/api-documenter-oufr/config/apiTocConfig.json b/build-tests/api-documenter-oufr/config/apiTocConfig.json new file mode 100644 index 00000000000..cb7ad128196 --- /dev/null +++ b/build-tests/api-documenter-oufr/config/apiTocConfig.json @@ -0,0 +1,119 @@ +{ + "tocConfig": { + "items": [ + { "name": "Office UI Fabric React", "href": "~/homepage/homepage.md" }, + { + "name": "Office UI Fabric React", + "href": "office-ui-fabric-react", + "extended": true, + "items": [ + { + "name": "Basic Inputs", + "items": [ + { "name": "Button", "items": [] }, + { "name": "Checkbox", "items": [] }, + { "name": "ChoiceGroup", "items": [] }, + { "name": "ComboBox", "items": [] }, + { "name": "Dropdown", "items": [] }, + { "name": "Label", "items": [] }, + { "name": "Link", "items": [] }, + { "name": "Rating", "items": [] }, + { "name": "SearchBox", "items": [] }, + { "name": "Slider", "items": [] }, + { "name": "SpinButton", "items": [] }, + { "name": "TextField", "items": [] }, + { "name": "Toggle", "items": [] } + ] + }, + { + "name": "Galleries & Pickers", + "items": [ + { "name": "Pickers", "items": [] }, + { "name": "Calendar", "items": [] }, + { "name": "ColorPicker", "items": [] }, + { "name": "DatePicker", "items": [] }, + { "name": "PeoplePicker", "items": [] }, + { "name": "SwatchColorPicker", "items": [] } + ] + }, + { + "name": "Items & Lists", + "items": [ + { "name": "List", "items": [] }, + { "name": "DetailsList", "items": [] }, + { "name": "GroupedList", "items": [] }, + { "name": "ActivityItem", "items": [] }, + { "name": "DocumentCard", "items": [] }, + { "name": "Facepile", "items": [] }, + { "name": "HoverCard", "items": [] }, + { "name": "Persona", "items": [] } + ] + }, + { + "name": "Commands, Menus & Navs", + "items": [ + { "name": "Breadcrumb", "items": [] }, + { "name": "CommandBar", "items": [] }, + { "name": "ContextualMenu", "items": [] }, + { "name": "Nav", "items": [] }, + { "name": "OverflowSet", "items": [] }, + { "name": "Pivot", "items": [] } + ] + }, + { + "name": "Notification & Engagement", + "items": [ + { "name": "Coachmark", "items": [] }, + { "name": "MessageBar", "items": [] }, + { "name": "TeachingBubble", "items": [] } + ] + }, + { + "name": "Progress", + "items": [ + { "name": "ProgressIndicator", "items": [] }, + { "name": "Shimmer", "items": [] }, + { "name": "Spinner", "items": [] } + ] + }, + { + "name": "Surfaces", + "items": [ + { "name": "Callout", "items": [] }, + { "name": "Dialog", "items": [] }, + { "name": "Modal", "items": [] }, + { "name": "Panel", "items": [] }, + { "name": "ScrollablePane", "items": [] }, + { "name": "Tooltip", "items": [] } + ] + }, + { + "name": "Utilities", + "items": [ + { "name": "Announced", "items": [] }, + { "name": "FocusTrapZone", "items": [] }, + { "name": "FocusZone", "items": [] }, + { "name": "Icon", "items": [] }, + { "name": "Image", "items": [] }, + { "name": "Keytips", "items": [] }, + { "name": "Layer", "items": [] }, + { "name": "MarqueeSelection", "items": [] }, + { "name": "Overlay", "items": [] }, + { "name": "ResizeGroup", "items": [] }, + { "name": "Selection", "items": [] }, + { "name": "Separator", "items": [] }, + { "name": "Stack", "items": [] }, + { "name": "Text", "items": [] }, + { "name": "Themes", "items": [] } + ] + }, + { "name": "References", "items": [] } + ] + } + ] + }, + "catchAllCategory": "References", + "noDuplicateEntries": true, + "filterByApiItemName": false, + "filterByInlineTag": "@docCategory" +} diff --git a/build-tests/api-documenter-oufr/config/generateSchema.js b/build-tests/api-documenter-oufr/config/generateSchema.js index e69de29bb2d..1aad160cbda 100644 --- a/build-tests/api-documenter-oufr/config/generateSchema.js +++ b/build-tests/api-documenter-oufr/config/generateSchema.js @@ -0,0 +1,174 @@ +const fs = require('fs'); + +// This is a copy of an object that we will import from @uifabric/fabric-website package +// to be in sync with changes to their controls page navigation +const categories = { + "Basic Inputs": { + Button: {}, + Checkbox: {}, + ChoiceGroup: {}, + ComboBox: {}, + Dropdown: {}, + Label: {}, + Link: {}, + Rating: {}, + SearchBox: {}, + Slider: {}, + SpinButton: {}, + TextField: {}, + Toggle: {} + }, + "Galleries & Pickers": { + Pickers: {}, + Calendar: {}, + ColorPicker: {}, + DatePicker: {}, + PeoplePicker: {}, + SwatchColorPicker: {} + }, + "Items & Lists": { + List: { title: "Basic List" }, + DetailsList: { + subPages: { + Basic: {}, + Compact: {}, + Grouped: {}, + LargeGrouped: {}, + CustomColumns: { + title: "Custom Item Columns", + url: "customitemcolumns" + }, + CustomRows: { title: "Custom Item Rows", url: "customitemrows" }, + CustomFooter: { title: "Custom Footer" }, + CustomGroupHeaders: { title: "Custom Group Headers" }, + Advanced: { title: "Variable Row Heights", url: "variablerowheights" }, + DragDrop: { title: "Drag & Drop", url: "draganddrop" }, + NavigatingFocus: { title: "Inner Navigation", url: "innernavigation" }, + Shimmer: {} + } + }, + GroupedList: {}, + ActivityItem: {}, + DocumentCard: {}, + Facepile: {}, + HoverCard: {}, + Persona: {} + }, + "Commands, Menus & Navs": { + Breadcrumb: {}, + CommandBar: {}, + ContextualMenu: {}, + Nav: {}, + OverflowSet: {}, + Pivot: {} + }, + "Notification & Engagement": { + Coachmark: {}, + MessageBar: {}, + TeachingBubble: {} + }, + Progress: { + ProgressIndicator: {}, + Shimmer: {}, + Spinner: {} + }, + Surfaces: { + Callout: {}, + Dialog: {}, + Modal: {}, + Panel: {}, + ScrollablePane: {}, + Tooltip: {} + }, + Utilities: { + Announced: { + subPages: { + QuickActions: { title: "Quick Actions" }, + SearchResults: { title: "Search Results" }, + LazyLoading: { title: "Lazy Loading" }, + BulkOperations: { title: "Bulk Operations" } + } + }, + FocusTrapZone: {}, + FocusZone: {}, + Icon: {}, + Image: {}, + Keytips: {}, + Layer: {}, + MarqueeSelection: {}, + Overlay: {}, + ResizeGroup: {}, + Selection: {}, + Separator: {}, + Stack: {}, + Text: {}, + Themes: {} + }, + "Fluent Theme": { + FluentTheme: { title: "Fluent Theme", url: "fluent-theme" } + }, + References: {}, + Other: {} +}; + +// function that will be running every time before calling api-documenter and generate a schema file +// the return of this function will write a schema that all it needs is just to fill the empty `items` arrays for each node that has one. + +// in the future we can make modifications to the logic so that to include additional things +// like pages with examples that have nothing to do with the API json files +function generateConfig(stateObj) { + const tocConfig = { + items: [ + { + name: "Office UI Fabric React", + href: "~/homepage/homepage.md" + }, + { + name: "Office UI Fabric React", + href: "office-ui-fabric-react", + extended: true, + items: [] + } + ] + }; + + // delete unnecessary navigation items for docs.microsoft but present on the Fabric website + delete stateObj["Fluent Theme"]; + delete stateObj["Other"]; + + const categories = Object.keys(stateObj); + + for (const category of categories) { + const configItem = { + name: category, + items: [] + }; + + const categoryItems = Object.keys(stateObj[category]); + for (const categoryItem of categoryItems) { + configItem.items.push({ + name: categoryItem, + items: [] + }); + } + + tocConfig.items[1].items.push(configItem); + } + + // config file is what we needs to have a standardized structure of things we wanna support in customizing the TOC + // here is just a few that might be generally useful + const config = { + tocConfig, + catchAllCategory: 'References', + noDuplicateEntries: true, + // some possible filters to fill the leaf nodes `items` arrays. + filterByApiItemName: false, + filterByInlineTag: '@docCategory' + } + + // writing file + const json = JSON.stringify(config); + fs.writeFileSync("apiTocConfig.json", json, "utf8"); +} + +generateConfig(categories); From 78f59df90530413d7217506be0f38293e91797a3 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Sat, 4 May 2019 01:42:46 -0700 Subject: [PATCH 03/19] setup the config --- apps/api-documenter/src/cli/BaseAction.ts | 15 +++ apps/api-documenter/src/cli/YamlAction.ts | 2 +- .../src/documenters/YamlDocumenter.ts | 4 +- .../config/api-documenter.json | 1 + .../config/apiTocConfig.json | 119 ------------------ .../config/generateSchema.js | 2 +- 6 files changed, 21 insertions(+), 122 deletions(-) create mode 100644 build-tests/api-documenter-oufr/config/api-documenter.json delete mode 100644 build-tests/api-documenter-oufr/config/apiTocConfig.json diff --git a/apps/api-documenter/src/cli/BaseAction.ts b/apps/api-documenter/src/cli/BaseAction.ts index 8a5fef78028..2a814d97412 100644 --- a/apps/api-documenter/src/cli/BaseAction.ts +++ b/apps/api-documenter/src/cli/BaseAction.ts @@ -21,9 +21,11 @@ import { export abstract class BaseAction extends CommandLineAction { protected inputFolder: string; protected outputFolder: string; + protected configFolder: string private _inputFolderParameter: CommandLineStringParameter; private _outputFolderParameter: CommandLineStringParameter; + private _configFolderParameter: CommandLineStringParameter; protected onDefineParameters(): void { // override this._inputFolderParameter = this.defineStringParameter({ @@ -42,6 +44,14 @@ export abstract class BaseAction extends CommandLineAction { + ` ANY EXISTING CONTENTS WILL BE DELETED!` + ` If omitted, the default is "./${this.actionName}"` }); + + this._configFolderParameter = this.defineStringParameter({ + parameterLongName: '--config-folder', + parameterShortName: '-c', + argumentName: 'FOLDER3', + description: `Specifies the path string where the config file is located` + + ` If omitted, the default is "./config"` + }); } protected buildApiModel(): ApiModel { @@ -51,6 +61,11 @@ export abstract class BaseAction extends CommandLineAction { if (!FileSystem.exists(this.inputFolder)) { throw new Error('The input folder does not exist: ' + this.inputFolder); } + + this.configFolder = this._configFolderParameter.value || './config'; + if (!FileSystem.exists(this.configFolder)) { + throw new Error('The config folder does not exist: ' + this.configFolder); + } this.outputFolder = this._outputFolderParameter.value || `./${this.actionName}`; FileSystem.ensureFolder(this.outputFolder); diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index 9ab34dce64d..1e7c9ac20b4 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -39,7 +39,7 @@ export class YamlAction extends BaseAction { const yamlDocumenter: YamlDocumenter = this._officeParameter.value ? new OfficeYamlDocumenter(apiModel, this.inputFolder) - : new YamlDocumenter(apiModel); + : new YamlDocumenter(apiModel, this.configFolder); yamlDocumenter.generateFiles(this.outputFolder); return Promise.resolve(); diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index ac25bf71594..6195349299b 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -55,6 +55,7 @@ const yamlApiSchema: JsonSchema = JsonSchema.fromFile(path.join(__dirname, '..', export class YamlDocumenter { private readonly _apiModel: ApiModel; private readonly _markdownEmitter: CustomMarkdownEmitter; + private readonly _configFolder: string; // This is used by the _linkToUidIfPossible() workaround. // It stores a mapping from type name (e.g. "MyClass") to the corresponding ApiItem. @@ -65,10 +66,11 @@ export class YamlDocumenter { private _outputFolder: string; - public constructor(apiModel: ApiModel) { + public constructor(apiModel: ApiModel, configFolder: string) { this._apiModel = apiModel; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByTypeName = new Map(); + this._configFolder = configFolder; this._initApiItemsByTypeName(); } diff --git a/build-tests/api-documenter-oufr/config/api-documenter.json b/build-tests/api-documenter-oufr/config/api-documenter.json new file mode 100644 index 00000000000..8d2dad9f9a6 --- /dev/null +++ b/build-tests/api-documenter-oufr/config/api-documenter.json @@ -0,0 +1 @@ +{"tocConfig":{"items":[{"name":"Office UI Fabric React","href":"~/homepage/homepage.md"},{"name":"Office UI Fabric React","href":"office-ui-fabric-react","extended":true,"items":[{"name":"Basic Inputs","items":[{"name":"Button","items":[]},{"name":"Checkbox","items":[]},{"name":"ChoiceGroup","items":[]},{"name":"ComboBox","items":[]},{"name":"Dropdown","items":[]},{"name":"Label","items":[]},{"name":"Link","items":[]},{"name":"Rating","items":[]},{"name":"SearchBox","items":[]},{"name":"Slider","items":[]},{"name":"SpinButton","items":[]},{"name":"TextField","items":[]},{"name":"Toggle","items":[]}]},{"name":"Galleries & Pickers","items":[{"name":"Pickers","items":[]},{"name":"Calendar","items":[]},{"name":"ColorPicker","items":[]},{"name":"DatePicker","items":[]},{"name":"PeoplePicker","items":[]},{"name":"SwatchColorPicker","items":[]}]},{"name":"Items & Lists","items":[{"name":"List","items":[]},{"name":"DetailsList","items":[]},{"name":"GroupedList","items":[]},{"name":"ActivityItem","items":[]},{"name":"DocumentCard","items":[]},{"name":"Facepile","items":[]},{"name":"HoverCard","items":[]},{"name":"Persona","items":[]}]},{"name":"Commands, Menus & Navs","items":[{"name":"Breadcrumb","items":[]},{"name":"CommandBar","items":[]},{"name":"ContextualMenu","items":[]},{"name":"Nav","items":[]},{"name":"OverflowSet","items":[]},{"name":"Pivot","items":[]}]},{"name":"Notification & Engagement","items":[{"name":"Coachmark","items":[]},{"name":"MessageBar","items":[]},{"name":"TeachingBubble","items":[]}]},{"name":"Progress","items":[{"name":"ProgressIndicator","items":[]},{"name":"Shimmer","items":[]},{"name":"Spinner","items":[]}]},{"name":"Surfaces","items":[{"name":"Callout","items":[]},{"name":"Dialog","items":[]},{"name":"Modal","items":[]},{"name":"Panel","items":[]},{"name":"ScrollablePane","items":[]},{"name":"Tooltip","items":[]}]},{"name":"Utilities","items":[{"name":"Announced","items":[]},{"name":"FocusTrapZone","items":[]},{"name":"FocusZone","items":[]},{"name":"Icon","items":[]},{"name":"Image","items":[]},{"name":"Keytips","items":[]},{"name":"Layer","items":[]},{"name":"MarqueeSelection","items":[]},{"name":"Overlay","items":[]},{"name":"ResizeGroup","items":[]},{"name":"Selection","items":[]},{"name":"Separator","items":[]},{"name":"Stack","items":[]},{"name":"Text","items":[]},{"name":"Themes","items":[]}]},{"name":"References","items":[]}]}]},"catchAllCategory":"References","noDuplicateEntries":true,"filterByApiItemName":false,"filterByInlineTag":"@docCategory"} \ No newline at end of file diff --git a/build-tests/api-documenter-oufr/config/apiTocConfig.json b/build-tests/api-documenter-oufr/config/apiTocConfig.json deleted file mode 100644 index cb7ad128196..00000000000 --- a/build-tests/api-documenter-oufr/config/apiTocConfig.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "tocConfig": { - "items": [ - { "name": "Office UI Fabric React", "href": "~/homepage/homepage.md" }, - { - "name": "Office UI Fabric React", - "href": "office-ui-fabric-react", - "extended": true, - "items": [ - { - "name": "Basic Inputs", - "items": [ - { "name": "Button", "items": [] }, - { "name": "Checkbox", "items": [] }, - { "name": "ChoiceGroup", "items": [] }, - { "name": "ComboBox", "items": [] }, - { "name": "Dropdown", "items": [] }, - { "name": "Label", "items": [] }, - { "name": "Link", "items": [] }, - { "name": "Rating", "items": [] }, - { "name": "SearchBox", "items": [] }, - { "name": "Slider", "items": [] }, - { "name": "SpinButton", "items": [] }, - { "name": "TextField", "items": [] }, - { "name": "Toggle", "items": [] } - ] - }, - { - "name": "Galleries & Pickers", - "items": [ - { "name": "Pickers", "items": [] }, - { "name": "Calendar", "items": [] }, - { "name": "ColorPicker", "items": [] }, - { "name": "DatePicker", "items": [] }, - { "name": "PeoplePicker", "items": [] }, - { "name": "SwatchColorPicker", "items": [] } - ] - }, - { - "name": "Items & Lists", - "items": [ - { "name": "List", "items": [] }, - { "name": "DetailsList", "items": [] }, - { "name": "GroupedList", "items": [] }, - { "name": "ActivityItem", "items": [] }, - { "name": "DocumentCard", "items": [] }, - { "name": "Facepile", "items": [] }, - { "name": "HoverCard", "items": [] }, - { "name": "Persona", "items": [] } - ] - }, - { - "name": "Commands, Menus & Navs", - "items": [ - { "name": "Breadcrumb", "items": [] }, - { "name": "CommandBar", "items": [] }, - { "name": "ContextualMenu", "items": [] }, - { "name": "Nav", "items": [] }, - { "name": "OverflowSet", "items": [] }, - { "name": "Pivot", "items": [] } - ] - }, - { - "name": "Notification & Engagement", - "items": [ - { "name": "Coachmark", "items": [] }, - { "name": "MessageBar", "items": [] }, - { "name": "TeachingBubble", "items": [] } - ] - }, - { - "name": "Progress", - "items": [ - { "name": "ProgressIndicator", "items": [] }, - { "name": "Shimmer", "items": [] }, - { "name": "Spinner", "items": [] } - ] - }, - { - "name": "Surfaces", - "items": [ - { "name": "Callout", "items": [] }, - { "name": "Dialog", "items": [] }, - { "name": "Modal", "items": [] }, - { "name": "Panel", "items": [] }, - { "name": "ScrollablePane", "items": [] }, - { "name": "Tooltip", "items": [] } - ] - }, - { - "name": "Utilities", - "items": [ - { "name": "Announced", "items": [] }, - { "name": "FocusTrapZone", "items": [] }, - { "name": "FocusZone", "items": [] }, - { "name": "Icon", "items": [] }, - { "name": "Image", "items": [] }, - { "name": "Keytips", "items": [] }, - { "name": "Layer", "items": [] }, - { "name": "MarqueeSelection", "items": [] }, - { "name": "Overlay", "items": [] }, - { "name": "ResizeGroup", "items": [] }, - { "name": "Selection", "items": [] }, - { "name": "Separator", "items": [] }, - { "name": "Stack", "items": [] }, - { "name": "Text", "items": [] }, - { "name": "Themes", "items": [] } - ] - }, - { "name": "References", "items": [] } - ] - } - ] - }, - "catchAllCategory": "References", - "noDuplicateEntries": true, - "filterByApiItemName": false, - "filterByInlineTag": "@docCategory" -} diff --git a/build-tests/api-documenter-oufr/config/generateSchema.js b/build-tests/api-documenter-oufr/config/generateSchema.js index 1aad160cbda..b64594c79ab 100644 --- a/build-tests/api-documenter-oufr/config/generateSchema.js +++ b/build-tests/api-documenter-oufr/config/generateSchema.js @@ -168,7 +168,7 @@ function generateConfig(stateObj) { // writing file const json = JSON.stringify(config); - fs.writeFileSync("apiTocConfig.json", json, "utf8"); + fs.writeFileSync("api-documenter.json", json, "utf8"); } generateConfig(categories); From 8d0fdbaa5e4bcd3295e37a17e39bbdb503d245ff Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Sat, 4 May 2019 02:10:23 -0700 Subject: [PATCH 04/19] Pipe config file all the way to YamlDocumenter --- apps/api-documenter/src/cli/YamlAction.ts | 4 ++-- .../src/documenters/YamlDocumenter.ts | 22 ++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index 1e7c9ac20b4..7278999c1f2 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -39,9 +39,9 @@ export class YamlAction extends BaseAction { const yamlDocumenter: YamlDocumenter = this._officeParameter.value ? new OfficeYamlDocumenter(apiModel, this.inputFolder) - : new YamlDocumenter(apiModel, this.configFolder); + : new YamlDocumenter(apiModel); - yamlDocumenter.generateFiles(this.outputFolder); + yamlDocumenter.generateFiles(this.outputFolder, this.configFolder); return Promise.resolve(); } } diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 6195349299b..e18d01479cc 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -55,30 +55,36 @@ const yamlApiSchema: JsonSchema = JsonSchema.fromFile(path.join(__dirname, '..', export class YamlDocumenter { private readonly _apiModel: ApiModel; private readonly _markdownEmitter: CustomMarkdownEmitter; - private readonly _configFolder: string; - + // This is used by the _linkToUidIfPossible() workaround. // It stores a mapping from type name (e.g. "MyClass") to the corresponding ApiItem. // If the mapping would be ambiguous (e.g. "MyClass" is defined by multiple packages) // then it is excluded from the mapping. Also excluded are ApiItem objects (such as package // and function) which are not typically used as a data type. private _apiItemsByTypeName: Map; - + private _outputFolder: string; - public constructor(apiModel: ApiModel, configFolder: string) { + // ideally this needs to be an interface with a defined shape a config file can take. And whoever creates the config + // should use it to leverage the type safety. + private _config: {}; + + public constructor(apiModel: ApiModel) { this._apiModel = apiModel; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByTypeName = new Map(); - this._configFolder = configFolder; - + this._initApiItemsByTypeName(); } - + /** @virtual */ - public generateFiles(outputFolder: string): void { + public generateFiles(outputFolder: string, configFolder?: string): void { this._outputFolder = outputFolder; + const configFilePath: string = configFolder ? path.join(configFolder, 'api-documenter.json') : ''; + this._config = configFilePath && JsonFile.load(configFilePath); + console.log(this._config); + console.log(); this._deleteOldOutputFiles(); From e64c063bd34a3b30d879018c612b72c0c43d8854 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Sun, 5 May 2019 22:12:32 -0700 Subject: [PATCH 05/19] Make some changes to how to load configs. --- apps/api-documenter/src/cli/BaseAction.ts | 15 --------------- apps/api-documenter/src/cli/YamlAction.ts | 2 +- .../src/documenters/YamlDocumenter.ts | 17 ++++++++++------- .../{config => }/api-documenter.json | 0 .../{config => }/generateSchema.js | 0 5 files changed, 11 insertions(+), 23 deletions(-) rename build-tests/api-documenter-oufr/{config => }/api-documenter.json (100%) rename build-tests/api-documenter-oufr/{config => }/generateSchema.js (100%) diff --git a/apps/api-documenter/src/cli/BaseAction.ts b/apps/api-documenter/src/cli/BaseAction.ts index 2a814d97412..8a5fef78028 100644 --- a/apps/api-documenter/src/cli/BaseAction.ts +++ b/apps/api-documenter/src/cli/BaseAction.ts @@ -21,11 +21,9 @@ import { export abstract class BaseAction extends CommandLineAction { protected inputFolder: string; protected outputFolder: string; - protected configFolder: string private _inputFolderParameter: CommandLineStringParameter; private _outputFolderParameter: CommandLineStringParameter; - private _configFolderParameter: CommandLineStringParameter; protected onDefineParameters(): void { // override this._inputFolderParameter = this.defineStringParameter({ @@ -44,14 +42,6 @@ export abstract class BaseAction extends CommandLineAction { + ` ANY EXISTING CONTENTS WILL BE DELETED!` + ` If omitted, the default is "./${this.actionName}"` }); - - this._configFolderParameter = this.defineStringParameter({ - parameterLongName: '--config-folder', - parameterShortName: '-c', - argumentName: 'FOLDER3', - description: `Specifies the path string where the config file is located` - + ` If omitted, the default is "./config"` - }); } protected buildApiModel(): ApiModel { @@ -61,11 +51,6 @@ export abstract class BaseAction extends CommandLineAction { if (!FileSystem.exists(this.inputFolder)) { throw new Error('The input folder does not exist: ' + this.inputFolder); } - - this.configFolder = this._configFolderParameter.value || './config'; - if (!FileSystem.exists(this.configFolder)) { - throw new Error('The config folder does not exist: ' + this.configFolder); - } this.outputFolder = this._outputFolderParameter.value || `./${this.actionName}`; FileSystem.ensureFolder(this.outputFolder); diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index 7278999c1f2..9ab34dce64d 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -41,7 +41,7 @@ export class YamlAction extends BaseAction { ? new OfficeYamlDocumenter(apiModel, this.inputFolder) : new YamlDocumenter(apiModel); - yamlDocumenter.generateFiles(this.outputFolder, this.configFolder); + yamlDocumenter.generateFiles(this.outputFolder); return Promise.resolve(); } } diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index e18d01479cc..8a25f0a1cf2 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -65,8 +65,8 @@ export class YamlDocumenter { private _outputFolder: string; - // ideally this needs to be an interface with a defined shape a config file can take. And whoever creates the config - // should use it to leverage the type safety. + // ideally the type needs to be an interface with a defined shape a config file can take. + // And whoever creates the config should use it to leverage the type safety. private _config: {}; public constructor(apiModel: ApiModel) { @@ -78,13 +78,16 @@ export class YamlDocumenter { } /** @virtual */ - public generateFiles(outputFolder: string, configFolder?: string): void { + public generateFiles(outputFolder: string): void { this._outputFolder = outputFolder; - const configFilePath: string = configFolder ? path.join(configFolder, 'api-documenter.json') : ''; - this._config = configFilePath && JsonFile.load(configFilePath); - console.log(this._config); - + try { + this._config = JsonFile.load('./api-documenter.json'); + console.log('Loaded custom configuration'); + } catch (error) { + console.log('No configuration found. Using the default'); + } + console.log(); this._deleteOldOutputFiles(); diff --git a/build-tests/api-documenter-oufr/config/api-documenter.json b/build-tests/api-documenter-oufr/api-documenter.json similarity index 100% rename from build-tests/api-documenter-oufr/config/api-documenter.json rename to build-tests/api-documenter-oufr/api-documenter.json diff --git a/build-tests/api-documenter-oufr/config/generateSchema.js b/build-tests/api-documenter-oufr/generateSchema.js similarity index 100% rename from build-tests/api-documenter-oufr/config/generateSchema.js rename to build-tests/api-documenter-oufr/generateSchema.js From 3e2ddb592927d61249338b69dc25dc9fa0a9ceb6 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Mon, 6 May 2019 01:06:34 -0700 Subject: [PATCH 06/19] Bring generic changes to api-documenter --- .../src/documenters/YamlDocumenter.ts | 86 ++++++++++++++++--- 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 8a25f0a1cf2..3b75efeaede 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -12,7 +12,7 @@ import { NewlineKind, InternalError } from '@microsoft/node-core-library'; -import { StringBuilder, DocSection, DocComment } from '@microsoft/tsdoc'; +import { StringBuilder, DocSection, DocComment, DocInlineTag } from '@microsoft/tsdoc'; import { ApiModel, ApiItem, @@ -55,28 +55,34 @@ const yamlApiSchema: JsonSchema = JsonSchema.fromFile(path.join(__dirname, '..', export class YamlDocumenter { private readonly _apiModel: ApiModel; private readonly _markdownEmitter: CustomMarkdownEmitter; - + // This is used by the _linkToUidIfPossible() workaround. // It stores a mapping from type name (e.g. "MyClass") to the corresponding ApiItem. // If the mapping would be ambiguous (e.g. "MyClass" is defined by multiple packages) // then it is excluded from the mapping. Also excluded are ApiItem objects (such as package // and function) which are not typically used as a data type. private _apiItemsByTypeName: Map; - + private _outputFolder: string; - // ideally the type needs to be an interface with a defined shape a config file can take. + // ideally the types needs to be an interface with a defined shape a config file can take. // And whoever creates the config should use it to leverage the type safety. - private _config: {}; +// tslint:disable-next-line: no-any + private _config: any; +// tslint:disable-next-line: no-any + private _tocPointerMap: any; // type could be an indexer +// tslint:disable-next-line: no-any + private _catchAllPointer: any; public constructor(apiModel: ApiModel) { this._apiModel = apiModel; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByTypeName = new Map(); - + this._tocPointerMap = {}; // need a type? + this._initApiItemsByTypeName(); } - + /** @virtual */ public generateFiles(outputFolder: string): void { this._outputFolder = outputFolder; @@ -84,10 +90,13 @@ export class YamlDocumenter { try { this._config = JsonFile.load('./api-documenter.json'); console.log('Loaded custom configuration'); + if (this._config.tocConfig) { + this._generateTocPointersMap(this._config.tocConfig); + } } catch (error) { console.log('No configuration found. Using the default'); } - + console.log(); this._deleteOldOutputFiles(); @@ -205,8 +214,11 @@ export class YamlDocumenter { rootItem.items!.push(...this._buildTocItems(apiItems)); const tocFilePath: string = path.join(this._outputFolder, 'toc.yml'); + + const tocFileToWrite: IYamlTocFile = this._config && this._config.tocConfig ? this._config.tocConfig : tocFile; + console.log('Writing ' + tocFilePath); - this._writeYamlFile(tocFile, tocFilePath, '', undefined); + this._writeYamlFile(tocFileToWrite, tocFilePath, '', undefined); } private _buildTocItems(apiItems: ReadonlyArray): IYamlTocItem[] { @@ -235,6 +247,21 @@ export class YamlDocumenter { name: apiItem.displayName, uid: this._getUid(apiItem) }; + // Filtering out the api-items as we build the tocItems array. + if (apiItem instanceof ApiDocumentedItem) { + const docInlineTag: DocInlineTag | undefined = + (this._config && this._config.filterByInlineTag) && + this._findInlineTagByName(this._config.filterByInlineTag, apiItem.tsdocComment); + + if (docInlineTag !== undefined && this._tocPointerMap[docInlineTag.tagContent.trim()]) { + this._tocPointerMap[docInlineTag.tagContent.trim()].items.push(tocItem); + } else { + if (this._catchAllPointer && this._catchAllPointer.items) { + this._catchAllPointer.items.push(tocItem); + } + } + } + } } @@ -501,7 +528,8 @@ export class YamlDocumenter { JsonFile.validateNoUndefinedMembers(dataObject); let stringified: string = yaml.safeDump(dataObject, { - lineWidth: 120 + lineWidth: 120, + noRefs: this._config && this._config.noDuplicateEntries ? true : false }); if (yamlMimeType) { @@ -679,4 +707,42 @@ export class YamlDocumenter { console.log('Deleting old output from ' + this._outputFolder); FileSystem.ensureEmptyFolder(this._outputFolder); } + + // Parses the tocConfig object to build a pointers map of nodes where we want to sort out the API items + // tslint:disable-next-line: no-any + private _generateTocPointersMap(tocConfig: any): void { + for (const tocItem of tocConfig.items) { + if (tocItem.items) { + if (tocItem.items.length > 0) { + this._generateTocPointersMap(tocItem); + } else { + // check for presence of the `catchAllCategory` config option + if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { + this._catchAllPointer = tocItem; + } else { + this._tocPointerMap[tocItem.name] = tocItem; + } + } + } + } + } + + // This is a direct copy of a @docCategory inline tag finder in office-ui-fabric-react, + // but is generic enough to be used for any inline tag + private _findInlineTagByName(tagName: string, docComment: DocComment | undefined): DocInlineTag | undefined { + if (docComment instanceof DocInlineTag) { + if (docComment.tagName === tagName) { + return docComment; + } + } + if (docComment) { + for (const childNode of docComment.getChildNodes()) { + const result: DocInlineTag | undefined = this._findInlineTagByName(tagName, childNode as DocComment); + if (result !== undefined) { + return result; + } + } + } + return undefined; + } } From b37f5fa6d8e9a64667caaa169c1a2794f3b0f009 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Mon, 6 May 2019 12:42:20 -0700 Subject: [PATCH 07/19] Change a nested if statement --- .../src/documenters/YamlDocumenter.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 3b75efeaede..91de206d984 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -712,16 +712,14 @@ export class YamlDocumenter { // tslint:disable-next-line: no-any private _generateTocPointersMap(tocConfig: any): void { for (const tocItem of tocConfig.items) { - if (tocItem.items) { - if (tocItem.items.length > 0) { + if (tocItem.items && tocItem.items.length > 0) { this._generateTocPointersMap(tocItem); + } else { + // check for presence of the `catchAllCategory` config option + if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { + this._catchAllPointer = tocItem; } else { - // check for presence of the `catchAllCategory` config option - if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { - this._catchAllPointer = tocItem; - } else { - this._tocPointerMap[tocItem.name] = tocItem; - } + this._tocPointerMap[tocItem.name] = tocItem; } } } From 15388bd603d9bf2b2c97bfde44bae1bdcd5ea69f Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Mon, 6 May 2019 16:03:50 -0700 Subject: [PATCH 08/19] Add some types to the new logic --- .../src/documenters/YamlDocumenter.ts | 46 +++---- apps/api-documenter/src/yaml/IYamlTocFile.ts | 39 ++++++ .../api-documenter-oufr/api-documenter.json | 120 +++++++++++++++++- 3 files changed, 182 insertions(+), 23 deletions(-) diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index 91de206d984..d84ace4861f 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -42,7 +42,8 @@ import { } from '../yaml/IYamlApiFile'; import { IYamlTocFile, - IYamlTocItem + IYamlTocItem, + IYamlTocConfigSchema } from '../yaml/IYamlTocFile'; import { Utilities } from '../utils/Utilities'; import { CustomMarkdownEmitter} from '../markdown/CustomMarkdownEmitter'; @@ -65,14 +66,9 @@ export class YamlDocumenter { private _outputFolder: string; - // ideally the types needs to be an interface with a defined shape a config file can take. - // And whoever creates the config should use it to leverage the type safety. -// tslint:disable-next-line: no-any - private _config: any; -// tslint:disable-next-line: no-any - private _tocPointerMap: any; // type could be an indexer -// tslint:disable-next-line: no-any - private _catchAllPointer: any; + private _config: IYamlTocConfigSchema; + private _tocPointerMap: { [key: string]: IYamlTocItem }; + private _catchAllPointer: IYamlTocItem; public constructor(apiModel: ApiModel) { this._apiModel = apiModel; @@ -250,11 +246,16 @@ export class YamlDocumenter { // Filtering out the api-items as we build the tocItems array. if (apiItem instanceof ApiDocumentedItem) { const docInlineTag: DocInlineTag | undefined = - (this._config && this._config.filterByInlineTag) && - this._findInlineTagByName(this._config.filterByInlineTag, apiItem.tsdocComment); + (this._config && this._config.filterByInlineTag) + ? this._findInlineTagByName(this._config.filterByInlineTag, apiItem.tsdocComment) + : undefined; - if (docInlineTag !== undefined && this._tocPointerMap[docInlineTag.tagContent.trim()]) { - this._tocPointerMap[docInlineTag.tagContent.trim()].items.push(tocItem); + const tagContent: string | undefined = + docInlineTag && docInlineTag.tagContent && docInlineTag.tagContent.trim(); + + if (tagContent && this._tocPointerMap[tagContent]) { + // null assertion used because when pointer map was created we checked for presence of empty `items` array + this._tocPointerMap[tagContent].items!.push(tocItem); } else { if (this._catchAllPointer && this._catchAllPointer.items) { this._catchAllPointer.items.push(tocItem); @@ -709,17 +710,18 @@ export class YamlDocumenter { } // Parses the tocConfig object to build a pointers map of nodes where we want to sort out the API items - // tslint:disable-next-line: no-any - private _generateTocPointersMap(tocConfig: any): void { - for (const tocItem of tocConfig.items) { - if (tocItem.items && tocItem.items.length > 0) { + private _generateTocPointersMap(tocConfig: IYamlTocFile | IYamlTocItem): void { + if (tocConfig.items) { + for (const tocItem of tocConfig.items) { + if (tocItem.items && tocItem.items.length > 0) { this._generateTocPointersMap(tocItem); - } else { - // check for presence of the `catchAllCategory` config option - if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { - this._catchAllPointer = tocItem; } else { - this._tocPointerMap[tocItem.name] = tocItem; + // check for presence of the `catchAllCategory` config option + if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { + this._catchAllPointer = tocItem; + } else { + this._tocPointerMap[tocItem.name] = tocItem; + } } } } diff --git a/apps/api-documenter/src/yaml/IYamlTocFile.ts b/apps/api-documenter/src/yaml/IYamlTocFile.ts index 142accb190b..56901de5a2d 100644 --- a/apps/api-documenter/src/yaml/IYamlTocFile.ts +++ b/apps/api-documenter/src/yaml/IYamlTocFile.ts @@ -34,3 +34,42 @@ export interface IYamlTocFile { items: IYamlTocItem[]; metadata?: { [key: string]: string }; } + +/** + * Typescript interface describing the config schema for toc.yml file format. + */ +export interface IYamlTocConfigSchema { + /** + * Represents the tree structure describing the toc.file format. + * Only the nodes that have an empty `items` array will be filled with API items + * that are matched with the filters provided. Everything else will be placed under a catchAll category + * that is highly recommended to be provided. + */ + tocConfig: IYamlTocFile; + + /** + * Optional category name that is recommended to include in the `tocConfig`, + * along with one of the filters: `filterByApiItemName` or `filterByInlineTag`. + * Any items that are not matched to the mentioned filters will be placed under this + * catchAll category. If none provided the items will not be included in the final toc.yml file. + */ + catchAllCategory?: string; + + /** + * When loading more than one api.json files that might include the same API items, + * toggle either to show duplicates or not. + */ + noDuplicateEntries?: boolean; + + /** + * Toggle either sorting of the API items should be made based on category name presence + * in the API item's name. + */ + filterByApiItemName?: boolean; + + /** + * Filter that can be used to sort the API items according to an inline custom tag + * that is present on them. + */ + filterByInlineTag?: string; +} diff --git a/build-tests/api-documenter-oufr/api-documenter.json b/build-tests/api-documenter-oufr/api-documenter.json index 8d2dad9f9a6..cb7ad128196 100644 --- a/build-tests/api-documenter-oufr/api-documenter.json +++ b/build-tests/api-documenter-oufr/api-documenter.json @@ -1 +1,119 @@ -{"tocConfig":{"items":[{"name":"Office UI Fabric React","href":"~/homepage/homepage.md"},{"name":"Office UI Fabric React","href":"office-ui-fabric-react","extended":true,"items":[{"name":"Basic Inputs","items":[{"name":"Button","items":[]},{"name":"Checkbox","items":[]},{"name":"ChoiceGroup","items":[]},{"name":"ComboBox","items":[]},{"name":"Dropdown","items":[]},{"name":"Label","items":[]},{"name":"Link","items":[]},{"name":"Rating","items":[]},{"name":"SearchBox","items":[]},{"name":"Slider","items":[]},{"name":"SpinButton","items":[]},{"name":"TextField","items":[]},{"name":"Toggle","items":[]}]},{"name":"Galleries & Pickers","items":[{"name":"Pickers","items":[]},{"name":"Calendar","items":[]},{"name":"ColorPicker","items":[]},{"name":"DatePicker","items":[]},{"name":"PeoplePicker","items":[]},{"name":"SwatchColorPicker","items":[]}]},{"name":"Items & Lists","items":[{"name":"List","items":[]},{"name":"DetailsList","items":[]},{"name":"GroupedList","items":[]},{"name":"ActivityItem","items":[]},{"name":"DocumentCard","items":[]},{"name":"Facepile","items":[]},{"name":"HoverCard","items":[]},{"name":"Persona","items":[]}]},{"name":"Commands, Menus & Navs","items":[{"name":"Breadcrumb","items":[]},{"name":"CommandBar","items":[]},{"name":"ContextualMenu","items":[]},{"name":"Nav","items":[]},{"name":"OverflowSet","items":[]},{"name":"Pivot","items":[]}]},{"name":"Notification & Engagement","items":[{"name":"Coachmark","items":[]},{"name":"MessageBar","items":[]},{"name":"TeachingBubble","items":[]}]},{"name":"Progress","items":[{"name":"ProgressIndicator","items":[]},{"name":"Shimmer","items":[]},{"name":"Spinner","items":[]}]},{"name":"Surfaces","items":[{"name":"Callout","items":[]},{"name":"Dialog","items":[]},{"name":"Modal","items":[]},{"name":"Panel","items":[]},{"name":"ScrollablePane","items":[]},{"name":"Tooltip","items":[]}]},{"name":"Utilities","items":[{"name":"Announced","items":[]},{"name":"FocusTrapZone","items":[]},{"name":"FocusZone","items":[]},{"name":"Icon","items":[]},{"name":"Image","items":[]},{"name":"Keytips","items":[]},{"name":"Layer","items":[]},{"name":"MarqueeSelection","items":[]},{"name":"Overlay","items":[]},{"name":"ResizeGroup","items":[]},{"name":"Selection","items":[]},{"name":"Separator","items":[]},{"name":"Stack","items":[]},{"name":"Text","items":[]},{"name":"Themes","items":[]}]},{"name":"References","items":[]}]}]},"catchAllCategory":"References","noDuplicateEntries":true,"filterByApiItemName":false,"filterByInlineTag":"@docCategory"} \ No newline at end of file +{ + "tocConfig": { + "items": [ + { "name": "Office UI Fabric React", "href": "~/homepage/homepage.md" }, + { + "name": "Office UI Fabric React", + "href": "office-ui-fabric-react", + "extended": true, + "items": [ + { + "name": "Basic Inputs", + "items": [ + { "name": "Button", "items": [] }, + { "name": "Checkbox", "items": [] }, + { "name": "ChoiceGroup", "items": [] }, + { "name": "ComboBox", "items": [] }, + { "name": "Dropdown", "items": [] }, + { "name": "Label", "items": [] }, + { "name": "Link", "items": [] }, + { "name": "Rating", "items": [] }, + { "name": "SearchBox", "items": [] }, + { "name": "Slider", "items": [] }, + { "name": "SpinButton", "items": [] }, + { "name": "TextField", "items": [] }, + { "name": "Toggle", "items": [] } + ] + }, + { + "name": "Galleries & Pickers", + "items": [ + { "name": "Pickers", "items": [] }, + { "name": "Calendar", "items": [] }, + { "name": "ColorPicker", "items": [] }, + { "name": "DatePicker", "items": [] }, + { "name": "PeoplePicker", "items": [] }, + { "name": "SwatchColorPicker", "items": [] } + ] + }, + { + "name": "Items & Lists", + "items": [ + { "name": "List", "items": [] }, + { "name": "DetailsList", "items": [] }, + { "name": "GroupedList", "items": [] }, + { "name": "ActivityItem", "items": [] }, + { "name": "DocumentCard", "items": [] }, + { "name": "Facepile", "items": [] }, + { "name": "HoverCard", "items": [] }, + { "name": "Persona", "items": [] } + ] + }, + { + "name": "Commands, Menus & Navs", + "items": [ + { "name": "Breadcrumb", "items": [] }, + { "name": "CommandBar", "items": [] }, + { "name": "ContextualMenu", "items": [] }, + { "name": "Nav", "items": [] }, + { "name": "OverflowSet", "items": [] }, + { "name": "Pivot", "items": [] } + ] + }, + { + "name": "Notification & Engagement", + "items": [ + { "name": "Coachmark", "items": [] }, + { "name": "MessageBar", "items": [] }, + { "name": "TeachingBubble", "items": [] } + ] + }, + { + "name": "Progress", + "items": [ + { "name": "ProgressIndicator", "items": [] }, + { "name": "Shimmer", "items": [] }, + { "name": "Spinner", "items": [] } + ] + }, + { + "name": "Surfaces", + "items": [ + { "name": "Callout", "items": [] }, + { "name": "Dialog", "items": [] }, + { "name": "Modal", "items": [] }, + { "name": "Panel", "items": [] }, + { "name": "ScrollablePane", "items": [] }, + { "name": "Tooltip", "items": [] } + ] + }, + { + "name": "Utilities", + "items": [ + { "name": "Announced", "items": [] }, + { "name": "FocusTrapZone", "items": [] }, + { "name": "FocusZone", "items": [] }, + { "name": "Icon", "items": [] }, + { "name": "Image", "items": [] }, + { "name": "Keytips", "items": [] }, + { "name": "Layer", "items": [] }, + { "name": "MarqueeSelection", "items": [] }, + { "name": "Overlay", "items": [] }, + { "name": "ResizeGroup", "items": [] }, + { "name": "Selection", "items": [] }, + { "name": "Separator", "items": [] }, + { "name": "Stack", "items": [] }, + { "name": "Text", "items": [] }, + { "name": "Themes", "items": [] } + ] + }, + { "name": "References", "items": [] } + ] + } + ] + }, + "catchAllCategory": "References", + "noDuplicateEntries": true, + "filterByApiItemName": false, + "filterByInlineTag": "@docCategory" +} From 252268e06d626600baf3785eb63f4bef046dc5b3 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Mon, 6 May 2019 16:54:17 -0700 Subject: [PATCH 09/19] Change file --- .../FabricDocumenter_2019-05-06-23-48.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json diff --git a/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json b/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json new file mode 100644 index 00000000000..61645e6099e --- /dev/null +++ b/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@microsoft/api-documenter", + "comment": "Adds optional config file `api-documenter.json` to allow building custom TOC for YamlDocumenter.", + "type": "minor" + } + ], + "packageName": "@microsoft/api-documenter", + "email": "vibraga@microsoft.com" +} \ No newline at end of file From 4fa3a4e307ed6b3bcf8890f2d12484cd52c482b2 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Mon, 6 May 2019 18:52:07 -0700 Subject: [PATCH 10/19] Change the test --- apps/api-documenter/.vscode/launch.json | 6 +- .../api-documenter-oufr/api-documenter.json | 119 ------------ .../api-documenter-oufr/generateSchema.js | 174 ------------------ .../api-documenter-test/api-documenter.json | 26 +++ .../config/api-extractor.json | 10 +- .../etc/api-documenter-test.api.json | 16 +- .../api-documenter-test.docbaseclass.md | 1 + .../markdown/api-documenter-test.docenum.md | 1 + .../api-documenter-test.idocinterface3.md | 1 + .../api-documenter-test.idocinterface4.md | 1 + .../api-documenter-test.systemevent.md | 1 + .../api-documenter-test/src/DocClass1.ts | 7 + .../api-documenter-test/src/DocEnums.ts | 1 + 13 files changed, 60 insertions(+), 304 deletions(-) delete mode 100644 build-tests/api-documenter-oufr/api-documenter.json delete mode 100644 build-tests/api-documenter-oufr/generateSchema.js create mode 100644 build-tests/api-documenter-test/api-documenter.json diff --git a/apps/api-documenter/.vscode/launch.json b/apps/api-documenter/.vscode/launch.json index adee0b47e55..332a6d1382d 100644 --- a/apps/api-documenter/.vscode/launch.json +++ b/apps/api-documenter/.vscode/launch.json @@ -9,9 +9,11 @@ "request": "launch", "name": "Example", "program": "${workspaceFolder}/lib/start.js", - "cwd": "${workspaceFolder}/../../build-tests/api-documenter-oufr", + "cwd": "${workspaceFolder}/../../build-tests/api-documenter-test", "args": [ - "yaml" + "yaml", + "--input-folder etc", + "--output-folder etc/yaml" ], "sourceMaps": true }, diff --git a/build-tests/api-documenter-oufr/api-documenter.json b/build-tests/api-documenter-oufr/api-documenter.json deleted file mode 100644 index cb7ad128196..00000000000 --- a/build-tests/api-documenter-oufr/api-documenter.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "tocConfig": { - "items": [ - { "name": "Office UI Fabric React", "href": "~/homepage/homepage.md" }, - { - "name": "Office UI Fabric React", - "href": "office-ui-fabric-react", - "extended": true, - "items": [ - { - "name": "Basic Inputs", - "items": [ - { "name": "Button", "items": [] }, - { "name": "Checkbox", "items": [] }, - { "name": "ChoiceGroup", "items": [] }, - { "name": "ComboBox", "items": [] }, - { "name": "Dropdown", "items": [] }, - { "name": "Label", "items": [] }, - { "name": "Link", "items": [] }, - { "name": "Rating", "items": [] }, - { "name": "SearchBox", "items": [] }, - { "name": "Slider", "items": [] }, - { "name": "SpinButton", "items": [] }, - { "name": "TextField", "items": [] }, - { "name": "Toggle", "items": [] } - ] - }, - { - "name": "Galleries & Pickers", - "items": [ - { "name": "Pickers", "items": [] }, - { "name": "Calendar", "items": [] }, - { "name": "ColorPicker", "items": [] }, - { "name": "DatePicker", "items": [] }, - { "name": "PeoplePicker", "items": [] }, - { "name": "SwatchColorPicker", "items": [] } - ] - }, - { - "name": "Items & Lists", - "items": [ - { "name": "List", "items": [] }, - { "name": "DetailsList", "items": [] }, - { "name": "GroupedList", "items": [] }, - { "name": "ActivityItem", "items": [] }, - { "name": "DocumentCard", "items": [] }, - { "name": "Facepile", "items": [] }, - { "name": "HoverCard", "items": [] }, - { "name": "Persona", "items": [] } - ] - }, - { - "name": "Commands, Menus & Navs", - "items": [ - { "name": "Breadcrumb", "items": [] }, - { "name": "CommandBar", "items": [] }, - { "name": "ContextualMenu", "items": [] }, - { "name": "Nav", "items": [] }, - { "name": "OverflowSet", "items": [] }, - { "name": "Pivot", "items": [] } - ] - }, - { - "name": "Notification & Engagement", - "items": [ - { "name": "Coachmark", "items": [] }, - { "name": "MessageBar", "items": [] }, - { "name": "TeachingBubble", "items": [] } - ] - }, - { - "name": "Progress", - "items": [ - { "name": "ProgressIndicator", "items": [] }, - { "name": "Shimmer", "items": [] }, - { "name": "Spinner", "items": [] } - ] - }, - { - "name": "Surfaces", - "items": [ - { "name": "Callout", "items": [] }, - { "name": "Dialog", "items": [] }, - { "name": "Modal", "items": [] }, - { "name": "Panel", "items": [] }, - { "name": "ScrollablePane", "items": [] }, - { "name": "Tooltip", "items": [] } - ] - }, - { - "name": "Utilities", - "items": [ - { "name": "Announced", "items": [] }, - { "name": "FocusTrapZone", "items": [] }, - { "name": "FocusZone", "items": [] }, - { "name": "Icon", "items": [] }, - { "name": "Image", "items": [] }, - { "name": "Keytips", "items": [] }, - { "name": "Layer", "items": [] }, - { "name": "MarqueeSelection", "items": [] }, - { "name": "Overlay", "items": [] }, - { "name": "ResizeGroup", "items": [] }, - { "name": "Selection", "items": [] }, - { "name": "Separator", "items": [] }, - { "name": "Stack", "items": [] }, - { "name": "Text", "items": [] }, - { "name": "Themes", "items": [] } - ] - }, - { "name": "References", "items": [] } - ] - } - ] - }, - "catchAllCategory": "References", - "noDuplicateEntries": true, - "filterByApiItemName": false, - "filterByInlineTag": "@docCategory" -} diff --git a/build-tests/api-documenter-oufr/generateSchema.js b/build-tests/api-documenter-oufr/generateSchema.js deleted file mode 100644 index b64594c79ab..00000000000 --- a/build-tests/api-documenter-oufr/generateSchema.js +++ /dev/null @@ -1,174 +0,0 @@ -const fs = require('fs'); - -// This is a copy of an object that we will import from @uifabric/fabric-website package -// to be in sync with changes to their controls page navigation -const categories = { - "Basic Inputs": { - Button: {}, - Checkbox: {}, - ChoiceGroup: {}, - ComboBox: {}, - Dropdown: {}, - Label: {}, - Link: {}, - Rating: {}, - SearchBox: {}, - Slider: {}, - SpinButton: {}, - TextField: {}, - Toggle: {} - }, - "Galleries & Pickers": { - Pickers: {}, - Calendar: {}, - ColorPicker: {}, - DatePicker: {}, - PeoplePicker: {}, - SwatchColorPicker: {} - }, - "Items & Lists": { - List: { title: "Basic List" }, - DetailsList: { - subPages: { - Basic: {}, - Compact: {}, - Grouped: {}, - LargeGrouped: {}, - CustomColumns: { - title: "Custom Item Columns", - url: "customitemcolumns" - }, - CustomRows: { title: "Custom Item Rows", url: "customitemrows" }, - CustomFooter: { title: "Custom Footer" }, - CustomGroupHeaders: { title: "Custom Group Headers" }, - Advanced: { title: "Variable Row Heights", url: "variablerowheights" }, - DragDrop: { title: "Drag & Drop", url: "draganddrop" }, - NavigatingFocus: { title: "Inner Navigation", url: "innernavigation" }, - Shimmer: {} - } - }, - GroupedList: {}, - ActivityItem: {}, - DocumentCard: {}, - Facepile: {}, - HoverCard: {}, - Persona: {} - }, - "Commands, Menus & Navs": { - Breadcrumb: {}, - CommandBar: {}, - ContextualMenu: {}, - Nav: {}, - OverflowSet: {}, - Pivot: {} - }, - "Notification & Engagement": { - Coachmark: {}, - MessageBar: {}, - TeachingBubble: {} - }, - Progress: { - ProgressIndicator: {}, - Shimmer: {}, - Spinner: {} - }, - Surfaces: { - Callout: {}, - Dialog: {}, - Modal: {}, - Panel: {}, - ScrollablePane: {}, - Tooltip: {} - }, - Utilities: { - Announced: { - subPages: { - QuickActions: { title: "Quick Actions" }, - SearchResults: { title: "Search Results" }, - LazyLoading: { title: "Lazy Loading" }, - BulkOperations: { title: "Bulk Operations" } - } - }, - FocusTrapZone: {}, - FocusZone: {}, - Icon: {}, - Image: {}, - Keytips: {}, - Layer: {}, - MarqueeSelection: {}, - Overlay: {}, - ResizeGroup: {}, - Selection: {}, - Separator: {}, - Stack: {}, - Text: {}, - Themes: {} - }, - "Fluent Theme": { - FluentTheme: { title: "Fluent Theme", url: "fluent-theme" } - }, - References: {}, - Other: {} -}; - -// function that will be running every time before calling api-documenter and generate a schema file -// the return of this function will write a schema that all it needs is just to fill the empty `items` arrays for each node that has one. - -// in the future we can make modifications to the logic so that to include additional things -// like pages with examples that have nothing to do with the API json files -function generateConfig(stateObj) { - const tocConfig = { - items: [ - { - name: "Office UI Fabric React", - href: "~/homepage/homepage.md" - }, - { - name: "Office UI Fabric React", - href: "office-ui-fabric-react", - extended: true, - items: [] - } - ] - }; - - // delete unnecessary navigation items for docs.microsoft but present on the Fabric website - delete stateObj["Fluent Theme"]; - delete stateObj["Other"]; - - const categories = Object.keys(stateObj); - - for (const category of categories) { - const configItem = { - name: category, - items: [] - }; - - const categoryItems = Object.keys(stateObj[category]); - for (const categoryItem of categoryItems) { - configItem.items.push({ - name: categoryItem, - items: [] - }); - } - - tocConfig.items[1].items.push(configItem); - } - - // config file is what we needs to have a standardized structure of things we wanna support in customizing the TOC - // here is just a few that might be generally useful - const config = { - tocConfig, - catchAllCategory: 'References', - noDuplicateEntries: true, - // some possible filters to fill the leaf nodes `items` arrays. - filterByApiItemName: false, - filterByInlineTag: '@docCategory' - } - - // writing file - const json = JSON.stringify(config); - fs.writeFileSync("api-documenter.json", json, "utf8"); -} - -generateConfig(categories); diff --git a/build-tests/api-documenter-test/api-documenter.json b/build-tests/api-documenter-test/api-documenter.json new file mode 100644 index 00000000000..dcfe31e6aa6 --- /dev/null +++ b/build-tests/api-documenter-test/api-documenter.json @@ -0,0 +1,26 @@ +{ + "tocConfig": { + "items": [ + { "name": "Test api-documenter", "href": "~/homepage/homepage.md" }, + { + "name": "Test Sample for AD", + "href": "api-documenter-test", + "extended": true, + "items": [ + { + "name": "Classes", + "items": [ + { "name": "DocBaseClass", "items": [] }, + { "name": "DocClass1", "items": [] } + ] + }, + { "name": "References", "items": [] } + ] + } + ] + }, + "catchAllCategory": "References", + "noDuplicateEntries": true, + "filterByApiItemName": false, + "filterByInlineTag": "@docCategory" +} diff --git a/build-tests/api-documenter-test/config/api-extractor.json b/build-tests/api-documenter-test/config/api-extractor.json index 2e554d054fb..b1ce0f05a41 100644 --- a/build-tests/api-documenter-test/config/api-extractor.json +++ b/build-tests/api-documenter-test/config/api-extractor.json @@ -16,5 +16,13 @@ "enabled": false }, - "testMode": true + "testMode": true, + + "messages": { + "tsdocMessageReporting": { + "tsdoc-undefined-tag": { + "logLevel": "none" + } + } + } } diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.json b/build-tests/api-documenter-test/etc/api-documenter-test.api.json index fa250f4f7f2..272ba683c18 100644 --- a/build-tests/api-documenter-test/etc/api-documenter-test.api.json +++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.json @@ -17,7 +17,7 @@ { "kind": "Class", "canonicalReference": "(DocBaseClass:class)", - "docComment": "/**\n * Example base class\n *\n * @public\n */\n", + "docComment": "/**\n * Example base class\n *\n * {@docCategory DocBaseClass}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -40,7 +40,7 @@ { "kind": "Class", "canonicalReference": "(DocClass1:class)", - "docComment": "/**\n * This is an example class.\n *\n * @remarks\n *\n * These are some remarks.\n *\n * The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `DocClass1` class.\n *\n * @defaultValue\n *\n * a default value for this function\n *\n * @public\n */\n", + "docComment": "/**\n * This is an example class.\n *\n * @remarks\n *\n * These are some remarks.\n *\n * The constructor for this class is marked as internal. Third-party code should not call the constructor directly or create subclasses that extend the `DocClass1` class.\n *\n * @defaultValue\n *\n * a default value for this function\n *\n * {@docCategory DocClass1}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -513,7 +513,7 @@ { "kind": "Enum", "canonicalReference": "(DocEnum:enum)", - "docComment": "/**\n * Docs for DocEnum\n *\n * @public\n */\n", + "docComment": "/**\n * Docs for DocEnum\n *\n * {@docCategory SystemEvent}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -701,7 +701,7 @@ { "kind": "Interface", "canonicalReference": "(IDocInterface1:interface)", - "docComment": "/**\n * @public\n */\n", + "docComment": "/**\n * {@docCategory DocBaseClass}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -754,7 +754,7 @@ { "kind": "Interface", "canonicalReference": "(IDocInterface2:interface)", - "docComment": "/**\n * @public\n */\n", + "docComment": "/**\n * {@docCategory DocBaseClass}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -822,7 +822,7 @@ { "kind": "Interface", "canonicalReference": "(IDocInterface3:interface)", - "docComment": "/**\n * Some less common TypeScript declaration kinds.\n *\n * @public\n */\n", + "docComment": "/**\n * Some less common TypeScript declaration kinds.\n *\n * {@docCategory DocClass1}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -972,7 +972,7 @@ { "kind": "Interface", "canonicalReference": "(IDocInterface4:interface)", - "docComment": "/**\n * Type union in an interface.\n *\n * @public\n */\n", + "docComment": "/**\n * Type union in an interface.\n *\n * {@docCategory DocClass1}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", @@ -1262,7 +1262,7 @@ { "kind": "Class", "canonicalReference": "(SystemEvent:class)", - "docComment": "/**\n * A class used to exposed events.\n *\n * @public\n */\n", + "docComment": "/**\n * A class used to exposed events.\n *\n * {@docCategory SystemEvent}\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md index 359be92d38c..19a41e17a3f 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md @@ -6,6 +6,7 @@ Example base class + Signature: ```typescript diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md index c6721a947a4..4cce685c2e7 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md @@ -6,6 +6,7 @@ Docs for DocEnum + Signature: ```typescript diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md index 860468d1404..1ddbc4017c3 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md @@ -6,6 +6,7 @@ Some less common TypeScript declaration kinds. + Signature: ```typescript diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md index ba20de23b33..3dda827e5a3 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md @@ -6,6 +6,7 @@ Type union in an interface. + Signature: ```typescript diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md index 0c3383cf828..47baad77696 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md @@ -6,6 +6,7 @@ A class used to exposed events. + Signature: ```typescript diff --git a/build-tests/api-documenter-test/src/DocClass1.ts b/build-tests/api-documenter-test/src/DocClass1.ts index 3e8e00858ec..a608f7dbd58 100644 --- a/build-tests/api-documenter-test/src/DocClass1.ts +++ b/build-tests/api-documenter-test/src/DocClass1.ts @@ -2,6 +2,7 @@ /** * A class used to exposed events. * @public + * {@docCategory SystemEvent} */ export class SystemEvent { /** @@ -14,12 +15,14 @@ export class SystemEvent { /** * Example base class * @public + * {@docCategory DocBaseClass} */ export class DocBaseClass { } /** * @public + * {@docCategory DocBaseClass} */ export interface IDocInterface1 { /** @@ -30,6 +33,7 @@ export interface IDocInterface1 { /** * @public + * {@docCategory DocBaseClass} */ export interface IDocInterface2 extends IDocInterface1 { /** @@ -41,6 +45,7 @@ export interface IDocInterface2 extends IDocInterface1 { /** * Some less common TypeScript declaration kinds. * @public + * {@docCategory DocClass1} */ export interface IDocInterface3 { /** @@ -70,6 +75,7 @@ export class Generic { } /** * Type union in an interface. * @public + * {@docCategory DocClass1} */ export interface IDocInterface4 { /** @@ -99,6 +105,7 @@ export interface IDocInterface4 { * These are some remarks. * @defaultValue a default value for this function * @public + * {@docCategory DocClass1} */ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInterface2 { /** diff --git a/build-tests/api-documenter-test/src/DocEnums.ts b/build-tests/api-documenter-test/src/DocEnums.ts index a60df6d230d..7428c569f15 100644 --- a/build-tests/api-documenter-test/src/DocEnums.ts +++ b/build-tests/api-documenter-test/src/DocEnums.ts @@ -4,6 +4,7 @@ /** * Docs for DocEnum * @public + * {@docCategory SystemEvent} */ export enum DocEnum { /** From 48180b96727646ddf60a4207e36c66426f80181b Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Mon, 6 May 2019 18:55:26 -0700 Subject: [PATCH 11/19] Adjust debugger --- apps/api-documenter/.vscode/launch.json | 6 ++- .../api-documenter-test/etc/yaml/toc.yml | 39 +++++++++++-------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/apps/api-documenter/.vscode/launch.json b/apps/api-documenter/.vscode/launch.json index 332a6d1382d..f6eb77a1aba 100644 --- a/apps/api-documenter/.vscode/launch.json +++ b/apps/api-documenter/.vscode/launch.json @@ -12,8 +12,10 @@ "cwd": "${workspaceFolder}/../../build-tests/api-documenter-test", "args": [ "yaml", - "--input-folder etc", - "--output-folder etc/yaml" + "--input-folder", + "etc", + "--output-folder", + "etc/yaml" ], "sourceMaps": true }, diff --git a/build-tests/api-documenter-test/etc/yaml/toc.yml b/build-tests/api-documenter-test/etc/yaml/toc.yml index f7a2d25ad08..6c4762ad691 100644 --- a/build-tests/api-documenter-test/etc/yaml/toc.yml +++ b/build-tests/api-documenter-test/etc/yaml/toc.yml @@ -1,28 +1,33 @@ items: - - name: SharePoint Framework reference - href: ~/overview/sharepoint.md + - name: Test api-documenter + href: ~/homepage/homepage.md + - name: Test Sample for AD + href: api-documenter-test + extended: true items: - - name: api-documenter-test - uid: api-documenter-test + - name: Classes items: - name: DocBaseClass - uid: api-documenter-test.DocBaseClass + items: + - name: DocBaseClass + uid: api-documenter-test.DocBaseClass + - name: IDocInterface1 + uid: api-documenter-test.IDocInterface1 + - name: IDocInterface2 + uid: api-documenter-test.IDocInterface2 - name: DocClass1 - uid: api-documenter-test.DocClass1 + items: + - name: DocClass1 + uid: api-documenter-test.DocClass1 + - name: IDocInterface3 + uid: api-documenter-test.IDocInterface3 + - name: IDocInterface4 + uid: api-documenter-test.IDocInterface4 + - name: References + items: - name: DocEnum uid: api-documenter-test.DocEnum - name: Generic uid: api-documenter-test.Generic - - name: IDocInterface1 - uid: api-documenter-test.IDocInterface1 - - name: IDocInterface2 - uid: api-documenter-test.IDocInterface2 - - name: IDocInterface3 - uid: api-documenter-test.IDocInterface3 - - name: IDocInterface4 - uid: api-documenter-test.IDocInterface4 - - name: OuterNamespace - items: - - name: InnerNamespace - name: SystemEvent uid: api-documenter-test.SystemEvent From 5de428b2cb919b229fc518f7566d939e687bf918 Mon Sep 17 00:00:00 2001 From: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> Date: Mon, 6 May 2019 21:51:21 -0700 Subject: [PATCH 12/19] Move IYamlTocConfigSchema into an IConfigFile interface with a corresponding DocumenterConfig class --- .../src/documenters/DocumenterConfig.ts | 33 ++++++++++++ .../src/documenters/IConfigFile.ts | 51 +++++++++++++++++++ .../src/schemas/api-documenter.schema.json | 18 +++++++ apps/api-documenter/src/yaml/IYamlTocFile.ts | 39 -------------- 4 files changed, 102 insertions(+), 39 deletions(-) create mode 100644 apps/api-documenter/src/documenters/DocumenterConfig.ts create mode 100644 apps/api-documenter/src/documenters/IConfigFile.ts create mode 100644 apps/api-documenter/src/schemas/api-documenter.schema.json diff --git a/apps/api-documenter/src/documenters/DocumenterConfig.ts b/apps/api-documenter/src/documenters/DocumenterConfig.ts new file mode 100644 index 00000000000..5304ad4cf0a --- /dev/null +++ b/apps/api-documenter/src/documenters/DocumenterConfig.ts @@ -0,0 +1,33 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'path'; +import { JsonSchema, JsonFile } from '@microsoft/node-core-library'; +import { IConfigFile } from './IConfigFile'; + +/** + * Helper for loading the api-documenter.json file format. Later when the schema is more mature, + * this class will be used to represent the validated and normalized configuration, whereas `IConfigFile` + * represents the raw JSON file structure. + */ +export class DocumenterConfig { + /** + * The JSON Schema for API Extractor config file (api-extractor.schema.json). + */ + public static readonly jsonSchema: JsonSchema = JsonSchema.fromFile( + path.join(__dirname, '../schemas/api-documenter.schema.json')); + + /** + * The config file name "api-extractor.json". + */ + public static readonly FILENAME: string = 'api-documenter.json'; + + /** + * Load and validate an api-documenter.json file. + */ + public static loadFile(configFilePath: string): IConfigFile { + const configFile: IConfigFile = JsonFile.loadAndValidate(configFilePath, DocumenterConfig.jsonSchema); + + return configFile; + } +} diff --git a/apps/api-documenter/src/documenters/IConfigFile.ts b/apps/api-documenter/src/documenters/IConfigFile.ts new file mode 100644 index 00000000000..983a694f775 --- /dev/null +++ b/apps/api-documenter/src/documenters/IConfigFile.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { IYamlTocFile } from '../yaml/IYamlTocFile'; + +/** + * Typescript interface describing the config schema for toc.yml file format. + */ +export interface IConfigTableOfContents { + /** + * Represents the tree structure describing the toc.file format. + * Only the nodes that have an empty `items` array will be filled with API items + * that are matched with the filters provided. Everything else will be placed under a catchAll category + * that is highly recommended to be provided. + */ + tocConfig: IYamlTocFile; + + /** + * Optional category name that is recommended to include in the `tocConfig`, + * along with one of the filters: `filterByApiItemName` or `filterByInlineTag`. + * Any items that are not matched to the mentioned filters will be placed under this + * catchAll category. If none provided the items will not be included in the final toc.yml file. + */ + catchAllCategory?: string; + + /** + * When loading more than one api.json files that might include the same API items, + * toggle either to show duplicates or not. + */ + noDuplicateEntries?: boolean; + + /** + * Toggle either sorting of the API items should be made based on category name presence + * in the API item's name. + */ + filterByApiItemName?: boolean; + + /** + * Filter that can be used to sort the API items according to an inline custom tag + * that is present on them. + */ + filterByInlineTag?: string; +} + +/** + * This interface represents the api-extractor.json file format. + */ +export interface IConfigFile { + /** {@inheritDoc IConfigTableOfContents} */ + tableOfContents?: IConfigTableOfContents; +} diff --git a/apps/api-documenter/src/schemas/api-documenter.schema.json b/apps/api-documenter/src/schemas/api-documenter.schema.json new file mode 100644 index 00000000000..9782261fce2 --- /dev/null +++ b/apps/api-documenter/src/schemas/api-documenter.schema.json @@ -0,0 +1,18 @@ +{ + "title": "API Documenter Configuration", + "description": "Describes how the API Documenter tool will process a project.", + "type": "object", + "properties": { + "$schema": { + "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", + "type": "string" + }, + + "tableOfContents": { + "description": "Configures how the table of contents is generated.", + "type": "object", + "additionalProperties": true + }, + + "additionalProperties": false +} diff --git a/apps/api-documenter/src/yaml/IYamlTocFile.ts b/apps/api-documenter/src/yaml/IYamlTocFile.ts index 56901de5a2d..142accb190b 100644 --- a/apps/api-documenter/src/yaml/IYamlTocFile.ts +++ b/apps/api-documenter/src/yaml/IYamlTocFile.ts @@ -34,42 +34,3 @@ export interface IYamlTocFile { items: IYamlTocItem[]; metadata?: { [key: string]: string }; } - -/** - * Typescript interface describing the config schema for toc.yml file format. - */ -export interface IYamlTocConfigSchema { - /** - * Represents the tree structure describing the toc.file format. - * Only the nodes that have an empty `items` array will be filled with API items - * that are matched with the filters provided. Everything else will be placed under a catchAll category - * that is highly recommended to be provided. - */ - tocConfig: IYamlTocFile; - - /** - * Optional category name that is recommended to include in the `tocConfig`, - * along with one of the filters: `filterByApiItemName` or `filterByInlineTag`. - * Any items that are not matched to the mentioned filters will be placed under this - * catchAll category. If none provided the items will not be included in the final toc.yml file. - */ - catchAllCategory?: string; - - /** - * When loading more than one api.json files that might include the same API items, - * toggle either to show duplicates or not. - */ - noDuplicateEntries?: boolean; - - /** - * Toggle either sorting of the API items should be made based on category name presence - * in the API item's name. - */ - filterByApiItemName?: boolean; - - /** - * Filter that can be used to sort the API items according to an inline custom tag - * that is present on them. - */ - filterByInlineTag?: string; -} From ce0f6798956127a46f005464b4818f92e4c4df1b Mon Sep 17 00:00:00 2001 From: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> Date: Mon, 6 May 2019 21:52:39 -0700 Subject: [PATCH 13/19] Add an api-documenter-template.json file that in the future could be emitted by an "api-documenter init" action; for now we'll use this as a sample to track the intended config file contents --- .../src/schemas/api-documenter-template.json | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 apps/api-documenter/src/schemas/api-documenter-template.json diff --git a/apps/api-documenter/src/schemas/api-documenter-template.json b/apps/api-documenter/src/schemas/api-documenter-template.json new file mode 100644 index 00000000000..7e83106ef00 --- /dev/null +++ b/apps/api-documenter/src/schemas/api-documenter-template.json @@ -0,0 +1,60 @@ +/** + * Config file for API Documenter. For more info, please visit: https://api-extractor.com + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-documenter.schema.json", + + /** + * Configures how the table of contents is generated. + */ + "tableOfContents": { + /** + * Allows hand-coded items to be injected into the table of contents. + * + * DEFAULT VALUE: (none) + */ + // "items": [ + // { "name": "Example Node", "href": "~/homepage/homepage.md" }, + // { + // "name": "API Reference", + // "items": [ + // { "name": "References" } + // ] + // } + // ], + + /** + * Optional category name that is recommended to include in the `tocConfig`, + * along with one of the filters: `filterByApiItemName` or `filterByInlineTag`. + * Any items that are not matched to the mentioned filters will be placed under this + * catchAll category. If none provided the items will not be included in the final toc.yml file. + * + * DEFAULT VALUE: (none) + */ + // "catchAllCategory": "References", + + /** + * When loading more than one api.json files that might include the same API items, + * toggle either to show duplicates or not. + * + * DEFAULT VALUE: false + */ + // "noDuplicateEntries": true, + + /** + * Toggle either sorting of the API items should be made based on category name presence + * in the API item's name. + * + * DEFAULT VALUE: false + */ + // "filterByApiItemName": false, + + /** + * Filter that can be used to sort the API items according to an inline custom tag + * that is present on them. + * + * DEFAULT VALUE: (none) + */ + // "filterByInlineTag": "@docCategory" + } +} From 336a2305d05042167e21a627e9c6d68576998fcd Mon Sep 17 00:00:00 2001 From: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> Date: Mon, 6 May 2019 21:52:56 -0700 Subject: [PATCH 14/19] Extract the experimental functionality into an ExperimentYamlDocumenter child class --- .../documenters/ExperimentYamlDocumenter.ts | 139 ++++++++++++++++++ .../src/documenters/YamlDocumenter.ts | 103 +++---------- 2 files changed, 156 insertions(+), 86 deletions(-) create mode 100644 apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts diff --git a/apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts new file mode 100644 index 00000000000..8a1f5371512 --- /dev/null +++ b/apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { PackageName } from '@microsoft/node-core-library'; +import { DocComment, DocInlineTag } from '@microsoft/tsdoc'; +import { ApiModel, ApiItem, ApiItemKind, ApiDocumentedItem } from '@microsoft/api-extractor-model'; + +import { IConfigFile, IConfigTableOfContents } from './IConfigFile'; +import { IYamlTocItem, IYamlTocFile } from '../yaml/IYamlTocFile'; +import { YamlDocumenter } from './YamlDocumenter'; + +/** + * EXPERIMENTAL - This documenter is a prototype of a new config file driven mode of operation for + * API Documenter. It is not ready for general usage yet. Its design may change in the future. + */ +export class ExperimentYamlDocumenter extends YamlDocumenter { + private _config: IConfigTableOfContents; + private _tocPointerMap: { [key: string]: IYamlTocItem }; + private _catchAllPointer: IYamlTocItem; + + public constructor(apiModel: ApiModel, configFile: IConfigFile) { + super(apiModel); + this._config = configFile.tableOfContents!; + + this._tocPointerMap = {}; // need a type? + + this._generateTocPointersMap(this._config.tocConfig); + } + + /** @override */ + protected buildYamlTocFile(apiItems: ReadonlyArray): IYamlTocFile { + this._buildTocItems2(apiItems); + return this._config.tocConfig; + } + + private _buildTocItems2(apiItems: ReadonlyArray): IYamlTocItem[] { + const tocItems: IYamlTocItem[] = []; + for (const apiItem of apiItems) { + let tocItem: IYamlTocItem; + + if (apiItem.kind === ApiItemKind.Namespace) { + // Namespaces don't have nodes yet + tocItem = { + name: apiItem.displayName + }; + } else { + if (this._shouldEmbed(apiItem.kind)) { + // Don't generate table of contents items for embedded definitions + continue; + } + + if (apiItem.kind === ApiItemKind.Package) { + tocItem = { + name: PackageName.getUnscopedName(apiItem.displayName), + uid: this._getUid(apiItem) + }; + } else { + tocItem = { + name: apiItem.displayName, + uid: this._getUid(apiItem) + }; + // Filtering out the api-items as we build the tocItems array. + if (apiItem instanceof ApiDocumentedItem) { + const docInlineTag: DocInlineTag | undefined = + (this._config && this._config.filterByInlineTag) + ? this._findInlineTagByName(this._config.filterByInlineTag, apiItem.tsdocComment) + : undefined; + + const tagContent: string | undefined = + docInlineTag && docInlineTag.tagContent && docInlineTag.tagContent.trim(); + + if (tagContent && this._tocPointerMap[tagContent]) { + // null assertion used because when pointer map was created we checked for presence of empty `items` array + this._tocPointerMap[tagContent].items!.push(tocItem); + } else { + if (this._catchAllPointer && this._catchAllPointer.items) { + this._catchAllPointer.items.push(tocItem); + } + } + } + + } + } + + tocItems.push(tocItem); + + let children: ReadonlyArray; + if (apiItem.kind === ApiItemKind.Package) { + // Skip over the entry point, since it's not part of the documentation hierarchy + children = apiItem.members[0].members; + } else { + children = apiItem.members; + } + + const childItems: IYamlTocItem[] = this._buildTocItems2(children); + if (childItems.length > 0) { + tocItem.items = childItems; + } + } + return tocItems; + } + + // Parses the tocConfig object to build a pointers map of nodes where we want to sort out the API items + private _generateTocPointersMap(tocConfig: IYamlTocFile | IYamlTocItem): void { + if (tocConfig.items) { + for (const tocItem of tocConfig.items) { + if (tocItem.items && tocItem.items.length > 0) { + this._generateTocPointersMap(tocItem); + } else { + // check for presence of the `catchAllCategory` config option + if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { + this._catchAllPointer = tocItem; + } else { + this._tocPointerMap[tocItem.name] = tocItem; + } + } + } + } + } + + // This is a direct copy of a @docCategory inline tag finder in office-ui-fabric-react, + // but is generic enough to be used for any inline tag + private _findInlineTagByName(tagName: string, docComment: DocComment | undefined): DocInlineTag | undefined { + if (docComment instanceof DocInlineTag) { + if (docComment.tagName === tagName) { + return docComment; + } + } + if (docComment) { + for (const childNode of docComment.getChildNodes()) { + const result: DocInlineTag | undefined = this._findInlineTagByName(tagName, childNode as DocComment); + if (result !== undefined) { + return result; + } + } + } + return undefined; + } +} diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index d84ace4861f..a9f052a64a5 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +// tslint:disable:member-ordering + import * as path from 'path'; import yaml = require('js-yaml'); @@ -12,7 +14,7 @@ import { NewlineKind, InternalError } from '@microsoft/node-core-library'; -import { StringBuilder, DocSection, DocComment, DocInlineTag } from '@microsoft/tsdoc'; +import { StringBuilder, DocSection, DocComment } from '@microsoft/tsdoc'; import { ApiModel, ApiItem, @@ -42,8 +44,7 @@ import { } from '../yaml/IYamlApiFile'; import { IYamlTocFile, - IYamlTocItem, - IYamlTocConfigSchema + IYamlTocItem } from '../yaml/IYamlTocFile'; import { Utilities } from '../utils/Utilities'; import { CustomMarkdownEmitter} from '../markdown/CustomMarkdownEmitter'; @@ -66,15 +67,10 @@ export class YamlDocumenter { private _outputFolder: string; - private _config: IYamlTocConfigSchema; - private _tocPointerMap: { [key: string]: IYamlTocItem }; - private _catchAllPointer: IYamlTocItem; - public constructor(apiModel: ApiModel) { this._apiModel = apiModel; this._markdownEmitter = new CustomMarkdownEmitter(this._apiModel); this._apiItemsByTypeName = new Map(); - this._tocPointerMap = {}; // need a type? this._initApiItemsByTypeName(); } @@ -83,16 +79,6 @@ export class YamlDocumenter { public generateFiles(outputFolder: string): void { this._outputFolder = outputFolder; - try { - this._config = JsonFile.load('./api-documenter.json'); - console.log('Loaded custom configuration'); - if (this._config.tocConfig) { - this._generateTocPointersMap(this._config.tocConfig); - } - } catch (error) { - console.log('No configuration found. Using the default'); - } - console.log(); this._deleteOldOutputFiles(); @@ -200,6 +186,15 @@ export class YamlDocumenter { * Write the table of contents */ private _writeTocFile(apiItems: ReadonlyArray): void { + const tocFile: IYamlTocFile = this.buildYamlTocFile(apiItems); + + const tocFilePath: string = path.join(this._outputFolder, 'toc.yml'); + console.log('Writing ' + tocFilePath); + this._writeYamlFile(tocFile, tocFilePath, '', undefined); + } + + /** @virtual */ + protected buildYamlTocFile(apiItems: ReadonlyArray): IYamlTocFile { const tocFile: IYamlTocFile = { items: [ ] }; @@ -208,13 +203,7 @@ export class YamlDocumenter { tocFile.items.push(rootItem); rootItem.items!.push(...this._buildTocItems(apiItems)); - - const tocFilePath: string = path.join(this._outputFolder, 'toc.yml'); - - const tocFileToWrite: IYamlTocFile = this._config && this._config.tocConfig ? this._config.tocConfig : tocFile; - - console.log('Writing ' + tocFilePath); - this._writeYamlFile(tocFileToWrite, tocFilePath, '', undefined); + return tocFile; } private _buildTocItems(apiItems: ReadonlyArray): IYamlTocItem[] { @@ -243,26 +232,6 @@ export class YamlDocumenter { name: apiItem.displayName, uid: this._getUid(apiItem) }; - // Filtering out the api-items as we build the tocItems array. - if (apiItem instanceof ApiDocumentedItem) { - const docInlineTag: DocInlineTag | undefined = - (this._config && this._config.filterByInlineTag) - ? this._findInlineTagByName(this._config.filterByInlineTag, apiItem.tsdocComment) - : undefined; - - const tagContent: string | undefined = - docInlineTag && docInlineTag.tagContent && docInlineTag.tagContent.trim(); - - if (tagContent && this._tocPointerMap[tagContent]) { - // null assertion used because when pointer map was created we checked for presence of empty `items` array - this._tocPointerMap[tagContent].items!.push(tocItem); - } else { - if (this._catchAllPointer && this._catchAllPointer.items) { - this._catchAllPointer.items.push(tocItem); - } - } - } - } } @@ -284,7 +253,7 @@ export class YamlDocumenter { return tocItems; } - private _shouldEmbed(apiItemKind: ApiItemKind): boolean { + protected _shouldEmbed(apiItemKind: ApiItemKind): boolean { switch (apiItemKind) { case ApiItemKind.Class: case ApiItemKind.Package: @@ -529,8 +498,7 @@ export class YamlDocumenter { JsonFile.validateNoUndefinedMembers(dataObject); let stringified: string = yaml.safeDump(dataObject, { - lineWidth: 120, - noRefs: this._config && this._config.noDuplicateEntries ? true : false + lineWidth: 120 }); if (yamlMimeType) { @@ -551,7 +519,7 @@ export class YamlDocumenter { * Calculate the DocFX "uid" for the ApiItem * Example: node-core-library.JsonFile.load */ - private _getUid(apiItem: ApiItem): string { + protected _getUid(apiItem: ApiItem): string { let result: string = ''; for (const hierarchyItem of apiItem.getHierarchy()) { @@ -708,41 +676,4 @@ export class YamlDocumenter { console.log('Deleting old output from ' + this._outputFolder); FileSystem.ensureEmptyFolder(this._outputFolder); } - - // Parses the tocConfig object to build a pointers map of nodes where we want to sort out the API items - private _generateTocPointersMap(tocConfig: IYamlTocFile | IYamlTocItem): void { - if (tocConfig.items) { - for (const tocItem of tocConfig.items) { - if (tocItem.items && tocItem.items.length > 0) { - this._generateTocPointersMap(tocItem); - } else { - // check for presence of the `catchAllCategory` config option - if (this._config && this._config.catchAllCategory && tocItem.name === this._config.catchAllCategory) { - this._catchAllPointer = tocItem; - } else { - this._tocPointerMap[tocItem.name] = tocItem; - } - } - } - } - } - - // This is a direct copy of a @docCategory inline tag finder in office-ui-fabric-react, - // but is generic enough to be used for any inline tag - private _findInlineTagByName(tagName: string, docComment: DocComment | undefined): DocInlineTag | undefined { - if (docComment instanceof DocInlineTag) { - if (docComment.tagName === tagName) { - return docComment; - } - } - if (docComment) { - for (const childNode of docComment.getChildNodes()) { - const result: DocInlineTag | undefined = this._findInlineTagByName(tagName, childNode as DocComment); - if (result !== undefined) { - return result; - } - } - } - return undefined; - } } From 34339cdf12b0abb5b6d70939e25a45a826198696 Mon Sep 17 00:00:00 2001 From: Pete Gonzalez <4673363+octogonz@users.noreply.github.com> Date: Mon, 6 May 2019 21:53:14 -0700 Subject: [PATCH 15/19] Add a new command-line action "api-documenter generate" --- .../src/cli/ApiDocumenterCommandLine.ts | 2 + apps/api-documenter/src/cli/GenerateAction.ts | 51 +++++++++++++++++++ .../src/schemas/api-documenter.schema.json | 2 +- .../api-documenter-test/api-documenter.json | 26 ---------- build-tests/api-documenter-test/build.js | 2 +- .../config/api-documenter.json | 30 +++++++++++ 6 files changed, 85 insertions(+), 28 deletions(-) create mode 100644 apps/api-documenter/src/cli/GenerateAction.ts delete mode 100644 build-tests/api-documenter-test/api-documenter.json create mode 100644 build-tests/api-documenter-test/config/api-documenter.json diff --git a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts index db47cb5f62b..b56cbc8a1ae 100644 --- a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts +++ b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts @@ -4,6 +4,7 @@ import { CommandLineParser } from '@microsoft/ts-command-line'; import { MarkdownAction } from './MarkdownAction'; import { YamlAction } from './YamlAction'; +import { GenerateAction } from './GenerateAction'; export class ApiDocumenterCommandLine extends CommandLineParser { constructor() { @@ -22,5 +23,6 @@ export class ApiDocumenterCommandLine extends CommandLineParser { private _populateActions(): void { this.addAction(new MarkdownAction(this)); this.addAction(new YamlAction(this)); + this.addAction(new GenerateAction(this)); } } diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts new file mode 100644 index 00000000000..208f3b977d1 --- /dev/null +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -0,0 +1,51 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'path'; + +import { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; +import { BaseAction } from './BaseAction'; + +import { ExperimentYamlDocumenter } from '../documenters/ExperimentYamlDocumenter'; +import { ApiModel } from '@microsoft/api-extractor-model'; +import { DocumenterConfig } from '../documenters/DocumenterConfig'; +import { FileSystem } from '@microsoft/node-core-library'; +import { IConfigFile } from '../documenters/IConfigFile'; + +export class GenerateAction extends BaseAction { + constructor(parser: ApiDocumenterCommandLine) { + super({ + actionName: 'generate', + summary: 'EXPERIMENTAL', + documentation: 'EXPERIMENTAL - This action is a prototype of a new config file driven mode of operation for' + + ' API Documenter. It is not ready for general usage yet. Its design may change in the future.' + }); + } + + protected onDefineParameters(): void { // override + super.onDefineParameters(); + } + + protected onExecute(): Promise { // override + // Look for the config file under the current folder + + let configFilePath: string = path.join(process.cwd(), DocumenterConfig.FILENAME); + + // First try the current folder + if (!FileSystem.exists(configFilePath)) { + // Otherwise try the standard "config" subfolder + configFilePath = path.join(process.cwd(), 'config', DocumenterConfig.FILENAME); + if (!FileSystem.exists(configFilePath)) { + throw new Error(`Unable to find ${DocumenterConfig.FILENAME} in the current folder or in a "config" subfolder`); + } + } + + const configFile: IConfigFile = DocumenterConfig.loadFile(configFilePath); + + const apiModel: ApiModel = this.buildApiModel(); + + const yamlDocumenter: ExperimentYamlDocumenter = new ExperimentYamlDocumenter(apiModel, configFile); + yamlDocumenter.generateFiles(this.outputFolder); + return Promise.resolve(); + } +} diff --git a/apps/api-documenter/src/schemas/api-documenter.schema.json b/apps/api-documenter/src/schemas/api-documenter.schema.json index 9782261fce2..95e76696cbf 100644 --- a/apps/api-documenter/src/schemas/api-documenter.schema.json +++ b/apps/api-documenter/src/schemas/api-documenter.schema.json @@ -13,6 +13,6 @@ "type": "object", "additionalProperties": true }, - + }, "additionalProperties": false } diff --git a/build-tests/api-documenter-test/api-documenter.json b/build-tests/api-documenter-test/api-documenter.json deleted file mode 100644 index dcfe31e6aa6..00000000000 --- a/build-tests/api-documenter-test/api-documenter.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "tocConfig": { - "items": [ - { "name": "Test api-documenter", "href": "~/homepage/homepage.md" }, - { - "name": "Test Sample for AD", - "href": "api-documenter-test", - "extended": true, - "items": [ - { - "name": "Classes", - "items": [ - { "name": "DocBaseClass", "items": [] }, - { "name": "DocClass1", "items": [] } - ] - }, - { "name": "References", "items": [] } - ] - } - ] - }, - "catchAllCategory": "References", - "noDuplicateEntries": true, - "filterByApiItemName": false, - "filterByInlineTag": "@docCategory" -} diff --git a/build-tests/api-documenter-test/build.js b/build-tests/api-documenter-test/build.js index 23a2e94281c..c2bd5b29fd0 100644 --- a/build-tests/api-documenter-test/build.js +++ b/build-tests/api-documenter-test/build.js @@ -26,7 +26,7 @@ if (process.argv.indexOf('--production') >= 0) { // Run the API Documenter command-line executeCommand('node node_modules/@microsoft/api-documenter/lib/start ' - + 'yaml --input-folder etc --output-folder etc/yaml'); + + 'generate --input-folder etc --output-folder etc/yaml'); executeCommand('node node_modules/@microsoft/api-documenter/lib/start ' + 'markdown --input-folder etc --output-folder etc/markdown'); diff --git a/build-tests/api-documenter-test/config/api-documenter.json b/build-tests/api-documenter-test/config/api-documenter.json new file mode 100644 index 00000000000..fba39a2d549 --- /dev/null +++ b/build-tests/api-documenter-test/config/api-documenter.json @@ -0,0 +1,30 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-documenter.schema.json", + + "tableOfContents": { + "tocConfig": { + "items": [ + { "name": "Test api-documenter", "href": "~/homepage/homepage.md" }, + { + "name": "Test Sample for AD", + "href": "api-documenter-test", + "extended": true, + "items": [ + { + "name": "Classes", + "items": [ + { "name": "DocBaseClass", "items": [] }, + { "name": "DocClass1", "items": [] } + ] + }, + { "name": "References", "items": [] } + ] + } + ] + }, + "catchAllCategory": "References", + "noDuplicateEntries": true, + "filterByApiItemName": false, + "filterByInlineTag": "@docCategory" + } +} From c65db70e99e0231a47d7872511015059a17c71f6 Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Wed, 15 May 2019 23:03:31 -0700 Subject: [PATCH 16/19] Sort imports and remove the debugger file --- apps/api-documenter/.vscode/launch.json | 23 ------------------- apps/api-documenter/src/cli/GenerateAction.ts | 6 ++--- 2 files changed, 3 insertions(+), 26 deletions(-) delete mode 100644 apps/api-documenter/.vscode/launch.json diff --git a/apps/api-documenter/.vscode/launch.json b/apps/api-documenter/.vscode/launch.json deleted file mode 100644 index f6eb77a1aba..00000000000 --- a/apps/api-documenter/.vscode/launch.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Example", - "program": "${workspaceFolder}/lib/start.js", - "cwd": "${workspaceFolder}/../../build-tests/api-documenter-test", - "args": [ - "yaml", - "--input-folder", - "etc", - "--output-folder", - "etc/yaml" - ], - "sourceMaps": true - }, - ] -} \ No newline at end of file diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts index 208f3b977d1..f96df26f02e 100644 --- a/apps/api-documenter/src/cli/GenerateAction.ts +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -5,12 +5,12 @@ import * as path from 'path'; import { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; - +import { DocumenterConfig } from '../documenters/DocumenterConfig'; import { ExperimentYamlDocumenter } from '../documenters/ExperimentYamlDocumenter'; +import { IConfigFile } from '../documenters/IConfigFile'; + import { ApiModel } from '@microsoft/api-extractor-model'; -import { DocumenterConfig } from '../documenters/DocumenterConfig'; import { FileSystem } from '@microsoft/node-core-library'; -import { IConfigFile } from '../documenters/IConfigFile'; export class GenerateAction extends BaseAction { constructor(parser: ApiDocumenterCommandLine) { From 6bbaa350f6178f7d2227b4c0f09dda8629bae3de Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Wed, 15 May 2019 23:24:47 -0700 Subject: [PATCH 17/19] Remove unnecessary override --- apps/api-documenter/src/cli/GenerateAction.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts index f96df26f02e..241952f769a 100644 --- a/apps/api-documenter/src/cli/GenerateAction.ts +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -22,10 +22,6 @@ export class GenerateAction extends BaseAction { }); } - protected onDefineParameters(): void { // override - super.onDefineParameters(); - } - protected onExecute(): Promise { // override // Look for the config file under the current folder From de5a492046fe706c439780d24f31103a48878bfa Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Thu, 16 May 2019 00:13:53 -0700 Subject: [PATCH 18/19] More feedback addressed --- apps/api-documenter/src/cli/GenerateAction.ts | 4 ++-- apps/api-documenter/src/documenters/DocumenterConfig.ts | 2 +- ...erimentYamlDocumenter.ts => ExperimentalYamlDocumenter.ts} | 4 ++-- .../etc/markdown/api-documenter-test.docbaseclass.md | 3 +-- .../api-documenter/FabricDocumenter_2019-05-06-23-48.json | 2 +- 5 files changed, 7 insertions(+), 8 deletions(-) rename apps/api-documenter/src/documenters/{ExperimentYamlDocumenter.ts => ExperimentalYamlDocumenter.ts} (97%) diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts index 241952f769a..0a84c4c835b 100644 --- a/apps/api-documenter/src/cli/GenerateAction.ts +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; import { DocumenterConfig } from '../documenters/DocumenterConfig'; -import { ExperimentYamlDocumenter } from '../documenters/ExperimentYamlDocumenter'; +import { ExperimentalYamlDocumenter } from '../documenters/ExperimentalYamlDocumenter'; import { IConfigFile } from '../documenters/IConfigFile'; import { ApiModel } from '@microsoft/api-extractor-model'; @@ -40,7 +40,7 @@ export class GenerateAction extends BaseAction { const apiModel: ApiModel = this.buildApiModel(); - const yamlDocumenter: ExperimentYamlDocumenter = new ExperimentYamlDocumenter(apiModel, configFile); + const yamlDocumenter: ExperimentalYamlDocumenter = new ExperimentalYamlDocumenter(apiModel, configFile); yamlDocumenter.generateFiles(this.outputFolder); return Promise.resolve(); } diff --git a/apps/api-documenter/src/documenters/DocumenterConfig.ts b/apps/api-documenter/src/documenters/DocumenterConfig.ts index 5304ad4cf0a..3f3b326e307 100644 --- a/apps/api-documenter/src/documenters/DocumenterConfig.ts +++ b/apps/api-documenter/src/documenters/DocumenterConfig.ts @@ -15,7 +15,7 @@ export class DocumenterConfig { * The JSON Schema for API Extractor config file (api-extractor.schema.json). */ public static readonly jsonSchema: JsonSchema = JsonSchema.fromFile( - path.join(__dirname, '../schemas/api-documenter.schema.json')); + path.join(__dirname, '..', 'schemas', 'api-documenter.schema.json')); /** * The config file name "api-extractor.json". diff --git a/apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts similarity index 97% rename from apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts rename to apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts index 8a1f5371512..11a0f8d5262 100644 --- a/apps/api-documenter/src/documenters/ExperimentYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts @@ -13,7 +13,7 @@ import { YamlDocumenter } from './YamlDocumenter'; * EXPERIMENTAL - This documenter is a prototype of a new config file driven mode of operation for * API Documenter. It is not ready for general usage yet. Its design may change in the future. */ -export class ExperimentYamlDocumenter extends YamlDocumenter { +export class ExperimentalYamlDocumenter extends YamlDocumenter { private _config: IConfigTableOfContents; private _tocPointerMap: { [key: string]: IYamlTocItem }; private _catchAllPointer: IYamlTocItem; @@ -22,7 +22,7 @@ export class ExperimentYamlDocumenter extends YamlDocumenter { super(apiModel); this._config = configFile.tableOfContents!; - this._tocPointerMap = {}; // need a type? + this._tocPointerMap = {}; this._generateTocPointersMap(this._config.tocConfig); } diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md index 19a41e17a3f..a1d44a28db9 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docbaseclass.md @@ -6,9 +6,8 @@ Example base class - Signature: ```typescript -export declare class DocBaseClass +export declare class DocBaseClass ``` diff --git a/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json b/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json index 61645e6099e..d9dcbd72d9d 100644 --- a/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json +++ b/common/changes/@microsoft/api-documenter/FabricDocumenter_2019-05-06-23-48.json @@ -2,7 +2,7 @@ "changes": [ { "packageName": "@microsoft/api-documenter", - "comment": "Adds optional config file `api-documenter.json` to allow building custom TOC for YamlDocumenter.", + "comment": "Add optional config file `api-documenter.json` to allow building custom Table of Contents for YamlDocumenter.", "type": "minor" } ], From 7218cff490e67566c9edd1b557973027a96f8dec Mon Sep 17 00:00:00 2001 From: VitalieBraga Date: Thu, 16 May 2019 00:28:31 -0700 Subject: [PATCH 19/19] Manually remove some blank lines --- .../etc/markdown/api-documenter-test.docenum.md | 3 +-- .../etc/markdown/api-documenter-test.idocinterface3.md | 3 +-- .../etc/markdown/api-documenter-test.idocinterface4.md | 3 +-- .../etc/markdown/api-documenter-test.systemevent.md | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md index 4cce685c2e7..08ce8f433d3 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.docenum.md @@ -6,11 +6,10 @@ Docs for DocEnum - Signature: ```typescript -export declare enum DocEnum +export declare enum DocEnum ``` ## Enumeration Members diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md index 1ddbc4017c3..7abd0978cee 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface3.md @@ -6,9 +6,8 @@ Some less common TypeScript declaration kinds. - Signature: ```typescript -export interface IDocInterface3 +export interface IDocInterface3 ``` diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md index 3dda827e5a3..c0c1b972b96 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.idocinterface4.md @@ -6,11 +6,10 @@ Type union in an interface. - Signature: ```typescript -export interface IDocInterface4 +export interface IDocInterface4 ``` ## Properties diff --git a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md index 47baad77696..c73c20bf510 100644 --- a/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md +++ b/build-tests/api-documenter-test/etc/markdown/api-documenter-test.systemevent.md @@ -6,11 +6,10 @@ A class used to exposed events. - Signature: ```typescript -export declare class SystemEvent +export declare class SystemEvent ``` ## Methods