From aa368c1b4b578b61650f7ecb9946d19a469545e2 Mon Sep 17 00:00:00 2001 From: Stacey Gammon Date: Wed, 24 Feb 2021 19:23:19 -0500 Subject: [PATCH] Automatically generated Api documentation (#86232) * auto generated mdx api doc system * Fix README.md * update core api docs after master merge * clean up signature * Update packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts Co-authored-by: Spencer * migrate to docs-util package * Remove bad links * fix ref to release-notes and add extra dats service folder * update name change * Update packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_type_kind.ts Co-authored-by: Brandon Kobel * Update packages/kbn-docs-utils/src/api_docs/utils.ts Co-authored-by: Brandon Kobel * review updates 1 * review feedback updates round 1 * Small refactor of extractImportReferences * Review feedback updates 2 * Review update 3 plus support for links in class interface heritage clause * debug failing test on ci only * Escape regex directory path * Update packages/kbn-docs-utils/src/api_docs/build_api_declarations/utils.ts Co-authored-by: Spencer * fix for commit suggestion Co-authored-by: Spencer Co-authored-by: spalger Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Brandon Kobel Co-authored-by: kobelb --- .gitignore | 1 + ...ibana-plugin-core-server.pluginmanifest.md | 1 + ...re-server.pluginmanifest.servicefolders.md | 13 + package.json | 4 +- .../plugins/parse_kibana_platform_plugin.ts | 2 + .../jest.config.js | 2 +- .../package.json | 2 +- .../kbn-docs-utils/src/api_docs/README.md | 12 + .../buid_api_declaration.test.ts | 85 ++ .../build_api_declaration.ts | 88 ++ .../build_arrow_fn_dec.ts | 63 + .../build_api_declarations/build_class_dec.ts | 47 + .../build_function_dec.ts | 60 + .../build_function_type_dec.ts | 45 + .../build_interface_dec.ts | 44 + .../build_parameter_decs.ts | 65 + .../build_type_literal_dec.ts | 55 + .../build_variable_dec.ts | 82 ++ .../extract_import_refs.test.ts | 96 ++ .../extract_import_refs.ts | 115 ++ .../build_api_declarations/get_signature.ts | 120 ++ .../build_api_declarations/get_type_kind.ts | 69 + .../build_api_declarations/js_doc_utils.ts | 87 ++ .../api_docs/build_api_declarations/utils.ts | 32 + .../src/api_docs/build_api_docs_cli.ts | 152 +++ .../src/api_docs/find_plugins.ts | 25 + .../get_declaration_nodes_for_plugin.ts | 73 + .../src/api_docs/get_plugin_api.ts | 135 ++ packages/kbn-docs-utils/src/api_docs/index.ts | 9 + .../api_docs/mdx/split_apis_by_folder.test.ts | 51 + .../src/api_docs/mdx/write_plugin_mdx_docs.ts | 143 ++ .../mdx/write_plugin_split_by_folder.test.ts | 72 + .../mdx/write_plugin_split_by_folder.ts | 69 + .../src/plugin_a/common/foo/index.ts | 9 + .../__fixtures__/src/plugin_a/common/index.ts | 13 + .../__fixtures__/src/plugin_a/kibana.json | 7 + .../src/plugin_a/public/classes.ts | 80 ++ .../src/plugin_a/public/const_vars.ts | 76 ++ .../__fixtures__/src/plugin_a/public/fns.ts | 78 ++ .../src/plugin_a/public/foo/index.ts | 13 + .../__fixtures__/src/plugin_a/public/index.ts | 24 + .../src/plugin_a/public/plugin.ts | 172 +++ .../__fixtures__/src/plugin_a/public/types.ts | 45 + .../tests/__fixtures__/src/tsconfig.json | 7 + .../src/api_docs/tests/api_doc_suite.test.ts | 397 ++++++ .../tests/kibana_platform_plugin_mock.ts | 30 + .../api_docs/tests/snapshots/plugin_a.json | 1 + .../src/api_docs/tests/snapshots/plugin_a.mdx | 34 + .../tests/snapshots/plugin_a_foo.json | 1 + .../api_docs/tests/snapshots/plugin_a_foo.mdx | 22 + .../src/api_docs/tsmorph_utils.ts | 38 + packages/kbn-docs-utils/src/api_docs/types.ts | 200 +++ .../kbn-docs-utils/src/api_docs/utils.test.ts | 83 ++ packages/kbn-docs-utils/src/api_docs/utils.ts | 208 +++ packages/kbn-docs-utils/src/index.ts | 10 + .../src/release_notes}/cli.ts | 0 .../src/release_notes}/formats/asciidoc.ts | 0 .../src/release_notes}/formats/csv.ts | 0 .../src/release_notes}/formats/format.ts | 0 .../src/release_notes}/formats/index.ts | 0 .../src/release_notes}/index.ts | 0 .../src/release_notes}/lib/classify_pr.ts | 0 .../lib/get_fix_references.test.ts | 0 .../release_notes}/lib/get_fix_references.ts | 0 .../lib/get_note_from_description.test.ts | 0 .../lib/get_note_from_description.ts | 0 .../src/release_notes}/lib/index.ts | 0 .../lib/irrelevant_pr_summary.ts | 0 .../src/release_notes}/lib/is_pr_relevant.ts | 0 .../src/release_notes}/lib/pr_api.ts | 0 .../src/release_notes}/lib/streams.ts | 0 .../src/release_notes}/lib/type_helpers.ts | 0 .../src/release_notes}/lib/version.test.ts | 0 .../src/release_notes}/lib/version.ts | 0 .../release_notes}/release_notes_config.ts | 0 .../tsconfig.json | 3 + packages/kbn-pm/dist/index.js | 1215 +++++++++-------- scripts/build_api_docs.js | 10 + scripts/release_notes.js | 2 +- src/core/kibana.json | 7 + .../discovery/plugin_manifest_parser.ts | 1 + src/core/server/plugins/types.ts | 6 + src/core/server/server.api.md | 9 +- src/plugins/data/kibana.json | 1 + yarn.lock | 55 +- 85 files changed, 4156 insertions(+), 620 deletions(-) create mode 100644 docs/development/core/server/kibana-plugin-core-server.pluginmanifest.servicefolders.md rename packages/{kbn-release-notes => kbn-docs-utils}/jest.config.js (89%) rename packages/{kbn-release-notes => kbn-docs-utils}/package.json (92%) create mode 100644 packages/kbn-docs-utils/src/api_docs/README.md create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/buid_api_declaration.test.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_api_declaration.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_class_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_type_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_interface_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_parameter_decs.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_type_literal_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_variable_dec.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.test.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_signature.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_type_kind.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/js_doc_utils.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_declarations/utils.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/build_api_docs_cli.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/find_plugins.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/get_declaration_nodes_for_plugin.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/get_plugin_api.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/index.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/mdx/split_apis_by_folder.test.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.test.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/tsconfig.json create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.json create mode 100644 packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx create mode 100644 packages/kbn-docs-utils/src/api_docs/tsmorph_utils.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/types.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/utils.test.ts create mode 100644 packages/kbn-docs-utils/src/api_docs/utils.ts create mode 100644 packages/kbn-docs-utils/src/index.ts rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/cli.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/formats/asciidoc.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/formats/csv.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/formats/format.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/formats/index.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/index.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/classify_pr.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/get_fix_references.test.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/get_fix_references.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/get_note_from_description.test.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/get_note_from_description.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/index.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/irrelevant_pr_summary.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/is_pr_relevant.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/pr_api.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/streams.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/type_helpers.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/version.test.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/lib/version.ts (100%) rename packages/{kbn-release-notes/src => kbn-docs-utils/src/release_notes}/release_notes_config.ts (100%) rename packages/{kbn-release-notes => kbn-docs-utils}/tsconfig.json (81%) create mode 100644 scripts/build_api_docs.js create mode 100644 src/core/kibana.json diff --git a/.gitignore b/.gitignore index 05f5291b2e4d6..919720f04c672 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .aws-config.json .signing-config.json +/api_docs .ackrc /.es /.chromium diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md index b0182a7c48e16..bd15b95d73ace 100644 --- a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md +++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.md @@ -28,6 +28,7 @@ Should never be used in code outside of Core but is exported for documentation p | [requiredBundles](./kibana-plugin-core-server.pluginmanifest.requiredbundles.md) | readonly string[] | List of plugin ids that this plugin's UI code imports modules from that are not in requiredPlugins. | | [requiredPlugins](./kibana-plugin-core-server.pluginmanifest.requiredplugins.md) | readonly PluginName[] | An optional list of the other plugins that \*\*must be\*\* installed and enabled for this plugin to function properly. | | [server](./kibana-plugin-core-server.pluginmanifest.server.md) | boolean | Specifies whether plugin includes some server-side specific functionality. | +| [serviceFolders](./kibana-plugin-core-server.pluginmanifest.servicefolders.md) | readonly string[] | Only used for the automatically generated API documentation. Specifying service folders will cause your plugin API reference to be broken up into sub sections. | | [ui](./kibana-plugin-core-server.pluginmanifest.ui.md) | boolean | Specifies whether plugin includes some client/browser specific functionality that should be included into client bundle via public/ui_plugin.js file. | | [version](./kibana-plugin-core-server.pluginmanifest.version.md) | string | Version of the plugin. | diff --git a/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.servicefolders.md b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.servicefolders.md new file mode 100644 index 0000000000000..8ee33bdfa0f3f --- /dev/null +++ b/docs/development/core/server/kibana-plugin-core-server.pluginmanifest.servicefolders.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-core-server](./kibana-plugin-core-server.md) > [PluginManifest](./kibana-plugin-core-server.pluginmanifest.md) > [serviceFolders](./kibana-plugin-core-server.pluginmanifest.servicefolders.md) + +## PluginManifest.serviceFolders property + +Only used for the automatically generated API documentation. Specifying service folders will cause your plugin API reference to be broken up into sub sections. + +Signature: + +```typescript +readonly serviceFolders?: readonly string[]; +``` diff --git a/package.json b/package.json index 0aec22e7e8222..19d11459d891e 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "test:ftr:runner": "node scripts/functional_test_runner", "checkLicenses": "node scripts/check_licenses --dev", "build": "node scripts/build --all-platforms", + "build:apidocs": "node scripts/build_api_docs", "start": "node scripts/kibana --dev", "debug": "node --nolazy --inspect scripts/kibana --dev", "debug-break": "node --nolazy --inspect-brk scripts/kibana --dev", @@ -364,7 +365,7 @@ "@kbn/plugin-generator": "link:packages/kbn-plugin-generator", "@kbn/plugin-helpers": "link:packages/kbn-plugin-helpers", "@kbn/pm": "link:packages/kbn-pm", - "@kbn/release-notes": "link:packages/kbn-release-notes", + "@kbn/docs-utils": "link:packages/kbn-docs-utils", "@kbn/storybook": "link:packages/kbn-storybook", "@kbn/telemetry-tools": "link:packages/kbn-telemetry-tools", "@kbn/test": "link:packages/kbn-test", @@ -819,6 +820,7 @@ "tinycolor2": "1.4.1", "topojson-client": "3.0.0", "ts-loader": "^7.0.5", + "ts-morph": "^9.1.0", "tsd": "^0.13.1", "typescript": "4.1.3", "typescript-fsa": "^3.0.0", diff --git a/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts b/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts index 62a6f1d347c9b..8d3fdb0f390c5 100644 --- a/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts +++ b/packages/kbn-dev-utils/src/plugins/parse_kibana_platform_plugin.ts @@ -29,6 +29,7 @@ interface Manifest { server: boolean; kibanaVersion: string; version: string; + serviceFolders: readonly string[]; requiredPlugins: readonly string[]; optionalPlugins: readonly string[]; requiredBundles: readonly string[]; @@ -64,6 +65,7 @@ export function parseKibanaPlatformPlugin(manifestPath: string): KibanaPlatformP id: manifest.id, version: manifest.version, kibanaVersion: manifest.kibanaVersion || manifest.version, + serviceFolders: manifest.serviceFolders || [], requiredPlugins: isValidDepsDeclaration(manifest.requiredPlugins, 'requiredPlugins'), optionalPlugins: isValidDepsDeclaration(manifest.optionalPlugins, 'optionalPlugins'), requiredBundles: isValidDepsDeclaration(manifest.requiredBundles, 'requiredBundles'), diff --git a/packages/kbn-release-notes/jest.config.js b/packages/kbn-docs-utils/jest.config.js similarity index 89% rename from packages/kbn-release-notes/jest.config.js rename to packages/kbn-docs-utils/jest.config.js index db5e48b1704fb..e9cdc1978231e 100644 --- a/packages/kbn-release-notes/jest.config.js +++ b/packages/kbn-docs-utils/jest.config.js @@ -9,5 +9,5 @@ module.exports = { preset: '@kbn/test', rootDir: '../..', - roots: ['/packages/kbn-release-notes'], + roots: ['/packages/kbn-docs-utils'], }; diff --git a/packages/kbn-release-notes/package.json b/packages/kbn-docs-utils/package.json similarity index 92% rename from packages/kbn-release-notes/package.json rename to packages/kbn-docs-utils/package.json index c325367c7d47e..6571f8c87dbfa 100644 --- a/packages/kbn-release-notes/package.json +++ b/packages/kbn-docs-utils/package.json @@ -1,5 +1,5 @@ { - "name": "@kbn/release-notes", + "name": "@kbn/docs-utils", "version": "1.0.0", "license": "SSPL-1.0 OR Elastic License 2.0", "private": "true", diff --git a/packages/kbn-docs-utils/src/api_docs/README.md b/packages/kbn-docs-utils/src/api_docs/README.md new file mode 100644 index 0000000000000..f980fe83b9596 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/README.md @@ -0,0 +1,12 @@ +# Autogenerated API documentation + +[RFC](../../../rfcs/text/0014_api_documentation.md) + +This is an experimental api documentation system that is managed by the Kibana Tech Leads until +we determine the value of such a system and what kind of maintenance burder it will incur. + +To generate the docs run + +``` +node scripts/build_api_docs +``` diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/buid_api_declaration.test.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/buid_api_declaration.test.ts new file mode 100644 index 0000000000000..31e0d59dcca8a --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/buid_api_declaration.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; +import { Project, Node } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; + +import { TypeKind, ApiScope } from '../types'; +import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock'; +import { getDeclarationNodesForPluginScope } from '../get_declaration_nodes_for_plugin'; +import { buildApiDeclaration } from './build_api_declaration'; +import { isNamedNode } from '../tsmorph_utils'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +let nodes: Node[]; +let plugins: KibanaPlatformPlugin[]; + +function getNodeName(node: Node): string { + return isNamedNode(node) ? node.getName() : ''; +} + +beforeAll(() => { + const tsConfigFilePath = Path.resolve(__dirname, '../tests/__fixtures__/src/tsconfig.json'); + const project = new Project({ + tsConfigFilePath, + }); + + plugins = [getKibanaPlatformPlugin('pluginA')]; + + nodes = getDeclarationNodesForPluginScope(project, plugins[0], ApiScope.CLIENT, log); +}); + +it('Test number primitive doc def', () => { + const node = nodes.find((n) => getNodeName(n) === 'aNum'); + expect(node).toBeDefined(); + const def = buildApiDeclaration(node!, plugins, log, plugins[0].manifest.id, ApiScope.CLIENT); + + expect(def.type).toBe(TypeKind.NumberKind); +}); + +it('Function type is exported as type with signature', () => { + const node = nodes.find((n) => getNodeName(n) === 'FnWithGeneric'); + expect(node).toBeDefined(); + const def = buildApiDeclaration(node!, plugins, log, plugins[0].manifest.id, ApiScope.CLIENT); + expect(def).toBeDefined(); + expect(def?.type).toBe(TypeKind.TypeKind); + expect(def?.signature?.length).toBeGreaterThan(0); +}); + +it('Test Interface Kind doc def', () => { + const node = nodes.find((n) => getNodeName(n) === 'ExampleInterface'); + expect(node).toBeDefined(); + const def = buildApiDeclaration(node!, plugins, log, plugins[0].manifest.id, ApiScope.CLIENT); + + expect(def.type).toBe(TypeKind.InterfaceKind); + expect(def.children).toBeDefined(); + expect(def.children!.length).toBe(3); +}); + +it('Test union export', () => { + const node = nodes.find((n) => getNodeName(n) === 'aUnionProperty'); + expect(node).toBeDefined(); + const def = buildApiDeclaration(node!, plugins, log, plugins[0].manifest.id, ApiScope.CLIENT); + expect(def.type).toBe(TypeKind.CompoundTypeKind); +}); + +it('Function inside interface has a label', () => { + const node = nodes.find((n) => getNodeName(n) === 'ExampleInterface'); + expect(node).toBeDefined(); + const def = buildApiDeclaration(node!, plugins, log, plugins[0].manifest.id, ApiScope.CLIENT); + + const fn = def!.children?.find((c) => c.label === 'aFn'); + expect(fn).toBeDefined(); + expect(fn?.label).toBe('aFn'); + expect(fn?.type).toBe(TypeKind.FunctionKind); +}); diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_api_declaration.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_api_declaration.ts new file mode 100644 index 0000000000000..3ee6676cf5e32 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_api_declaration.ts @@ -0,0 +1,88 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Node } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { buildClassDec } from './build_class_dec'; +import { buildFunctionDec } from './build_function_dec'; +import { getCommentsFromNode } from './js_doc_utils'; +import { isNamedNode } from '../tsmorph_utils'; +import { AnchorLink, ApiDeclaration } from '../types'; +import { buildVariableDec } from './build_variable_dec'; +import { getApiSectionId } from '../utils'; +import { getSourceForNode } from './utils'; +import { buildTypeLiteralDec } from './build_type_literal_dec'; +import { ApiScope } from '../types'; +import { getSignature } from './get_signature'; +import { buildInterfaceDec } from './build_interface_dec'; +import { getTypeKind } from './get_type_kind'; + +/** + * A potentially recursive function, depending on the node type, that builds a JSON like structure + * that can be passed to the elastic-docs component for rendering as an API. Nodes like classes, + * interfaces, objects and functions will have children for their properties, members and parameters. + * + * @param node The ts-morph node to build an ApiDeclaration for. + * @param plugins The list of plugins registered is used for building cross plugin links by looking up + * the plugin by import path. We could accomplish the same thing via a regex on the import path, but this lets us + * decouple plugin path from plugin id. + * @param log Logs messages to console. + * @param pluginName The name of the plugin this declaration belongs to. + * @param scope The scope this declaration belongs to (server, public, or common). + * @param parentApiId If this declaration is nested inside another declaration, it should have a parent id. This + * is used to create the anchor link to this API item. + * @param name An optional name to pass through which will be used instead of node.getName, if it + * exists. For some types, like Parameters, the name comes on the parent node, but we want the doc def + * to be built from the TypedNode + */ +export function buildApiDeclaration( + node: Node, + plugins: KibanaPlatformPlugin[], + log: ToolingLog, + pluginName: string, + scope: ApiScope, + parentApiId?: string, + name?: string +): ApiDeclaration { + const apiName = name ? name : isNamedNode(node) ? node.getName() : 'Unnamed'; + log.debug(`Building API Declaration for ${apiName} of kind ${node.getKindName()}`); + const apiId = parentApiId ? parentApiId + '.' + apiName : apiName; + const anchorLink: AnchorLink = { scope, pluginName, apiName: apiId }; + + if (Node.isClassDeclaration(node)) { + return buildClassDec(node, plugins, anchorLink, log); + } else if (Node.isInterfaceDeclaration(node)) { + return buildInterfaceDec(node, plugins, anchorLink, log); + } else if ( + Node.isMethodSignature(node) || + Node.isFunctionDeclaration(node) || + Node.isMethodDeclaration(node) || + Node.isConstructorDeclaration(node) + ) { + return buildFunctionDec(node, plugins, anchorLink, log); + } else if ( + Node.isPropertySignature(node) || + Node.isPropertyDeclaration(node) || + Node.isShorthandPropertyAssignment(node) || + Node.isPropertyAssignment(node) || + Node.isVariableDeclaration(node) + ) { + return buildVariableDec(node, plugins, anchorLink, log); + } else if (Node.isTypeLiteralNode(node)) { + return buildTypeLiteralDec(node, plugins, anchorLink, log, apiName); + } + + return { + id: getApiSectionId(anchorLink), + type: getTypeKind(node), + label: apiName, + description: getCommentsFromNode(node), + source: getSourceForNode(node), + signature: getSignature(node, plugins, log), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts new file mode 100644 index 0000000000000..146fcf4fa4d0a --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_arrow_fn_dec.ts @@ -0,0 +1,63 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; + +import { + ArrowFunction, + VariableDeclaration, + PropertyDeclaration, + PropertySignature, + ShorthandPropertyAssignment, + PropertyAssignment, +} from 'ts-morph'; +import { getApiSectionId } from '../utils'; +import { getCommentsFromNode } from './js_doc_utils'; +import { AnchorLink, TypeKind } from '../types'; +import { getSourceForNode } from './utils'; +import { buildApiDecsForParameters } from './build_parameter_decs'; +import { getSignature } from './get_signature'; +import { getJSDocReturnTagComment } from './js_doc_utils'; + +/** + * Arrow functions are handled differently than regular functions because you need the arrow function + * initializer as well as the node. The initializer is where the parameters are grabbed from and the + * signature, while the node has the comments and name. + * + * @param node + * @param initializer + * @param plugins + * @param anchorLink + * @param log + */ +export function getArrowFunctionDec( + node: + | VariableDeclaration + | PropertyDeclaration + | PropertySignature + | ShorthandPropertyAssignment + | PropertyAssignment, + initializer: ArrowFunction, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +) { + log.debug( + `Getting Arrow Function doc def for node ${node.getName()} of kind ${node.getKindName()}` + ); + return { + id: getApiSectionId(anchorLink), + type: TypeKind.FunctionKind, + children: buildApiDecsForParameters(initializer.getParameters(), plugins, anchorLink, log), + signature: getSignature(initializer, plugins, log), + description: getCommentsFromNode(node), + label: node.getName(), + source: getSourceForNode(node), + returnComment: getJSDocReturnTagComment(node), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_class_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_class_dec.ts new file mode 100644 index 0000000000000..2ccce506dde53 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_class_dec.ts @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { ClassDeclaration } from 'ts-morph'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { getCommentsFromNode } from './js_doc_utils'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getSourceForNode, isPrivate } from './utils'; +import { getApiSectionId } from '../utils'; +import { getSignature } from './get_signature'; + +export function buildClassDec( + node: ClassDeclaration, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +): ApiDeclaration { + return { + id: getApiSectionId(anchorLink), + type: TypeKind.ClassKind, + label: node.getName() || 'Missing label', + description: getCommentsFromNode(node), + signature: getSignature(node, plugins, log), + children: node.getMembers().reduce((acc, m) => { + if (!isPrivate(m)) { + acc.push( + buildApiDeclaration( + m, + plugins, + log, + anchorLink.pluginName, + anchorLink.scope, + anchorLink.apiName + ) + ); + } + return acc; + }, [] as ApiDeclaration[]), + source: getSourceForNode(node), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_dec.ts new file mode 100644 index 0000000000000..2936699152a83 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_dec.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { + FunctionDeclaration, + MethodDeclaration, + ConstructorDeclaration, + Node, + MethodSignature, +} from 'ts-morph'; + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { buildApiDecsForParameters } from './build_parameter_decs'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { getCommentsFromNode } from './js_doc_utils'; +import { getApiSectionId } from '../utils'; +import { getJSDocReturnTagComment, getJSDocs, getJSDocTagNames } from './js_doc_utils'; +import { getSourceForNode } from './utils'; +import { getSignature } from './get_signature'; + +/** + * Takes the various function-like node declaration types and converts them into an ApiDeclaration. + * @param node + * @param plugins + * @param anchorLink + * @param log + */ +export function buildFunctionDec( + node: FunctionDeclaration | MethodDeclaration | ConstructorDeclaration | MethodSignature, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +): ApiDeclaration { + const label = Node.isConstructorDeclaration(node) + ? 'Constructor' + : node.getName() || '(WARN: Missing name)'; + log.debug(`Getting function doc def for node ${label} of kind ${node.getKindName()}`); + return { + id: getApiSectionId(anchorLink), + type: TypeKind.FunctionKind, + label, + signature: getSignature(node, plugins, log), + description: getCommentsFromNode(node), + children: buildApiDecsForParameters( + node.getParameters(), + plugins, + anchorLink, + log, + getJSDocs(node) + ), + tags: getJSDocTagNames(node), + returnComment: getJSDocReturnTagComment(node), + source: getSourceForNode(node), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_type_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_type_dec.ts new file mode 100644 index 0000000000000..3cd4317e23f0c --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_function_type_dec.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { FunctionTypeNode, JSDoc } from 'ts-morph'; +import { getApiSectionId } from '../utils'; +import { getCommentsFromNode } from './js_doc_utils'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { buildApiDecsForParameters } from './build_parameter_decs'; +import { extractImportReferences } from './extract_import_refs'; +import { getJSDocReturnTagComment, getJSDocs, getJSDocTagNames } from './js_doc_utils'; +import { getSourceForNode } from './utils'; + +export function buildApiDecFromFunctionType( + name: string, + node: FunctionTypeNode, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog, + jsDocs?: JSDoc[] +): ApiDeclaration { + log.debug(`Getting Function Type doc def for node ${name} of kind ${node.getKindName()}`); + return { + type: TypeKind.FunctionKind, + id: getApiSectionId(anchorLink), + label: name, + signature: extractImportReferences(node.getType().getText(), plugins, log), + description: getCommentsFromNode(node), + tags: jsDocs ? getJSDocTagNames(jsDocs) : [], + returnComment: jsDocs ? getJSDocReturnTagComment(jsDocs) : [], + children: buildApiDecsForParameters( + node.getParameters(), + plugins, + anchorLink, + log, + jsDocs || getJSDocs(node) + ), + source: getSourceForNode(node), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_interface_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_interface_dec.ts new file mode 100644 index 0000000000000..2329aa2190d95 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_interface_dec.ts @@ -0,0 +1,44 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { InterfaceDeclaration } from 'ts-morph'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { getCommentsFromNode } from './js_doc_utils'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getSourceForNode } from './utils'; +import { getApiSectionId } from '../utils'; +import { getSignature } from './get_signature'; + +export function buildInterfaceDec( + node: InterfaceDeclaration, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +): ApiDeclaration { + return { + id: getApiSectionId(anchorLink), + type: TypeKind.InterfaceKind, + label: node.getName(), + signature: getSignature(node, plugins, log), + description: getCommentsFromNode(node), + children: node + .getMembers() + .map((m) => + buildApiDeclaration( + m, + plugins, + log, + anchorLink.pluginName, + anchorLink.scope, + anchorLink.apiName + ) + ), + source: getSourceForNode(node), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_parameter_decs.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_parameter_decs.ts new file mode 100644 index 0000000000000..e420f76357f75 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_parameter_decs.ts @@ -0,0 +1,65 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ParameterDeclaration, JSDoc, SyntaxKind } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { extractImportReferences } from './extract_import_refs'; +import { AnchorLink, ApiDeclaration } from '../types'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getJSDocParamComment } from './js_doc_utils'; +import { getSourceForNode } from './utils'; +import { getTypeKind } from './get_type_kind'; + +/** + * A helper function to capture function parameters, whether it comes from an arrow function, a regular function or + * a function type. + * + * @param params + * @param plugins + * @param anchorLink + * @param log + * @param jsDocs + */ +export function buildApiDecsForParameters( + params: ParameterDeclaration[], + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog, + jsDocs?: JSDoc[] +): ApiDeclaration[] { + return params.reduce((acc, param) => { + const label = param.getName(); + log.debug(`Getting parameter doc def for ${label} of kind ${param.getKindName()}`); + // Literal types are non primitives that aren't references to other types. We add them as a more + // defined node, with children. + // If we don't want the docs to be too deeply nested we could avoid this special handling. + if (param.getTypeNode() && param.getTypeNode()!.getKind() === SyntaxKind.TypeLiteral) { + acc.push( + buildApiDeclaration( + param.getTypeNode()!, + plugins, + log, + anchorLink.pluginName, + anchorLink.scope, + anchorLink.apiName, + label + ) + ); + } else { + acc.push({ + type: getTypeKind(param), + label, + isRequired: param.getType().isNullable() === false, + signature: extractImportReferences(param.getType().getText(), plugins, log), + description: jsDocs ? getJSDocParamComment(jsDocs, label) : [], + source: getSourceForNode(param), + }); + } + return acc; + }, [] as ApiDeclaration[]); +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_type_literal_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_type_literal_dec.ts new file mode 100644 index 0000000000000..39d47d5bacba1 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_type_literal_dec.ts @@ -0,0 +1,55 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { TypeLiteralNode } from 'ts-morph'; +import { getApiSectionId } from '../utils'; +import { getCommentsFromNode } from './js_doc_utils'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getSourceForNode } from './utils'; + +/** + * This captures function parameters that are object types, and makes sure their + * properties are recursively walked so they are expandable in the docs. + * + * The test verifying `crazyFunction` will fail without this special handling. + * + * @param node + * @param plugins + * @param anchorLink + * @param log + * @param name + */ +export function buildTypeLiteralDec( + node: TypeLiteralNode, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog, + name: string +): ApiDeclaration { + return { + id: getApiSectionId(anchorLink), + type: TypeKind.ObjectKind, + label: name, + description: getCommentsFromNode(node), + children: node + .getMembers() + .map((m) => + buildApiDeclaration( + m, + plugins, + log, + anchorLink.pluginName, + anchorLink.scope, + anchorLink.apiName + ) + ), + source: getSourceForNode(node), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_variable_dec.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_variable_dec.ts new file mode 100644 index 0000000000000..3e0b48de1e18b --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/build_variable_dec.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { + VariableDeclaration, + Node, + PropertyAssignment, + PropertyDeclaration, + PropertySignature, + ShorthandPropertyAssignment, +} from 'ts-morph'; +import { getApiSectionId } from '../utils'; +import { getCommentsFromNode } from './js_doc_utils'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { getArrowFunctionDec } from './build_arrow_fn_dec'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getSourceForNode } from './utils'; +import { getSignature } from './get_signature'; +import { getTypeKind } from './get_type_kind'; + +/** + * Special handling for objects and arrow functions which are variable or property node types. + * Objects and arrow functions need their children extracted recursively. This uses the name from the + * node, but checks for an initializer to get inline arrow functions and objects defined recursively. + * + * @param node + * @param plugins + * @param anchorLink + * @param log + */ +export function buildVariableDec( + node: + | VariableDeclaration + | PropertyAssignment + | PropertyDeclaration + | PropertySignature + | ShorthandPropertyAssignment, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +): ApiDeclaration { + log.debug('buildVariableDec for ' + node.getName()); + const initializer = node.getInitializer(); + // Recusively list object properties as children. + if (initializer && Node.isObjectLiteralExpression(initializer)) { + return { + id: getApiSectionId(anchorLink), + type: TypeKind.ObjectKind, + children: initializer.getProperties().map((prop) => { + return buildApiDeclaration( + prop, + plugins, + log, + anchorLink.pluginName, + anchorLink.scope, + anchorLink.apiName + ); + }), + description: getCommentsFromNode(node), + label: node.getName(), + source: getSourceForNode(node), + }; + } else if (initializer && Node.isArrowFunction(initializer)) { + return getArrowFunctionDec(node, initializer, plugins, anchorLink, log); + } + + // Otherwise return it just as a single entry. + return { + id: getApiSectionId(anchorLink), + type: getTypeKind(node), + label: node.getName(), + description: getCommentsFromNode(node), + source: getSourceForNode(node), + signature: getSignature(node, plugins, log), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.test.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.test.ts new file mode 100644 index 0000000000000..a757df2ece366 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.test.ts @@ -0,0 +1,96 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { getPluginApiDocId } from '../utils'; +import { extractImportReferences } from './extract_import_refs'; +import { ApiScope, Reference } from '../types'; +import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock'; + +const plugin = getKibanaPlatformPlugin('pluginA'); +const plugins: KibanaPlatformPlugin[] = [plugin]; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +it('when there are no imports', () => { + const results = extractImportReferences(`(param: string) => Bar`, plugins, log); + expect(results.length).toBe(1); + expect(results[0]).toBe('(param: string) => Bar'); +}); + +it('test extractImportReference', () => { + const results = extractImportReferences( + `(param: string) => import("${plugin.directory}/public/bar").Bar`, + plugins, + log + ); + expect(results.length).toBe(2); + expect(results[0]).toBe('(param: string) => '); + expect(results[1]).toEqual({ + text: 'Bar', + docId: getPluginApiDocId('plugin_a', log), + section: 'def-public.Bar', + pluginId: 'pluginA', + scope: ApiScope.CLIENT, + }); +}); + +it('test extractImportReference with public folder nested under server folder', () => { + const results = extractImportReferences( + `import("${plugin.directory}/server/routes/public/bar").Bar`, + plugins, + log + ); + expect(results.length).toBe(1); + expect(results[0]).toEqual({ + text: 'Bar', + docId: getPluginApiDocId('plugin_a', log), + section: 'def-server.Bar', + pluginId: 'pluginA', + scope: ApiScope.SERVER, + }); +}); + +it('test extractImportReference with two imports', () => { + const results = extractImportReferences( + ``, + plugins, + log + ); + expect(results.length).toBe(5); + expect(results[0]).toBe(''); +}); + +it('test extractImportReference with unknown imports', () => { + const results = extractImportReferences( + ``, + plugins, + log + ); + expect(results.length).toBe(3); + expect(results[0]).toBe(''); +}); + +it('test single link', () => { + const results = extractImportReferences( + `import("${plugin.directory}/public/foo/index").FooFoo`, + plugins, + log + ); + expect(results.length).toBe(1); + expect((results[0] as Reference).text).toBe('FooFoo'); +}); diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.ts new file mode 100644 index 0000000000000..1147e15a1acb6 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/extract_import_refs.ts @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { getApiSectionId, getPluginApiDocId, getPluginForPath } from '../utils'; +import { ApiScope, TextWithLinks } from '../types'; + +/** + * + * @param text A string that may include an API item that was imported from another file. For example: + * "export type foo = string | import("kibana/src/plugins/a_plugin/public/path").Bar". + * @param plugins The list of registered Kibana plugins. Used to get the plugin id, which is then used to create + * the DocLink to that plugin's page, based off the relative path of any imports. + * @param log Logging utility for debuging + * + * @returns An array structure that can be used to create react DocLinks. For example, the above text would return + * something like: + * [ "export type foo = string | ", // Just a string for the pretext + * { id: "a_plugin", section: "public.Bar", text: "Bar" } // An object with info to create the DocLink. + * ] + */ +export function extractImportReferences( + text: string, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): TextWithLinks { + const texts: TextWithLinks = []; + let pos = 0; + let textSegment: string | undefined = text; + const max = 5; + while (textSegment) { + pos++; + if (pos > max) break; + + const ref = extractImportRef(textSegment); + if (ref) { + const { name, path, index, length } = ref; + if (index !== 0) { + texts.push(textSegment.substr(0, index)); + } + const plugin = getPluginForPath(path, plugins); + + if (!plugin) { + if (path.indexOf('plugin') >= 0) { + log.warning('WARN: no plugin found for reference path ' + path); + } + // If we can't create a link for this, still remove the import("..."). part to make + // it easier to read. + const str = textSegment.substr(index + length - name.length, name.length); + if (str && str !== '') { + texts.push(str); + } + } else { + const section = getApiSectionId({ + pluginName: plugin.manifest.id, + scope: getScopeFromPath(path, plugin, log), + apiName: name, + }); + texts.push({ + pluginId: plugin.manifest.id, + scope: getScopeFromPath(path, plugin, log), + docId: getPluginApiDocId(plugin.manifest.id, log, { + serviceFolders: plugin.manifest.serviceFolders, + apiPath: path, + directory: plugin.directory, + }), + section, + text: name, + }); + } + textSegment = textSegment.substr(index + length); + } else { + if (textSegment && textSegment !== '') { + texts.push(textSegment); + } + textSegment = undefined; + } + } + return texts; +} + +function extractImportRef( + str: string +): { path: string; name: string; index: number; length: number } | undefined { + const groups = str.match(/import\("(.*?)"\)\.(\w*)/); + if (groups) { + const path = groups[1]; + const name = groups[2]; + const index = groups.index!; + const length = groups[0].length; + return { path, name, index, length }; + } +} + +/** + * + * @param path An absolute path to a file inside a plugin directory. + */ +function getScopeFromPath(path: string, plugin: KibanaPlatformPlugin, log: ToolingLog): ApiScope { + if (path.startsWith(`${plugin.directory}/public/`)) { + return ApiScope.CLIENT; + } else if (path.startsWith(`${plugin.directory}/server/`)) { + return ApiScope.SERVER; + } else if (path.startsWith(`${plugin.directory}/common/`)) { + return ApiScope.COMMON; + } else { + log.warning(`Unexpected path encountered ${path}`); + return ApiScope.COMMON; + } +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_signature.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_signature.ts new file mode 100644 index 0000000000000..b7df94a03638f --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_signature.ts @@ -0,0 +1,120 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { Node, Type } from 'ts-morph'; +import { isNamedNode } from '../tsmorph_utils'; +import { Reference } from '../types'; +import { extractImportReferences } from './extract_import_refs'; +import { getTypeKind } from './get_type_kind'; + +/** + * Special logic for creating the signature based on the type of node. See https://github.com/dsherret/ts-morph/issues/923#issue-795332729 + * for some issues that have been encountered in getting these accurate. + * + * By passing node to `getText`, ala `node.getType().getText(node)`, all reference links + * will be lost. However, if you do _not_ pass node, there are quite a few situations where it returns a reference + * to itself and has no helpful information. + * + * @param node + * @param plugins + * @param log + */ +export function getSignature( + node: Node, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): Array | undefined { + let signature = ''; + // node.getType() on a TypeAliasDeclaration is just a reference to itself. If we don't special case this, then + // `export type Foo = string | number;` would show up with a signagure of `Foo` that is a link to itself, instead of + // `string | number`. + if (Node.isTypeAliasDeclaration(node)) { + signature = getSignatureForTypeAlias(node.getType(), log, node); + } else if (Node.isFunctionDeclaration(node)) { + // See https://github.com/dsherret/ts-morph/issues/907#issue-770284331. + // Unfortunately this has to be manually pieced together, or it comes up as "typeof TheFunction" + const params = node + .getParameters() + .map((p) => `${p.getName()}: ${p.getType().getText()}`) + .join(', '); + const returnType = node.getReturnType().getText(); + signature = `(${params}) => ${returnType}`; + } else if (Node.isInterfaceDeclaration(node) || Node.isClassDeclaration(node)) { + // Need to tack on manually any type parameters or "extends/implements" section. + const heritageClause = node + .getHeritageClauses() + .map((h) => { + const heritance = h.getText().indexOf('implements') > -1 ? 'implements' : 'extends'; + return `${heritance} ${h.getTypeNodes().map((n) => n.getType().getText())}`; + }) + .join(' '); + signature = `${node.getType().getText()}${heritageClause ? ' ' + heritageClause : ''}`; + } else { + // Here, 'node' is explicitly *not* passed in to `getText` otherwise arrow functions won't + // include reference links. Tests will break if you add it in here, or remove it from above. + // There is test coverage for all this oddness. + signature = node.getType().getText(); + } + + // Don't return the signature if it's the same as the type (string, string) + if (getTypeKind(node).toString() === signature) return undefined; + + const referenceLinks = extractImportReferences(signature, plugins, log); + + // Don't return the signature if it's a single self referential link. + if ( + isNamedNode(node) && + referenceLinks.length === 1 && + typeof referenceLinks[0] === 'object' && + (referenceLinks[0] as Reference).text === node.getName() + ) { + return undefined; + } + + return referenceLinks; +} + +/** + * Not all types are handled here, but does return links for the more common ones. + */ +function getSignatureForTypeAlias(type: Type, log: ToolingLog, node?: Node): string { + if (type.isUnion()) { + return type + .getUnionTypes() + .map((nestedType) => getSignatureForTypeAlias(nestedType, log)) + .join(' | '); + } else if (node && type.getCallSignatures().length >= 1) { + return type + .getCallSignatures() + .map((sig) => { + const params = sig + .getParameters() + .map((p) => `${p.getName()}: ${p.getTypeAtLocation(node).getText()}`) + .join(', '); + const returnType = sig.getReturnType().getText(); + return `(${params}) => ${returnType}`; + }) + .join(' '); + } else if (node) { + const symbol = node.getSymbol(); + if (symbol) { + const declarations = symbol + .getDeclarations() + .map((d) => d.getType().getText(node)) + .join(' '); + if (symbol.getDeclarations().length !== 1) { + log.error( + `Node is type alias declaration with more than one declaration. This is not handled! ${declarations} and node is ${node.getText()}` + ); + } + return declarations; + } + } + return type.getText(); +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_type_kind.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_type_kind.ts new file mode 100644 index 0000000000000..592833f40cebf --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/get_type_kind.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Type, Node } from 'ts-morph'; +import { TypeKind } from '../types'; + +export function getTypeKind(node: Node): TypeKind { + if (Node.isTypeAliasDeclaration(node)) { + return TypeKind.TypeKind; + } else { + return getTypeKindForType(node.getType()); + } +} + +function getTypeKindForType(type: Type): TypeKind { + // I think a string literal is also a string... but just in case, checking both. + if (type.isString() || type.isStringLiteral()) { + return TypeKind.StringKind; + } else if (type.isNumber() || type.isNumberLiteral()) { + return TypeKind.NumberKind; + + // I could be wrong about this logic. Does this existance of a call signature mean it's a function? + } else if (type.getCallSignatures().length > 0) { + return TypeKind.FunctionKind; + } else if (type.isArray()) { + // Arrays are also objects, check this first. + return TypeKind.ArrayKind; + } else if (type.isObject()) { + return TypeKind.ObjectKind; + } else if (type.isBoolean() || type.isBooleanLiteral()) { + return TypeKind.BooleanKind; + } else if (type.isEnum() || type.isEnumLiteral()) { + return TypeKind.EnumKind; + } else if (type.isUnion()) { + // Special handling for "type | undefined" which happens alot and should be represented in docs as + // "type", but with an "optional" flag. Anything more complicated will just be returned as a + // "CompoundType". + if (getIsTypeOptional(type) && type.getUnionTypes().length === 2) { + const otherType = type.getUnionTypes().find((u) => u.isUndefined() === false); + if (otherType) { + return getTypeKindForType(otherType); + } + } + } else if (type.isAny()) { + return TypeKind.AnyKind; + } else if (type.isUnknown()) { + return TypeKind.UnknownKind; + } + + if (type.isUnionOrIntersection()) { + return TypeKind.CompoundTypeKind; + } + + return TypeKind.Uncategorized; +} + +function getIsTypeOptional(type: Type): boolean { + if (type.isUnion()) { + const unions = type.getUnionTypes(); + return unions.find((u) => u.isUndefined()) !== undefined; + } else { + return false; + } +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/js_doc_utils.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/js_doc_utils.ts new file mode 100644 index 0000000000000..baac7153dfb75 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/js_doc_utils.ts @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { JSDoc, JSDocTag, Node } from 'ts-morph'; +import { TextWithLinks } from '../types'; + +/** + * Extracts comments out of the node to use as the description. + */ +export function getCommentsFromNode(node: Node): TextWithLinks | undefined { + let comments: TextWithLinks | undefined; + const jsDocs = getJSDocs(node); + if (jsDocs) { + return getTextWithLinks(jsDocs.map((jsDoc) => jsDoc.getDescription()).join('\n')); + } else { + comments = getTextWithLinks( + node + .getLeadingCommentRanges() + .map((c) => c.getText()) + .join('\n') + ); + } + + return comments; +} + +export function getJSDocs(node: Node): JSDoc[] | undefined { + if (Node.isJSDocableNode(node)) { + return node.getJsDocs(); + } else if (Node.isVariableDeclaration(node)) { + const gparent = node.getParent()?.getParent(); + if (Node.isJSDocableNode(gparent)) { + return gparent.getJsDocs(); + } + } +} + +export function getJSDocReturnTagComment(node: Node | JSDoc[]): TextWithLinks { + const tags = getJSDocTags(node); + const returnTag = tags.find((tag) => Node.isJSDocReturnTag(tag)); + if (returnTag) return getTextWithLinks(returnTag.getComment()); + return []; +} + +export function getJSDocParamComment(node: Node | JSDoc[], name: string): TextWithLinks { + const tags = getJSDocTags(node); + const paramTag = tags.find((tag) => Node.isJSDocParameterTag(tag) && tag.getName() === name); + if (paramTag) return getTextWithLinks(paramTag.getComment()); + return []; +} + +export function getJSDocTagNames(node: Node | JSDoc[]): string[] { + return getJSDocTags(node).reduce((tags, tag) => { + if (tag.getTagName() !== 'param' && tag.getTagName() !== 'returns') { + tags.push(tag.getTagName()); + } + return tags; + }, [] as string[]); +} + +function getJSDocTags(node: Node | JSDoc[]): JSDocTag[] { + const jsDocs = node instanceof Array ? node : getJSDocs(node); + if (!jsDocs) return []; + + return jsDocs.reduce((tagsAcc, jsDoc) => { + tagsAcc.push(...jsDoc.getTags()); + return tagsAcc; + }, [] as JSDocTag[]); +} + +/** + * TODO. This feature is not implemented yet. It will be used to create links for comments + * that use {@link AnotherAPIItemInThisPlugin}. + * + * @param text + */ +function getTextWithLinks(text?: string): TextWithLinks { + if (text) return [text]; + else return []; + // TODO: + // Replace `@links` in comments with relative api links. +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_declarations/utils.ts b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/utils.ts new file mode 100644 index 0000000000000..9efa96b6e9676 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_declarations/utils.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ +import Path from 'path'; +import { REPO_ROOT, kibanaPackageJson } from '@kbn/utils'; +import { ParameterDeclaration, ClassMemberTypes, Node } from 'ts-morph'; +import { SourceLink } from '../types'; + +export function isPrivate(node: ParameterDeclaration | ClassMemberTypes): boolean { + return node.getModifiers().find((mod) => mod.getText() === 'private') !== undefined; +} + +/** + * Change the absolute path into a relative one. + */ +function getRelativePath(fullPath: string): string { + return Path.relative(REPO_ROOT, fullPath); +} + +export function getSourceForNode(node: Node): SourceLink { + const path = getRelativePath(node.getSourceFile().getFilePath()); + const lineNumber = node.getStartLineNumber(); + return { + path, + lineNumber, + link: `https://github.com/elastic/kibana/tree/${kibanaPackageJson.branch}${path}#L${lineNumber}`, + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/build_api_docs_cli.ts b/packages/kbn-docs-utils/src/api_docs/build_api_docs_cli.ts new file mode 100644 index 0000000000000..ac6d6088c25c0 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/build_api_docs_cli.ts @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Fs from 'fs'; +import Path from 'path'; + +import { REPO_ROOT, run } from '@kbn/dev-utils'; +import { Project } from 'ts-morph'; + +import { getPluginApi } from './get_plugin_api'; +import { writePluginDocs } from './mdx/write_plugin_mdx_docs'; +import { ApiDeclaration, PluginApi } from './types'; +import { findPlugins } from './find_plugins'; +import { removeBrokenLinks } from './utils'; + +export interface PluginInfo { + apiCount: number; + apiCountMissingComments: number; + id: string; + missingApiItems: string[]; +} + +export function runBuildApiDocsCli() { + run( + async ({ log }) => { + const project = getTsProject(REPO_ROOT); + + const plugins = findPlugins(); + + const pluginInfos: { + [key: string]: PluginInfo; + } = {}; + + const outputFolder = Path.resolve(REPO_ROOT, 'api_docs'); + if (!Fs.existsSync(outputFolder)) { + Fs.mkdirSync(outputFolder); + } else { + // Delete all files except the README that warns about the auto-generated nature of + // the folder. + const files = Fs.readdirSync(outputFolder); + files.forEach((file) => { + if (file.indexOf('README.md') < 0) { + Fs.rmSync(Path.resolve(outputFolder, file)); + } + }); + } + + const pluginApiMap: { [key: string]: PluginApi } = {}; + plugins.map((plugin) => { + pluginApiMap[plugin.manifest.id] = getPluginApi(project, plugin, plugins, log); + }); + + const missingApiItems: { [key: string]: string[] } = {}; + + plugins.forEach((plugin) => { + const id = plugin.manifest.id; + const pluginApi = pluginApiMap[id]; + removeBrokenLinks(pluginApi, missingApiItems, pluginApiMap); + }); + + plugins.forEach((plugin) => { + const id = plugin.manifest.id; + const pluginApi = pluginApiMap[id]; + const info = { + id, + apiCount: countApiForPlugin(pluginApi), + apiCountMissingComments: countMissingCommentsApiForPlugin(pluginApi), + missingApiItems: missingApiItems[id], + }; + + if (info.apiCount > 0) { + writePluginDocs(outputFolder, pluginApi, log); + pluginInfos[id] = info; + } + }); + + // eslint-disable-next-line no-console + console.table(pluginInfos); + }, + { + log: { + defaultLevel: 'debug', + }, + } + ); +} + +function getTsProject(repoPath: string) { + const xpackTsConfig = `${repoPath}/tsconfig.json`; + const project = new Project({ + tsConfigFilePath: xpackTsConfig, + }); + project.addSourceFilesAtPaths(`${repoPath}/x-pack/plugins/**/*{.d.ts,.ts}`); + project.resolveSourceFileDependencies(); + return project; +} + +function countMissingCommentsApiForPlugin(doc: PluginApi) { + return ( + doc.client.reduce((sum, def) => { + return sum + countMissingCommentsForApi(def); + }, 0) + + doc.server.reduce((sum, def) => { + return sum + countMissingCommentsForApi(def); + }, 0) + + doc.common.reduce((sum, def) => { + return sum + countMissingCommentsForApi(def); + }, 0) + ); +} + +function countMissingCommentsForApi(doc: ApiDeclaration): number { + const missingCnt = doc.description && doc.description.length > 0 ? 0 : 1; + if (!doc.children) return missingCnt; + else + return ( + missingCnt + + doc.children.reduce((sum, child) => { + return sum + countMissingCommentsForApi(child); + }, 0) + ); +} + +function countApiForPlugin(doc: PluginApi) { + return ( + doc.client.reduce((sum, def) => { + return sum + countApi(def); + }, 0) + + doc.server.reduce((sum, def) => { + return sum + countApi(def); + }, 0) + + doc.common.reduce((sum, def) => { + return sum + countApi(def); + }, 0) + ); +} + +function countApi(doc: ApiDeclaration): number { + if (!doc.children) return 1; + else + return ( + 1 + + doc.children.reduce((sum, child) => { + return sum + countApi(child); + }, 0) + ); +} diff --git a/packages/kbn-docs-utils/src/api_docs/find_plugins.ts b/packages/kbn-docs-utils/src/api_docs/find_plugins.ts new file mode 100644 index 0000000000000..004124f13889d --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/find_plugins.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; + +import { getPluginSearchPaths } from '@kbn/config'; +import { simpleKibanaPlatformPluginDiscovery, REPO_ROOT } from '@kbn/dev-utils'; + +export function findPlugins() { + const pluginSearchPaths = getPluginSearchPaths({ + rootDir: REPO_ROOT, + oss: false, + examples: false, + }); + + return simpleKibanaPlatformPluginDiscovery(pluginSearchPaths, [ + // discover "core" as a plugin + Path.resolve(REPO_ROOT, 'src/core'), + ]); +} diff --git a/packages/kbn-docs-utils/src/api_docs/get_declaration_nodes_for_plugin.ts b/packages/kbn-docs-utils/src/api_docs/get_declaration_nodes_for_plugin.ts new file mode 100644 index 0000000000000..6676c5e753c9b --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/get_declaration_nodes_for_plugin.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { Project, SourceFile, Node } from 'ts-morph'; +import { ApiScope } from './types'; +import { isNamedNode, getSourceFileMatching } from './tsmorph_utils'; + +/** + * Determines which file in the project to grab nodes from, depending on the plugin and scope, then returns those nodes. + * + * @param project - TS project. + * @param plugin - The plugin we are interested in. + * @param scope - The "scope" of the API we want to extract: public, server or common. + * @param log - logging utility. + * + * @return Every publically exported Node from the given plugin and scope (public, server, common). + */ +export function getDeclarationNodesForPluginScope( + project: Project, + plugin: KibanaPlatformPlugin, + scope: ApiScope, + log: ToolingLog +): Node[] { + const path = Path.join(`${plugin.directory}`, scope.toString(), 'index.ts'); + const file = getSourceFileMatching(project, path); + + if (file) { + return getExportedFileDeclarations(file, log); + } else { + log.debug(`No file found: ${path}`); + return []; + } +} + +/** + * + * @param source the file we want to extract exported declaration nodes from. + * @param log + */ +function getExportedFileDeclarations(source: SourceFile, log: ToolingLog): Node[] { + const nodes: Node[] = []; + const exported = source.getExportedDeclarations(); + + // Filter out the exported declarations that exist only for the plugin system itself. + exported.forEach((val) => { + val.forEach((ed) => { + const name: string = isNamedNode(ed) ? ed.getName() : ''; + + // Every plugin will have an export called "plugin". Don't bother listing + // it, it's only for the plugin infrastructure. + // Config is also a common export on the server side that is just for the + // plugin infrastructure. + if (name === 'plugin' || name === 'config') { + return; + } + if (name && name !== '') { + nodes.push(ed); + } else { + log.warning(`API with missing name encountered.`); + } + }); + }); + + log.debug(`Collected ${nodes.length} exports from file ${source.getFilePath()}`); + return nodes; +} diff --git a/packages/kbn-docs-utils/src/api_docs/get_plugin_api.ts b/packages/kbn-docs-utils/src/api_docs/get_plugin_api.ts new file mode 100644 index 0000000000000..ede60e95ce2b9 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/get_plugin_api.ts @@ -0,0 +1,135 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; +import { Node, Project, Type } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { ApiScope, Lifecycle } from './types'; +import { ApiDeclaration, PluginApi } from './types'; +import { buildApiDeclaration } from './build_api_declarations/build_api_declaration'; +import { getDeclarationNodesForPluginScope } from './get_declaration_nodes_for_plugin'; +import { getSourceFileMatching } from './tsmorph_utils'; + +/** + * Collects all the information neccessary to generate this plugins mdx api file(s). + */ +export function getPluginApi( + project: Project, + plugin: KibanaPlatformPlugin, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): PluginApi { + const client = getDeclarations(project, plugin, ApiScope.CLIENT, plugins, log); + const server = getDeclarations(project, plugin, ApiScope.SERVER, plugins, log); + const common = getDeclarations(project, plugin, ApiScope.COMMON, plugins, log); + return { + id: plugin.manifest.id, + client, + server, + common, + serviceFolders: plugin.manifest.serviceFolders, + }; +} + +/** + * + * @returns All exported ApiDeclarations for the given plugin and scope (client, server, common), broken into + * groups of typescript kinds (functions, classes, interfaces, etc). + */ +function getDeclarations( + project: Project, + plugin: KibanaPlatformPlugin, + scope: ApiScope, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): ApiDeclaration[] { + const nodes = getDeclarationNodesForPluginScope(project, plugin, scope, log); + + const contractTypes = getContractTypes(project, plugin, scope); + + const declarations = nodes.reduce((acc, node) => { + const apiDec = buildApiDeclaration(node, plugins, log, plugin.manifest.id, scope); + // Filter out apis with the @internal flag on them. + if (!apiDec.tags || apiDec.tags.indexOf('internal') < 0) { + // buildApiDeclaration doesn't set the lifecycle, so we set it here. + const lifecycle = getLifecycle(node, contractTypes); + acc.push({ + ...apiDec, + lifecycle, + initialIsOpen: lifecycle !== undefined, + }); + } + return acc; + }, []); + + // We have all the ApiDeclarations, now lets group them by typescript kinds. + return declarations; +} + +/** + * Checks if this node is one of the special start or setup contract interface types. We pull these + * to the top of the API docs. + * + * @param node ts-morph node + * @param contractTypeNames the start and setup contract interface names + * @returns Which, if any, lifecycle contract this node happens to represent. + */ +function getLifecycle( + node: Node, + contractTypeNames: { start?: Type; setup?: Type } +): Lifecycle | undefined { + // Note this logic is not tested if a plugin uses "as", + // like export { Setup as MyPluginSetup } from ..." + if (contractTypeNames.start && node.getType() === contractTypeNames.start) { + return Lifecycle.START; + } + + if (contractTypeNames.setup && node.getType() === contractTypeNames.setup) { + return Lifecycle.SETUP; + } +} + +/** + * + * @param project + * @param plugin the plugin we are interested in. + * @param scope Whether we are interested in the client or server plugin contracts. + * Common scope will never return anything. + * @returns the name of the two types used for Start and Setup contracts, if they + * exist and were exported from the plugin class. + */ +function getContractTypes( + project: Project, + plugin: KibanaPlatformPlugin, + scope: ApiScope +): { setup?: Type; start?: Type } { + const contractTypes: { setup?: Type; start?: Type } = {}; + const file = getSourceFileMatching( + project, + Path.join(`${plugin.directory}`, scope.toString(), 'plugin.ts') + ); + if (file) { + file.getClasses().forEach((c) => { + c.getImplements().forEach((i) => { + let index = 0; + i.getType() + .getTypeArguments() + .forEach((arg) => { + // Setup type comes first + if (index === 0) { + contractTypes.setup = arg; + } else if (index === 1) { + contractTypes.start = arg; + } + index++; + }); + }); + }); + } + return contractTypes; +} diff --git a/packages/kbn-docs-utils/src/api_docs/index.ts b/packages/kbn-docs-utils/src/api_docs/index.ts new file mode 100644 index 0000000000000..8dca507764a79 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './build_api_docs_cli'; diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/split_apis_by_folder.test.ts b/packages/kbn-docs-utils/src/api_docs/mdx/split_apis_by_folder.test.ts new file mode 100644 index 0000000000000..67e17c95d2298 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/mdx/split_apis_by_folder.test.ts @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import Path from 'path'; +import { Project } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; + +import { PluginApi } from '../types'; +import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock'; +import { getPluginApi } from '../get_plugin_api'; +import { splitApisByFolder } from './write_plugin_split_by_folder'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +let doc: PluginApi; + +beforeAll(() => { + const tsConfigFilePath = Path.resolve(__dirname, '../tests/__fixtures__/src/tsconfig.json'); + const project = new Project({ + tsConfigFilePath, + }); + + expect(project.getSourceFiles().length).toBeGreaterThan(0); + + const pluginA = getKibanaPlatformPlugin('pluginA'); + pluginA.manifest.serviceFolders = ['foo']; + const plugins: KibanaPlatformPlugin[] = [pluginA]; + + doc = getPluginApi(project, plugins[0], plugins, log); +}); + +test('foo service has all exports', () => { + expect(doc?.client.length).toBe(33); + const split = splitApisByFolder(doc); + expect(split.length).toBe(2); + + const fooDoc = split.find((d) => d.id === 'pluginA.foo'); + const mainDoc = split.find((d) => d.id === 'pluginA'); + + expect(fooDoc?.common.length).toBe(1); + expect(fooDoc?.client.length).toBe(2); + expect(mainDoc?.client.length).toBe(31); +}); diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts new file mode 100644 index 0000000000000..b35515eb9d209 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_mdx_docs.ts @@ -0,0 +1,143 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog } from '@kbn/dev-utils'; +import fs from 'fs'; +import Path from 'path'; +import dedent from 'dedent'; +import { PluginApi, ScopeApi } from '../types'; +import { + countScopeApi, + getPluginApiDocId, + snakeToCamel, + camelToSnake, + groupPluginApi, +} from '../utils'; +import { writePluginDocSplitByFolder } from './write_plugin_split_by_folder'; + +/** + * Converts the plugin doc to mdx and writes it into the file system. If the plugin, + * has serviceFolders specified in it's kibana.json, multiple mdx files will be written. + * + * @param folder The location the mdx files will be written too. + * @param doc Contains the information of the plugin that will be written into mdx. + * @param log Used for logging debug and error information. + */ +export function writePluginDocs(folder: string, doc: PluginApi, log: ToolingLog): void { + if (doc.serviceFolders) { + log.debug(`Splitting plugin ${doc.id}`); + writePluginDocSplitByFolder(folder, doc, log); + } else { + writePluginDoc(folder, doc, log); + } +} + +function hasPublicApi(doc: PluginApi): boolean { + return doc.client.length > 0 || doc.server.length > 0 || doc.common.length > 0; +} + +/** + * Converts the plugin doc to mdx and writes it into the file system. Ignores + * the serviceFolders setting. Use {@link writePluginDocs} if you wish to split + * the plugin into potentially multiple mdx files. + * + * @param folder The location the mdx file will be written too. + * @param doc Contains the information of the plugin that will be written into mdx. + * @param log Used for logging debug and error information. + */ +export function writePluginDoc(folder: string, doc: PluginApi, log: ToolingLog): void { + if (!hasPublicApi(doc)) { + log.debug(`${doc.id} does not have a public api. Skipping.`); + return; + } + + log.debug(`Writing plugin file for ${doc.id}`); + + const fileName = getFileName(doc.id); + // Append "obj" to avoid special names in here. 'case' is one in particular that + // caused issues. + const json = getJsonName(fileName) + 'Obj'; + let mdx = + dedent(` +--- +id: ${getPluginApiDocId(doc.id, log)} +slug: /kibana-dev-docs/${doc.id}PluginApi +title: ${doc.id} +image: https://source.unsplash.com/400x175/?github +summary: API docs for the ${doc.id} plugin +date: 2020-11-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '${doc.id}'] +--- + +import ${json} from './${fileName}.json'; + +`) + '\n\n'; + + const scopedDoc = { + ...doc, + client: groupPluginApi(doc.client), + common: groupPluginApi(doc.common), + server: groupPluginApi(doc.server), + }; + fs.writeFileSync(Path.resolve(folder, fileName + '.json'), JSON.stringify(scopedDoc)); + + mdx += scopApiToMdx(scopedDoc.client, 'Client', json, 'client'); + mdx += scopApiToMdx(scopedDoc.server, 'Server', json, 'server'); + mdx += scopApiToMdx(scopedDoc.common, 'Common', json, 'common'); + + fs.writeFileSync(Path.resolve(folder, fileName + '.mdx'), mdx); +} + +function getJsonName(name: string): string { + return snakeToCamel(getFileName(name)); +} + +function getFileName(name: string): string { + return camelToSnake(name.replace('.', '_')); +} + +function scopApiToMdx(scope: ScopeApi, title: string, json: string, scopeName: string): string { + let mdx = ''; + if (countScopeApi(scope) > 0) { + mdx += `## ${title}\n\n`; + + if (scope.setup) { + mdx += `### Setup\n`; + mdx += `\n`; + } + if (scope.start) { + mdx += `### Start\n`; + mdx += `\n`; + } + if (scope.objects.length > 0) { + mdx += `### Objects\n`; + mdx += `\n`; + } + if (scope.functions.length > 0) { + mdx += `### Functions\n`; + mdx += `\n`; + } + if (scope.classes.length > 0) { + mdx += `### Classes\n`; + mdx += `\n`; + } + if (scope.interfaces.length > 0) { + mdx += `### Interfaces\n`; + mdx += `\n`; + } + if (scope.enums.length > 0) { + mdx += `### Enums\n`; + mdx += `\n`; + } + if (scope.misc.length > 0) { + mdx += `### Consts, variables and types\n`; + mdx += `\n`; + } + } + return mdx; +} diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.test.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.test.ts new file mode 100644 index 0000000000000..153b3299d8136 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.test.ts @@ -0,0 +1,72 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Project } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { splitApisByFolder } from './write_plugin_split_by_folder'; +import { getPluginApi } from '../get_plugin_api'; +import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +it('splitApisByFolder test splitting plugin by service folder', () => { + const project = new Project({ useInMemoryFileSystem: true }); + project.createSourceFile( + 'src/plugins/example/public/index.ts', + ` +import { bar } from './a_service/foo/bar'; +import { Zed, zed } from './a_service/zed'; +import { util } from './utils'; + +export { bar, Zed, zed, mainFoo, util }; +` + ); + project.createSourceFile( + 'src/plugins/example/public/a_service/zed.ts', + `export const zed: string = 'hi'; +export interface Zed = { zed: string }` + ); + project.createSourceFile( + 'src/plugins/example/public/a_service/foo/bar.ts', + `export const bar: string = 'bar';` + ); + project.createSourceFile( + 'src/plugins/example/public/utils.ts', + `export const util: string = 'Util';` + ); + + const plugin = getKibanaPlatformPlugin('example', '/src/plugins/example'); + const plugins: KibanaPlatformPlugin[] = [ + { + ...plugin, + manifest: { + ...plugin.manifest, + serviceFolders: ['a_service'], + }, + }, + ]; + + const doc = getPluginApi(project, plugins[0], plugins, log); + const docs = splitApisByFolder(doc); + + // The api at the main level, and one on a service level. + expect(docs.length).toBe(2); + + const mainDoc = docs.find((d) => d.id === 'example'); + + expect(mainDoc).toBeDefined(); + + const serviceDoc = docs.find((d) => d.id === 'example.aService'); + + expect(serviceDoc).toBeDefined(); + + expect(serviceDoc?.client.length).toBe(3); +}); diff --git a/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.ts b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.ts new file mode 100644 index 0000000000000..f5d547fc03520 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/mdx/write_plugin_split_by_folder.ts @@ -0,0 +1,69 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ToolingLog } from '@kbn/dev-utils'; +import { snakeToCamel } from '../utils'; +import { PluginApi, ApiDeclaration } from '../types'; +import { writePluginDoc } from './write_plugin_mdx_docs'; + +export function writePluginDocSplitByFolder(folder: string, doc: PluginApi, log: ToolingLog) { + const apisByFolder = splitApisByFolder(doc); + + log.debug(`Split ${doc.id} into ${apisByFolder.length} services`); + apisByFolder.forEach((docDef) => { + writePluginDoc(folder, docDef, log); + }); +} + +export function splitApisByFolder(pluginDoc: PluginApi): PluginApi[] { + const pluginDocDefsByFolder: { [key: string]: PluginApi } = {}; + const mainPluginDocDef = createServicePluginDocDef(pluginDoc); + + pluginDoc.client.forEach((dec: ApiDeclaration) => { + addSection(dec, 'client', mainPluginDocDef, pluginDocDefsByFolder, pluginDoc.serviceFolders!); + }); + pluginDoc.server.forEach((dec: ApiDeclaration) => { + addSection(dec, 'server', mainPluginDocDef, pluginDocDefsByFolder, pluginDoc.serviceFolders!); + }); + pluginDoc.common.forEach((dec: ApiDeclaration) => { + addSection(dec, 'common', mainPluginDocDef, pluginDocDefsByFolder, pluginDoc.serviceFolders!); + }); + + return [...Object.values(pluginDocDefsByFolder), mainPluginDocDef]; +} + +function addSection( + dec: ApiDeclaration, + scope: 'client' | 'server' | 'common', + mainPluginDocDef: PluginApi, + pluginServices: { [key: string]: PluginApi }, + serviceFolders: readonly string[] +) { + const scopeFolder = scope === 'client' ? 'public' : scope; + const matchGroup = dec.source.path.match(`.*?\/${scopeFolder}\/([^\/]*?)\/`); + const serviceFolderName = matchGroup ? matchGroup[1] : undefined; + + if (serviceFolderName && serviceFolders.find((f) => f === serviceFolderName)) { + const service = snakeToCamel(serviceFolderName); + if (!pluginServices[service]) { + pluginServices[service] = createServicePluginDocDef(mainPluginDocDef, service); + } + pluginServices[service][scope].push(dec); + } else { + mainPluginDocDef[scope].push(dec); + } +} + +function createServicePluginDocDef(pluginDoc: PluginApi, service?: string): PluginApi { + return { + id: service ? pluginDoc.id + '.' + service : pluginDoc.id, + client: [], + server: [], + common: [], + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts new file mode 100644 index 0000000000000..198856dbb10c4 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const commonFoo = 'COMMON VAR!'; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts new file mode 100644 index 0000000000000..3fb7e375b2542 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { commonFoo } from './foo'; + +export interface ImACommonType { + goo: number; +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json new file mode 100644 index 0000000000000..84b46caa70802 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/kibana.json @@ -0,0 +1,7 @@ +{ + "id": "pluginA", + "summary": "This an example plugin for testing the api documentation system", + "version": "kibana", + "serviceFolders": ["foo"] + } + \ No newline at end of file diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts new file mode 100644 index 0000000000000..c68d146f71502 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts @@ -0,0 +1,80 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +/* eslint-disable max-classes-per-file */ + +import { ImAType } from './types'; + +/** + * An interface with a generic. + */ +export interface WithGen { + t: T; +} + +export interface AnotherInterface { + t: T; +} + +export class ExampleClass implements AnotherInterface { + /** + * This should not be exposed in the docs! + */ + private privateVar: string; + + public component?: React.ComponentType; + + constructor(public t: T) { + this.privateVar = 'hi'; + } + + /** + * an arrow fn on a class. + * @param a im a string + */ + arrowFn = (a: ImAType): ImAType => a; + + /** + * A function on a class. + * @param a a param + */ + getVar(a: ImAType) { + return this.privateVar; + } +} + +export class CrazyClass

extends ExampleClass> {} + +/** + * This is an example interface so we can see how it appears inside the API + * documentation system. + */ +export interface ExampleInterface extends AnotherInterface { + /** + * This gets a promise that resolves to a string. + */ + getAPromiseThatResolvesToString: () => Promise; + + /** + * This function takes a generic. It was sometimes being tripped on + * and returned as an unknown type with no signature. + */ + aFnWithGen: (t: T) => void; + + /** + * These are not coming back properly. + */ + aFn(): void; +} + +/** + * An interface that has a react component. + */ +export interface IReturnAReactComponent { + component: React.ComponentType; +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts new file mode 100644 index 0000000000000..52abd520f8259 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { CrazyClass } from './classes'; +import { notAnArrowFn } from './fns'; +import { ImAType } from './types'; + +/** + * Some of the plugins wrap static exports in an object to create + * a namespace like this. + */ +export const aPretendNamespaceObj = { + /** + * The docs should show this inline comment. + */ + notAnArrowFn, + + /** + * Should this comment show up? + */ + aPropertyMisdirection: notAnArrowFn, + + /** + * I'm a property inline fun. + */ + aPropertyInlineFn: (a: ImAType): ImAType => { + return a; + }, + + /** + * The only way for this to have a comment is to grab this. + */ + aPropertyStr: 'Hi', + + /** + * Will this nested object have it's children extracted appropriately? + */ + nestedObj: { + foo: 'string', + }, +}; + +/** + * This is a complicated union type + */ +export const aUnionProperty: string | number | (() => string) | CrazyClass = '6'; + +/** + * This is an array of strings. The type is explicit. + */ +export const aStrArray: string[] = ['hi', 'bye']; + +/** + * This is an array of numbers. The type is implied. + */ +export const aNumArray = [1, 3, 4]; + +/** + * A string that says hi to you! + */ +export const aStr: string = 'hi'; + +/** + * It's a number. A special number. + */ +export const aNum = 10; + +/** + * I'm a type of string, but more specifically, a literal string type. + */ +export const literalString = 'HI'; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts new file mode 100644 index 0000000000000..c341a80c0875d --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts @@ -0,0 +1,78 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { TypeWithGeneric, ImAType } from './types'; + +/** + * This is a non arrow function. + * + * @param a The letter A + * @param b Feed me to the function + * @param c So many params + * @param d a great param + * @param e Another comment + * @returns something! + */ +export function notAnArrowFn( + a: string, + b: number | undefined, + c: TypeWithGeneric, + d: ImAType, + e?: string +): TypeWithGeneric { + return ['hi']; +} + +/** + * This is an arrow function. + * + * @param a The letter A + * @param b Feed me to the function + * @param c So many params + * @param d a great param + * @param e Another comment + * @returns something! + */ +export const arrowFn = ( + a: string, + b: number | undefined, + c: TypeWithGeneric, + d: ImAType, + e?: string +): TypeWithGeneric => { + return ['hi']; +}; + +/** + * Who would write such a complicated function?? Ewwww. + * + * According to https://jsdoc.app/tags-param.html#parameters-with-properties, + * this is how destructured arguements should be commented. + * + * @param obj A very crazy parameter that is destructured when passing in. + * @param objWithFn Im an object with a function. Destructed! + * @param objWithFn.fn A fn. + * @param objWithStr Im an object with a string. Destructed! + * @param objWithStr.str A str. + * + * @returns I have no idea. + * + */ +export const crazyFunction = ( + obj: { hi: string }, + { fn }: { fn: (foo: { param: string }) => number }, + { str }: { str: string } +) => () => () => fn({ param: str }); + +interface ImNotExported { + foo: string; +} + +export const fnWithNonExportedRef = (a: ImNotExported) => 'shi'; + +export type NotAnArrowFnType = typeof notAnArrowFn; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts new file mode 100644 index 0000000000000..67db6d1a15db5 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export const doTheFooFnThing = () => {}; + +export type FooType = () => 'foo'; + +export type ImNotExportedFromIndex = () => { bar: string }; diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts new file mode 100644 index 0000000000000..89bfb07e515ff --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { PluginA, Setup, Start, SearchSpec } from './plugin'; +export { Setup, Start, SearchSpec }; + +export { doTheFooFnThing, FooType } from './foo'; + +export * from './fns'; +export * from './classes'; +export * from './const_vars'; +export * from './types'; + +export const imAnAny: any = 'hi'; +export const imAnUnknown: unknown = 'hi'; + +export function plugin() { + return new PluginA(); +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts new file mode 100644 index 0000000000000..839dc828c1886 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts @@ -0,0 +1,172 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +// The logic for grabbing Setup and Start types relies on implementing an +// interface with at least two type args. Since the test code isn't adding +// every import file, use this mock, otherwise it won't have the type and will +// fail. +interface PluginMock { + setup(): Sp; + start(): St; +} + +/** + * The SearchSpec interface contains settings for creating a new SearchService, like + * username and password. + */ +export interface SearchSpec { + /** + * Stores the username. Duh, + */ + username: string; + /** + * Stores the password. I hope it's encrypted! + */ + password: string; +} + +/** + * The type of search language. + */ +export enum SearchLanguage { + /** + * The SQL SearchLanguage type + */ + SQL, + /** + * The EQL SearchLanguage type. Support sequences. + */ + EQL, + /** + * The ES DSL SearchLanguage type. It's the default. + */ + ES_DSL, +} + +/** + * Access start functionality from your plugin's start function by adding the example + * plugin as a dependency. + * + * ```ts + * Class MyPlugin { + * start(core: CoreDependencies, { example }: PluginDependencies) { + * // Here you can access this functionality. + * example.getSearchLanguage(); + * } + * } + * ``` + */ +export interface Start { + /** + * @returns The currently selected {@link SearchLanguage} + */ + getSearchLanguage: () => SearchLanguage; +} + +/** + * Access setup functionality from your plugin's setup function by adding the example + * plugin as a dependency. + * + * ```ts + * Class MyPlugin { + * setup(core: CoreDependencies, { example }: PluginDependencies) { + * // Here you can access this functionality. + * example.getSearchService(); + * } + * } + * ``` + */ +export interface Setup { + /** + * A factory function that returns a new instance of Foo based + * on the spec. We aren't sure if this is a good function so it's marked + * beta. That should be clear in the docs because of the js doc tag. + * + * @param searchSpec Provide the settings neccessary to create a new Search Service + * + * @returns the id of the search service. + * + * @beta + */ + getSearchService: (searchSpec: SearchSpec) => string; + + /** + * This uses an inlined object type rather than referencing an exported type, which is discouraged. + * prefer the way {@link getSearchService} is typed. + * + * @param searchSpec Provide the settings neccessary to create a new Search Service + */ + getSearchService2: (searchSpec: { username: string; password: string }) => string; + + /** + * This function does the thing and it's so good at it! But we decided to deprecate it + * anyway. I hope that's clear to developers in the docs! + * + * @param thingOne Thing one comment + * @param thingTwo ThingTwo comment + * @param thingThree Thing three is an object with a nested var + * + * @deprecated + * + */ + doTheThing: (thingOne: number, thingTwo: string, thingThree: { nestedVar: number }) => void; + + /** + * Who would write such a complicated function?? Ew, how will the obj parameter appear in docs? + * + * @param obj A funky parameter. + * + * @returns It's hard to tell but I think this returns a function that returns an object with a + * property that is a function that returns a string. Whoa. + * + */ + fnWithInlineParams: (obj: { + fn: (foo: { param: string }) => number; + }) => () => { retFoo: () => string }; + + /** + * Hi, I'm a comment for an id string! + */ + id: string; +} + +/** + * This comment won't show up in the API docs. + */ +function getSearchService() { + return 'hi'; +} + +function fnWithInlineParams() { + return () => ({ + retFoo: () => 'hi', + }); +} + +/** + * The example search plugin is a fake plugin that is built only to test our api documentation system. + * + */ +export class PluginA implements PluginMock { + setup() { + return { + // Don't put comments here - they won't show up. What's here shouldn't matter because + // the API documentation system works off the type `Setup`. + doTheThing: () => {}, + fnWithInlineParams, + getSearchService, + getSearchService2: getSearchService, + registerSearch: () => {}, + id: '123', + }; + } + + start() { + return { getSearchLanguage: () => SearchLanguage.EQL }; + } +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts new file mode 100644 index 0000000000000..0f06f08018c22 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts @@ -0,0 +1,45 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { ImACommonType } from '../common'; +import { FooType, ImNotExportedFromIndex } from './foo'; + +/** + * How should a potentially undefined type show up. + */ +export type StringOrUndefinedType = string | undefined; + +export type TypeWithGeneric = T[]; + +export type ImAType = string | number | TypeWithGeneric | FooType | ImACommonType; + +/** + * This is a type that defines a function. + * + * @param t This is a generic T type. It can be anything. + */ +export type FnWithGeneric = (t: T) => TypeWithGeneric; + +/** + * Comments on enums. + */ +export enum DayOfWeek { + THURSDAY, + FRIDAY, // How about this comment, hmmm? + SATURDAY, +} + +/** + * Calling node.getSymbol().getDeclarations() will return > 1 declaration. + */ +export type MultipleDeclarationsType = TypeWithGeneric; + +export type IRefANotExportedType = ImNotExportedFromIndex | { zed: 'hi' }; +export interface ImAnObject { + foo: FnWithGeneric; +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/tsconfig.json b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/tsconfig.json new file mode 100644 index 0000000000000..57353d8847ae1 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "incremental": false, + "strictNullChecks": true, + }, + "include": ["./**/*"] +} \ No newline at end of file diff --git a/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts b/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts new file mode 100644 index 0000000000000..f32e58bdfc023 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/api_doc_suite.test.ts @@ -0,0 +1,397 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import fs from 'fs'; +import Path from 'path'; + +import { Project } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; + +import { writePluginDocs } from '../mdx/write_plugin_mdx_docs'; +import { ApiDeclaration, PluginApi, Reference, TextWithLinks, TypeKind } from '../types'; +import { getKibanaPlatformPlugin } from './kibana_platform_plugin_mock'; +import { getPluginApi } from '../get_plugin_api'; +import { groupPluginApi } from '../utils'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +let doc: PluginApi; +let mdxOutputFolder: string; + +function linkCount(signature: TextWithLinks): number { + return signature.reduce((cnt, next) => (typeof next === 'string' ? cnt : cnt + 1), 0); +} + +function fnIsCorrect(fn: ApiDeclaration | undefined) { + expect(fn).toBeDefined(); + expect(fn?.type).toBe(TypeKind.FunctionKind); + // The signature should contain a link to ExampleInterface param. + expect(fn?.signature).toBeDefined(); + expect(linkCount(fn!.signature!)).toBe(3); + + expect(fn?.children!.length).toBe(5); + expect(fn?.returnComment!.length).toBe(1); + + const p1 = fn?.children!.find((c) => c.label === 'a'); + expect(p1).toBeDefined(); + expect(p1!.type).toBe(TypeKind.StringKind); + expect(p1!.isRequired).toBe(true); + expect(p1!.signature?.length).toBe(1); + expect(linkCount(p1!.signature!)).toBe(0); + + const p2 = fn?.children!.find((c) => c.label === 'b'); + expect(p2).toBeDefined(); + expect(p2!.isRequired).toBe(false); + expect(p2!.type).toBe(TypeKind.NumberKind); + expect(p2!.signature?.length).toBe(1); + expect(linkCount(p2!.signature!)).toBe(0); + + const p3 = fn?.children!.find((c) => c.label === 'c'); + expect(p3).toBeDefined(); + expect(p3!.isRequired).toBe(true); + expect(p3!.type).toBe(TypeKind.ArrayKind); + expect(linkCount(p3!.signature!)).toBe(1); + + const p4 = fn?.children!.find((c) => c.label === 'd'); + expect(p4).toBeDefined(); + expect(p4!.isRequired).toBe(true); + expect(p4!.type).toBe(TypeKind.CompoundTypeKind); + expect(p4!.signature?.length).toBe(1); + expect(linkCount(p4!.signature!)).toBe(1); + + const p5 = fn?.children!.find((c) => c.label === 'e'); + expect(p5).toBeDefined(); + expect(p5!.isRequired).toBe(false); + expect(p5!.type).toBe(TypeKind.StringKind); + expect(p5!.signature?.length).toBe(1); + expect(linkCount(p5!.signature!)).toBe(0); +} + +beforeAll(() => { + const tsConfigFilePath = Path.resolve(__dirname, '__fixtures__/src/tsconfig.json'); + const project = new Project({ + tsConfigFilePath, + }); + + expect(project.getSourceFiles().length).toBeGreaterThan(0); + + const pluginA = getKibanaPlatformPlugin('pluginA'); + pluginA.manifest.serviceFolders = ['foo']; + const plugins: KibanaPlatformPlugin[] = [pluginA]; + + doc = getPluginApi(project, plugins[0], plugins, log); + + mdxOutputFolder = Path.resolve(__dirname, 'snapshots'); + writePluginDocs(mdxOutputFolder, doc, log); +}); + +it('Setup type is extracted', () => { + const grouped = groupPluginApi(doc.client); + expect(grouped.setup).toBeDefined(); +}); + +it('service mdx file was created', () => { + expect(fs.existsSync(Path.resolve(mdxOutputFolder, 'plugin_a_foo.mdx'))).toBe(true); +}); + +it('Setup type has comment', () => { + const grouped = groupPluginApi(doc.client); + expect(grouped.setup!.description).toBeDefined(); + expect(grouped.setup!.description).toMatchInlineSnapshot(` + Array [ + " + Access setup functionality from your plugin's setup function by adding the example + plugin as a dependency. + + \`\`\`ts + Class MyPlugin { + setup(core: CoreDependencies, { example }: PluginDependencies) { + // Here you can access this functionality. + example.getSearchService(); + } + } + \`\`\`", + ] + `); +}); + +it('const exported from common folder is correct', () => { + const fooConst = doc.common.find((c) => c.label === 'commonFoo'); + expect(fooConst).toBeDefined(); + + expect(fooConst!.source.path.replace(Path.sep, '/')).toContain( + 'src/plugin_a/common/foo/index.ts' + ); + expect(fooConst!.signature![0]).toBe('"COMMON VAR!"'); +}); + +describe('functions', () => { + it('function referencing missing type has link removed', () => { + const fn = doc.client.find((c) => c.label === 'fnWithNonExportedRef'); + expect(linkCount(fn?.signature!)).toBe(0); + }); + it('arrow function is exported correctly', () => { + const fn = doc.client.find((c) => c.label === 'arrowFn'); + // Using the same data as the not an arrow function so this is refactored. + fnIsCorrect(fn); + }); + + it('non arrow function is exported correctly', () => { + const fn = doc.client.find((c) => c.label === 'notAnArrowFn'); + // Using the same data as the arrow function so this is refactored. + fnIsCorrect(fn); + }); + + it('crazyFunction is typed correctly', () => { + const fn = doc.client!.find((c) => c.label === 'crazyFunction'); + + expect(fn).toBeDefined(); + + const obj = fn?.children?.find((c) => c.label === 'obj'); + expect(obj).toBeDefined(); + expect(obj!.children?.length).toBe(1); + + const hi = obj?.children?.find((c) => c.label === 'hi'); + expect(hi).toBeDefined(); + + const obj2 = fn?.children?.find((c) => c.label === '{ fn }'); + expect(obj2).toBeDefined(); + expect(obj2!.children?.length).toBe(1); + + const fn2 = obj2?.children?.find((c) => c.label === 'fn'); + expect(fn2).toBeDefined(); + expect(fn2?.type).toBe(TypeKind.FunctionKind); + }); +}); + +describe('objects', () => { + it('Object exported correctly', () => { + const obj = doc.client.find((c) => c.label === 'aPretendNamespaceObj'); + expect(obj).toBeDefined(); + + const fn = obj?.children?.find((c) => c.label === 'notAnArrowFn'); + expect(fn?.signature).toBeDefined(); + // Should just be typeof notAnArrowFn. + expect(linkCount(fn?.signature!)).toBe(1); + // Comment should be the inline one. + expect(fn?.description).toMatchInlineSnapshot(` + Array [ + "/** + * The docs should show this inline comment. + */", + ] + `); + + const fn2 = obj?.children?.find((c) => c.label === 'aPropertyInlineFn'); + expect(fn2?.signature).toBeDefined(); + // Should include 2 links to ImAType + expect(linkCount(fn2?.signature!)).toBe(2); + expect(fn2?.children).toBeDefined(); + + const nestedObj = obj?.children?.find((c) => c.label === 'nestedObj'); + // We aren't giving objects a signature. The children should contain all the information. + expect(nestedObj?.signature).toBeUndefined(); + expect(nestedObj?.children).toBeDefined(); + expect(nestedObj?.type).toBe(TypeKind.ObjectKind); + const foo = nestedObj?.children?.find((c) => c.label === 'foo'); + expect(foo?.type).toBe(TypeKind.StringKind); + }); +}); + +describe('Misc types', () => { + it('Explicitly typed array is returned with the correct type', () => { + const aStrArray = doc.client.find((c) => c.label === 'aStrArray'); + expect(aStrArray).toBeDefined(); + expect(aStrArray?.type).toBe(TypeKind.ArrayKind); + }); + + it('Implicitly typed array is returned with the correct type', () => { + const aNumArray = doc.client.find((c) => c.label === 'aNumArray'); + expect(aNumArray).toBeDefined(); + expect(aNumArray?.type).toBe(TypeKind.ArrayKind); + }); + + it('Explicitly typed string is returned with the correct type', () => { + const aStr = doc.client.find((c) => c.label === 'aStr'); + expect(aStr).toBeDefined(); + expect(aStr?.type).toBe(TypeKind.StringKind); + // signature would be the same as type, so it should be removed. + expect(aStr?.signature).toBeUndefined(); + }); + + it('Implicitly typed number is returned with the correct type', () => { + const aNum = doc.client.find((c) => c.label === 'aNum'); + expect(aNum).toBeDefined(); + expect(aNum?.type).toBe(TypeKind.NumberKind); + }); + + it('aUnionProperty is exported as a CompoundType with a call signature', () => { + const prop = doc.client.find((c) => c.label === 'aUnionProperty'); + expect(prop).toBeDefined(); + expect(prop?.type).toBe(TypeKind.CompoundTypeKind); + expect(linkCount(prop?.signature!)).toBe(1); + }); + + it('Function type is exported correctly', () => { + const fnType = doc.client.find((c) => c.label === 'FnWithGeneric'); + expect(fnType).toBeDefined(); + expect(fnType?.type).toBe(TypeKind.TypeKind); + expect(fnType?.signature!).toMatchInlineSnapshot(` + Array [ + "(t: T) => ", + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + `); + expect(linkCount(fnType?.signature!)).toBe(1); + }); + + it('Union type is exported correctly', () => { + const type = doc.client.find((c) => c.label === 'ImAType'); + expect(type).toBeDefined(); + expect(type?.type).toBe(TypeKind.TypeKind); + expect(type?.signature).toBeDefined(); + expect(type?.signature!).toMatchInlineSnapshot(` + Array [ + "string | number | ", + Object { + "docId": "kibPluginAFooPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.FooType", + "text": "FooType", + }, + " | ", + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + " | ", + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "common", + "section": "def-common.ImACommonType", + "text": "ImACommonType", + }, + ] + `); + + expect(linkCount(type?.signature!)).toBe(3); + expect((type!.signature![1] as Reference).docId).toBe('kibPluginAFooPluginApi'); + }); +}); + +describe('interfaces and classes', () => { + it('Basic interface exported correctly', () => { + const anInterface = doc.client.find((c) => c.label === 'IReturnAReactComponent'); + expect(anInterface).toBeDefined(); + + // Make sure it doesn't include a self referential link. + expect(anInterface?.signature).toBeUndefined(); + }); + + it('Interface which extends exported correctly', () => { + const exampleInterface = doc.client.find((c) => c.label === 'ExampleInterface'); + expect(exampleInterface).toBeDefined(); + expect(exampleInterface?.signature).toBeDefined(); + expect(exampleInterface?.type).toBe(TypeKind.InterfaceKind); + + expect(linkCount(exampleInterface?.signature!)).toBe(2); + + // TODO: uncomment if the bug is fixed. + // This is wrong, the link should be to `AnotherInterface` + // Another bug, this link is not being captured. + expect(exampleInterface?.signature).toMatchInlineSnapshot(` + Array [ + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.ExampleInterface", + "text": "ExampleInterface", + }, + " extends ", + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.AnotherInterface", + "text": "AnotherInterface", + }, + "", + ] + `); + }); + + it('Non arrow function on interface is exported as function type', () => { + const exampleInterface = doc.client.find((c) => c.label === 'ExampleInterface'); + expect(exampleInterface).toBeDefined(); + + const fn = exampleInterface!.children?.find((c) => c.label === 'aFn'); + expect(fn).toBeDefined(); + expect(fn?.type).toBe(TypeKind.FunctionKind); + }); + + it('Class exported correctly', () => { + const clss = doc.client.find((c) => c.label === 'CrazyClass'); + expect(clss).toBeDefined(); + expect(clss?.signature).toBeDefined(); + expect(clss?.type).toBe(TypeKind.ClassKind); + expect(clss?.signature).toMatchInlineSnapshot(` + Array [ + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.CrazyClass", + "text": "CrazyClass", + }, + "

extends ", + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.ExampleClass", + "text": "ExampleClass", + }, + "<", + Object { + "docId": "kibPluginAPluginApi", + "pluginId": "pluginA", + "scope": "public", + "section": "def-public.WithGen", + "text": "WithGen", + }, + "

>", + ] + `); + expect(linkCount(clss?.signature!)).toBe(3); + }); + + it('Function with generic inside interface is exported with function type', () => { + const exampleInterface = doc.client.find((c) => c.label === 'ExampleInterface'); + expect(exampleInterface).toBeDefined(); + + const fnWithGeneric = exampleInterface?.children?.find((c) => c.label === 'aFnWithGen'); + expect(fnWithGeneric).toBeDefined(); + expect(fnWithGeneric?.type).toBe(TypeKind.FunctionKind); + }); +}); diff --git a/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts b/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts new file mode 100644 index 0000000000000..9debca91b7ca8 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/kibana_platform_plugin_mock.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPlatformPlugin } from '@kbn/dev-utils'; +import Path from 'path'; + +export function getKibanaPlatformPlugin(id: string, dir?: string): KibanaPlatformPlugin { + const directory = dir ?? Path.resolve(__dirname, '__fixtures__/src/plugin_a'); + return { + manifest: { + id, + ui: true, + server: true, + kibanaVersion: '1', + version: '1', + serviceFolders: [], + requiredPlugins: [], + requiredBundles: [], + optionalPlugins: [], + extraPublicDirs: [], + }, + directory, + manifestPath: Path.resolve(directory, 'kibana.json'), + }; +} diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json new file mode 100644 index 0000000000000..db25b8c4f021e --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.json @@ -0,0 +1 @@ +{"id":"pluginA","client":{"classes":[{"id":"def-public.ExampleClass","type":"Class","label":"ExampleClass","description":[],"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ExampleClass","text":"ExampleClass"}," implements ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.AnotherInterface","text":"AnotherInterface"},""],"children":[{"id":"def-public.ExampleClass.component","type":"CompoundType","label":"component","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":30,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L30"},"signature":["React.ComponentClass<{}, any> | React.FunctionComponent<{}> | undefined"]},{"id":"def-public.ExampleClass.Unnamed","type":"Function","label":"Constructor","signature":["any"],"description":[],"children":[{"type":"Uncategorized","label":"t","isRequired":true,"signature":["T"],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":32,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L32"}}],"tags":[],"returnComment":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":32,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L32"}},{"id":"def-public.ExampleClass.arrowFn","type":"Function","children":[{"type":"CompoundType","label":"a","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":40,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L40"}}],"signature":["(a: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},") => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":["\nan arrow fn on a class."],"label":"arrowFn","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":40,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L40"},"returnComment":[]},{"id":"def-public.ExampleClass.getVar","type":"Function","label":"getVar","signature":["(a: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},") => string"],"description":["\nA function on a class."],"children":[{"type":"CompoundType","label":"a","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":["a param"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":46,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L46"}}],"tags":[],"returnComment":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":46,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L46"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":24,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L24"},"initialIsOpen":false},{"id":"def-public.CrazyClass","type":"Class","label":"CrazyClass","description":[],"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.CrazyClass","text":"CrazyClass"},"

extends ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ExampleClass","text":"ExampleClass"},"<",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.WithGen","text":"WithGen"},"

>"],"children":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":51,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L51"},"initialIsOpen":false}],"functions":[{"id":"def-public.notAnArrowFn","type":"Function","label":"notAnArrowFn","signature":["(a: string, b: number | undefined, c: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},", d: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},", e: string | undefined) => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["\nThis is a non arrow function.\n"],"children":[{"type":"string","label":"a","isRequired":true,"signature":["string"],"description":["The letter A"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":22,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L22"}},{"type":"number","label":"b","isRequired":false,"signature":["number | undefined"],"description":["Feed me to the function"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":23,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L23"}},{"type":"Array","label":"c","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["So many params"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":24,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L24"}},{"type":"CompoundType","label":"d","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":["a great param"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":25,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L25"}},{"type":"string","label":"e","isRequired":false,"signature":["string | undefined"],"description":["Another comment"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L26"}}],"tags":[],"returnComment":["something!"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":21,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L21"},"initialIsOpen":false},{"id":"def-public.arrowFn","type":"Function","children":[{"type":"string","label":"a","isRequired":true,"signature":["string"],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":42,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L42"}},{"type":"number","label":"b","isRequired":false,"signature":["number | undefined"],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":43,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L43"}},{"type":"Array","label":"c","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":44,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L44"}},{"type":"CompoundType","label":"d","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":45,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L45"}},{"type":"string","label":"e","isRequired":false,"signature":["string | undefined"],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":46,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L46"}}],"signature":["(a: string, b: number | undefined, c: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},", d: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},", e?: string | undefined) => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["\nThis is an arrow function.\n"],"label":"arrowFn","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":41,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L41"},"returnComment":["something!"],"initialIsOpen":false},{"id":"def-public.crazyFunction","type":"Function","children":[{"id":"def-public.crazyFunction.obj","type":"Object","label":"obj","description":[],"children":[{"id":"def-public.crazyFunction.obj.hi","type":"string","label":"hi","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":67,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L67"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":67,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L67"}},{"id":"def-public.crazyFunction.{-fn }","type":"Object","label":"{ fn }","description":[],"children":[{"id":"def-public.crazyFunction.{-fn }.fn","type":"Function","label":"fn","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":68,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L68"},"signature":["(foo: { param: string; }) => number"]}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":68,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L68"}},{"id":"def-public.crazyFunction.{-str }","type":"Object","label":"{ str }","description":[],"children":[{"id":"def-public.crazyFunction.{-str }.str","type":"string","label":"str","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":69,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L69"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":69,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L69"}}],"signature":["(obj: { hi: string; }, { fn }: { fn: (foo: { param: string; }) => number; }, { str }: { str: string; }) => () => () => number"],"description":["\nWho would write such a complicated function?? Ewwww.\n\nAccording to https://jsdoc.app/tags-param.html#parameters-with-properties,\nthis is how destructured arguements should be commented.\n"],"label":"crazyFunction","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":66,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L66"},"returnComment":["I have no idea."],"initialIsOpen":false},{"id":"def-public.fnWithNonExportedRef","type":"Function","children":[{"type":"Object","label":"a","isRequired":true,"signature":["ImNotExported"],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":76,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L76"}}],"signature":["(a: ImNotExported) => string"],"description":[],"label":"fnWithNonExportedRef","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":76,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L76"},"returnComment":[],"initialIsOpen":false}],"interfaces":[{"id":"def-public.SearchSpec","type":"Interface","label":"SearchSpec","description":["\nThe SearchSpec interface contains settings for creating a new SearchService, like\nusername and password."],"children":[{"id":"def-public.SearchSpec.username","type":"string","label":"username","description":["\nStores the username. Duh,"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L26"}},{"id":"def-public.SearchSpec.password","type":"string","label":"password","description":["\nStores the password. I hope it's encrypted!"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":30,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L30"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":22,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L22"},"initialIsOpen":false},{"id":"def-public.WithGen","type":"Interface","label":"WithGen","signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.WithGen","text":"WithGen"},""],"description":["\nAn interface with a generic."],"children":[{"id":"def-public.WithGen.t","type":"Uncategorized","label":"t","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":17,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L17"},"signature":["T"]}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":16,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L16"},"initialIsOpen":false},{"id":"def-public.AnotherInterface","type":"Interface","label":"AnotherInterface","signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.AnotherInterface","text":"AnotherInterface"},""],"description":[],"children":[{"id":"def-public.AnotherInterface.t","type":"Uncategorized","label":"t","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":21,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L21"},"signature":["T"]}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":20,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L20"},"initialIsOpen":false},{"id":"def-public.ExampleInterface","type":"Interface","label":"ExampleInterface","signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ExampleInterface","text":"ExampleInterface"}," extends ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.AnotherInterface","text":"AnotherInterface"},""],"description":["\nThis is an example interface so we can see how it appears inside the API\ndocumentation system."],"children":[{"id":"def-public.ExampleInterface.getAPromiseThatResolvesToString","type":"Function","label":"getAPromiseThatResolvesToString","description":["\nThis gets a promise that resolves to a string."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":61,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L61"},"signature":["() => Promise"]},{"id":"def-public.ExampleInterface.aFnWithGen","type":"Function","label":"aFnWithGen","description":["\nThis function takes a generic. It was sometimes being tripped on\nand returned as an unknown type with no signature."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":67,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L67"},"signature":["(t: T) => void"]},{"id":"def-public.ExampleInterface.aFn","type":"Function","label":"aFn","signature":["() => void"],"description":["\nThese are not coming back properly."],"children":[],"tags":[],"returnComment":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":72,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L72"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":57,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L57"},"initialIsOpen":false},{"id":"def-public.IReturnAReactComponent","type":"Interface","label":"IReturnAReactComponent","description":["\nAn interface that has a react component."],"children":[{"id":"def-public.IReturnAReactComponent.component","type":"CompoundType","label":"component","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":79,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L79"},"signature":["React.ComponentType<{}>"]}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts","lineNumber":78,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/classes.ts#L78"},"initialIsOpen":false},{"id":"def-public.ImAnObject","type":"Interface","label":"ImAnObject","description":[],"children":[{"id":"def-public.ImAnObject.foo","type":"Function","label":"foo","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":44,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L44"},"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.FnWithGeneric","text":"FnWithGeneric"}]}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":43,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L43"},"initialIsOpen":false}],"enums":[{"id":"def-public.DayOfWeek","type":"Enum","label":"DayOfWeek","description":["\nComments on enums."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":31,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L31"},"initialIsOpen":false}],"misc":[{"id":"def-public.imAnAny","type":"Any","label":"imAnAny","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts","lineNumber":19,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts#L19"},"signature":["any"],"initialIsOpen":false},{"id":"def-public.imAnUnknown","type":"Unknown","label":"imAnUnknown","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts","lineNumber":20,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/index.ts#L20"},"signature":["unknown"],"initialIsOpen":false},{"id":"def-public.NotAnArrowFnType","type":"Type","label":"NotAnArrowFnType","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts","lineNumber":78,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/fns.ts#L78"},"signature":["(a: string, b: number | undefined, c: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},", d: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},", e: string | undefined) => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"initialIsOpen":false},{"id":"def-public.aUnionProperty","type":"CompoundType","label":"aUnionProperty","description":["\nThis is a complicated union type"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":51,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L51"},"signature":["string | number | (() => string) | ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.CrazyClass","text":"CrazyClass"},""],"initialIsOpen":false},{"id":"def-public.aStrArray","type":"Array","label":"aStrArray","description":["\nThis is an array of strings. The type is explicit."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":56,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L56"},"signature":["string[]"],"initialIsOpen":false},{"id":"def-public.aNumArray","type":"Array","label":"aNumArray","description":["\nThis is an array of numbers. The type is implied."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":61,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L61"},"signature":["number[]"],"initialIsOpen":false},{"id":"def-public.aStr","type":"string","label":"aStr","description":["\nA string that says hi to you!"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":66,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L66"},"initialIsOpen":false},{"id":"def-public.aNum","type":"number","label":"aNum","description":["\nIt's a number. A special number."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":71,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L71"},"signature":["10"],"initialIsOpen":false},{"id":"def-public.literalString","type":"string","label":"literalString","description":["\nI'm a type of string, but more specifically, a literal string type."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":76,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L76"},"signature":["\"HI\""],"initialIsOpen":false},{"id":"def-public.StringOrUndefinedType","type":"Type","label":"StringOrUndefinedType","description":["\nHow should a potentially undefined type show up."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":15,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L15"},"signature":["undefined | string"],"initialIsOpen":false},{"id":"def-public.TypeWithGeneric","type":"Type","label":"TypeWithGeneric","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":17,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L17"},"signature":["T[]"],"initialIsOpen":false},{"id":"def-public.ImAType","type":"Type","label":"ImAType","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":19,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L19"},"signature":["string | number | ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAFooPluginApi","section":"def-public.FooType","text":"FooType"}," | ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"}," | ",{"pluginId":"pluginA","scope":"common","docId":"kibPluginAPluginApi","section":"def-common.ImACommonType","text":"ImACommonType"}],"initialIsOpen":false},{"id":"def-public.FnWithGeneric","type":"Type","label":"FnWithGeneric","description":["\nThis is a type that defines a function.\n"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L26"},"signature":["(t: T) => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"initialIsOpen":false},{"id":"def-public.MultipleDeclarationsType","type":"Type","label":"MultipleDeclarationsType","description":["\nCalling node.getSymbol().getDeclarations() will return > 1 declaration."],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":40,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L40"},"signature":["(typeof DayOfWeek)[]"],"initialIsOpen":false},{"id":"def-public.IRefANotExportedType","type":"Type","label":"IRefANotExportedType","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts","lineNumber":42,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/types.ts#L42"},"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAFooPluginApi","section":"def-public.ImNotExportedFromIndex","text":"ImNotExportedFromIndex"}," | { zed: \"hi\"; }"],"initialIsOpen":false}],"objects":[{"id":"def-public.aPretendNamespaceObj","type":"Object","children":[{"id":"def-public.aPretendNamespaceObj.notAnArrowFn","type":"Function","label":"notAnArrowFn","description":["/**\n * The docs should show this inline comment.\n */"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":21,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L21"},"signature":["typeof ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.notAnArrowFn","text":"notAnArrowFn"}]},{"id":"def-public.aPretendNamespaceObj.aPropertyMisdirection","type":"Function","label":"aPropertyMisdirection","description":["/**\n * Should this comment show up?\n */"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L26"},"signature":["typeof ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.notAnArrowFn","text":"notAnArrowFn"}]},{"id":"def-public.aPretendNamespaceObj.aPropertyInlineFn","type":"Function","children":[{"type":"CompoundType","label":"a","isRequired":true,"signature":[{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":31,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L31"}}],"signature":["(a: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},") => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":["/**\n * I'm a property inline fun.\n */"],"label":"aPropertyInlineFn","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":31,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L31"},"returnComment":[]},{"id":"def-public.aPretendNamespaceObj.aPropertyStr","type":"string","label":"aPropertyStr","description":["/**\n * The only way for this to have a comment is to grab this.\n */"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":38,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L38"}},{"id":"def-public.aPretendNamespaceObj.nestedObj","type":"Object","children":[{"id":"def-public.aPretendNamespaceObj.nestedObj.foo","type":"string","label":"foo","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":44,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L44"}}],"description":["/**\n * Will this nested object have it's children extracted appropriately?\n */"],"label":"nestedObj","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":43,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L43"}}],"description":["\nSome of the plugins wrap static exports in an object to create\na namespace like this."],"label":"aPretendNamespaceObj","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts","lineNumber":17,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/const_vars.ts#L17"},"initialIsOpen":false}],"setup":{"id":"def-public.Setup","type":"Interface","label":"Setup","description":["\nAccess setup functionality from your plugin's setup function by adding the example\nplugin as a dependency.\n\n```ts\nClass MyPlugin {\n setup(core: CoreDependencies, { example }: PluginDependencies) {\n // Here you can access this functionality.\n example.getSearchService();\n }\n}\n```"],"children":[{"id":"def-public.Setup.getSearchService","type":"Function","label":"getSearchService","description":["\nA factory function that returns a new instance of Foo based\non the spec. We aren't sure if this is a good function so it's marked\nbeta. That should be clear in the docs because of the js doc tag.\n"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":96,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L96"},"signature":["(searchSpec: ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.SearchSpec","text":"SearchSpec"},") => string"]},{"id":"def-public.Setup.getSearchService2","type":"Function","label":"getSearchService2","description":["\nThis uses an inlined object type rather than referencing an exported type, which is discouraged.\nprefer the way {@link getSearchService} is typed.\n"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":104,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L104"},"signature":["(searchSpec: { username: string; password: string; }) => string"]},{"id":"def-public.Setup.doTheThing","type":"Function","label":"doTheThing","description":["\nThis function does the thing and it's so good at it! But we decided to deprecate it\nanyway. I hope that's clear to developers in the docs!\n"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":117,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L117"},"signature":["(thingOne: number, thingTwo: string, thingThree: { nestedVar: number; }) => void"]},{"id":"def-public.Setup.fnWithInlineParams","type":"Function","label":"fnWithInlineParams","description":["\nWho would write such a complicated function?? Ew, how will the obj parameter appear in docs?\n"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":128,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L128"},"signature":["(obj: { fn: (foo: { param: string; }) => number; }) => () => { retFoo: () => string; }"]},{"id":"def-public.Setup.id","type":"string","label":"id","description":["\nHi, I'm a comment for an id string!"],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":135,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L135"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":84,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L84"},"lifecycle":"setup","initialIsOpen":true},"start":{"id":"def-public.Start","type":"Interface","label":"Start","description":["\nAccess start functionality from your plugin's start function by adding the example\nplugin as a dependency.\n\n```ts\nClass MyPlugin {\n start(core: CoreDependencies, { example }: PluginDependencies) {\n // Here you can access this functionality.\n example.getSearchLanguage();\n }\n}\n```"],"children":[{"id":"def-public.Start.getSearchLanguage","type":"Function","label":"getSearchLanguage","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":68,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L68"},"signature":["() => ",{"pluginId":"pluginA","scope":"public","docId":"kibPluginAPluginApi","section":"def-public.SearchLanguage","text":"SearchLanguage"}]}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts","lineNumber":64,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/plugin.ts#L64"},"lifecycle":"start","initialIsOpen":true}},"server":{"classes":[],"functions":[],"interfaces":[],"enums":[],"misc":[],"objects":[]},"common":{"classes":[],"functions":[],"interfaces":[{"id":"def-common.ImACommonType","type":"Interface","label":"ImACommonType","description":[],"children":[{"id":"def-common.ImACommonType.goo","type":"number","label":"goo","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts","lineNumber":12,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts#L12"}}],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts","lineNumber":11,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/index.ts#L11"},"initialIsOpen":false}],"enums":[],"misc":[],"objects":[]}} \ No newline at end of file diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx new file mode 100644 index 0000000000000..615bf7cb2460d --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a.mdx @@ -0,0 +1,34 @@ +--- +id: kibPluginAPluginApi +slug: /kibana-dev-docs/pluginAPluginApi +title: pluginA +image: https://source.unsplash.com/400x175/?github +summary: API docs for the pluginA plugin +date: 2020-11-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA'] +--- + +import pluginAObj from './plugin_a.json'; + +## Client + +### Setup + +### Start + +### Objects + +### Functions + +### Classes + +### Interfaces + +### Enums + +### Consts, variables and types + +## Common + +### Interfaces + diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.json b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.json new file mode 100644 index 0000000000000..8b5ec5f3da960 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.json @@ -0,0 +1 @@ +{"id":"pluginA.foo","client":{"classes":[],"functions":[{"id":"def-public.doTheFooFnThing","type":"Function","children":[],"signature":["() => void"],"description":[],"label":"doTheFooFnThing","source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts","lineNumber":9,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts#L9"},"returnComment":[],"initialIsOpen":false}],"interfaces":[],"enums":[],"misc":[{"id":"def-public.FooType","type":"Type","label":"FooType","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts","lineNumber":11,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index.ts#L11"},"signature":["() => \"foo\""],"initialIsOpen":false}],"objects":[]},"server":{"classes":[],"functions":[],"interfaces":[],"enums":[],"misc":[],"objects":[]},"common":{"classes":[],"functions":[],"interfaces":[],"enums":[],"misc":[{"id":"def-common.commonFoo","type":"string","label":"commonFoo","description":[],"source":{"path":"/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts","lineNumber":9,"link":"https://github.com/elastic/kibana/tree/master/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/common/foo/index.ts#L9"},"signature":["\"COMMON VAR!\""],"initialIsOpen":false}],"objects":[]}} \ No newline at end of file diff --git a/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx new file mode 100644 index 0000000000000..a4f05fdeb2076 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tests/snapshots/plugin_a_foo.mdx @@ -0,0 +1,22 @@ +--- +id: kibPluginAFooPluginApi +slug: /kibana-dev-docs/pluginA.fooPluginApi +title: pluginA.foo +image: https://source.unsplash.com/400x175/?github +summary: API docs for the pluginA.foo plugin +date: 2020-11-16 +tags: ['contributor', 'dev', 'apidocs', 'kibana', 'pluginA.foo'] +--- + +import pluginAFooObj from './plugin_a_foo.json'; + +## Client + +### Functions + +### Consts, variables and types + +## Common + +### Consts, variables and types + diff --git a/packages/kbn-docs-utils/src/api_docs/tsmorph_utils.ts b/packages/kbn-docs-utils/src/api_docs/tsmorph_utils.ts new file mode 100644 index 0000000000000..f78c538019e2f --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/tsmorph_utils.ts @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { Node, SourceFile, Project } from 'ts-morph'; + +export interface NamedNode extends Node { + getName(): string; +} + +/** + * ts-morph has a Node.isNamedNode fn but it isn't returning true for all types + * that will have node.getName. + */ +export function isNamedNode(node: Node | NamedNode): node is NamedNode { + return (node as NamedNode).getName !== undefined; +} + +/** + * Helper function to find a source file at a given location. Used to extract + * index.ts files at a given scope. + * + * @param project The ts morph project which contains all the source files + * @param absolutePath The absolute path of the file we want to find + * @returns a source file that exists at the location of the relative path. + */ +export function getSourceFileMatching( + project: Project, + absolutePath: string +): SourceFile | undefined { + return project.getSourceFiles().find((file) => { + return file.getFilePath().startsWith(absolutePath); + }); +} diff --git a/packages/kbn-docs-utils/src/api_docs/types.ts b/packages/kbn-docs-utils/src/api_docs/types.ts new file mode 100644 index 0000000000000..c41cd42e6b424 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/types.ts @@ -0,0 +1,200 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export interface AnchorLink { + /** + * The plugin that contains the API being referenced. + */ + pluginName: string; + /** + * It's possible the client and the server both emit an API with + * the same name so we need scope in here to add uniqueness. + */ + scope: ApiScope; + /** + * The name of the api. + */ + apiName: string; +} + +/** + * The kinds of typescript types we want to show in the docs. `Unknown` is used if + * we aren't accounting for a particular type. See {@link getPropertyTypeKind} + */ +export enum TypeKind { + ClassKind = 'Class', + FunctionKind = 'Function', + ObjectKind = 'Object', + EnumKind = 'Enum', + InterfaceKind = 'Interface', + /** + * Maps to the typescript syntax kind `TypeReferences`. For example, + * export type FooFn = () => string will be a TypeKind, not a FunctionKind. + */ + TypeKind = 'Type', + /** + * Uncategorized is used if a type is encountered that isn't handled. + */ + Uncategorized = 'Uncategorized', + UnknownKind = 'Unknown', // Maps to the unknown typescript type + AnyKind = 'Any', // Maps to the any typescript type + StringKind = 'string', + NumberKind = 'number', + BooleanKind = 'boolean', + ArrayKind = 'Array', + /** + * This will cover things like string | number, or A & B, for lack of something better to put here. + */ + CompoundTypeKind = 'CompoundType', +} + +export interface ScopeApi { + setup?: ApiDeclaration; + start?: ApiDeclaration; + functions: ApiDeclaration[]; + objects: ApiDeclaration[]; + classes: ApiDeclaration[]; + interfaces: ApiDeclaration[]; + enums: ApiDeclaration[]; + misc: ApiDeclaration[]; +} + +export interface PluginApi { + id: string; + serviceFolders?: readonly string[]; + client: ApiDeclaration[]; + server: ApiDeclaration[]; + common: ApiDeclaration[]; +} + +/** + * This is used for displaying code or comments that may contain reference links. For example, a function + * signature that is `(a: import("src/plugin_b").Bar) => void` will be parsed into the following Array: + * + * ```ts + * [ + * '(a: ', + * { docId: 'pluginB', section: 'Bar', text: 'Bar' }, + * ') => void' + * ] + * ``` + * + * This is then used to render text with nested DocLinks so it looks like this: + * + * `(a: => ) => void` + */ +export type TextWithLinks = Array; + +/** + * The information neccessary to build a DocLink. + */ +export interface Reference { + pluginId: string; + scope: ApiScope; + docId: string; + section: string; + text: string; +} + +/** + * This type should eventually be replaced by something inside elastic-docs. + * It's what will be passed to an elastic-docs supplied component to make + * the API docs pretty. + */ +export interface ApiDeclaration { + /** + * Used for an anchor link to this Api. Can't use label as there can be two labels with the same + * text within the Client section and the Server section. + */ + id?: string; + + /** + * The name of the api. + */ + label: string; + + /** + * Should the list be expanded or collapsed initially? + */ + initialIsOpen?: boolean; + + /** + * The kind of type this API represents, e.g. string, number, Object, Interface, Class. + */ + type: TypeKind; + + /** + * Certain types have children. For instance classes have class members, functions will list + * their parameters here, classes will list their class members here, and objects and interfaces + * will list their properties. + */ + children?: ApiDeclaration[]; + + /** + * TODO + */ + isRequired?: boolean; + + /** + * Api node comment. + */ + description?: TextWithLinks; + + /** + * If the type is a function, it's signature should be displayed. Currently this overlaps with type + * sometimes, and will sometimes be left empty for large types (like classes and interfaces). + */ + signature?: TextWithLinks; + + /** + * Relevant for functions with @returns comments. + */ + returnComment?: TextWithLinks; + + /** + * Will contain the tags on a comment, like `beta` or `deprecated`. + * Won't include param or returns tags. + */ + tags?: string[]; + + /** + * Every plugn that exposes functionality from their setup and start contract + * should have a single exported type for each. These get pulled to the top because + * they are accessed differently than other exported functionality and types. + */ + lifecycle?: Lifecycle; + + /** + * Used to create links to github to view the code for this API. + */ + source: SourceLink; +} + +export interface SourceLink { + path: string; + lineNumber: number; + link: string; +} + +/** + * Developers will need to know whether these APIs are available on the client, server, or both. + */ +export enum ApiScope { + CLIENT = 'public', + SERVER = 'server', + COMMON = 'common', +} + +/** + * Start and Setup interfaces are special - their functionality is not imported statically but + * accessible via the dependent plugins start and setup functions. + */ +export enum Lifecycle { + START = 'start', + SETUP = 'setup', +} diff --git a/packages/kbn-docs-utils/src/api_docs/utils.test.ts b/packages/kbn-docs-utils/src/api_docs/utils.test.ts new file mode 100644 index 0000000000000..a506405616a47 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/utils.test.ts @@ -0,0 +1,83 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import Path from 'path'; +import { Project } from 'ts-morph'; +import { findPlugins } from './find_plugins'; +import { getPluginApi } from './get_plugin_api'; +import { getKibanaPlatformPlugin } from './tests/kibana_platform_plugin_mock'; +import { PluginApi } from './types'; +import { getPluginForPath, getServiceForPath, removeBrokenLinks } from './utils'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +it('test getPluginForPath', () => { + const plugins = findPlugins(); + const path = Path.resolve(__dirname, '../../../../src/plugins/embeddable/public/service/file.ts'); + expect(getPluginForPath(path, plugins)).toBeDefined(); +}); + +it('test getServiceForPath', () => { + expect(getServiceForPath('src/plugins/embed/public/service/file.ts', 'src/plugins/embed')).toBe( + 'service' + ); + expect( + getServiceForPath('src/plugins/embed/public/service/subfolder/file.ts', 'src/plugins/embed') + ).toBe('service'); + expect( + getServiceForPath('src/plugins/embed/public/file.ts', 'src/plugins/embed') + ).toBeUndefined(); + expect( + getServiceForPath('/src/plugins/embed/server/another_service/index', '/src/plugins/embed') + ).toBe('another_service'); + expect(getServiceForPath('src/plugins/embed/server/no_ending', 'src/plugins/embed')).toBe( + undefined + ); + expect( + getServiceForPath('src/plugins/embed/server/routes/public/foo/index.ts', 'src/plugins/embed') + ).toBe('routes'); + expect(getServiceForPath('src/plugins/embed/server/f.ts', 'src/plugins/embed')).toBeUndefined(); + + expect( + getServiceForPath( + '/var/lib/jenkins/workspace/elastic+kibana+pipeline-pull-request/kibana/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a/public/foo/index', + '/var/lib/jenkins/workspace/elastic+kibana+pipeline-pull-request/kibana/packages/kbn-docs-utils/src/api_docs/tests/__fixtures__/src/plugin_a' + ) + ).toBe('foo'); +}); + +it('test removeBrokenLinks', () => { + const tsConfigFilePath = Path.resolve(__dirname, 'tests/__fixtures__/src/tsconfig.json'); + const project = new Project({ + tsConfigFilePath, + }); + + expect(project.getSourceFiles().length).toBeGreaterThan(0); + + const pluginA = getKibanaPlatformPlugin('pluginA'); + pluginA.manifest.serviceFolders = ['foo']; + const plugins: KibanaPlatformPlugin[] = [pluginA]; + + const pluginApiMap: { [key: string]: PluginApi } = {}; + plugins.map((plugin) => { + pluginApiMap[plugin.manifest.id] = getPluginApi(project, plugin, plugins, log); + }); + + const missingApiItems: { [key: string]: string[] } = {}; + + plugins.forEach((plugin) => { + const id = plugin.manifest.id; + const pluginApi = pluginApiMap[id]; + removeBrokenLinks(pluginApi, missingApiItems, pluginApiMap); + }); + expect(missingApiItems.pluginA.indexOf('public.ImNotExportedFromIndex')).toBeGreaterThan(-1); +}); diff --git a/packages/kbn-docs-utils/src/api_docs/utils.ts b/packages/kbn-docs-utils/src/api_docs/utils.ts new file mode 100644 index 0000000000000..34162aa330911 --- /dev/null +++ b/packages/kbn-docs-utils/src/api_docs/utils.ts @@ -0,0 +1,208 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { + AnchorLink, + ApiDeclaration, + ScopeApi, + TypeKind, + Lifecycle, + PluginApi, + ApiScope, +} from './types'; + +function capitalize(str: string): string { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +export const camelToSnake = (str: string): string => str.replace(/([A-Z])/g, '_$1').toLowerCase(); + +export const snakeToCamel = (str: string): string => + str.replace(/([-_][a-z])/g, (group) => group.toUpperCase().replace('-', '').replace('_', '')); + +/** + * Returns the plugin that the file belongs to. + * @param path An absolute file path that can point to a file nested inside a plugin + * @param plugins A list of plugins to search through. + */ +export function getPluginForPath( + path: string, + plugins: KibanaPlatformPlugin[] +): KibanaPlatformPlugin | undefined { + return plugins.find((plugin) => path.startsWith(plugin.directory)); +} + +/** + * Groups ApiDeclarations by typescript kind - classes, functions, enums, etc, so they + * can be displayed separately in the mdx files. + */ +export function groupPluginApi(declarations: ApiDeclaration[]): ScopeApi { + const scope = createEmptyScope(); + + declarations.forEach((declaration) => { + addApiDeclarationToScope(declaration, scope); + }); + + return scope; +} + +function escapeRegExp(regexp: string) { + return regexp.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +/** + * If the file is at the top level, returns undefined, otherwise returns the + * name of the first nested folder in the plugin. For example a path of + * 'src/plugins/data/public/search_services/file.ts' would return 'search_service' while + * 'src/plugin/data/server/file.ts' would return undefined. + * @param path + */ +export function getServiceForPath(path: string, pluginDirectory: string): string | undefined { + const dir = escapeRegExp(pluginDirectory); + const publicMatchGroups = path.match(`${dir}\/public\/([^\/]*)\/`); + const serverMatchGroups = path.match(`${dir}\/server\/([^\/]*)\/`); + const commonMatchGroups = path.match(`${dir}\/common\/([^\/]*)\/`); + + if (publicMatchGroups && publicMatchGroups.length > 1) { + return publicMatchGroups[1]; + } else if (serverMatchGroups && serverMatchGroups.length > 1) { + return serverMatchGroups[1]; + } else if (commonMatchGroups && commonMatchGroups.length > 1) { + return commonMatchGroups[1]; + } +} + +export function getPluginApiDocId( + id: string, + log: ToolingLog, + serviceInfo?: { + serviceFolders: readonly string[]; + apiPath: string; + directory: string; + } +) { + let service = ''; + const cleanName = id.replace('.', '_'); + if (serviceInfo) { + const serviceName = getServiceForPath(serviceInfo.apiPath, serviceInfo.directory); + log.debug( + `Service for path ${serviceInfo.apiPath} and ${serviceInfo.directory} is ${serviceName}` + ); + const serviceFolder = serviceInfo.serviceFolders?.find((f) => f === serviceName); + + if (serviceFolder) { + service = snakeToCamel(serviceFolder); + } + } + + return `kib${capitalize(snakeToCamel(cleanName)) + capitalize(service)}PluginApi`; +} + +export function getApiSectionId(link: AnchorLink) { + const id = `def-${link.scope}.${link.apiName}`.replace(' ', '-'); + return id; +} + +export function countScopeApi(api: ScopeApi): number { + return ( + (api.setup ? 1 : 0) + + (api.start ? 1 : 0) + + api.classes.length + + api.interfaces.length + + api.functions.length + + api.objects.length + + api.enums.length + + api.misc.length + ); +} + +export function createEmptyScope(): ScopeApi { + return { + classes: [], + functions: [], + interfaces: [], + enums: [], + misc: [], + objects: [], + }; +} + +/** + * Takes the ApiDeclaration and puts it in the appropriate section of the ScopeApi based + * on its TypeKind. + */ +export function addApiDeclarationToScope(declaration: ApiDeclaration, scope: ScopeApi): void { + if (declaration.lifecycle === Lifecycle.SETUP) { + scope.setup = declaration; + } else if (declaration.lifecycle === Lifecycle.START) { + scope.start = declaration; + } else { + switch (declaration.type) { + case TypeKind.ClassKind: + scope.classes.push(declaration); + break; + case TypeKind.InterfaceKind: + scope.interfaces.push(declaration); + break; + case TypeKind.EnumKind: + scope.enums.push(declaration); + break; + case TypeKind.FunctionKind: + scope.functions.push(declaration); + break; + case TypeKind.ObjectKind: + scope.objects.push(declaration); + break; + default: + scope.misc.push(declaration); + } + } +} + +export function removeBrokenLinks( + pluginApi: PluginApi, + missingApiItems: { [key: string]: string[] }, + pluginApiMap: { [key: string]: PluginApi } +) { + (['client', 'common', 'server'] as Array<'client' | 'server' | 'common'>).forEach((scope) => { + pluginApi[scope].forEach((api) => { + if (api.signature) { + api.signature = api.signature.map((sig) => { + if (typeof sig !== 'string') { + if (apiItemExists(sig.text, sig.scope, pluginApiMap[sig.pluginId]) === false) { + if (missingApiItems[sig.pluginId] === undefined) { + missingApiItems[sig.pluginId] = []; + } + missingApiItems[sig.pluginId].push(`${sig.scope}.${sig.text}`); + return sig.text; + } + } + return sig; + }); + } + }); + }); +} + +function apiItemExists(name: string, scope: ApiScope, pluginApi: PluginApi): boolean { + return ( + pluginApi[scopeAccessor(scope)].findIndex((dec: ApiDeclaration) => dec.label === name) >= 0 + ); +} + +function scopeAccessor(scope: ApiScope): 'server' | 'common' | 'client' { + switch (scope) { + case ApiScope.CLIENT: + return 'client'; + case ApiScope.SERVER: + return 'server'; + default: + return 'common'; + } +} diff --git a/packages/kbn-docs-utils/src/index.ts b/packages/kbn-docs-utils/src/index.ts new file mode 100644 index 0000000000000..24aef1bf891f6 --- /dev/null +++ b/packages/kbn-docs-utils/src/index.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export * from './release_notes'; +export * from './api_docs'; diff --git a/packages/kbn-release-notes/src/cli.ts b/packages/kbn-docs-utils/src/release_notes/cli.ts similarity index 100% rename from packages/kbn-release-notes/src/cli.ts rename to packages/kbn-docs-utils/src/release_notes/cli.ts diff --git a/packages/kbn-release-notes/src/formats/asciidoc.ts b/packages/kbn-docs-utils/src/release_notes/formats/asciidoc.ts similarity index 100% rename from packages/kbn-release-notes/src/formats/asciidoc.ts rename to packages/kbn-docs-utils/src/release_notes/formats/asciidoc.ts diff --git a/packages/kbn-release-notes/src/formats/csv.ts b/packages/kbn-docs-utils/src/release_notes/formats/csv.ts similarity index 100% rename from packages/kbn-release-notes/src/formats/csv.ts rename to packages/kbn-docs-utils/src/release_notes/formats/csv.ts diff --git a/packages/kbn-release-notes/src/formats/format.ts b/packages/kbn-docs-utils/src/release_notes/formats/format.ts similarity index 100% rename from packages/kbn-release-notes/src/formats/format.ts rename to packages/kbn-docs-utils/src/release_notes/formats/format.ts diff --git a/packages/kbn-release-notes/src/formats/index.ts b/packages/kbn-docs-utils/src/release_notes/formats/index.ts similarity index 100% rename from packages/kbn-release-notes/src/formats/index.ts rename to packages/kbn-docs-utils/src/release_notes/formats/index.ts diff --git a/packages/kbn-release-notes/src/index.ts b/packages/kbn-docs-utils/src/release_notes/index.ts similarity index 100% rename from packages/kbn-release-notes/src/index.ts rename to packages/kbn-docs-utils/src/release_notes/index.ts diff --git a/packages/kbn-release-notes/src/lib/classify_pr.ts b/packages/kbn-docs-utils/src/release_notes/lib/classify_pr.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/classify_pr.ts rename to packages/kbn-docs-utils/src/release_notes/lib/classify_pr.ts diff --git a/packages/kbn-release-notes/src/lib/get_fix_references.test.ts b/packages/kbn-docs-utils/src/release_notes/lib/get_fix_references.test.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/get_fix_references.test.ts rename to packages/kbn-docs-utils/src/release_notes/lib/get_fix_references.test.ts diff --git a/packages/kbn-release-notes/src/lib/get_fix_references.ts b/packages/kbn-docs-utils/src/release_notes/lib/get_fix_references.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/get_fix_references.ts rename to packages/kbn-docs-utils/src/release_notes/lib/get_fix_references.ts diff --git a/packages/kbn-release-notes/src/lib/get_note_from_description.test.ts b/packages/kbn-docs-utils/src/release_notes/lib/get_note_from_description.test.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/get_note_from_description.test.ts rename to packages/kbn-docs-utils/src/release_notes/lib/get_note_from_description.test.ts diff --git a/packages/kbn-release-notes/src/lib/get_note_from_description.ts b/packages/kbn-docs-utils/src/release_notes/lib/get_note_from_description.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/get_note_from_description.ts rename to packages/kbn-docs-utils/src/release_notes/lib/get_note_from_description.ts diff --git a/packages/kbn-release-notes/src/lib/index.ts b/packages/kbn-docs-utils/src/release_notes/lib/index.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/index.ts rename to packages/kbn-docs-utils/src/release_notes/lib/index.ts diff --git a/packages/kbn-release-notes/src/lib/irrelevant_pr_summary.ts b/packages/kbn-docs-utils/src/release_notes/lib/irrelevant_pr_summary.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/irrelevant_pr_summary.ts rename to packages/kbn-docs-utils/src/release_notes/lib/irrelevant_pr_summary.ts diff --git a/packages/kbn-release-notes/src/lib/is_pr_relevant.ts b/packages/kbn-docs-utils/src/release_notes/lib/is_pr_relevant.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/is_pr_relevant.ts rename to packages/kbn-docs-utils/src/release_notes/lib/is_pr_relevant.ts diff --git a/packages/kbn-release-notes/src/lib/pr_api.ts b/packages/kbn-docs-utils/src/release_notes/lib/pr_api.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/pr_api.ts rename to packages/kbn-docs-utils/src/release_notes/lib/pr_api.ts diff --git a/packages/kbn-release-notes/src/lib/streams.ts b/packages/kbn-docs-utils/src/release_notes/lib/streams.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/streams.ts rename to packages/kbn-docs-utils/src/release_notes/lib/streams.ts diff --git a/packages/kbn-release-notes/src/lib/type_helpers.ts b/packages/kbn-docs-utils/src/release_notes/lib/type_helpers.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/type_helpers.ts rename to packages/kbn-docs-utils/src/release_notes/lib/type_helpers.ts diff --git a/packages/kbn-release-notes/src/lib/version.test.ts b/packages/kbn-docs-utils/src/release_notes/lib/version.test.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/version.test.ts rename to packages/kbn-docs-utils/src/release_notes/lib/version.test.ts diff --git a/packages/kbn-release-notes/src/lib/version.ts b/packages/kbn-docs-utils/src/release_notes/lib/version.ts similarity index 100% rename from packages/kbn-release-notes/src/lib/version.ts rename to packages/kbn-docs-utils/src/release_notes/lib/version.ts diff --git a/packages/kbn-release-notes/src/release_notes_config.ts b/packages/kbn-docs-utils/src/release_notes/release_notes_config.ts similarity index 100% rename from packages/kbn-release-notes/src/release_notes_config.ts rename to packages/kbn-docs-utils/src/release_notes/release_notes_config.ts diff --git a/packages/kbn-release-notes/tsconfig.json b/packages/kbn-docs-utils/tsconfig.json similarity index 81% rename from packages/kbn-release-notes/tsconfig.json rename to packages/kbn-docs-utils/tsconfig.json index 02209a29e5817..3c683f487b9f2 100644 --- a/packages/kbn-release-notes/tsconfig.json +++ b/packages/kbn-docs-utils/tsconfig.json @@ -8,5 +8,8 @@ }, "include": [ "src/**/*" + ], + "exclude": [ + "**/__fixtures__/**/*" ] } diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 51e8a617e2446..f9ddbcac1e09d 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -94,7 +94,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _cli__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "run", function() { return _cli__WEBPACK_IMPORTED_MODULE_0__["run"]; }); -/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(519); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(518); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildBazelProductionProjects"]; }); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildNonBazelProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildNonBazelProductionProjects"]; }); @@ -108,7 +108,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(251); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "transformDependencies", function() { return _utils_package_json__WEBPACK_IMPORTED_MODULE_4__["transformDependencies"]; }); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(518); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(517); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; }); /* @@ -59481,7 +59481,7 @@ __webpack_require__.r(__webpack_exports__); /* harmony import */ var is_path_inside__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(is_path_inside__WEBPACK_IMPORTED_MODULE_2__); /* harmony import */ var _yarn_lock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(365); /* harmony import */ var _projects__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(248); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(518); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(517); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } @@ -59638,9 +59638,9 @@ class Kibana { "use strict"; const minimatch = __webpack_require__(150); -const arrayUnion = __webpack_require__(515); -const arrayDiffer = __webpack_require__(516); -const arrify = __webpack_require__(517); +const arrayUnion = __webpack_require__(145); +const arrayDiffer = __webpack_require__(515); +const arrify = __webpack_require__(516); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -59670,18 +59670,6 @@ module.exports = (list, patterns, options = {}) => { "use strict"; -module.exports = (...arguments_) => { - return [...new Set([].concat(...arguments_))]; -}; - - -/***/ }), -/* 516 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - const arrayDiffer = (array, ...values) => { const rest = new Set([].concat(...values)); return array.filter(element => !rest.has(element)); @@ -59691,7 +59679,7 @@ module.exports = arrayDiffer; /***/ }), -/* 517 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59721,7 +59709,7 @@ module.exports = arrify; /***/ }), -/* 518 */ +/* 517 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -59780,12 +59768,12 @@ function getProjectPaths({ } /***/ }), -/* 519 */ +/* 518 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(520); +/* harmony import */ var _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(519); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return _build_bazel_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildBazelProductionProjects"]; }); /* harmony import */ var _build_non_bazel_production_projects__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(745); @@ -59802,15 +59790,15 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 520 */ +/* 519 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildBazelProductionProjects", function() { return buildBazelProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(521); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(520); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(737); +/* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(736); /* harmony import */ var globby__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(globby__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); @@ -59910,7 +59898,7 @@ async function applyCorrectPermissions(project, kibanaRoot, buildRoot) { } /***/ }), -/* 521 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59918,14 +59906,14 @@ async function applyCorrectPermissions(project, kibanaRoot, buildRoot) { const EventEmitter = __webpack_require__(156); const path = __webpack_require__(4); const os = __webpack_require__(121); -const pMap = __webpack_require__(522); -const arrify = __webpack_require__(517); -const globby = __webpack_require__(525); -const hasGlob = __webpack_require__(721); -const cpFile = __webpack_require__(723); -const junk = __webpack_require__(733); -const pFilter = __webpack_require__(734); -const CpyError = __webpack_require__(736); +const pMap = __webpack_require__(521); +const arrify = __webpack_require__(516); +const globby = __webpack_require__(524); +const hasGlob = __webpack_require__(720); +const cpFile = __webpack_require__(722); +const junk = __webpack_require__(732); +const pFilter = __webpack_require__(733); +const CpyError = __webpack_require__(735); const defaultOptions = { ignoreJunk: true @@ -60076,12 +60064,12 @@ module.exports = (source, destination, { /***/ }), -/* 522 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const AggregateError = __webpack_require__(523); +const AggregateError = __webpack_require__(522); module.exports = async ( iterable, @@ -60164,12 +60152,12 @@ module.exports = async ( /***/ }), -/* 523 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const indentString = __webpack_require__(524); +const indentString = __webpack_require__(523); const cleanStack = __webpack_require__(244); const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); @@ -60218,7 +60206,7 @@ module.exports = AggregateError; /***/ }), -/* 524 */ +/* 523 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60260,17 +60248,17 @@ module.exports = (string, count = 1, options) => { /***/ }), -/* 525 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(526); +const arrayUnion = __webpack_require__(525); const glob = __webpack_require__(147); -const fastGlob = __webpack_require__(528); -const dirGlob = __webpack_require__(714); -const gitignore = __webpack_require__(717); +const fastGlob = __webpack_require__(527); +const dirGlob = __webpack_require__(713); +const gitignore = __webpack_require__(716); const DEFAULT_FILTER = () => false; @@ -60415,12 +60403,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 526 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(527); +var arrayUniq = __webpack_require__(526); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -60428,7 +60416,7 @@ module.exports = function () { /***/ }), -/* 527 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60497,10 +60485,10 @@ if ('Set' in global) { /***/ }), -/* 528 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(529); +const pkg = __webpack_require__(528); module.exports = pkg.async; module.exports.default = pkg.async; @@ -60513,19 +60501,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 529 */ +/* 528 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(530); -var taskManager = __webpack_require__(531); -var reader_async_1 = __webpack_require__(685); -var reader_stream_1 = __webpack_require__(709); -var reader_sync_1 = __webpack_require__(710); -var arrayUtils = __webpack_require__(712); -var streamUtils = __webpack_require__(713); +var optionsManager = __webpack_require__(529); +var taskManager = __webpack_require__(530); +var reader_async_1 = __webpack_require__(684); +var reader_stream_1 = __webpack_require__(708); +var reader_sync_1 = __webpack_require__(709); +var arrayUtils = __webpack_require__(711); +var streamUtils = __webpack_require__(712); /** * Synchronous API. */ @@ -60591,7 +60579,7 @@ function isString(source) { /***/ }), -/* 530 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60629,13 +60617,13 @@ exports.prepare = prepare; /***/ }), -/* 531 */ +/* 530 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(532); +var patternUtils = __webpack_require__(531); /** * Generate tasks based on parent directory of each pattern. */ @@ -60726,16 +60714,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 532 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(533); +var globParent = __webpack_require__(532); var isGlob = __webpack_require__(172); -var micromatch = __webpack_require__(536); +var micromatch = __webpack_require__(535); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -60881,15 +60869,15 @@ exports.matchAny = matchAny; /***/ }), -/* 533 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(4); -var isglob = __webpack_require__(534); -var pathDirname = __webpack_require__(535); +var isglob = __webpack_require__(533); +var pathDirname = __webpack_require__(534); var isWin32 = __webpack_require__(121).platform() === 'win32'; module.exports = function globParent(str) { @@ -60912,7 +60900,7 @@ module.exports = function globParent(str) { /***/ }), -/* 534 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -60943,7 +60931,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 535 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61093,7 +61081,7 @@ module.exports.win32 = win32; /***/ }), -/* 536 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61104,18 +61092,18 @@ module.exports.win32 = win32; */ var util = __webpack_require__(112); -var braces = __webpack_require__(537); -var toRegex = __webpack_require__(538); -var extend = __webpack_require__(651); +var braces = __webpack_require__(536); +var toRegex = __webpack_require__(537); +var extend = __webpack_require__(650); /** * Local dependencies */ -var compilers = __webpack_require__(653); -var parsers = __webpack_require__(680); -var cache = __webpack_require__(681); -var utils = __webpack_require__(682); +var compilers = __webpack_require__(652); +var parsers = __webpack_require__(679); +var cache = __webpack_require__(680); +var utils = __webpack_require__(681); var MAX_LENGTH = 1024 * 64; /** @@ -61977,7 +61965,7 @@ module.exports = micromatch; /***/ }), -/* 537 */ +/* 536 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61987,18 +61975,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(538); -var unique = __webpack_require__(560); -var extend = __webpack_require__(561); +var toRegex = __webpack_require__(537); +var unique = __webpack_require__(559); +var extend = __webpack_require__(560); /** * Local dependencies */ -var compilers = __webpack_require__(563); -var parsers = __webpack_require__(576); -var Braces = __webpack_require__(580); -var utils = __webpack_require__(564); +var compilers = __webpack_require__(562); +var parsers = __webpack_require__(575); +var Braces = __webpack_require__(579); +var utils = __webpack_require__(563); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -62302,16 +62290,16 @@ module.exports = braces; /***/ }), -/* 538 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(539); -var define = __webpack_require__(545); -var extend = __webpack_require__(553); -var not = __webpack_require__(557); +var safe = __webpack_require__(538); +var define = __webpack_require__(544); +var extend = __webpack_require__(552); +var not = __webpack_require__(556); var MAX_LENGTH = 1024 * 64; /** @@ -62464,10 +62452,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 539 */ +/* 538 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(540); +var parse = __webpack_require__(539); var types = parse.types; module.exports = function (re, opts) { @@ -62513,13 +62501,13 @@ function isRegExp (x) { /***/ }), -/* 540 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(541); -var types = __webpack_require__(542); -var sets = __webpack_require__(543); -var positions = __webpack_require__(544); +var util = __webpack_require__(540); +var types = __webpack_require__(541); +var sets = __webpack_require__(542); +var positions = __webpack_require__(543); module.exports = function(regexpStr) { @@ -62801,11 +62789,11 @@ module.exports.types = types; /***/ }), -/* 541 */ +/* 540 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(542); -var sets = __webpack_require__(543); +var types = __webpack_require__(541); +var sets = __webpack_require__(542); // All of these are private and only used by randexp. @@ -62918,7 +62906,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 542 */ +/* 541 */ /***/ (function(module, exports) { module.exports = { @@ -62934,10 +62922,10 @@ module.exports = { /***/ }), -/* 543 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(542); +var types = __webpack_require__(541); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -63022,10 +63010,10 @@ exports.anyChar = function() { /***/ }), -/* 544 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(542); +var types = __webpack_require__(541); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -63045,7 +63033,7 @@ exports.end = function() { /***/ }), -/* 545 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63058,8 +63046,8 @@ exports.end = function() { -var isobject = __webpack_require__(546); -var isDescriptor = __webpack_require__(547); +var isobject = __webpack_require__(545); +var isDescriptor = __webpack_require__(546); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -63090,7 +63078,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 546 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63109,7 +63097,7 @@ module.exports = function isObject(val) { /***/ }), -/* 547 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63122,9 +63110,9 @@ module.exports = function isObject(val) { -var typeOf = __webpack_require__(548); -var isAccessor = __webpack_require__(549); -var isData = __webpack_require__(551); +var typeOf = __webpack_require__(547); +var isAccessor = __webpack_require__(548); +var isData = __webpack_require__(550); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -63138,7 +63126,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 548 */ +/* 547 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -63273,7 +63261,7 @@ function isBuffer(val) { /***/ }), -/* 549 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63286,7 +63274,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(550); +var typeOf = __webpack_require__(549); // accessor descriptor properties var accessor = { @@ -63349,7 +63337,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 550 */ +/* 549 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -63484,7 +63472,7 @@ function isBuffer(val) { /***/ }), -/* 551 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63497,7 +63485,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(552); +var typeOf = __webpack_require__(551); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -63540,7 +63528,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 552 */ +/* 551 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -63675,14 +63663,14 @@ function isBuffer(val) { /***/ }), -/* 553 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(554); -var assignSymbols = __webpack_require__(556); +var isExtendable = __webpack_require__(553); +var assignSymbols = __webpack_require__(555); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -63742,7 +63730,7 @@ function isEnum(obj, key) { /***/ }), -/* 554 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63755,7 +63743,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(555); +var isPlainObject = __webpack_require__(554); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -63763,7 +63751,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 555 */ +/* 554 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63776,7 +63764,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(546); +var isObject = __webpack_require__(545); function isObjectObject(o) { return isObject(o) === true @@ -63807,7 +63795,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 556 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63854,14 +63842,14 @@ module.exports = function(receiver, objects) { /***/ }), -/* 557 */ +/* 556 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(558); -var safe = __webpack_require__(539); +var extend = __webpack_require__(557); +var safe = __webpack_require__(538); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -63933,14 +63921,14 @@ module.exports = toRegex; /***/ }), -/* 558 */ +/* 557 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(559); -var assignSymbols = __webpack_require__(556); +var isExtendable = __webpack_require__(558); +var assignSymbols = __webpack_require__(555); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -64000,7 +63988,7 @@ function isEnum(obj, key) { /***/ }), -/* 559 */ +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64013,7 +64001,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(555); +var isPlainObject = __webpack_require__(554); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -64021,7 +64009,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 560 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64071,13 +64059,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 561 */ +/* 560 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(562); +var isObject = __webpack_require__(561); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -64111,7 +64099,7 @@ function hasOwn(obj, key) { /***/ }), -/* 562 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64131,13 +64119,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 563 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(564); +var utils = __webpack_require__(563); module.exports = function(braces, options) { braces.compiler @@ -64420,25 +64408,25 @@ function hasQueue(node) { /***/ }), -/* 564 */ +/* 563 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(565); +var splitString = __webpack_require__(564); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(561); -utils.flatten = __webpack_require__(568); -utils.isObject = __webpack_require__(546); -utils.fillRange = __webpack_require__(569); -utils.repeat = __webpack_require__(575); -utils.unique = __webpack_require__(560); +utils.extend = __webpack_require__(560); +utils.flatten = __webpack_require__(567); +utils.isObject = __webpack_require__(545); +utils.fillRange = __webpack_require__(568); +utils.repeat = __webpack_require__(574); +utils.unique = __webpack_require__(559); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -64770,7 +64758,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 565 */ +/* 564 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64783,7 +64771,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(566); +var extend = __webpack_require__(565); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -64948,14 +64936,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 566 */ +/* 565 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(567); -var assignSymbols = __webpack_require__(556); +var isExtendable = __webpack_require__(566); +var assignSymbols = __webpack_require__(555); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -65015,7 +65003,7 @@ function isEnum(obj, key) { /***/ }), -/* 567 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65028,7 +65016,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(555); +var isPlainObject = __webpack_require__(554); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -65036,7 +65024,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 568 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65065,7 +65053,7 @@ function flat(arr, res) { /***/ }), -/* 569 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65079,10 +65067,10 @@ function flat(arr, res) { var util = __webpack_require__(112); -var isNumber = __webpack_require__(570); -var extend = __webpack_require__(561); -var repeat = __webpack_require__(573); -var toRegex = __webpack_require__(574); +var isNumber = __webpack_require__(569); +var extend = __webpack_require__(560); +var repeat = __webpack_require__(572); +var toRegex = __webpack_require__(573); /** * Return a range of numbers or letters. @@ -65280,7 +65268,7 @@ module.exports = fillRange; /***/ }), -/* 570 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65293,7 +65281,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(571); +var typeOf = __webpack_require__(570); module.exports = function isNumber(num) { var type = typeOf(num); @@ -65309,10 +65297,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 571 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(572); +var isBuffer = __webpack_require__(571); var toString = Object.prototype.toString; /** @@ -65431,7 +65419,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 572 */ +/* 571 */ /***/ (function(module, exports) { /*! @@ -65458,7 +65446,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 573 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65535,7 +65523,7 @@ function repeat(str, num) { /***/ }), -/* 574 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65548,8 +65536,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(573); -var isNumber = __webpack_require__(570); +var repeat = __webpack_require__(572); +var isNumber = __webpack_require__(569); var cache = {}; function toRegexRange(min, max, options) { @@ -65836,7 +65824,7 @@ module.exports = toRegexRange; /***/ }), -/* 575 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65861,14 +65849,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 576 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(577); -var utils = __webpack_require__(564); +var Node = __webpack_require__(576); +var utils = __webpack_require__(563); /** * Braces parsers @@ -66228,15 +66216,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 577 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(546); -var define = __webpack_require__(578); -var utils = __webpack_require__(579); +var isObject = __webpack_require__(545); +var define = __webpack_require__(577); +var utils = __webpack_require__(578); var ownNames; /** @@ -66727,7 +66715,7 @@ exports = module.exports = Node; /***/ }), -/* 578 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66740,7 +66728,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(547); +var isDescriptor = __webpack_require__(546); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -66765,13 +66753,13 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 579 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(571); +var typeOf = __webpack_require__(570); var utils = module.exports; /** @@ -67791,17 +67779,17 @@ function assert(val, message) { /***/ }), -/* 580 */ +/* 579 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(561); -var Snapdragon = __webpack_require__(581); -var compilers = __webpack_require__(563); -var parsers = __webpack_require__(576); -var utils = __webpack_require__(564); +var extend = __webpack_require__(560); +var Snapdragon = __webpack_require__(580); +var compilers = __webpack_require__(562); +var parsers = __webpack_require__(575); +var utils = __webpack_require__(563); /** * Customize Snapdragon parser and renderer @@ -67902,17 +67890,17 @@ module.exports = Braces; /***/ }), -/* 581 */ +/* 580 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(582); -var define = __webpack_require__(609); -var Compiler = __webpack_require__(619); -var Parser = __webpack_require__(648); -var utils = __webpack_require__(628); +var Base = __webpack_require__(581); +var define = __webpack_require__(608); +var Compiler = __webpack_require__(618); +var Parser = __webpack_require__(647); +var utils = __webpack_require__(627); var regexCache = {}; var cache = {}; @@ -68083,20 +68071,20 @@ module.exports.Parser = Parser; /***/ }), -/* 582 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var define = __webpack_require__(583); -var CacheBase = __webpack_require__(584); -var Emitter = __webpack_require__(585); -var isObject = __webpack_require__(546); -var merge = __webpack_require__(603); -var pascal = __webpack_require__(606); -var cu = __webpack_require__(607); +var define = __webpack_require__(582); +var CacheBase = __webpack_require__(583); +var Emitter = __webpack_require__(584); +var isObject = __webpack_require__(545); +var merge = __webpack_require__(602); +var pascal = __webpack_require__(605); +var cu = __webpack_require__(606); /** * Optionally define a custom `cache` namespace to use. @@ -68525,7 +68513,7 @@ module.exports.namespace = namespace; /***/ }), -/* 583 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68538,7 +68526,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(547); +var isDescriptor = __webpack_require__(546); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -68563,21 +68551,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 584 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(546); -var Emitter = __webpack_require__(585); -var visit = __webpack_require__(586); -var toPath = __webpack_require__(589); -var union = __webpack_require__(590); -var del = __webpack_require__(594); -var get = __webpack_require__(592); -var has = __webpack_require__(599); -var set = __webpack_require__(602); +var isObject = __webpack_require__(545); +var Emitter = __webpack_require__(584); +var visit = __webpack_require__(585); +var toPath = __webpack_require__(588); +var union = __webpack_require__(589); +var del = __webpack_require__(593); +var get = __webpack_require__(591); +var has = __webpack_require__(598); +var set = __webpack_require__(601); /** * Create a `Cache` constructor that when instantiated will @@ -68831,7 +68819,7 @@ module.exports.namespace = namespace; /***/ }), -/* 585 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { @@ -69000,7 +68988,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 586 */ +/* 585 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69013,8 +69001,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(587); -var mapVisit = __webpack_require__(588); +var visit = __webpack_require__(586); +var mapVisit = __webpack_require__(587); module.exports = function(collection, method, val) { var result; @@ -69037,7 +69025,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 587 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69050,7 +69038,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(546); +var isObject = __webpack_require__(545); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -69077,14 +69065,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 588 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var visit = __webpack_require__(587); +var visit = __webpack_require__(586); /** * Map `visit` over an array of objects. @@ -69121,7 +69109,7 @@ function isObject(val) { /***/ }), -/* 589 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69134,7 +69122,7 @@ function isObject(val) { -var typeOf = __webpack_require__(571); +var typeOf = __webpack_require__(570); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -69161,16 +69149,16 @@ function filter(arr) { /***/ }), -/* 590 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(562); -var union = __webpack_require__(591); -var get = __webpack_require__(592); -var set = __webpack_require__(593); +var isObject = __webpack_require__(561); +var union = __webpack_require__(590); +var get = __webpack_require__(591); +var set = __webpack_require__(592); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -69198,7 +69186,7 @@ function arrayify(val) { /***/ }), -/* 591 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69234,7 +69222,7 @@ module.exports = function union(init) { /***/ }), -/* 592 */ +/* 591 */ /***/ (function(module, exports) { /*! @@ -69290,7 +69278,7 @@ function toString(val) { /***/ }), -/* 593 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69303,10 +69291,10 @@ function toString(val) { -var split = __webpack_require__(565); -var extend = __webpack_require__(561); -var isPlainObject = __webpack_require__(555); -var isObject = __webpack_require__(562); +var split = __webpack_require__(564); +var extend = __webpack_require__(560); +var isPlainObject = __webpack_require__(554); +var isObject = __webpack_require__(561); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -69352,7 +69340,7 @@ function isValidKey(key) { /***/ }), -/* 594 */ +/* 593 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69365,8 +69353,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(546); -var has = __webpack_require__(595); +var isObject = __webpack_require__(545); +var has = __webpack_require__(594); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -69391,7 +69379,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 595 */ +/* 594 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69404,9 +69392,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(596); -var hasValues = __webpack_require__(598); -var get = __webpack_require__(592); +var isObject = __webpack_require__(595); +var hasValues = __webpack_require__(597); +var get = __webpack_require__(591); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -69417,7 +69405,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 596 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69430,7 +69418,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(597); +var isArray = __webpack_require__(596); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -69438,7 +69426,7 @@ module.exports = function isObject(val) { /***/ }), -/* 597 */ +/* 596 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -69449,7 +69437,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 598 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69492,7 +69480,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 599 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69505,9 +69493,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(546); -var hasValues = __webpack_require__(600); -var get = __webpack_require__(592); +var isObject = __webpack_require__(545); +var hasValues = __webpack_require__(599); +var get = __webpack_require__(591); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -69515,7 +69503,7 @@ module.exports = function(val, prop) { /***/ }), -/* 600 */ +/* 599 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69528,8 +69516,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(601); -var isNumber = __webpack_require__(570); +var typeOf = __webpack_require__(600); +var isNumber = __webpack_require__(569); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -69582,10 +69570,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 601 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(572); +var isBuffer = __webpack_require__(571); var toString = Object.prototype.toString; /** @@ -69707,7 +69695,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 602 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69720,10 +69708,10 @@ module.exports = function kindOf(val) { -var split = __webpack_require__(565); -var extend = __webpack_require__(561); -var isPlainObject = __webpack_require__(555); -var isObject = __webpack_require__(562); +var split = __webpack_require__(564); +var extend = __webpack_require__(560); +var isPlainObject = __webpack_require__(554); +var isObject = __webpack_require__(561); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -69769,14 +69757,14 @@ function isValidKey(key) { /***/ }), -/* 603 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(604); -var forIn = __webpack_require__(605); +var isExtendable = __webpack_require__(603); +var forIn = __webpack_require__(604); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -69840,7 +69828,7 @@ module.exports = mixinDeep; /***/ }), -/* 604 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69853,7 +69841,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(555); +var isPlainObject = __webpack_require__(554); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -69861,7 +69849,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 605 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69884,7 +69872,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 606 */ +/* 605 */ /***/ (function(module, exports) { /*! @@ -69911,14 +69899,14 @@ module.exports = pascalcase; /***/ }), -/* 607 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var utils = __webpack_require__(608); +var utils = __webpack_require__(607); /** * Expose class utils @@ -70283,7 +70271,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 608 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70297,10 +70285,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(591); -utils.define = __webpack_require__(609); -utils.isObj = __webpack_require__(546); -utils.staticExtend = __webpack_require__(616); +utils.union = __webpack_require__(590); +utils.define = __webpack_require__(608); +utils.isObj = __webpack_require__(545); +utils.staticExtend = __webpack_require__(615); /** @@ -70311,7 +70299,7 @@ module.exports = utils; /***/ }), -/* 609 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70324,7 +70312,7 @@ module.exports = utils; -var isDescriptor = __webpack_require__(610); +var isDescriptor = __webpack_require__(609); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -70349,7 +70337,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 610 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70362,9 +70350,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(611); -var isAccessor = __webpack_require__(612); -var isData = __webpack_require__(614); +var typeOf = __webpack_require__(610); +var isAccessor = __webpack_require__(611); +var isData = __webpack_require__(613); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -70378,7 +70366,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 611 */ +/* 610 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -70531,7 +70519,7 @@ function isBuffer(val) { /***/ }), -/* 612 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70544,7 +70532,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(613); +var typeOf = __webpack_require__(612); // accessor descriptor properties var accessor = { @@ -70607,10 +70595,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 613 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(572); +var isBuffer = __webpack_require__(571); var toString = Object.prototype.toString; /** @@ -70729,7 +70717,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 614 */ +/* 613 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70742,7 +70730,7 @@ module.exports = function kindOf(val) { -var typeOf = __webpack_require__(615); +var typeOf = __webpack_require__(614); // data descriptor properties var data = { @@ -70791,10 +70779,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 615 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(572); +var isBuffer = __webpack_require__(571); var toString = Object.prototype.toString; /** @@ -70913,7 +70901,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 616 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70926,8 +70914,8 @@ module.exports = function kindOf(val) { -var copy = __webpack_require__(617); -var define = __webpack_require__(609); +var copy = __webpack_require__(616); +var define = __webpack_require__(608); var util = __webpack_require__(112); /** @@ -71010,15 +70998,15 @@ module.exports = extend; /***/ }), -/* 617 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(571); -var copyDescriptor = __webpack_require__(618); -var define = __webpack_require__(609); +var typeOf = __webpack_require__(570); +var copyDescriptor = __webpack_require__(617); +var define = __webpack_require__(608); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -71191,7 +71179,7 @@ module.exports.has = has; /***/ }), -/* 618 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71279,16 +71267,16 @@ function isObject(val) { /***/ }), -/* 619 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(620); -var define = __webpack_require__(609); -var debug = __webpack_require__(622)('snapdragon:compiler'); -var utils = __webpack_require__(628); +var use = __webpack_require__(619); +var define = __webpack_require__(608); +var debug = __webpack_require__(621)('snapdragon:compiler'); +var utils = __webpack_require__(627); /** * Create a new `Compiler` with the given `options`. @@ -71442,7 +71430,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(647); + var sourcemaps = __webpack_require__(646); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -71463,7 +71451,7 @@ module.exports = Compiler; /***/ }), -/* 620 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71476,7 +71464,7 @@ module.exports = Compiler; -var utils = __webpack_require__(621); +var utils = __webpack_require__(620); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -71591,7 +71579,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 621 */ +/* 620 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71605,8 +71593,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(609); -utils.isObject = __webpack_require__(546); +utils.define = __webpack_require__(608); +utils.isObject = __webpack_require__(545); utils.isString = function(val) { @@ -71621,7 +71609,7 @@ module.exports = utils; /***/ }), -/* 622 */ +/* 621 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71630,14 +71618,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(623); + module.exports = __webpack_require__(622); } else { - module.exports = __webpack_require__(626); + module.exports = __webpack_require__(625); } /***/ }), -/* 623 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71646,7 +71634,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(624); +exports = module.exports = __webpack_require__(623); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -71828,7 +71816,7 @@ function localstorage() { /***/ }), -/* 624 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { @@ -71844,7 +71832,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(625); +exports.humanize = __webpack_require__(624); /** * The currently active debug mode names, and names to skip. @@ -72036,7 +72024,7 @@ function coerce(val) { /***/ }), -/* 625 */ +/* 624 */ /***/ (function(module, exports) { /** @@ -72194,7 +72182,7 @@ function plural(ms, n, name) { /***/ }), -/* 626 */ +/* 625 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -72210,7 +72198,7 @@ var util = __webpack_require__(112); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(624); +exports = module.exports = __webpack_require__(623); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -72389,7 +72377,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(627); + var net = __webpack_require__(626); stream = new net.Socket({ fd: fd, readable: false, @@ -72448,13 +72436,13 @@ exports.enable(load()); /***/ }), -/* 627 */ +/* 626 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 628 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -72464,9 +72452,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(561); -exports.SourceMap = __webpack_require__(629); -exports.sourceMapResolve = __webpack_require__(640); +exports.extend = __webpack_require__(560); +exports.SourceMap = __webpack_require__(628); +exports.sourceMapResolve = __webpack_require__(639); /** * Convert backslash in the given string to forward slashes @@ -72509,7 +72497,7 @@ exports.last = function(arr, n) { /***/ }), -/* 629 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -72517,13 +72505,13 @@ exports.last = function(arr, n) { * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -exports.SourceMapGenerator = __webpack_require__(630).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(636).SourceMapConsumer; -exports.SourceNode = __webpack_require__(639).SourceNode; +exports.SourceMapGenerator = __webpack_require__(629).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(635).SourceMapConsumer; +exports.SourceNode = __webpack_require__(638).SourceNode; /***/ }), -/* 630 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72533,10 +72521,10 @@ exports.SourceNode = __webpack_require__(639).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(631); -var util = __webpack_require__(633); -var ArraySet = __webpack_require__(634).ArraySet; -var MappingList = __webpack_require__(635).MappingList; +var base64VLQ = __webpack_require__(630); +var util = __webpack_require__(632); +var ArraySet = __webpack_require__(633).ArraySet; +var MappingList = __webpack_require__(634).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -72945,7 +72933,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 631 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72985,7 +72973,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(632); +var base64 = __webpack_require__(631); // A single base 64 digit can contain 6 bits of data. For the base 64 variable // length quantities we use in the source map spec, the first bit is the sign, @@ -73091,7 +73079,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 632 */ +/* 631 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73164,7 +73152,7 @@ exports.decode = function (charCode) { /***/ }), -/* 633 */ +/* 632 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73587,7 +73575,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 634 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73597,7 +73585,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(633); +var util = __webpack_require__(632); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -73714,7 +73702,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 635 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73724,7 +73712,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(633); +var util = __webpack_require__(632); /** * Determine whether mappingB is after mappingA with respect to generated @@ -73799,7 +73787,7 @@ exports.MappingList = MappingList; /***/ }), -/* 636 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73809,11 +73797,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(633); -var binarySearch = __webpack_require__(637); -var ArraySet = __webpack_require__(634).ArraySet; -var base64VLQ = __webpack_require__(631); -var quickSort = __webpack_require__(638).quickSort; +var util = __webpack_require__(632); +var binarySearch = __webpack_require__(636); +var ArraySet = __webpack_require__(633).ArraySet; +var base64VLQ = __webpack_require__(630); +var quickSort = __webpack_require__(637).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -74887,7 +74875,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 637 */ +/* 636 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75004,7 +74992,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 638 */ +/* 637 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75124,7 +75112,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 639 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -75134,8 +75122,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(630).SourceMapGenerator; -var util = __webpack_require__(633); +var SourceMapGenerator = __webpack_require__(629).SourceMapGenerator; +var util = __webpack_require__(632); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -75543,17 +75531,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 640 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(641) -var resolveUrl = __webpack_require__(642) -var decodeUriComponent = __webpack_require__(643) -var urix = __webpack_require__(645) -var atob = __webpack_require__(646) +var sourceMappingURL = __webpack_require__(640) +var resolveUrl = __webpack_require__(641) +var decodeUriComponent = __webpack_require__(642) +var urix = __webpack_require__(644) +var atob = __webpack_require__(645) @@ -75851,7 +75839,7 @@ module.exports = { /***/ }), -/* 641 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -75914,7 +75902,7 @@ void (function(root, factory) { /***/ }), -/* 642 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -75932,13 +75920,13 @@ module.exports = resolveUrl /***/ }), -/* 643 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(644) +var decodeUriComponent = __webpack_require__(643) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -75949,7 +75937,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 644 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76050,7 +76038,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 645 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -76073,7 +76061,7 @@ module.exports = urix /***/ }), -/* 646 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76087,7 +76075,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 647 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76095,8 +76083,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(134); var path = __webpack_require__(4); -var define = __webpack_require__(609); -var utils = __webpack_require__(628); +var define = __webpack_require__(608); +var utils = __webpack_require__(627); /** * Expose `mixin()`. @@ -76239,19 +76227,19 @@ exports.comment = function(node) { /***/ }), -/* 648 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(620); +var use = __webpack_require__(619); var util = __webpack_require__(112); -var Cache = __webpack_require__(649); -var define = __webpack_require__(609); -var debug = __webpack_require__(622)('snapdragon:parser'); -var Position = __webpack_require__(650); -var utils = __webpack_require__(628); +var Cache = __webpack_require__(648); +var define = __webpack_require__(608); +var debug = __webpack_require__(621)('snapdragon:parser'); +var Position = __webpack_require__(649); +var utils = __webpack_require__(627); /** * Create a new `Parser` with the given `input` and `options`. @@ -76779,7 +76767,7 @@ module.exports = Parser; /***/ }), -/* 649 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76886,13 +76874,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 650 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(609); +var define = __webpack_require__(608); /** * Store position for a node @@ -76907,14 +76895,14 @@ module.exports = function Position(start, parser) { /***/ }), -/* 651 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(652); -var assignSymbols = __webpack_require__(556); +var isExtendable = __webpack_require__(651); +var assignSymbols = __webpack_require__(555); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -76974,7 +76962,7 @@ function isEnum(obj, key) { /***/ }), -/* 652 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76987,7 +76975,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(555); +var isPlainObject = __webpack_require__(554); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -76995,14 +76983,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 653 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(654); -var extglob = __webpack_require__(669); +var nanomatch = __webpack_require__(653); +var extglob = __webpack_require__(668); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -77079,7 +77067,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 654 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77090,17 +77078,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(112); -var toRegex = __webpack_require__(538); -var extend = __webpack_require__(655); +var toRegex = __webpack_require__(537); +var extend = __webpack_require__(654); /** * Local dependencies */ -var compilers = __webpack_require__(657); -var parsers = __webpack_require__(658); -var cache = __webpack_require__(661); -var utils = __webpack_require__(663); +var compilers = __webpack_require__(656); +var parsers = __webpack_require__(657); +var cache = __webpack_require__(660); +var utils = __webpack_require__(662); var MAX_LENGTH = 1024 * 64; /** @@ -77924,14 +77912,14 @@ module.exports = nanomatch; /***/ }), -/* 655 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(656); -var assignSymbols = __webpack_require__(556); +var isExtendable = __webpack_require__(655); +var assignSymbols = __webpack_require__(555); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -77991,7 +77979,7 @@ function isEnum(obj, key) { /***/ }), -/* 656 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78004,7 +77992,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(555); +var isPlainObject = __webpack_require__(554); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -78012,7 +78000,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 657 */ +/* 656 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78358,15 +78346,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 658 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(557); -var toRegex = __webpack_require__(538); -var isOdd = __webpack_require__(659); +var regexNot = __webpack_require__(556); +var toRegex = __webpack_require__(537); +var isOdd = __webpack_require__(658); /** * Characters to use in negation regex (we want to "not" match @@ -78752,7 +78740,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 659 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78765,7 +78753,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(660); +var isNumber = __webpack_require__(659); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -78779,7 +78767,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 660 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78807,14 +78795,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 661 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(662))(); +module.exports = new (__webpack_require__(661))(); /***/ }), -/* 662 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78827,7 +78815,7 @@ module.exports = new (__webpack_require__(662))(); -var MapCache = __webpack_require__(649); +var MapCache = __webpack_require__(648); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -78949,7 +78937,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 663 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78962,14 +78950,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(664)(); -var Snapdragon = __webpack_require__(581); -utils.define = __webpack_require__(665); -utils.diff = __webpack_require__(666); -utils.extend = __webpack_require__(655); -utils.pick = __webpack_require__(667); -utils.typeOf = __webpack_require__(668); -utils.unique = __webpack_require__(560); +var isWindows = __webpack_require__(663)(); +var Snapdragon = __webpack_require__(580); +utils.define = __webpack_require__(664); +utils.diff = __webpack_require__(665); +utils.extend = __webpack_require__(654); +utils.pick = __webpack_require__(666); +utils.typeOf = __webpack_require__(667); +utils.unique = __webpack_require__(559); /** * Returns true if the given value is effectively an empty string @@ -79335,7 +79323,7 @@ utils.unixify = function(options) { /***/ }), -/* 664 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -79363,7 +79351,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 665 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79376,8 +79364,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(546); -var isDescriptor = __webpack_require__(547); +var isobject = __webpack_require__(545); +var isDescriptor = __webpack_require__(546); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -79408,7 +79396,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 666 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79462,7 +79450,7 @@ function diffArray(one, two) { /***/ }), -/* 667 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79475,7 +79463,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(546); +var isObject = __webpack_require__(545); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -79504,7 +79492,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 668 */ +/* 667 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -79639,7 +79627,7 @@ function isBuffer(val) { /***/ }), -/* 669 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79649,18 +79637,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(561); -var unique = __webpack_require__(560); -var toRegex = __webpack_require__(538); +var extend = __webpack_require__(560); +var unique = __webpack_require__(559); +var toRegex = __webpack_require__(537); /** * Local dependencies */ -var compilers = __webpack_require__(670); -var parsers = __webpack_require__(676); -var Extglob = __webpack_require__(679); -var utils = __webpack_require__(678); +var compilers = __webpack_require__(669); +var parsers = __webpack_require__(675); +var Extglob = __webpack_require__(678); +var utils = __webpack_require__(677); var MAX_LENGTH = 1024 * 64; /** @@ -79977,13 +79965,13 @@ module.exports = extglob; /***/ }), -/* 670 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(671); +var brackets = __webpack_require__(670); /** * Extglob compilers @@ -80153,7 +80141,7 @@ module.exports = function(extglob) { /***/ }), -/* 671 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80163,17 +80151,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(672); -var parsers = __webpack_require__(674); +var compilers = __webpack_require__(671); +var parsers = __webpack_require__(673); /** * Module dependencies */ -var debug = __webpack_require__(622)('expand-brackets'); -var extend = __webpack_require__(561); -var Snapdragon = __webpack_require__(581); -var toRegex = __webpack_require__(538); +var debug = __webpack_require__(621)('expand-brackets'); +var extend = __webpack_require__(560); +var Snapdragon = __webpack_require__(580); +var toRegex = __webpack_require__(537); /** * Parses the given POSIX character class `pattern` and returns a @@ -80371,13 +80359,13 @@ module.exports = brackets; /***/ }), -/* 672 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(673); +var posix = __webpack_require__(672); module.exports = function(brackets) { brackets.compiler @@ -80465,7 +80453,7 @@ module.exports = function(brackets) { /***/ }), -/* 673 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80494,14 +80482,14 @@ module.exports = { /***/ }), -/* 674 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(675); -var define = __webpack_require__(609); +var utils = __webpack_require__(674); +var define = __webpack_require__(608); /** * Text regex @@ -80720,14 +80708,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 675 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(538); -var regexNot = __webpack_require__(557); +var toRegex = __webpack_require__(537); +var regexNot = __webpack_require__(556); var cached; /** @@ -80761,15 +80749,15 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 676 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(671); -var define = __webpack_require__(677); -var utils = __webpack_require__(678); +var brackets = __webpack_require__(670); +var define = __webpack_require__(676); +var utils = __webpack_require__(677); /** * Characters to use in text regex (we want to "not" match @@ -80924,7 +80912,7 @@ module.exports = parsers; /***/ }), -/* 677 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80937,7 +80925,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(547); +var isDescriptor = __webpack_require__(546); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -80962,14 +80950,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 678 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(557); -var Cache = __webpack_require__(662); +var regex = __webpack_require__(556); +var Cache = __webpack_require__(661); /** * Utils @@ -81038,7 +81026,7 @@ utils.createRegex = function(str) { /***/ }), -/* 679 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81048,16 +81036,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(581); -var define = __webpack_require__(677); -var extend = __webpack_require__(561); +var Snapdragon = __webpack_require__(580); +var define = __webpack_require__(676); +var extend = __webpack_require__(560); /** * Local dependencies */ -var compilers = __webpack_require__(670); -var parsers = __webpack_require__(676); +var compilers = __webpack_require__(669); +var parsers = __webpack_require__(675); /** * Customize Snapdragon parser and renderer @@ -81123,16 +81111,16 @@ module.exports = Extglob; /***/ }), -/* 680 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(669); -var nanomatch = __webpack_require__(654); -var regexNot = __webpack_require__(557); -var toRegex = __webpack_require__(538); +var extglob = __webpack_require__(668); +var nanomatch = __webpack_require__(653); +var regexNot = __webpack_require__(556); +var toRegex = __webpack_require__(537); var not; /** @@ -81213,14 +81201,14 @@ function textRegex(pattern) { /***/ }), -/* 681 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(662))(); +module.exports = new (__webpack_require__(661))(); /***/ }), -/* 682 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81233,13 +81221,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(581); -utils.define = __webpack_require__(683); -utils.diff = __webpack_require__(666); -utils.extend = __webpack_require__(651); -utils.pick = __webpack_require__(667); -utils.typeOf = __webpack_require__(684); -utils.unique = __webpack_require__(560); +var Snapdragon = __webpack_require__(580); +utils.define = __webpack_require__(682); +utils.diff = __webpack_require__(665); +utils.extend = __webpack_require__(650); +utils.pick = __webpack_require__(666); +utils.typeOf = __webpack_require__(683); +utils.unique = __webpack_require__(559); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -81536,7 +81524,7 @@ utils.unixify = function(options) { /***/ }), -/* 683 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81549,8 +81537,8 @@ utils.unixify = function(options) { -var isobject = __webpack_require__(546); -var isDescriptor = __webpack_require__(547); +var isobject = __webpack_require__(545); +var isDescriptor = __webpack_require__(546); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -81581,7 +81569,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 684 */ +/* 683 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -81716,7 +81704,7 @@ function isBuffer(val) { /***/ }), -/* 685 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81735,9 +81723,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(686); -var reader_1 = __webpack_require__(699); -var fs_stream_1 = __webpack_require__(703); +var readdir = __webpack_require__(685); +var reader_1 = __webpack_require__(698); +var fs_stream_1 = __webpack_require__(702); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -81798,15 +81786,15 @@ exports.default = ReaderAsync; /***/ }), -/* 686 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(687); -const readdirAsync = __webpack_require__(695); -const readdirStream = __webpack_require__(698); +const readdirSync = __webpack_require__(686); +const readdirAsync = __webpack_require__(694); +const readdirStream = __webpack_require__(697); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -81890,7 +81878,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 687 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81898,11 +81886,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(688); +const DirectoryReader = __webpack_require__(687); let syncFacade = { - fs: __webpack_require__(693), - forEach: __webpack_require__(694), + fs: __webpack_require__(692), + forEach: __webpack_require__(693), sync: true }; @@ -81931,7 +81919,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 688 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81940,9 +81928,9 @@ function readdirSync (dir, options, internalOptions) { const Readable = __webpack_require__(138).Readable; const EventEmitter = __webpack_require__(156).EventEmitter; const path = __webpack_require__(4); -const normalizeOptions = __webpack_require__(689); -const stat = __webpack_require__(691); -const call = __webpack_require__(692); +const normalizeOptions = __webpack_require__(688); +const stat = __webpack_require__(690); +const call = __webpack_require__(691); /** * Asynchronously reads the contents of a directory and streams the results @@ -82318,14 +82306,14 @@ module.exports = DirectoryReader; /***/ }), -/* 689 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(690); +const globToRegExp = __webpack_require__(689); module.exports = normalizeOptions; @@ -82502,7 +82490,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 690 */ +/* 689 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -82639,13 +82627,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 691 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(692); +const call = __webpack_require__(691); module.exports = stat; @@ -82720,7 +82708,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 692 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82781,14 +82769,14 @@ function callOnce (fn) { /***/ }), -/* 693 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const call = __webpack_require__(692); +const call = __webpack_require__(691); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -82852,7 +82840,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 694 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82881,7 +82869,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 695 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82889,12 +82877,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(696); -const DirectoryReader = __webpack_require__(688); +const maybe = __webpack_require__(695); +const DirectoryReader = __webpack_require__(687); let asyncFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(697), + forEach: __webpack_require__(696), async: true }; @@ -82936,7 +82924,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 696 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82963,7 +82951,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 697 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82999,7 +82987,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 698 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83007,11 +82995,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(688); +const DirectoryReader = __webpack_require__(687); let streamFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(697), + forEach: __webpack_require__(696), async: true }; @@ -83031,16 +83019,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 699 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var deep_1 = __webpack_require__(700); -var entry_1 = __webpack_require__(702); -var pathUtil = __webpack_require__(701); +var deep_1 = __webpack_require__(699); +var entry_1 = __webpack_require__(701); +var pathUtil = __webpack_require__(700); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -83106,14 +83094,14 @@ exports.default = Reader; /***/ }), -/* 700 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(701); -var patternUtils = __webpack_require__(532); +var pathUtils = __webpack_require__(700); +var patternUtils = __webpack_require__(531); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -83196,7 +83184,7 @@ exports.default = DeepFilter; /***/ }), -/* 701 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83227,14 +83215,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 702 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(701); -var patternUtils = __webpack_require__(532); +var pathUtils = __webpack_require__(700); +var patternUtils = __webpack_require__(531); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -83319,7 +83307,7 @@ exports.default = EntryFilter; /***/ }), -/* 703 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83339,8 +83327,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(138); -var fsStat = __webpack_require__(704); -var fs_1 = __webpack_require__(708); +var fsStat = __webpack_require__(703); +var fs_1 = __webpack_require__(707); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -83390,14 +83378,14 @@ exports.default = FileSystemStream; /***/ }), -/* 704 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(705); -const statProvider = __webpack_require__(707); +const optionsManager = __webpack_require__(704); +const statProvider = __webpack_require__(706); /** * Asynchronous API. */ @@ -83428,13 +83416,13 @@ exports.statSync = statSync; /***/ }), -/* 705 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(706); +const fsAdapter = __webpack_require__(705); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -83447,7 +83435,7 @@ exports.prepare = prepare; /***/ }), -/* 706 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83470,7 +83458,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 707 */ +/* 706 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83522,7 +83510,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 708 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83553,7 +83541,7 @@ exports.default = FileSystem; /***/ }), -/* 709 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83573,9 +83561,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(138); -var readdir = __webpack_require__(686); -var reader_1 = __webpack_require__(699); -var fs_stream_1 = __webpack_require__(703); +var readdir = __webpack_require__(685); +var reader_1 = __webpack_require__(698); +var fs_stream_1 = __webpack_require__(702); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -83643,7 +83631,7 @@ exports.default = ReaderStream; /***/ }), -/* 710 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83662,9 +83650,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(686); -var reader_1 = __webpack_require__(699); -var fs_sync_1 = __webpack_require__(711); +var readdir = __webpack_require__(685); +var reader_1 = __webpack_require__(698); +var fs_sync_1 = __webpack_require__(710); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -83724,7 +83712,7 @@ exports.default = ReaderSync; /***/ }), -/* 711 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83743,8 +83731,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(704); -var fs_1 = __webpack_require__(708); +var fsStat = __webpack_require__(703); +var fs_1 = __webpack_require__(707); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -83790,7 +83778,7 @@ exports.default = FileSystemSync; /***/ }), -/* 712 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83806,7 +83794,7 @@ exports.flatten = flatten; /***/ }), -/* 713 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83827,13 +83815,13 @@ exports.merge = merge; /***/ }), -/* 714 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(715); +const pathType = __webpack_require__(714); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -83899,13 +83887,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 715 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const pify = __webpack_require__(716); +const pify = __webpack_require__(715); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -83948,7 +83936,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 716 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84039,17 +84027,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 717 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(528); -const gitIgnore = __webpack_require__(718); -const pify = __webpack_require__(719); -const slash = __webpack_require__(720); +const fastGlob = __webpack_require__(527); +const gitIgnore = __webpack_require__(717); +const pify = __webpack_require__(718); +const slash = __webpack_require__(719); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -84147,7 +84135,7 @@ module.exports.sync = options => { /***/ }), -/* 718 */ +/* 717 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -84616,7 +84604,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 719 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84691,7 +84679,7 @@ module.exports = (input, options) => { /***/ }), -/* 720 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84709,7 +84697,7 @@ module.exports = input => { /***/ }), -/* 721 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84722,7 +84710,7 @@ module.exports = input => { -var isGlob = __webpack_require__(722); +var isGlob = __webpack_require__(721); module.exports = function hasGlob(val) { if (val == null) return false; @@ -84742,7 +84730,7 @@ module.exports = function hasGlob(val) { /***/ }), -/* 722 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -84773,17 +84761,17 @@ module.exports = function isGlob(str) { /***/ }), -/* 723 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(134); -const pEvent = __webpack_require__(724); -const CpFileError = __webpack_require__(727); -const fs = __webpack_require__(729); -const ProgressEmitter = __webpack_require__(732); +const pEvent = __webpack_require__(723); +const CpFileError = __webpack_require__(726); +const fs = __webpack_require__(728); +const ProgressEmitter = __webpack_require__(731); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -84897,12 +84885,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 724 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(725); +const pTimeout = __webpack_require__(724); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -85193,12 +85181,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 725 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(726); +const pFinally = __webpack_require__(725); class TimeoutError extends Error { constructor(message) { @@ -85244,7 +85232,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 726 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85266,12 +85254,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 727 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(728); +const NestedError = __webpack_require__(727); class CpFileError extends NestedError { constructor(message, nested) { @@ -85285,7 +85273,7 @@ module.exports = CpFileError; /***/ }), -/* 728 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(112).inherits; @@ -85341,16 +85329,16 @@ module.exports = NestedError; /***/ }), -/* 729 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const fs = __webpack_require__(133); -const makeDir = __webpack_require__(730); -const pEvent = __webpack_require__(724); -const CpFileError = __webpack_require__(727); +const makeDir = __webpack_require__(729); +const pEvent = __webpack_require__(723); +const CpFileError = __webpack_require__(726); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -85447,7 +85435,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 730 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85455,7 +85443,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(134); const path = __webpack_require__(4); const {promisify} = __webpack_require__(112); -const semver = __webpack_require__(731); +const semver = __webpack_require__(730); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -85610,7 +85598,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 731 */ +/* 730 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -87212,7 +87200,7 @@ function coerce (version, options) { /***/ }), -/* 732 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87253,7 +87241,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 733 */ +/* 732 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87299,12 +87287,12 @@ exports.default = module.exports; /***/ }), -/* 734 */ +/* 733 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(735); +const pMap = __webpack_require__(734); const pFilter = async (iterable, filterer, options) => { const values = await pMap( @@ -87321,7 +87309,7 @@ module.exports.default = pFilter; /***/ }), -/* 735 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -87400,12 +87388,12 @@ module.exports.default = pMap; /***/ }), -/* 736 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(728); +const NestedError = __webpack_require__(727); class CpyError extends NestedError { constructor(message, nested) { @@ -87419,14 +87407,14 @@ module.exports = CpyError; /***/ }), -/* 737 */ +/* 736 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const arrayUnion = __webpack_require__(526); +const arrayUnion = __webpack_require__(737); const glob = __webpack_require__(147); -const fastGlob = __webpack_require__(528); +const fastGlob = __webpack_require__(527); const dirGlob = __webpack_require__(738); const gitignore = __webpack_require__(742); @@ -87553,6 +87541,19 @@ module.exports.hasMagic = (patterns, opts) => [] module.exports.gitignore = gitignore; +/***/ }), +/* 737 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var arrayUniq = __webpack_require__(526); + +module.exports = function () { + return arrayUniq([].concat.apply([], arguments)); +}; + + /***/ }), /* 738 */ /***/ (function(module, exports, __webpack_require__) { @@ -87771,7 +87772,7 @@ module.exports = (obj, opts) => { const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(528); +const fastGlob = __webpack_require__(527); const gitIgnore = __webpack_require__(743); const pify = __webpack_require__(741); const slash = __webpack_require__(744); @@ -88324,13 +88325,13 @@ __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildNonBazelProductionProjects", function() { return buildNonBazelProductionProjects; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getProductionProjects", function() { return getProductionProjects; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProject", function() { return buildProject; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(521); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(520); /* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(cpy__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(143); /* harmony import */ var del__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(del__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(4); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(518); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(517); /* harmony import */ var _utils_fs__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(131); /* harmony import */ var _utils_log__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(246); /* harmony import */ var _utils_package_json__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(251); diff --git a/scripts/build_api_docs.js b/scripts/build_api_docs.js new file mode 100644 index 0000000000000..3e26a2d87895c --- /dev/null +++ b/scripts/build_api_docs.js @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +require('../src/setup_node_env'); +require('@kbn/docs-utils').runBuildApiDocsCli(); diff --git a/scripts/release_notes.js b/scripts/release_notes.js index f22c00f4643b0..7408ce322677c 100644 --- a/scripts/release_notes.js +++ b/scripts/release_notes.js @@ -7,4 +7,4 @@ */ require('../src/setup_node_env/no_transpilation'); -require('@kbn/release-notes').runReleaseNotesCli(); +require('@kbn/docs-utils').runReleaseNotesCli(); diff --git a/src/core/kibana.json b/src/core/kibana.json new file mode 100644 index 0000000000000..49f838dbc4ee5 --- /dev/null +++ b/src/core/kibana.json @@ -0,0 +1,7 @@ +{ + "id": "core", + "summary": "The core plugin has core functionality", + "version": "kibana", + "serviceFolders": ["http", "saved_objects", "chrome", "application"] + } + \ No newline at end of file diff --git a/src/core/server/plugins/discovery/plugin_manifest_parser.ts b/src/core/server/plugins/discovery/plugin_manifest_parser.ts index eae0e73e86c46..7ac629534ba08 100644 --- a/src/core/server/plugins/discovery/plugin_manifest_parser.ts +++ b/src/core/server/plugins/discovery/plugin_manifest_parser.ts @@ -47,6 +47,7 @@ const KNOWN_MANIFEST_FIELDS = (() => { server: true, extraPublicDirs: true, requiredBundles: true, + serviceFolders: true, }; return new Set(Object.keys(manifestFields)); diff --git a/src/core/server/plugins/types.ts b/src/core/server/plugins/types.ts index 45db98201b758..a6086bd6f17e8 100644 --- a/src/core/server/plugins/types.ts +++ b/src/core/server/plugins/types.ts @@ -169,6 +169,12 @@ export interface PluginManifest { * @deprecated */ readonly extraPublicDirs?: string[]; + + /** + * Only used for the automatically generated API documentation. Specifying service + * folders will cause your plugin API reference to be broken up into sub sections. + */ + readonly serviceFolders?: readonly string[]; } /** diff --git a/src/core/server/server.api.md b/src/core/server/server.api.md index 2177da84b2b53..f3ebfe1e09bac 100644 --- a/src/core/server/server.api.md +++ b/src/core/server/server.api.md @@ -1882,6 +1882,7 @@ export interface PluginManifest { readonly requiredBundles: readonly string[]; readonly requiredPlugins: readonly PluginName[]; readonly server: boolean; + readonly serviceFolders?: readonly string[]; readonly ui: boolean; readonly version: string; } @@ -3197,9 +3198,9 @@ export const validBodyOutput: readonly ["data", "stream"]; // Warnings were encountered during analysis: // // src/core/server/http/router/response.ts:297:3 - (ae-forgotten-export) The symbol "KibanaResponse" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:280:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:280:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:283:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts -// src/core/server/plugins/types.ts:388:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" +// src/core/server/plugins/types.ts:286:3 - (ae-forgotten-export) The symbol "KibanaConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:286:3 - (ae-forgotten-export) The symbol "SharedGlobalConfigKeys" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:289:3 - (ae-forgotten-export) The symbol "SavedObjectsConfigType" needs to be exported by the entry point index.d.ts +// src/core/server/plugins/types.ts:394:5 - (ae-unresolved-link) The @link reference could not be resolved: The package "kibana" does not have an export "create" ``` diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index a09ab12f0c6f0..452b081d6387f 100644 --- a/src/plugins/data/kibana.json +++ b/src/plugins/data/kibana.json @@ -10,6 +10,7 @@ "share", "inspector" ], + "serviceFolders": ["search", "index_patterns", "query", "autocomplete", "ui", "field_formats"], "optionalPlugins": ["usageCollection"], "extraPublicDirs": ["common"], "requiredBundles": [ diff --git a/yarn.lock b/yarn.lock index a1d95b00b2a0e..a97f45319d057 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2107,6 +2107,14 @@ enabled "2.0.x" kuler "^2.0.0" +"@dsherret/to-absolute-glob@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dsherret/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz#1f6475dc8bd974cea07a2daf3864b317b1dd332c" + integrity sha1-H2R13IvZdM6gei2vOGSzF7HdMyw= + dependencies: + is-absolute "^1.0.0" + is-negated-glob "^1.0.0" + "@elastic/apm-rum-core@^5.7.0": version "5.7.0" resolved "https://registry.yarnpkg.com/@elastic/apm-rum-core/-/apm-rum-core-5.7.0.tgz#2213987285324781e2ebeca607f3a71245da5a84" @@ -3428,6 +3436,10 @@ version "0.0.0" uid "" +"@kbn/docs-utils@link:packages/kbn-docs-utils": + version "0.0.0" + uid "" + "@kbn/es-archiver@link:packages/kbn-es-archiver": version "0.0.0" uid "" @@ -3484,10 +3496,6 @@ version "0.0.0" uid "" -"@kbn/release-notes@link:packages/kbn-release-notes": - version "0.0.0" - uid "" - "@kbn/std@link:packages/kbn-std": version "0.0.0" uid "" @@ -5134,6 +5142,18 @@ dependencies: "@babel/runtime" "^7.10.2" +"@ts-morph/common@~0.7.0": + version "0.7.3" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.7.3.tgz#380020c278e4aa6cecedf362a1157591d1003267" + integrity sha512-M6Tcu0EZDLL8Ht7WAYz7yJfDZ9eArhqR8XZ9Mk3q8jwU6MKFAttrw3JtW4JhneqTz7pZMv4XaimEdXI0E4K4rg== + dependencies: + "@dsherret/to-absolute-glob" "^2.0.2" + fast-glob "^3.2.4" + is-negated-glob "^1.0.0" + mkdirp "^1.0.4" + multimatch "^5.0.0" + typescript "~4.1.2" + "@turf/along@6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/@turf/along/-/along-6.0.1.tgz#595cecdc48fc7fcfa83c940a8e3eb24d4c2e04d4" @@ -10561,6 +10581,11 @@ coa@^2.0.2: chalk "^2.4.1" q "^1.1.2" +code-block-writer@^10.1.1: + version "10.1.1" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-10.1.1.tgz#ad5684ed4bfb2b0783c8b131281ae84ee640a42f" + integrity sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw== + code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" @@ -21176,6 +21201,17 @@ multimatch@^4.0.0: arrify "^2.0.1" minimatch "^3.0.4" +multimatch@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" + integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== + dependencies: + "@types/minimatch" "^3.0.3" + array-differ "^3.0.0" + array-union "^2.1.0" + arrify "^2.0.1" + minimatch "^3.0.4" + multiparty@^4.1.2: version "4.2.1" resolved "https://registry.yarnpkg.com/multiparty/-/multiparty-4.2.1.tgz#d9b6c46d8b8deab1ee70c734b0af771dd46e0b13" @@ -28444,6 +28480,15 @@ ts-log@2.1.4: resolved "https://registry.yarnpkg.com/ts-log/-/ts-log-2.1.4.tgz#063c5ad1cbab5d49d258d18015963489fb6fb59a" integrity sha512-P1EJSoyV+N3bR/IWFeAqXzKPZwHpnLY6j7j58mAvewHRipo+BQM2Y1f9Y9BjEQznKwgqqZm7H8iuixmssU7tYQ== +ts-morph@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-9.1.0.tgz#10d2088387c71f3c674f82492a3cec1e3538f0dd" + integrity sha512-sei4u651MBenr27sD6qLDXN3gZ4thiX71E3qV7SuVtDas0uvK2LtgZkIYUf9DKm/fLJ6AB/+yhRJ1vpEBJgy7Q== + dependencies: + "@dsherret/to-absolute-glob" "^2.0.2" + "@ts-morph/common" "~0.7.0" + code-block-writer "^10.1.1" + ts-pnp@^1.1.6: version "1.2.0" resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" @@ -28648,7 +28693,7 @@ typescript-tuple@^2.2.1: dependencies: typescript-compare "^0.0.2" -typescript@4.1.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.5.3, typescript@~3.7.2: +typescript@4.1.3, typescript@^3.2.2, typescript@^3.3.3333, typescript@^3.5.3, typescript@~3.7.2, typescript@~4.1.2: version "4.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==