diff --git a/.gitignore b/.gitignore index 79d022a2d701b97..04013d7b7a6ec0c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .aws-config.json .signing-config.json +/api_docs .ackrc /.es /.chromium diff --git a/package.json b/package.json index 42949a701413119..f62a8bff509e0f9 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", @@ -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 68e84e5c21a5581..76c8dca754740e8 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 @@ -8,11 +8,13 @@ import Path from 'path'; import loadJsonFile from 'load-json-file'; +import { REPO_ROOT } from '@kbn/utils'; export interface KibanaPlatformPlugin { readonly directory: string; readonly manifestPath: string; readonly manifest: Manifest; + readonly relativeDirectory: string; } function isValidDepsDeclaration(input: unknown, type: string): string[] { @@ -29,6 +31,7 @@ interface Manifest { server: boolean; kibanaVersion: string; version: string; + serviceFolders: readonly string[]; requiredPlugins: readonly string[]; optionalPlugins: readonly string[]; requiredBundles: readonly string[]; @@ -54,6 +57,7 @@ export function parseKibanaPlatformPlugin(manifestPath: string): KibanaPlatformP } return { + relativeDirectory: Path.dirname(manifestPath).slice(REPO_ROOT.length), directory: Path.dirname(manifestPath), manifestPath, manifest: { @@ -64,6 +68,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-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 95ab46582723e6f..7f9c40846ceb4f2 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__(510); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(509); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _production__WEBPACK_IMPORTED_MODULE_1__["buildProductionProjects"]; }); /* harmony import */ var _utils_projects__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(248); @@ -106,7 +106,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__(509); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(508); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "getProjectPaths", function() { return _config__WEBPACK_IMPORTED_MODULE_5__["getProjectPaths"]; }); /* @@ -58925,7 +58925,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__(509); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(508); 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; } @@ -59082,9 +59082,9 @@ class Kibana { "use strict"; const minimatch = __webpack_require__(150); -const arrayUnion = __webpack_require__(506); -const arrayDiffer = __webpack_require__(507); -const arrify = __webpack_require__(508); +const arrayUnion = __webpack_require__(145); +const arrayDiffer = __webpack_require__(506); +const arrify = __webpack_require__(507); module.exports = (list, patterns, options = {}) => { list = arrify(list); @@ -59114,18 +59114,6 @@ module.exports = (list, patterns, options = {}) => { "use strict"; -module.exports = (...arguments_) => { - return [...new Set([].concat(...arguments_))]; -}; - - -/***/ }), -/* 507 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - const arrayDiffer = (array, ...values) => { const rest = new Set([].concat(...values)); return array.filter(element => !rest.has(element)); @@ -59135,7 +59123,7 @@ module.exports = arrayDiffer; /***/ }), -/* 508 */ +/* 507 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59165,7 +59153,7 @@ module.exports = arrify; /***/ }), -/* 509 */ +/* 508 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -59224,12 +59212,12 @@ function getProjectPaths({ } /***/ }), -/* 510 */ +/* 509 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(511); +/* harmony import */ var _build_production_projects__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(510); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return _build_production_projects__WEBPACK_IMPORTED_MODULE_0__["buildProductionProjects"]; }); /* @@ -59242,19 +59230,19 @@ __webpack_require__.r(__webpack_exports__); /***/ }), -/* 511 */ +/* 510 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "buildProductionProjects", function() { return buildProductionProjects; }); -/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(512); +/* harmony import */ var cpy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(511); /* 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__(509); +/* harmony import */ var _config__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(508); /* 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); @@ -59380,7 +59368,7 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { } /***/ }), -/* 512 */ +/* 511 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59388,14 +59376,14 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { const EventEmitter = __webpack_require__(156); const path = __webpack_require__(4); const os = __webpack_require__(121); -const pMap = __webpack_require__(513); -const arrify = __webpack_require__(508); -const globby = __webpack_require__(514); -const hasGlob = __webpack_require__(710); -const cpFile = __webpack_require__(712); -const junk = __webpack_require__(722); -const pFilter = __webpack_require__(723); -const CpyError = __webpack_require__(725); +const pMap = __webpack_require__(512); +const arrify = __webpack_require__(507); +const globby = __webpack_require__(513); +const hasGlob = __webpack_require__(709); +const cpFile = __webpack_require__(711); +const junk = __webpack_require__(721); +const pFilter = __webpack_require__(722); +const CpyError = __webpack_require__(724); const defaultOptions = { ignoreJunk: true @@ -59546,7 +59534,7 @@ module.exports = (source, destination, { /***/ }), -/* 513 */ +/* 512 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59634,17 +59622,17 @@ module.exports = async ( /***/ }), -/* 514 */ +/* 513 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const arrayUnion = __webpack_require__(515); +const arrayUnion = __webpack_require__(514); const glob = __webpack_require__(147); -const fastGlob = __webpack_require__(517); -const dirGlob = __webpack_require__(703); -const gitignore = __webpack_require__(706); +const fastGlob = __webpack_require__(516); +const dirGlob = __webpack_require__(702); +const gitignore = __webpack_require__(705); const DEFAULT_FILTER = () => false; @@ -59789,12 +59777,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 515 */ +/* 514 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(516); +var arrayUniq = __webpack_require__(515); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -59802,7 +59790,7 @@ module.exports = function () { /***/ }), -/* 516 */ +/* 515 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -59871,10 +59859,10 @@ if ('Set' in global) { /***/ }), -/* 517 */ +/* 516 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(518); +const pkg = __webpack_require__(517); module.exports = pkg.async; module.exports.default = pkg.async; @@ -59887,19 +59875,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 518 */ +/* 517 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(519); -var taskManager = __webpack_require__(520); -var reader_async_1 = __webpack_require__(674); -var reader_stream_1 = __webpack_require__(698); -var reader_sync_1 = __webpack_require__(699); -var arrayUtils = __webpack_require__(701); -var streamUtils = __webpack_require__(702); +var optionsManager = __webpack_require__(518); +var taskManager = __webpack_require__(519); +var reader_async_1 = __webpack_require__(673); +var reader_stream_1 = __webpack_require__(697); +var reader_sync_1 = __webpack_require__(698); +var arrayUtils = __webpack_require__(700); +var streamUtils = __webpack_require__(701); /** * Synchronous API. */ @@ -59965,7 +59953,7 @@ function isString(source) { /***/ }), -/* 519 */ +/* 518 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60003,13 +59991,13 @@ exports.prepare = prepare; /***/ }), -/* 520 */ +/* 519 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(521); +var patternUtils = __webpack_require__(520); /** * Generate tasks based on parent directory of each pattern. */ @@ -60100,16 +60088,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 521 */ +/* 520 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var globParent = __webpack_require__(522); +var globParent = __webpack_require__(521); var isGlob = __webpack_require__(172); -var micromatch = __webpack_require__(525); +var micromatch = __webpack_require__(524); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -60255,15 +60243,15 @@ exports.matchAny = matchAny; /***/ }), -/* 522 */ +/* 521 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(4); -var isglob = __webpack_require__(523); -var pathDirname = __webpack_require__(524); +var isglob = __webpack_require__(522); +var pathDirname = __webpack_require__(523); var isWin32 = __webpack_require__(121).platform() === 'win32'; module.exports = function globParent(str) { @@ -60286,7 +60274,7 @@ module.exports = function globParent(str) { /***/ }), -/* 523 */ +/* 522 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -60317,7 +60305,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 524 */ +/* 523 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60467,7 +60455,7 @@ module.exports.win32 = win32; /***/ }), -/* 525 */ +/* 524 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -60478,18 +60466,18 @@ module.exports.win32 = win32; */ var util = __webpack_require__(112); -var braces = __webpack_require__(526); -var toRegex = __webpack_require__(527); -var extend = __webpack_require__(640); +var braces = __webpack_require__(525); +var toRegex = __webpack_require__(526); +var extend = __webpack_require__(639); /** * Local dependencies */ -var compilers = __webpack_require__(642); -var parsers = __webpack_require__(669); -var cache = __webpack_require__(670); -var utils = __webpack_require__(671); +var compilers = __webpack_require__(641); +var parsers = __webpack_require__(668); +var cache = __webpack_require__(669); +var utils = __webpack_require__(670); var MAX_LENGTH = 1024 * 64; /** @@ -61351,7 +61339,7 @@ module.exports = micromatch; /***/ }), -/* 526 */ +/* 525 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -61361,18 +61349,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(527); -var unique = __webpack_require__(549); -var extend = __webpack_require__(550); +var toRegex = __webpack_require__(526); +var unique = __webpack_require__(548); +var extend = __webpack_require__(549); /** * Local dependencies */ -var compilers = __webpack_require__(552); -var parsers = __webpack_require__(565); -var Braces = __webpack_require__(569); -var utils = __webpack_require__(553); +var compilers = __webpack_require__(551); +var parsers = __webpack_require__(564); +var Braces = __webpack_require__(568); +var utils = __webpack_require__(552); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -61676,16 +61664,16 @@ module.exports = braces; /***/ }), -/* 527 */ +/* 526 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(528); -var define = __webpack_require__(534); -var extend = __webpack_require__(542); -var not = __webpack_require__(546); +var safe = __webpack_require__(527); +var define = __webpack_require__(533); +var extend = __webpack_require__(541); +var not = __webpack_require__(545); var MAX_LENGTH = 1024 * 64; /** @@ -61838,10 +61826,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 528 */ +/* 527 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(529); +var parse = __webpack_require__(528); var types = parse.types; module.exports = function (re, opts) { @@ -61887,13 +61875,13 @@ function isRegExp (x) { /***/ }), -/* 529 */ +/* 528 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(530); -var types = __webpack_require__(531); -var sets = __webpack_require__(532); -var positions = __webpack_require__(533); +var util = __webpack_require__(529); +var types = __webpack_require__(530); +var sets = __webpack_require__(531); +var positions = __webpack_require__(532); module.exports = function(regexpStr) { @@ -62175,11 +62163,11 @@ module.exports.types = types; /***/ }), -/* 530 */ +/* 529 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(531); -var sets = __webpack_require__(532); +var types = __webpack_require__(530); +var sets = __webpack_require__(531); // All of these are private and only used by randexp. @@ -62292,7 +62280,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 531 */ +/* 530 */ /***/ (function(module, exports) { module.exports = { @@ -62308,10 +62296,10 @@ module.exports = { /***/ }), -/* 532 */ +/* 531 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(531); +var types = __webpack_require__(530); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -62396,10 +62384,10 @@ exports.anyChar = function() { /***/ }), -/* 533 */ +/* 532 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(531); +var types = __webpack_require__(530); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -62419,7 +62407,7 @@ exports.end = function() { /***/ }), -/* 534 */ +/* 533 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62432,8 +62420,8 @@ exports.end = function() { -var isobject = __webpack_require__(535); -var isDescriptor = __webpack_require__(536); +var isobject = __webpack_require__(534); +var isDescriptor = __webpack_require__(535); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -62464,7 +62452,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 535 */ +/* 534 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62483,7 +62471,7 @@ module.exports = function isObject(val) { /***/ }), -/* 536 */ +/* 535 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62496,9 +62484,9 @@ module.exports = function isObject(val) { -var typeOf = __webpack_require__(537); -var isAccessor = __webpack_require__(538); -var isData = __webpack_require__(540); +var typeOf = __webpack_require__(536); +var isAccessor = __webpack_require__(537); +var isData = __webpack_require__(539); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -62512,7 +62500,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 537 */ +/* 536 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -62647,7 +62635,7 @@ function isBuffer(val) { /***/ }), -/* 538 */ +/* 537 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62660,7 +62648,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(539); +var typeOf = __webpack_require__(538); // accessor descriptor properties var accessor = { @@ -62723,7 +62711,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 539 */ +/* 538 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -62858,7 +62846,7 @@ function isBuffer(val) { /***/ }), -/* 540 */ +/* 539 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -62871,7 +62859,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(541); +var typeOf = __webpack_require__(540); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -62914,7 +62902,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 541 */ +/* 540 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -63049,14 +63037,14 @@ function isBuffer(val) { /***/ }), -/* 542 */ +/* 541 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(543); -var assignSymbols = __webpack_require__(545); +var isExtendable = __webpack_require__(542); +var assignSymbols = __webpack_require__(544); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -63116,7 +63104,7 @@ function isEnum(obj, key) { /***/ }), -/* 543 */ +/* 542 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63129,7 +63117,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(543); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -63137,7 +63125,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 544 */ +/* 543 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63150,7 +63138,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(535); +var isObject = __webpack_require__(534); function isObjectObject(o) { return isObject(o) === true @@ -63181,7 +63169,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 545 */ +/* 544 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63228,14 +63216,14 @@ module.exports = function(receiver, objects) { /***/ }), -/* 546 */ +/* 545 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(547); -var safe = __webpack_require__(528); +var extend = __webpack_require__(546); +var safe = __webpack_require__(527); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -63307,14 +63295,14 @@ module.exports = toRegex; /***/ }), -/* 547 */ +/* 546 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(548); -var assignSymbols = __webpack_require__(545); +var isExtendable = __webpack_require__(547); +var assignSymbols = __webpack_require__(544); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -63374,7 +63362,7 @@ function isEnum(obj, key) { /***/ }), -/* 548 */ +/* 547 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63387,7 +63375,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(543); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -63395,7 +63383,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 549 */ +/* 548 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63445,13 +63433,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 550 */ +/* 549 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(551); +var isObject = __webpack_require__(550); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -63485,7 +63473,7 @@ function hasOwn(obj, key) { /***/ }), -/* 551 */ +/* 550 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -63505,13 +63493,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 552 */ +/* 551 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(553); +var utils = __webpack_require__(552); module.exports = function(braces, options) { braces.compiler @@ -63794,25 +63782,25 @@ function hasQueue(node) { /***/ }), -/* 553 */ +/* 552 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(554); +var splitString = __webpack_require__(553); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(550); -utils.flatten = __webpack_require__(557); -utils.isObject = __webpack_require__(535); -utils.fillRange = __webpack_require__(558); -utils.repeat = __webpack_require__(564); -utils.unique = __webpack_require__(549); +utils.extend = __webpack_require__(549); +utils.flatten = __webpack_require__(556); +utils.isObject = __webpack_require__(534); +utils.fillRange = __webpack_require__(557); +utils.repeat = __webpack_require__(563); +utils.unique = __webpack_require__(548); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -64144,7 +64132,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 554 */ +/* 553 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64157,7 +64145,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(555); +var extend = __webpack_require__(554); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -64322,14 +64310,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 555 */ +/* 554 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(556); -var assignSymbols = __webpack_require__(545); +var isExtendable = __webpack_require__(555); +var assignSymbols = __webpack_require__(544); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -64389,7 +64377,7 @@ function isEnum(obj, key) { /***/ }), -/* 556 */ +/* 555 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64402,7 +64390,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(543); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -64410,7 +64398,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 557 */ +/* 556 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64439,7 +64427,7 @@ function flat(arr, res) { /***/ }), -/* 558 */ +/* 557 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64453,10 +64441,10 @@ function flat(arr, res) { var util = __webpack_require__(112); -var isNumber = __webpack_require__(559); -var extend = __webpack_require__(550); -var repeat = __webpack_require__(562); -var toRegex = __webpack_require__(563); +var isNumber = __webpack_require__(558); +var extend = __webpack_require__(549); +var repeat = __webpack_require__(561); +var toRegex = __webpack_require__(562); /** * Return a range of numbers or letters. @@ -64654,7 +64642,7 @@ module.exports = fillRange; /***/ }), -/* 559 */ +/* 558 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64667,7 +64655,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(560); +var typeOf = __webpack_require__(559); module.exports = function isNumber(num) { var type = typeOf(num); @@ -64683,10 +64671,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 560 */ +/* 559 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(561); +var isBuffer = __webpack_require__(560); var toString = Object.prototype.toString; /** @@ -64805,7 +64793,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 561 */ +/* 560 */ /***/ (function(module, exports) { /*! @@ -64832,7 +64820,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 562 */ +/* 561 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64909,7 +64897,7 @@ function repeat(str, num) { /***/ }), -/* 563 */ +/* 562 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -64922,8 +64910,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(562); -var isNumber = __webpack_require__(559); +var repeat = __webpack_require__(561); +var isNumber = __webpack_require__(558); var cache = {}; function toRegexRange(min, max, options) { @@ -65210,7 +65198,7 @@ module.exports = toRegexRange; /***/ }), -/* 564 */ +/* 563 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -65235,14 +65223,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 565 */ +/* 564 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(566); -var utils = __webpack_require__(553); +var Node = __webpack_require__(565); +var utils = __webpack_require__(552); /** * Braces parsers @@ -65602,15 +65590,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 566 */ +/* 565 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(535); -var define = __webpack_require__(567); -var utils = __webpack_require__(568); +var isObject = __webpack_require__(534); +var define = __webpack_require__(566); +var utils = __webpack_require__(567); var ownNames; /** @@ -66101,7 +66089,7 @@ exports = module.exports = Node; /***/ }), -/* 567 */ +/* 566 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -66114,7 +66102,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(536); +var isDescriptor = __webpack_require__(535); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -66139,13 +66127,13 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 568 */ +/* 567 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(560); +var typeOf = __webpack_require__(559); var utils = module.exports; /** @@ -67165,17 +67153,17 @@ function assert(val, message) { /***/ }), -/* 569 */ +/* 568 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(550); -var Snapdragon = __webpack_require__(570); -var compilers = __webpack_require__(552); -var parsers = __webpack_require__(565); -var utils = __webpack_require__(553); +var extend = __webpack_require__(549); +var Snapdragon = __webpack_require__(569); +var compilers = __webpack_require__(551); +var parsers = __webpack_require__(564); +var utils = __webpack_require__(552); /** * Customize Snapdragon parser and renderer @@ -67276,17 +67264,17 @@ module.exports = Braces; /***/ }), -/* 570 */ +/* 569 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(571); -var define = __webpack_require__(598); -var Compiler = __webpack_require__(608); -var Parser = __webpack_require__(637); -var utils = __webpack_require__(617); +var Base = __webpack_require__(570); +var define = __webpack_require__(597); +var Compiler = __webpack_require__(607); +var Parser = __webpack_require__(636); +var utils = __webpack_require__(616); var regexCache = {}; var cache = {}; @@ -67457,20 +67445,20 @@ module.exports.Parser = Parser; /***/ }), -/* 571 */ +/* 570 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var define = __webpack_require__(572); -var CacheBase = __webpack_require__(573); -var Emitter = __webpack_require__(574); -var isObject = __webpack_require__(535); -var merge = __webpack_require__(592); -var pascal = __webpack_require__(595); -var cu = __webpack_require__(596); +var define = __webpack_require__(571); +var CacheBase = __webpack_require__(572); +var Emitter = __webpack_require__(573); +var isObject = __webpack_require__(534); +var merge = __webpack_require__(591); +var pascal = __webpack_require__(594); +var cu = __webpack_require__(595); /** * Optionally define a custom `cache` namespace to use. @@ -67899,7 +67887,7 @@ module.exports.namespace = namespace; /***/ }), -/* 572 */ +/* 571 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -67912,7 +67900,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(536); +var isDescriptor = __webpack_require__(535); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -67937,21 +67925,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 573 */ +/* 572 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(535); -var Emitter = __webpack_require__(574); -var visit = __webpack_require__(575); -var toPath = __webpack_require__(578); -var union = __webpack_require__(579); -var del = __webpack_require__(583); -var get = __webpack_require__(581); -var has = __webpack_require__(588); -var set = __webpack_require__(591); +var isObject = __webpack_require__(534); +var Emitter = __webpack_require__(573); +var visit = __webpack_require__(574); +var toPath = __webpack_require__(577); +var union = __webpack_require__(578); +var del = __webpack_require__(582); +var get = __webpack_require__(580); +var has = __webpack_require__(587); +var set = __webpack_require__(590); /** * Create a `Cache` constructor that when instantiated will @@ -68205,7 +68193,7 @@ module.exports.namespace = namespace; /***/ }), -/* 574 */ +/* 573 */ /***/ (function(module, exports, __webpack_require__) { @@ -68374,7 +68362,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 575 */ +/* 574 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68387,8 +68375,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(576); -var mapVisit = __webpack_require__(577); +var visit = __webpack_require__(575); +var mapVisit = __webpack_require__(576); module.exports = function(collection, method, val) { var result; @@ -68411,7 +68399,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 576 */ +/* 575 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68424,7 +68412,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(535); +var isObject = __webpack_require__(534); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -68451,14 +68439,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 577 */ +/* 576 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var visit = __webpack_require__(576); +var visit = __webpack_require__(575); /** * Map `visit` over an array of objects. @@ -68495,7 +68483,7 @@ function isObject(val) { /***/ }), -/* 578 */ +/* 577 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68508,7 +68496,7 @@ function isObject(val) { -var typeOf = __webpack_require__(560); +var typeOf = __webpack_require__(559); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -68535,16 +68523,16 @@ function filter(arr) { /***/ }), -/* 579 */ +/* 578 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(551); -var union = __webpack_require__(580); -var get = __webpack_require__(581); -var set = __webpack_require__(582); +var isObject = __webpack_require__(550); +var union = __webpack_require__(579); +var get = __webpack_require__(580); +var set = __webpack_require__(581); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -68572,7 +68560,7 @@ function arrayify(val) { /***/ }), -/* 580 */ +/* 579 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68608,7 +68596,7 @@ module.exports = function union(init) { /***/ }), -/* 581 */ +/* 580 */ /***/ (function(module, exports) { /*! @@ -68664,7 +68652,7 @@ function toString(val) { /***/ }), -/* 582 */ +/* 581 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68677,10 +68665,10 @@ function toString(val) { -var split = __webpack_require__(554); -var extend = __webpack_require__(550); -var isPlainObject = __webpack_require__(544); -var isObject = __webpack_require__(551); +var split = __webpack_require__(553); +var extend = __webpack_require__(549); +var isPlainObject = __webpack_require__(543); +var isObject = __webpack_require__(550); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -68726,7 +68714,7 @@ function isValidKey(key) { /***/ }), -/* 583 */ +/* 582 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68739,8 +68727,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(535); -var has = __webpack_require__(584); +var isObject = __webpack_require__(534); +var has = __webpack_require__(583); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -68765,7 +68753,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 584 */ +/* 583 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68778,9 +68766,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(585); -var hasValues = __webpack_require__(587); -var get = __webpack_require__(581); +var isObject = __webpack_require__(584); +var hasValues = __webpack_require__(586); +var get = __webpack_require__(580); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -68791,7 +68779,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 585 */ +/* 584 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68804,7 +68792,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(586); +var isArray = __webpack_require__(585); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -68812,7 +68800,7 @@ module.exports = function isObject(val) { /***/ }), -/* 586 */ +/* 585 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -68823,7 +68811,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 587 */ +/* 586 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68866,7 +68854,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 588 */ +/* 587 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68879,9 +68867,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(535); -var hasValues = __webpack_require__(589); -var get = __webpack_require__(581); +var isObject = __webpack_require__(534); +var hasValues = __webpack_require__(588); +var get = __webpack_require__(580); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -68889,7 +68877,7 @@ module.exports = function(val, prop) { /***/ }), -/* 589 */ +/* 588 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -68902,8 +68890,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(590); -var isNumber = __webpack_require__(559); +var typeOf = __webpack_require__(589); +var isNumber = __webpack_require__(558); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -68956,10 +68944,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 590 */ +/* 589 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(561); +var isBuffer = __webpack_require__(560); var toString = Object.prototype.toString; /** @@ -69081,7 +69069,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 591 */ +/* 590 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69094,10 +69082,10 @@ module.exports = function kindOf(val) { -var split = __webpack_require__(554); -var extend = __webpack_require__(550); -var isPlainObject = __webpack_require__(544); -var isObject = __webpack_require__(551); +var split = __webpack_require__(553); +var extend = __webpack_require__(549); +var isPlainObject = __webpack_require__(543); +var isObject = __webpack_require__(550); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -69143,14 +69131,14 @@ function isValidKey(key) { /***/ }), -/* 592 */ +/* 591 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(593); -var forIn = __webpack_require__(594); +var isExtendable = __webpack_require__(592); +var forIn = __webpack_require__(593); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -69214,7 +69202,7 @@ module.exports = mixinDeep; /***/ }), -/* 593 */ +/* 592 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69227,7 +69215,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(543); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -69235,7 +69223,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 594 */ +/* 593 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69258,7 +69246,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 595 */ +/* 594 */ /***/ (function(module, exports) { /*! @@ -69285,14 +69273,14 @@ module.exports = pascalcase; /***/ }), -/* 596 */ +/* 595 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(112); -var utils = __webpack_require__(597); +var utils = __webpack_require__(596); /** * Expose class utils @@ -69657,7 +69645,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 597 */ +/* 596 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69671,10 +69659,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(580); -utils.define = __webpack_require__(598); -utils.isObj = __webpack_require__(535); -utils.staticExtend = __webpack_require__(605); +utils.union = __webpack_require__(579); +utils.define = __webpack_require__(597); +utils.isObj = __webpack_require__(534); +utils.staticExtend = __webpack_require__(604); /** @@ -69685,7 +69673,7 @@ module.exports = utils; /***/ }), -/* 598 */ +/* 597 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69698,7 +69686,7 @@ module.exports = utils; -var isDescriptor = __webpack_require__(599); +var isDescriptor = __webpack_require__(598); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -69723,7 +69711,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 599 */ +/* 598 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69736,9 +69724,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(600); -var isAccessor = __webpack_require__(601); -var isData = __webpack_require__(603); +var typeOf = __webpack_require__(599); +var isAccessor = __webpack_require__(600); +var isData = __webpack_require__(602); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -69752,7 +69740,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 600 */ +/* 599 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -69905,7 +69893,7 @@ function isBuffer(val) { /***/ }), -/* 601 */ +/* 600 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -69918,7 +69906,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(602); +var typeOf = __webpack_require__(601); // accessor descriptor properties var accessor = { @@ -69981,10 +69969,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 602 */ +/* 601 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(561); +var isBuffer = __webpack_require__(560); var toString = Object.prototype.toString; /** @@ -70103,7 +70091,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 603 */ +/* 602 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70116,7 +70104,7 @@ module.exports = function kindOf(val) { -var typeOf = __webpack_require__(604); +var typeOf = __webpack_require__(603); // data descriptor properties var data = { @@ -70165,10 +70153,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 604 */ +/* 603 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(561); +var isBuffer = __webpack_require__(560); var toString = Object.prototype.toString; /** @@ -70287,7 +70275,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 605 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70300,8 +70288,8 @@ module.exports = function kindOf(val) { -var copy = __webpack_require__(606); -var define = __webpack_require__(598); +var copy = __webpack_require__(605); +var define = __webpack_require__(597); var util = __webpack_require__(112); /** @@ -70384,15 +70372,15 @@ module.exports = extend; /***/ }), -/* 606 */ +/* 605 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(560); -var copyDescriptor = __webpack_require__(607); -var define = __webpack_require__(598); +var typeOf = __webpack_require__(559); +var copyDescriptor = __webpack_require__(606); +var define = __webpack_require__(597); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -70565,7 +70553,7 @@ module.exports.has = has; /***/ }), -/* 607 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70653,16 +70641,16 @@ function isObject(val) { /***/ }), -/* 608 */ +/* 607 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(609); -var define = __webpack_require__(598); -var debug = __webpack_require__(611)('snapdragon:compiler'); -var utils = __webpack_require__(617); +var use = __webpack_require__(608); +var define = __webpack_require__(597); +var debug = __webpack_require__(610)('snapdragon:compiler'); +var utils = __webpack_require__(616); /** * Create a new `Compiler` with the given `options`. @@ -70816,7 +70804,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(636); + var sourcemaps = __webpack_require__(635); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -70837,7 +70825,7 @@ module.exports = Compiler; /***/ }), -/* 609 */ +/* 608 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70850,7 +70838,7 @@ module.exports = Compiler; -var utils = __webpack_require__(610); +var utils = __webpack_require__(609); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -70965,7 +70953,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 610 */ +/* 609 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -70979,8 +70967,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(598); -utils.isObject = __webpack_require__(535); +utils.define = __webpack_require__(597); +utils.isObject = __webpack_require__(534); utils.isString = function(val) { @@ -70995,7 +70983,7 @@ module.exports = utils; /***/ }), -/* 611 */ +/* 610 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71004,14 +70992,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(612); + module.exports = __webpack_require__(611); } else { - module.exports = __webpack_require__(615); + module.exports = __webpack_require__(614); } /***/ }), -/* 612 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71020,7 +71008,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(613); +exports = module.exports = __webpack_require__(612); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -71202,7 +71190,7 @@ function localstorage() { /***/ }), -/* 613 */ +/* 612 */ /***/ (function(module, exports, __webpack_require__) { @@ -71218,7 +71206,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(614); +exports.humanize = __webpack_require__(613); /** * The currently active debug mode names, and names to skip. @@ -71410,7 +71398,7 @@ function coerce(val) { /***/ }), -/* 614 */ +/* 613 */ /***/ (function(module, exports) { /** @@ -71568,7 +71556,7 @@ function plural(ms, n, name) { /***/ }), -/* 615 */ +/* 614 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -71584,7 +71572,7 @@ var util = __webpack_require__(112); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(613); +exports = module.exports = __webpack_require__(612); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -71763,7 +71751,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(616); + var net = __webpack_require__(615); stream = new net.Socket({ fd: fd, readable: false, @@ -71822,13 +71810,13 @@ exports.enable(load()); /***/ }), -/* 616 */ +/* 615 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 617 */ +/* 616 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -71838,9 +71826,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(550); -exports.SourceMap = __webpack_require__(618); -exports.sourceMapResolve = __webpack_require__(629); +exports.extend = __webpack_require__(549); +exports.SourceMap = __webpack_require__(617); +exports.sourceMapResolve = __webpack_require__(628); /** * Convert backslash in the given string to forward slashes @@ -71883,7 +71871,7 @@ exports.last = function(arr, n) { /***/ }), -/* 618 */ +/* 617 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -71891,13 +71879,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__(619).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(625).SourceMapConsumer; -exports.SourceNode = __webpack_require__(628).SourceNode; +exports.SourceMapGenerator = __webpack_require__(618).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(624).SourceMapConsumer; +exports.SourceNode = __webpack_require__(627).SourceNode; /***/ }), -/* 619 */ +/* 618 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -71907,10 +71895,10 @@ exports.SourceNode = __webpack_require__(628).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(620); -var util = __webpack_require__(622); -var ArraySet = __webpack_require__(623).ArraySet; -var MappingList = __webpack_require__(624).MappingList; +var base64VLQ = __webpack_require__(619); +var util = __webpack_require__(621); +var ArraySet = __webpack_require__(622).ArraySet; +var MappingList = __webpack_require__(623).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -72319,7 +72307,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 620 */ +/* 619 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72359,7 +72347,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(621); +var base64 = __webpack_require__(620); // 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, @@ -72465,7 +72453,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 621 */ +/* 620 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72538,7 +72526,7 @@ exports.decode = function (charCode) { /***/ }), -/* 622 */ +/* 621 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72961,7 +72949,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 623 */ +/* 622 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -72971,7 +72959,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(622); +var util = __webpack_require__(621); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -73088,7 +73076,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 624 */ +/* 623 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73098,7 +73086,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(622); +var util = __webpack_require__(621); /** * Determine whether mappingB is after mappingA with respect to generated @@ -73173,7 +73161,7 @@ exports.MappingList = MappingList; /***/ }), -/* 625 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -73183,11 +73171,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(622); -var binarySearch = __webpack_require__(626); -var ArraySet = __webpack_require__(623).ArraySet; -var base64VLQ = __webpack_require__(620); -var quickSort = __webpack_require__(627).quickSort; +var util = __webpack_require__(621); +var binarySearch = __webpack_require__(625); +var ArraySet = __webpack_require__(622).ArraySet; +var base64VLQ = __webpack_require__(619); +var quickSort = __webpack_require__(626).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -74261,7 +74249,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 626 */ +/* 625 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74378,7 +74366,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 627 */ +/* 626 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74498,7 +74486,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 628 */ +/* 627 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -74508,8 +74496,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(619).SourceMapGenerator; -var util = __webpack_require__(622); +var SourceMapGenerator = __webpack_require__(618).SourceMapGenerator; +var util = __webpack_require__(621); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -74917,17 +74905,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 629 */ +/* 628 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(630) -var resolveUrl = __webpack_require__(631) -var decodeUriComponent = __webpack_require__(632) -var urix = __webpack_require__(634) -var atob = __webpack_require__(635) +var sourceMappingURL = __webpack_require__(629) +var resolveUrl = __webpack_require__(630) +var decodeUriComponent = __webpack_require__(631) +var urix = __webpack_require__(633) +var atob = __webpack_require__(634) @@ -75225,7 +75213,7 @@ module.exports = { /***/ }), -/* 630 */ +/* 629 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -75288,7 +75276,7 @@ void (function(root, factory) { /***/ }), -/* 631 */ +/* 630 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -75306,13 +75294,13 @@ module.exports = resolveUrl /***/ }), -/* 632 */ +/* 631 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(633) +var decodeUriComponent = __webpack_require__(632) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -75323,7 +75311,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 633 */ +/* 632 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75424,7 +75412,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 634 */ +/* 633 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -75447,7 +75435,7 @@ module.exports = urix /***/ }), -/* 635 */ +/* 634 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75461,7 +75449,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 636 */ +/* 635 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -75469,8 +75457,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(134); var path = __webpack_require__(4); -var define = __webpack_require__(598); -var utils = __webpack_require__(617); +var define = __webpack_require__(597); +var utils = __webpack_require__(616); /** * Expose `mixin()`. @@ -75613,19 +75601,19 @@ exports.comment = function(node) { /***/ }), -/* 637 */ +/* 636 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(609); +var use = __webpack_require__(608); var util = __webpack_require__(112); -var Cache = __webpack_require__(638); -var define = __webpack_require__(598); -var debug = __webpack_require__(611)('snapdragon:parser'); -var Position = __webpack_require__(639); -var utils = __webpack_require__(617); +var Cache = __webpack_require__(637); +var define = __webpack_require__(597); +var debug = __webpack_require__(610)('snapdragon:parser'); +var Position = __webpack_require__(638); +var utils = __webpack_require__(616); /** * Create a new `Parser` with the given `input` and `options`. @@ -76153,7 +76141,7 @@ module.exports = Parser; /***/ }), -/* 638 */ +/* 637 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76260,13 +76248,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 639 */ +/* 638 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(598); +var define = __webpack_require__(597); /** * Store position for a node @@ -76281,14 +76269,14 @@ module.exports = function Position(start, parser) { /***/ }), -/* 640 */ +/* 639 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(641); -var assignSymbols = __webpack_require__(545); +var isExtendable = __webpack_require__(640); +var assignSymbols = __webpack_require__(544); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -76348,7 +76336,7 @@ function isEnum(obj, key) { /***/ }), -/* 641 */ +/* 640 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76361,7 +76349,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(543); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -76369,14 +76357,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 642 */ +/* 641 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(643); -var extglob = __webpack_require__(658); +var nanomatch = __webpack_require__(642); +var extglob = __webpack_require__(657); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -76453,7 +76441,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 643 */ +/* 642 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -76464,17 +76452,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(112); -var toRegex = __webpack_require__(527); -var extend = __webpack_require__(644); +var toRegex = __webpack_require__(526); +var extend = __webpack_require__(643); /** * Local dependencies */ -var compilers = __webpack_require__(646); -var parsers = __webpack_require__(647); -var cache = __webpack_require__(650); -var utils = __webpack_require__(652); +var compilers = __webpack_require__(645); +var parsers = __webpack_require__(646); +var cache = __webpack_require__(649); +var utils = __webpack_require__(651); var MAX_LENGTH = 1024 * 64; /** @@ -77298,14 +77286,14 @@ module.exports = nanomatch; /***/ }), -/* 644 */ +/* 643 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(645); -var assignSymbols = __webpack_require__(545); +var isExtendable = __webpack_require__(644); +var assignSymbols = __webpack_require__(544); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -77365,7 +77353,7 @@ function isEnum(obj, key) { /***/ }), -/* 645 */ +/* 644 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77378,7 +77366,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(544); +var isPlainObject = __webpack_require__(543); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -77386,7 +77374,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 646 */ +/* 645 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -77732,15 +77720,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 647 */ +/* 646 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(546); -var toRegex = __webpack_require__(527); -var isOdd = __webpack_require__(648); +var regexNot = __webpack_require__(545); +var toRegex = __webpack_require__(526); +var isOdd = __webpack_require__(647); /** * Characters to use in negation regex (we want to "not" match @@ -78126,7 +78114,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 648 */ +/* 647 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78139,7 +78127,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(649); +var isNumber = __webpack_require__(648); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -78153,7 +78141,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 649 */ +/* 648 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78181,14 +78169,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 650 */ +/* 649 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(651))(); +module.exports = new (__webpack_require__(650))(); /***/ }), -/* 651 */ +/* 650 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78201,7 +78189,7 @@ module.exports = new (__webpack_require__(651))(); -var MapCache = __webpack_require__(638); +var MapCache = __webpack_require__(637); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -78323,7 +78311,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 652 */ +/* 651 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78336,14 +78324,14 @@ var path = __webpack_require__(4); * Module dependencies */ -var isWindows = __webpack_require__(653)(); -var Snapdragon = __webpack_require__(570); -utils.define = __webpack_require__(654); -utils.diff = __webpack_require__(655); -utils.extend = __webpack_require__(644); -utils.pick = __webpack_require__(656); -utils.typeOf = __webpack_require__(657); -utils.unique = __webpack_require__(549); +var isWindows = __webpack_require__(652)(); +var Snapdragon = __webpack_require__(569); +utils.define = __webpack_require__(653); +utils.diff = __webpack_require__(654); +utils.extend = __webpack_require__(643); +utils.pick = __webpack_require__(655); +utils.typeOf = __webpack_require__(656); +utils.unique = __webpack_require__(548); /** * Returns true if the given value is effectively an empty string @@ -78709,7 +78697,7 @@ utils.unixify = function(options) { /***/ }), -/* 653 */ +/* 652 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -78737,7 +78725,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 654 */ +/* 653 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78750,8 +78738,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(535); -var isDescriptor = __webpack_require__(536); +var isobject = __webpack_require__(534); +var isDescriptor = __webpack_require__(535); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -78782,7 +78770,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 655 */ +/* 654 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78836,7 +78824,7 @@ function diffArray(one, two) { /***/ }), -/* 656 */ +/* 655 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -78849,7 +78837,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(535); +var isObject = __webpack_require__(534); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -78878,7 +78866,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 657 */ +/* 656 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -79013,7 +79001,7 @@ function isBuffer(val) { /***/ }), -/* 658 */ +/* 657 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79023,18 +79011,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(550); -var unique = __webpack_require__(549); -var toRegex = __webpack_require__(527); +var extend = __webpack_require__(549); +var unique = __webpack_require__(548); +var toRegex = __webpack_require__(526); /** * Local dependencies */ -var compilers = __webpack_require__(659); -var parsers = __webpack_require__(665); -var Extglob = __webpack_require__(668); -var utils = __webpack_require__(667); +var compilers = __webpack_require__(658); +var parsers = __webpack_require__(664); +var Extglob = __webpack_require__(667); +var utils = __webpack_require__(666); var MAX_LENGTH = 1024 * 64; /** @@ -79351,13 +79339,13 @@ module.exports = extglob; /***/ }), -/* 659 */ +/* 658 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(660); +var brackets = __webpack_require__(659); /** * Extglob compilers @@ -79527,7 +79515,7 @@ module.exports = function(extglob) { /***/ }), -/* 660 */ +/* 659 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79537,17 +79525,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(661); -var parsers = __webpack_require__(663); +var compilers = __webpack_require__(660); +var parsers = __webpack_require__(662); /** * Module dependencies */ -var debug = __webpack_require__(611)('expand-brackets'); -var extend = __webpack_require__(550); -var Snapdragon = __webpack_require__(570); -var toRegex = __webpack_require__(527); +var debug = __webpack_require__(610)('expand-brackets'); +var extend = __webpack_require__(549); +var Snapdragon = __webpack_require__(569); +var toRegex = __webpack_require__(526); /** * Parses the given POSIX character class `pattern` and returns a @@ -79745,13 +79733,13 @@ module.exports = brackets; /***/ }), -/* 661 */ +/* 660 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(662); +var posix = __webpack_require__(661); module.exports = function(brackets) { brackets.compiler @@ -79839,7 +79827,7 @@ module.exports = function(brackets) { /***/ }), -/* 662 */ +/* 661 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -79868,14 +79856,14 @@ module.exports = { /***/ }), -/* 663 */ +/* 662 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(664); -var define = __webpack_require__(598); +var utils = __webpack_require__(663); +var define = __webpack_require__(597); /** * Text regex @@ -80094,14 +80082,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 664 */ +/* 663 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(527); -var regexNot = __webpack_require__(546); +var toRegex = __webpack_require__(526); +var regexNot = __webpack_require__(545); var cached; /** @@ -80135,15 +80123,15 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 665 */ +/* 664 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(660); -var define = __webpack_require__(666); -var utils = __webpack_require__(667); +var brackets = __webpack_require__(659); +var define = __webpack_require__(665); +var utils = __webpack_require__(666); /** * Characters to use in text regex (we want to "not" match @@ -80298,7 +80286,7 @@ module.exports = parsers; /***/ }), -/* 666 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80311,7 +80299,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(536); +var isDescriptor = __webpack_require__(535); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -80336,14 +80324,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 667 */ +/* 666 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(546); -var Cache = __webpack_require__(651); +var regex = __webpack_require__(545); +var Cache = __webpack_require__(650); /** * Utils @@ -80412,7 +80400,7 @@ utils.createRegex = function(str) { /***/ }), -/* 668 */ +/* 667 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80422,16 +80410,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(570); -var define = __webpack_require__(666); -var extend = __webpack_require__(550); +var Snapdragon = __webpack_require__(569); +var define = __webpack_require__(665); +var extend = __webpack_require__(549); /** * Local dependencies */ -var compilers = __webpack_require__(659); -var parsers = __webpack_require__(665); +var compilers = __webpack_require__(658); +var parsers = __webpack_require__(664); /** * Customize Snapdragon parser and renderer @@ -80497,16 +80485,16 @@ module.exports = Extglob; /***/ }), -/* 669 */ +/* 668 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(658); -var nanomatch = __webpack_require__(643); -var regexNot = __webpack_require__(546); -var toRegex = __webpack_require__(527); +var extglob = __webpack_require__(657); +var nanomatch = __webpack_require__(642); +var regexNot = __webpack_require__(545); +var toRegex = __webpack_require__(526); var not; /** @@ -80587,14 +80575,14 @@ function textRegex(pattern) { /***/ }), -/* 670 */ +/* 669 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(651))(); +module.exports = new (__webpack_require__(650))(); /***/ }), -/* 671 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80607,13 +80595,13 @@ var path = __webpack_require__(4); * Module dependencies */ -var Snapdragon = __webpack_require__(570); -utils.define = __webpack_require__(672); -utils.diff = __webpack_require__(655); -utils.extend = __webpack_require__(640); -utils.pick = __webpack_require__(656); -utils.typeOf = __webpack_require__(673); -utils.unique = __webpack_require__(549); +var Snapdragon = __webpack_require__(569); +utils.define = __webpack_require__(671); +utils.diff = __webpack_require__(654); +utils.extend = __webpack_require__(639); +utils.pick = __webpack_require__(655); +utils.typeOf = __webpack_require__(672); +utils.unique = __webpack_require__(548); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -80910,7 +80898,7 @@ utils.unixify = function(options) { /***/ }), -/* 672 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80923,8 +80911,8 @@ utils.unixify = function(options) { -var isobject = __webpack_require__(535); -var isDescriptor = __webpack_require__(536); +var isobject = __webpack_require__(534); +var isDescriptor = __webpack_require__(535); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -80955,7 +80943,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 673 */ +/* 672 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -81090,7 +81078,7 @@ function isBuffer(val) { /***/ }), -/* 674 */ +/* 673 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81109,9 +81097,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(675); -var reader_1 = __webpack_require__(688); -var fs_stream_1 = __webpack_require__(692); +var readdir = __webpack_require__(674); +var reader_1 = __webpack_require__(687); +var fs_stream_1 = __webpack_require__(691); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -81172,15 +81160,15 @@ exports.default = ReaderAsync; /***/ }), -/* 675 */ +/* 674 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(676); -const readdirAsync = __webpack_require__(684); -const readdirStream = __webpack_require__(687); +const readdirSync = __webpack_require__(675); +const readdirAsync = __webpack_require__(683); +const readdirStream = __webpack_require__(686); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -81264,7 +81252,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 676 */ +/* 675 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81272,11 +81260,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(677); +const DirectoryReader = __webpack_require__(676); let syncFacade = { - fs: __webpack_require__(682), - forEach: __webpack_require__(683), + fs: __webpack_require__(681), + forEach: __webpack_require__(682), sync: true }; @@ -81305,7 +81293,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 677 */ +/* 676 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81314,9 +81302,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__(678); -const stat = __webpack_require__(680); -const call = __webpack_require__(681); +const normalizeOptions = __webpack_require__(677); +const stat = __webpack_require__(679); +const call = __webpack_require__(680); /** * Asynchronously reads the contents of a directory and streams the results @@ -81692,14 +81680,14 @@ module.exports = DirectoryReader; /***/ }), -/* 678 */ +/* 677 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const globToRegExp = __webpack_require__(679); +const globToRegExp = __webpack_require__(678); module.exports = normalizeOptions; @@ -81876,7 +81864,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 679 */ +/* 678 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -82013,13 +82001,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 680 */ +/* 679 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(681); +const call = __webpack_require__(680); module.exports = stat; @@ -82094,7 +82082,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 681 */ +/* 680 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82155,14 +82143,14 @@ function callOnce (fn) { /***/ }), -/* 682 */ +/* 681 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const call = __webpack_require__(681); +const call = __webpack_require__(680); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -82226,7 +82214,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 683 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82255,7 +82243,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 684 */ +/* 683 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82263,12 +82251,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(685); -const DirectoryReader = __webpack_require__(677); +const maybe = __webpack_require__(684); +const DirectoryReader = __webpack_require__(676); let asyncFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(686), + forEach: __webpack_require__(685), async: true }; @@ -82310,7 +82298,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 685 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82337,7 +82325,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 686 */ +/* 685 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82373,7 +82361,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 687 */ +/* 686 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82381,11 +82369,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(677); +const DirectoryReader = __webpack_require__(676); let streamFacade = { fs: __webpack_require__(134), - forEach: __webpack_require__(686), + forEach: __webpack_require__(685), async: true }; @@ -82405,16 +82393,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 688 */ +/* 687 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(4); -var deep_1 = __webpack_require__(689); -var entry_1 = __webpack_require__(691); -var pathUtil = __webpack_require__(690); +var deep_1 = __webpack_require__(688); +var entry_1 = __webpack_require__(690); +var pathUtil = __webpack_require__(689); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -82480,14 +82468,14 @@ exports.default = Reader; /***/ }), -/* 689 */ +/* 688 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(690); -var patternUtils = __webpack_require__(521); +var pathUtils = __webpack_require__(689); +var patternUtils = __webpack_require__(520); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -82570,7 +82558,7 @@ exports.default = DeepFilter; /***/ }), -/* 690 */ +/* 689 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82601,14 +82589,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 691 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(690); -var patternUtils = __webpack_require__(521); +var pathUtils = __webpack_require__(689); +var patternUtils = __webpack_require__(520); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -82693,7 +82681,7 @@ exports.default = EntryFilter; /***/ }), -/* 692 */ +/* 691 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82713,8 +82701,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(138); -var fsStat = __webpack_require__(693); -var fs_1 = __webpack_require__(697); +var fsStat = __webpack_require__(692); +var fs_1 = __webpack_require__(696); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -82764,14 +82752,14 @@ exports.default = FileSystemStream; /***/ }), -/* 693 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(694); -const statProvider = __webpack_require__(696); +const optionsManager = __webpack_require__(693); +const statProvider = __webpack_require__(695); /** * Asynchronous API. */ @@ -82802,13 +82790,13 @@ exports.statSync = statSync; /***/ }), -/* 694 */ +/* 693 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(695); +const fsAdapter = __webpack_require__(694); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -82821,7 +82809,7 @@ exports.prepare = prepare; /***/ }), -/* 695 */ +/* 694 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82844,7 +82832,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 696 */ +/* 695 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82896,7 +82884,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 697 */ +/* 696 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82927,7 +82915,7 @@ exports.default = FileSystem; /***/ }), -/* 698 */ +/* 697 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82947,9 +82935,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(138); -var readdir = __webpack_require__(675); -var reader_1 = __webpack_require__(688); -var fs_stream_1 = __webpack_require__(692); +var readdir = __webpack_require__(674); +var reader_1 = __webpack_require__(687); +var fs_stream_1 = __webpack_require__(691); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -83017,7 +83005,7 @@ exports.default = ReaderStream; /***/ }), -/* 699 */ +/* 698 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83036,9 +83024,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(675); -var reader_1 = __webpack_require__(688); -var fs_sync_1 = __webpack_require__(700); +var readdir = __webpack_require__(674); +var reader_1 = __webpack_require__(687); +var fs_sync_1 = __webpack_require__(699); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -83098,7 +83086,7 @@ exports.default = ReaderSync; /***/ }), -/* 700 */ +/* 699 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83117,8 +83105,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(693); -var fs_1 = __webpack_require__(697); +var fsStat = __webpack_require__(692); +var fs_1 = __webpack_require__(696); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -83164,7 +83152,7 @@ exports.default = FileSystemSync; /***/ }), -/* 701 */ +/* 700 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83180,7 +83168,7 @@ exports.flatten = flatten; /***/ }), -/* 702 */ +/* 701 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83201,13 +83189,13 @@ exports.merge = merge; /***/ }), -/* 703 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); -const pathType = __webpack_require__(704); +const pathType = __webpack_require__(703); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -83273,13 +83261,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 704 */ +/* 703 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); -const pify = __webpack_require__(705); +const pify = __webpack_require__(704); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -83322,7 +83310,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 705 */ +/* 704 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83413,17 +83401,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 706 */ +/* 705 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(134); const path = __webpack_require__(4); -const fastGlob = __webpack_require__(517); -const gitIgnore = __webpack_require__(707); -const pify = __webpack_require__(708); -const slash = __webpack_require__(709); +const fastGlob = __webpack_require__(516); +const gitIgnore = __webpack_require__(706); +const pify = __webpack_require__(707); +const slash = __webpack_require__(708); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -83521,7 +83509,7 @@ module.exports.sync = options => { /***/ }), -/* 707 */ +/* 706 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -83990,7 +83978,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 708 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84065,7 +84053,7 @@ module.exports = (input, options) => { /***/ }), -/* 709 */ +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84083,7 +84071,7 @@ module.exports = input => { /***/ }), -/* 710 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84096,7 +84084,7 @@ module.exports = input => { -var isGlob = __webpack_require__(711); +var isGlob = __webpack_require__(710); module.exports = function hasGlob(val) { if (val == null) return false; @@ -84116,7 +84104,7 @@ module.exports = function hasGlob(val) { /***/ }), -/* 711 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -84147,17 +84135,17 @@ module.exports = function isGlob(str) { /***/ }), -/* 712 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(4); const {constants: fsConstants} = __webpack_require__(134); -const pEvent = __webpack_require__(713); -const CpFileError = __webpack_require__(716); -const fs = __webpack_require__(718); -const ProgressEmitter = __webpack_require__(721); +const pEvent = __webpack_require__(712); +const CpFileError = __webpack_require__(715); +const fs = __webpack_require__(717); +const ProgressEmitter = __webpack_require__(720); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -84271,12 +84259,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 713 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(714); +const pTimeout = __webpack_require__(713); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -84567,12 +84555,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 714 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(715); +const pFinally = __webpack_require__(714); class TimeoutError extends Error { constructor(message) { @@ -84618,7 +84606,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 715 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84640,12 +84628,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 716 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(717); +const NestedError = __webpack_require__(716); class CpFileError extends NestedError { constructor(message, nested) { @@ -84659,7 +84647,7 @@ module.exports = CpFileError; /***/ }), -/* 717 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(112).inherits; @@ -84715,16 +84703,16 @@ module.exports = NestedError; /***/ }), -/* 718 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(112); const fs = __webpack_require__(133); -const makeDir = __webpack_require__(719); -const pEvent = __webpack_require__(713); -const CpFileError = __webpack_require__(716); +const makeDir = __webpack_require__(718); +const pEvent = __webpack_require__(712); +const CpFileError = __webpack_require__(715); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -84821,7 +84809,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 719 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84829,7 +84817,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__(720); +const semver = __webpack_require__(719); const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); @@ -84984,7 +84972,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 720 */ +/* 719 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -86586,7 +86574,7 @@ function coerce (version, options) { /***/ }), -/* 721 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86627,7 +86615,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 722 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86673,12 +86661,12 @@ exports.default = module.exports; /***/ }), -/* 723 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pMap = __webpack_require__(724); +const pMap = __webpack_require__(723); const pFilter = async (iterable, filterer, options) => { const values = await pMap( @@ -86695,7 +86683,7 @@ module.exports.default = pFilter; /***/ }), -/* 724 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86774,12 +86762,12 @@ module.exports.default = pMap; /***/ }), -/* 725 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(717); +const NestedError = __webpack_require__(716); class CpyError extends NestedError { constructor(message, nested) { diff --git a/scripts/build_api_docs.js b/scripts/build_api_docs.js new file mode 100644 index 000000000000000..039c9aaad3fcb72 --- /dev/null +++ b/scripts/build_api_docs.js @@ -0,0 +1,21 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +require('../src/setup_node_env'); +require('../src/dev/build_api_docs/run'); diff --git a/src/core/kibana.json b/src/core/kibana.json new file mode 100644 index 000000000000000..49f838dbc4ee564 --- /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 3cacae7f1c07290..aac8a65f8a52073 100644 --- a/src/core/server/plugins/discovery/plugin_manifest_parser.ts +++ b/src/core/server/plugins/discovery/plugin_manifest_parser.ts @@ -48,6 +48,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 3f75269100911e7..920f8cf19e8350c 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/dev/build_api_docs/build_api_declarations/buid_api_declaration.test.ts b/src/dev/build_api_docs/build_api_declarations/buid_api_declaration.test.ts new file mode 100644 index 000000000000000..8013845e9b61813 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/buid_api_declaration.test.ts @@ -0,0 +1,177 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import fs from 'fs'; +import Path from 'path'; +import { Project, Node } from 'ts-morph'; +import { REPO_ROOT } from '@kbn/utils'; +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 { getNodeName } from '../tsmorph_utils'; +import { buildApiDeclaration } from './build_api_declaration'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +let nodes: Node[]; +let plugins: KibanaPlatformPlugin[]; + +beforeAll(() => { + const project = new Project({ useInMemoryFileSystem: true }); + const folder = Path.resolve( + REPO_ROOT, + 'src', + 'dev', + 'build_api_docs', + 'tests', + 'src', + 'plugin_a', + 'server' + ); + const pluginFile: string = fs.readFileSync(Path.resolve(folder, 'plugin.ts')).toString(); + const indexFile: string = fs.readFileSync(Path.resolve(folder, 'index.ts')).toString(); + const utilsFile: string = fs.readFileSync(Path.resolve(folder, 'utils.ts')).toString(); + project.createSourceFile('example/public/plugin.ts', pluginFile); + project.createSourceFile('example/public/index.ts', indexFile); + project.createSourceFile('example/public/utils.ts', utilsFile); + + plugins = [getKibanaPlatformPlugin('example', 'example')]; + + 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.Number); +}); + +it('Function type is exported as type with signature', () => { + const node = nodes.find((n) => getNodeName(n) === 'FnType'); + 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.CompoundType); +}); + +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); +}); + +// 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); +// }); + +// it('Setup type has comment', () => { +// expect(doc.client[0].description).toBeDefined(); +// expect(doc.client[0].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('setup type has signature', () => { +// // // // Make sure the signature contains a link to the `SearchSpec` type. +// // expect(doc.client.setup[0].signature.length).toBe(3); +// // // Should contain the `SearchSpec` type. +// // expect(doc.client.setup[0].children.length).toBe(1); +// }); + +// it('fnWithInlineParams parameter is typed correctly', () => { +// const fnWithInlineParams = doc.client[0].children!.find((c) => c.label === 'fnWithInlineParams'); + +// expect(fnWithInlineParams).toBeDefined(); + +// const objParam = fnWithInlineParams?.children?.find((c) => c.label === 'obj'); +// expect(objParam).toBeDefined(); +// }); + +// it('Exported object property which is a function, utilityFunction, lists parameters', () => { +// const aNamespace = doc.client.find((c) => c.label === 'aNamespace'); +// expect(aNamespace).toBeDefined(); + +// const utilityFn = aNamespace?.children?.find((c) => c.label === 'utilityFunction'); +// expect(utilityFn).toBeDefined(); + +// expect(utilityFn?.children).toBeDefined(); +// expect(utilityFn?.children!.length).toBe(1); +// expect(utilityFn?.children![0].signature).toEqual(['UtilityFn']); +// }); + +// 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.Array); +// }); + +// 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.Array); +// }); + +// 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.String); +// }); + +// 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.Number); +// }); diff --git a/src/dev/build_api_docs/build_api_declarations/build_api_declaration.ts b/src/dev/build_api_docs/build_api_declarations/build_api_declaration.ts new file mode 100644 index 000000000000000..6f7f45ae3a082e0 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/build_api_declaration.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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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, isNamedNode } from '../tsmorph_utils'; +import { AnchorLink, ApiDeclaration, TextWithLinks, TypeKind } from '../types'; +import { buildApiDecForProperty } from './build_property_dec'; +import { buildApiDecFromVariable } from './build_variable_dec'; +import { getApiSectionId } from '../utils'; +import { getSourceForNode } from './utils'; +import { buildApiDecFromTypeLiteral } from './build_type_literal_dec'; +import { ApiScope } from '../types'; +import { getSignature } from './get_signature'; + +/** + * 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 parentAnchorLink Used to build a nested id for the API. If this is a top level plugin API, parentAnchorLink.apiId + * will be undefined. + * @param log Logs messages to console. + * @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(`getDocDef for ${apiName} of kind ${node.getKindName()}`); + const apiId = parentApiId ? parentApiId + '.' + apiName : apiName; + const anchorLink: AnchorLink = { scope, pluginName, apiName: apiId }; + + let description: TextWithLinks | undefined; + + if (Node.isJSDocableNode(node)) { + description = getCommentsFromNode(node); + } + + if (Node.isClassDeclaration(node)) { + return buildClassDec(node, plugins, anchorLink, log); + } + + if (Node.isInterfaceDeclaration(node)) { + return { + id: getApiSectionId(anchorLink), + type: TypeKind.InterfaceKind, + label: node.getName(), + signature: getSignature(node, plugins, log), + description, + children: node + .getMembers() + .map((m) => buildApiDeclaration(m, plugins, log, pluginName, scope, apiId)), + source: getSourceForNode(node), + }; + } + + if ( + Node.isMethodSignature(node) || + Node.isFunctionDeclaration(node) || + Node.isMethodDeclaration(node) || + Node.isConstructorDeclaration(node) + ) { + return buildFunctionDec(node, plugins, anchorLink, log); + } + + if (Node.isTypeAliasDeclaration(node)) { + return { + id: getApiSectionId(anchorLink), + type: TypeKind.TypeKind, + label: node.getName() || 'No name', + description, + source: getSourceForNode(node), + signature: getSignature(node, plugins, log), + }; + } + + if ( + Node.isPropertySignature(node) || + Node.isPropertyDeclaration(node) || + Node.isShorthandPropertyAssignment(node) + ) { + return buildApiDecForProperty(node, plugins, anchorLink, log); + } + + if (Node.isVariableDeclaration(node)) { + return buildApiDecFromVariable(node, plugins, anchorLink, log); + } + + if (Node.isTypeLiteralNode(node)) { + return buildApiDecFromTypeLiteral(node, plugins, anchorLink, log, apiName); + } + + return { + id: getApiSectionId(anchorLink), + type: TypeKind.Unknown, + label: node.getKindName(), + description: getCommentsFromNode(node), + source: getSourceForNode(node), + }; +} diff --git a/src/dev/build_api_docs/build_api_declarations/build_arrow_fn_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_arrow_fn_dec.ts new file mode 100644 index 000000000000000..5949f00b0b25f6f --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/build_arrow_fn_dec.ts @@ -0,0 +1,46 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; + +import { + ArrowFunction, + VariableDeclaration, + PropertyDeclaration, + PropertySignature, + ShorthandPropertyAssignment, +} from 'ts-morph'; +import { getApiSectionId } from '../utils'; +import { getCommentsFromNode } from '../tsmorph_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'; + +export function getArrowFunctionDec( + node: VariableDeclaration | PropertyDeclaration | PropertySignature | ShorthandPropertyAssignment, + 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/src/dev/build_api_docs/build_api_declarations/build_class_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_class_dec.ts new file mode 100644 index 000000000000000..27094a92fe56c29 --- /dev/null +++ b/src/dev/build_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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 '../tsmorph_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/src/dev/build_api_docs/build_api_declarations/build_function_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_function_dec.ts new file mode 100644 index 000000000000000..6ba4814535318fa --- /dev/null +++ b/src/dev/build_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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 '../tsmorph_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/src/dev/build_api_docs/build_api_declarations/build_function_type_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_function_type_dec.ts new file mode 100644 index 000000000000000..50c43deb1943cc7 --- /dev/null +++ b/src/dev/build_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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 '../tsmorph_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/src/dev/build_api_docs/build_api_declarations/build_parameter_decs.ts b/src/dev/build_api_docs/build_api_declarations/build_parameter_decs.ts new file mode 100644 index 000000000000000..b56f7aefaeac9e2 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/build_parameter_decs.ts @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 { getPropertyTypeKind } from '../utils'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getJSDocParamComment } from './js_doc_utils'; +import { getSourceForNode } from './utils'; + +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. + // I'm not sure I want to account for this use case, but rather encourage anything more nested or complicated to + // use a TypeReference instead of inline object literals. + if (param.getTypeNode() && param.getTypeNode()!.getKind() === SyntaxKind.TypeLiteral) { + acc.push( + buildApiDeclaration( + param.getTypeNode()!, + plugins, + log, + anchorLink.pluginName, + anchorLink.scope, + anchorLink.apiName, + label + ) + ); + } else { + const type = getPropertyTypeKind(param.getType()); + acc.push({ + type, + 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/src/dev/build_api_docs/build_api_declarations/build_property_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_property_dec.ts new file mode 100644 index 000000000000000..3515af28388310c --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/build_property_dec.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { + PropertyDeclaration, + PropertySignature, + Node, + ShorthandPropertyAssignment, +} from 'ts-morph'; +import { getApiSectionId, getPropertyTypeKind } from '../utils'; +import { getCommentsFromNode } from '../tsmorph_utils'; +import { AnchorLink, ApiDeclaration } from '../types'; +import { getArrowFunctionDec } from './build_arrow_fn_dec'; +import { buildFunctionDec } from './build_function_dec'; +import { buildApiDecFromFunctionType } from './build_function_type_dec'; +import { extractImportReferences } from './extract_import_refs'; +import { getJSDocs } from './js_doc_utils'; +import { getSourceForNode } from './utils'; + +/** + * + * @param node + * @param plugins + * @param anchorLink + * @param log + * + * @returns a DocDef build for a property that exists on an interface or object. This function is recursive because + * the property may be a function or object itself. + */ +export function buildApiDecForProperty( + node: PropertyDeclaration | PropertySignature | ShorthandPropertyAssignment, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +): ApiDeclaration { + log.debug(`Getting Property doc def for node ${node.getName()} of kind ${node.getKindName()}`); + const jsDocs = getJSDocs(node); + const callSigs = node.getType().getCallSignatures(); + if (callSigs && callSigs.length > 0) { + let fnDocDef: ApiDeclaration | undefined; + callSigs.forEach((sig) => { + const dec = sig.getDeclaration(); + log.debug( + `Node ${node.getName()} of kind ${node.getKindName()} has a call signature declaration of type ${dec.getKindName()}` + ); + if (Node.isFunctionDeclaration(dec)) { + fnDocDef = buildFunctionDec(dec, plugins, anchorLink, log); + } else if (Node.isFunctionTypeNode(dec)) { + fnDocDef = buildApiDecFromFunctionType( + node.getName(), + dec, + plugins, + anchorLink, + log, + jsDocs + ); + } + }); + if (fnDocDef) + return { + ...fnDocDef, + // The call signature won't have the comment on it. Use this instead. + description: getCommentsFromNode(node), + }; + } + const initializer = node.getInitializer(); + if (initializer && Node.isArrowFunction(initializer)) { + return getArrowFunctionDec(node, initializer, plugins, anchorLink, log); + } else { + log.debug(`Was not able to create a function doc def for this property`); + return { + id: getApiSectionId(anchorLink), + type: getPropertyTypeKind(node.getType()), + label: node.getName() || 'no name', + signature: extractImportReferences(node.getType().getText(), plugins, log), + description: getCommentsFromNode(node), + source: getSourceForNode(node), + }; + } +} diff --git a/src/dev/build_api_docs/build_api_declarations/build_type_literal_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_type_literal_dec.ts new file mode 100644 index 000000000000000..a7432c77051acf3 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/build_type_literal_dec.ts @@ -0,0 +1,43 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 '../tsmorph_utils'; +import { AnchorLink, ApiDeclaration, TypeKind } from '../types'; +import { buildApiDeclaration } from './build_api_declaration'; +import { getSourceForNode } from './utils'; + +export function buildApiDecFromTypeLiteral( + 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/src/dev/build_api_docs/build_api_declarations/build_variable_dec.ts b/src/dev/build_api_docs/build_api_declarations/build_variable_dec.ts new file mode 100644 index 000000000000000..01988d0de5a4cab --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/build_variable_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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { VariableDeclaration, Node } from 'ts-morph'; +import { getApiSectionId, getPropertyTypeKind } from '../utils'; +import { getCommentsFromNode } from '../tsmorph_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'; + +export function buildApiDecFromVariable( + node: VariableDeclaration, + plugins: KibanaPlatformPlugin[], + anchorLink: AnchorLink, + log: ToolingLog +): ApiDeclaration { + log.debug('buildApiDecFromVariable for ' + node.getName()); + const initializer = node.getInitializer(); + // Object variables can be large, we want to break down their properties. + if (initializer && Node.isObjectLiteralExpression(initializer)) { + log.debug(`${node.getName()} VariableDeclaration is an object literal`); + 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)) { + log.debug(`${node.getName()} VariableDeclaration is an arrow function`); + return getArrowFunctionDec(node, initializer, plugins, anchorLink, log); + } + // Otherwise return it just as a single entry. + return { + id: getApiSectionId(anchorLink), + type: getPropertyTypeKind(node.getType()), + label: node.getName(), + description: getCommentsFromNode(node), + source: getSourceForNode(node), + signature: getSignature(node, plugins, log), + }; +} diff --git a/src/dev/build_api_docs/build_api_declarations/extract_import_refs.test.ts b/src/dev/build_api_docs/build_api_declarations/extract_import_refs.test.ts new file mode 100644 index 000000000000000..c6cb8883f7a5fb9 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/extract_import_refs.test.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 { Reference } from '../types'; +import { getKibanaPlatformPlugin } from '../tests/kibana_platform_plugin_mock'; + +const plugins: KibanaPlatformPlugin[] = [getKibanaPlatformPlugin('pluginA', 'plugin_a')]; + +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_a/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'), + section: 'def-public.Bar', + }); +}); + +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(''); +}); diff --git a/src/dev/build_api_docs/build_api_declarations/extract_import_refs.ts b/src/dev/build_api_docs/build_api_declarations/extract_import_refs.ts new file mode 100644 index 000000000000000..c71fd35833273a2 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/extract_import_refs.ts @@ -0,0 +1,84 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { getApiSectionId, getPluginApiDocId, getPluginForPath } from '../utils'; +import { ApiScope, Reference } from '../types'; + +export function extractImportReferences( + text: string, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): Array { + const texts: Array = []; + let pos = 0; + let textSegment: string | undefined = text; + const max = 5; + + log.debug('Extracting references from ' + text); + while (textSegment) { + pos++; + if (pos > max) break; + + const ref = extractImportRef(textSegment); + if (ref) { + const index = textSegment.indexOf('import("'); + texts.push(textSegment.substr(0, index)); + const { name, path } = ref; + const lengthOfImport = 'import(".")'.length + path.length + name.length; + 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. + texts.push(textSegment.substr(index + lengthOfImport - name.length, name.length)); + } else { + const section = getApiSectionId({ + pluginName: plugin.manifest.id, + scope: getScopeFromPath(path, log), + apiName: name, + }); + texts.push({ + docId: getPluginApiDocId(plugin.manifest.id, plugin.manifest.serviceFolders, path), + section, + text: name, + }); + } + textSegment = textSegment.substr(index + lengthOfImport); + } else { + texts.push(textSegment); + textSegment = undefined; + } + } + return texts; +} + +export function extractImportRef(str: string): { path: string; name: string } | undefined { + const groups = str.match(/import\("(.*?)"\)\.(\w*)/); + if (groups) { + const path = groups[1]; + const name = groups[2]; + return { path, name }; + } +} + +function getScopeFromPath(path: string, log: ToolingLog): ApiScope { + if (path.indexOf('/public/') >= 0) { + return ApiScope.CLIENT; + } else if (path.indexOf('/server/') >= 0) { + return ApiScope.SERVER; + } else if (path.indexOf('/common/') >= 0) { + return ApiScope.COMMON; + } else { + log.warning(`Unexpected path encountered ${path}`); + return ApiScope.COMMON; + } +} diff --git a/src/dev/build_api_docs/build_api_declarations/get_signature.ts b/src/dev/build_api_docs/build_api_declarations/get_signature.ts new file mode 100644 index 000000000000000..d811017e13fa93c --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/get_signature.ts @@ -0,0 +1,74 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { KibanaPlatformPlugin, ToolingLog } from '@kbn/dev-utils'; +import { Node } from 'ts-morph'; +import { Reference } from '../types'; +import { extractImportReferences } from './extract_import_refs'; + +/** + * 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 { + // // 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)) { + const symbol = node.getSymbol(); + if (symbol) { + const declarations = symbol.getDeclarations(); + if (declarations.length === 1) { + // Unfortunately we are losing some reference links here. + return extractImportReferences(declarations[0].getType().getText(node), plugins, log); + } + } + } + + 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(); + return extractImportReferences(`(${params}) => ${returnType}`, plugins, log); + } + + // Need to tack on manually any type parameters or "extends/implements" section. + if (Node.isInterfaceDeclaration(node) || Node.isClassDeclaration(node)) { + const heritageClause = node + .getHeritageClauses() + .map((h) => h.getText()) + .join(' '); + + return extractImportReferences( + `${node.getType().getText()}${heritageClause ? ' ' + heritageClause : ''}`, + plugins, + log + ); + } + + // 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. + return extractImportReferences(node.getType().getText(), plugins, log); +} diff --git a/src/dev/build_api_docs/build_api_declarations/get_text_with_links.ts b/src/dev/build_api_docs/build_api_declarations/get_text_with_links.ts new file mode 100644 index 000000000000000..48f6dee17eee2ba --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/get_text_with_links.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { TextWithLinks } from '../types'; + +export function getTextWithLinks( + text?: string + // api: Api, + // apis: { [key: string]: Api }, + // plugins: PluginInfo[] +): TextWithLinks { + if (text) return [text]; + else return []; + // TODO: + // Replace `@links` in comments with relative api links. +} diff --git a/src/dev/build_api_docs/build_api_declarations/js_doc_utils.ts b/src/dev/build_api_docs/build_api_declarations/js_doc_utils.ts new file mode 100644 index 000000000000000..b83080b26ff0bfc --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/js_doc_utils.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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { JSDoc, JSDocTag, Node } from 'ts-morph'; +import { TextWithLinks } from '../types'; +import { getTextWithLinks } from './get_text_with_links'; + +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 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[]); +} + +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[]); +} diff --git a/src/dev/build_api_docs/build_api_declarations/sort_api_decs.test.ts b/src/dev/build_api_docs/build_api_declarations/sort_api_decs.test.ts new file mode 100644 index 000000000000000..0f278cab6c99952 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/sort_api_decs.test.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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { Lifecycle } from '../types'; +import { sortApiDeclarations } from './sort_api_decs'; +import { ApiDeclaration, TypeKind } from '../types'; + +it('sortDocDefs sorts', () => { + const docDefs: ApiDeclaration[] = [ + { + label: 'b', + type: TypeKind.InterfaceKind, + source: { path: '', lineNumber: 3, link: '' }, + }, + { + label: 'a', + type: TypeKind.InterfaceKind, + source: { path: '', lineNumber: 3, link: '' }, + }, + { + label: 'z', + type: TypeKind.InterfaceKind, + source: { path: '', lineNumber: 3, link: '' }, + lifecycle: Lifecycle.SETUP, + }, + { + label: 'y', + type: TypeKind.InterfaceKind, + source: { path: '', lineNumber: 3, link: '' }, + lifecycle: Lifecycle.START, + }, + ]; + + const sort = docDefs.sort(sortApiDeclarations); + + expect(sort[0].label).toBe('z'); + expect(sort[1].label).toBe('y'); + expect(sort[2].label).toBe('a'); + expect(sort[3].label).toBe('b'); +}); diff --git a/src/dev/build_api_docs/build_api_declarations/sort_api_decs.ts b/src/dev/build_api_docs/build_api_declarations/sort_api_decs.ts new file mode 100644 index 000000000000000..ce52fe75d31ee8e --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/sort_api_decs.ts @@ -0,0 +1,35 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { ApiDeclaration } from '../types'; + +/** + * Use to sort an array of DocDefs first by setup lifecycle type, then start, + * then the rest alphabetically. + * + * @param a + * @param b + */ +export function sortApiDeclarations(a: ApiDeclaration, b: ApiDeclaration) { + // Setup type first, then start type, then alphabetically. + if (a.lifecycle === 'setup') return -1; + else if (b.lifecycle === 'setup') return 1; + + if (a.lifecycle === 'start') return -1; + else if (b.lifecycle === 'start') return 1; + + const aName = a.label || ''; + const bName = b.label || ''; + if (aName < bName) { + return -1; + } + if (aName > bName) { + return 1; + } + return 0; +} diff --git a/src/dev/build_api_docs/build_api_declarations/utils.ts b/src/dev/build_api_docs/build_api_declarations/utils.ts new file mode 100644 index 000000000000000..b037b88345355b6 --- /dev/null +++ b/src/dev/build_api_docs/build_api_declarations/utils.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +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 { + const index = fullPath.indexOf(REPO_ROOT); + if (index >= 0) { + return fullPath.slice(REPO_ROOT.length); + } else { + return 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/src/dev/build_api_docs/build_api_docs.ts b/src/dev/build_api_docs/build_api_docs.ts new file mode 100644 index 000000000000000..6c10e629d195f47 --- /dev/null +++ b/src/dev/build_api_docs/build_api_docs.ts @@ -0,0 +1,136 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import fs from 'fs'; +import Path from 'path'; +import { REPO_ROOT } from '@kbn/dev-utils'; +import { ToolingLog } from '@kbn/dev-utils'; +import { Project } from 'ts-morph'; +import { getPluginApi } from './get_plugin_api'; +import { writePluginDocs } from './mdx/write_plugin_mdx_docs'; +import { findPlugins } from '../plugin_discovery'; +import { ApiDeclaration, PluginApi } from './types'; +import { mergeScopeApi } from './utils'; + +const log = new ToolingLog({ + level: 'debug', + writeTo: process.stdout, +}); + +function getTsProject(repoPath: string) { + const xpackTsConfig = `${repoPath}/x-pack/tsconfig.json`; + const project = new Project({ + tsConfigFilePath: xpackTsConfig, + }); + project.addSourceFilesAtPaths(`${repoPath}/examples/**/*{.d.ts,.ts}`); + project.addSourceFilesAtPaths(`${repoPath}/src/plugins/**/*{.d.ts,.ts}`); + project.addSourceFilesAtPaths(`${repoPath}/x-pack/plugins/**/*{.d.ts,.ts}`); + project.resolveSourceFileDependencies(); + return project; +} + +export function buildApiDocs() { + const project = getTsProject(REPO_ROOT); + + const plugins = Array.from( + findPlugins({ + oss: false, + examples: false, + // Use this to capture "core" as a plugin. + extraPluginScanDirs: [Path.resolve(REPO_ROOT, 'src')], + }).values() + ); + + const pluginInfos: Array<{ + apiCount: number; + apiCountMissingComments: number; + plugin: string; + }> = []; + + 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)); + } + }); + } + + plugins.forEach((plugin) => { + const doc = getPluginApi(project, plugin, plugins, log); + const info = { + plugin: plugin.manifest.id, + apiCount: countApiForPlugin(doc), + apiCountMissingComments: countMissingCommentsApiForPlugin(doc), + }; + + if (info.apiCount > 0) { + writePluginDocs(outputFolder, doc, log); + pluginInfos.push(info); + } + }); + + // eslint-disable-next-line no-console + console.table(pluginInfos); +} + +function countMissingCommentsApiForPlugin(doc: PluginApi) { + return ( + mergeScopeApi(doc.client).reduce((sum, def) => { + return sum + countMissingCommentsForApi(def); + }, 0) + + mergeScopeApi(doc.server).reduce((sum, def) => { + return sum + countMissingCommentsForApi(def); + }, 0) + + mergeScopeApi(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 ( + mergeScopeApi(doc.client).reduce((sum, def) => { + return sum + countApi(def); + }, 0) + + mergeScopeApi(doc.server).reduce((sum, def) => { + return sum + countApi(def); + }, 0) + + mergeScopeApi(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/src/dev/build_api_docs/get_declaration_nodes_for_plugin.ts b/src/dev/build_api_docs/get_declaration_nodes_for_plugin.ts new file mode 100644 index 000000000000000..e4fc3f65747a171 --- /dev/null +++ b/src/dev/build_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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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.relativeDirectory}`, 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/src/dev/build_api_docs/get_plugin_api.ts b/src/dev/build_api_docs/get_plugin_api.ts new file mode 100644 index 000000000000000..43e5ad05d24001c --- /dev/null +++ b/src/dev/build_api_docs/get_plugin_api.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import Path from 'path'; +import { Node, Project } from 'ts-morph'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { ApiScope, Lifecycle, ScopeApi } 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'; +import { groupPluginApi } from './utils'; + +/** + * Returns information neccessary to create the mdx files. + * + * @param plugin + * @param apis + * @param plugins + * @param log + */ +export function getPluginApi( + project: Project, + plugin: KibanaPlatformPlugin, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): PluginApi { + const client = getScopeApi(project, plugin, ApiScope.CLIENT, plugins, log); + const server = getScopeApi(project, plugin, ApiScope.SERVER, plugins, log); + const common = getScopeApi(project, plugin, ApiScope.COMMON, plugins, log); + return { + id: plugin.manifest.id, + client, + server, + common, + serviceFolders: plugin.manifest.serviceFolders, + }; +} + +function getScopeApi( + project: Project, + plugin: KibanaPlatformPlugin, + scope: ApiScope, + plugins: KibanaPlatformPlugin[], + log: ToolingLog +): ScopeApi { + const nodes = getDeclarationNodesForPluginScope(project, plugin, scope, log); + + const contractTypes = getContractTypeNames(project, plugin, scope); + + const declarations = nodes.reduce((acc, node) => { + const lifecycle = getLifecycle(node, contractTypes); + 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) { + acc.push({ + ...apiDec, + lifecycle, + initialIsOpen: lifecycle !== undefined, + }); + } + return acc; + }, []); + + return groupPluginApi(declarations); +} + +function getLifecycle( + node: Node, + contractTypeNames: { start?: string; setup?: string } +): Lifecycle | undefined { + // Note this logic is not tested if a plugin uses "as", + // like export { Setup as MyPluginSetup } from ..." + if (contractTypeNames.start && node.getType().getText() === contractTypeNames.start) { + return Lifecycle.START; + } + + if (contractTypeNames.setup && node.getType().getText() === contractTypeNames.setup) { + return Lifecycle.SETUP; + } +} + +export function getContractTypeNames( + project: Project, + plugin: KibanaPlatformPlugin, + scope: ApiScope +): { setup?: string; start?: string } { + const contractTypes: { setup?: string; start?: string } = {}; + const file = getSourceFileMatching( + project, + Path.join(`${plugin.relativeDirectory}`, 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.getText(); + } else if (index === 1) { + contractTypes.start = arg.getText(); + } + index++; + }); + }); + }); + } + return contractTypes; +} diff --git a/src/dev/build_api_docs/mdx/split_apis_by_folder.test.ts b/src/dev/build_api_docs/mdx/split_apis_by_folder.test.ts new file mode 100644 index 000000000000000..92fbb696c490627 --- /dev/null +++ b/src/dev/build_api_docs/mdx/split_apis_by_folder.test.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import Path from 'path'; +import { Project } from 'ts-morph'; +import { REPO_ROOT } from '@kbn/utils'; +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( + REPO_ROOT, + 'src', + 'dev', + 'build_api_docs', + 'tests', + 'src', + 'tsconfig.json' + ); + const project = new Project({ + tsConfigFilePath, + }); + + expect(project.getSourceFiles().length).toBeGreaterThan(0); + + const pluginA = getKibanaPlatformPlugin('pluginA', 'plugin_a'); + pluginA.manifest.serviceFolders = ['foo']; + const plugins: KibanaPlatformPlugin[] = [pluginA]; + + doc = getPluginApi(project, plugins[0], plugins, log); +}); + +test('foo service has all exports', () => { + expect(doc?.client.objects.length).toBe(1); + 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.misc.length).toBe(1); + expect(fooDoc?.client.functions.length).toBe(1); + expect(fooDoc?.client.objects.length).toBe(0); + expect(mainDoc?.client.objects.length).toBe(1); +}); diff --git a/src/dev/build_api_docs/mdx/write_plugin_mdx_docs.ts b/src/dev/build_api_docs/mdx/write_plugin_mdx_docs.ts new file mode 100644 index 000000000000000..ab94568880e5bab --- /dev/null +++ b/src/dev/build_api_docs/mdx/write_plugin_mdx_docs.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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 } 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 ( + countScopeApi(doc.client) > 0 || countScopeApi(doc.server) > 0 || countScopeApi(doc.common) > 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)} +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'; + + fs.writeFileSync(Path.resolve(folder, fileName + '.json'), JSON.stringify(doc)); + + mdx += scopApiToMdx(doc.client, 'Client', json, 'client'); + mdx += scopApiToMdx(doc.server, 'Server', json, 'server'); + mdx += scopApiToMdx(doc.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/src/dev/build_api_docs/mdx/write_plugin_split_by_folder.test.ts b/src/dev/build_api_docs/mdx/write_plugin_split_by_folder.test.ts new file mode 100644 index 000000000000000..087990adaed254c --- /dev/null +++ b/src/dev/build_api_docs/mdx/write_plugin_split_by_folder.test.ts @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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', '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(); + + expect(mainDoc?.client.misc.length).toBe(1); + + const serviceDoc = docs.find((d) => d.id === 'example.aService'); + + expect(serviceDoc).toBeDefined(); + + expect(serviceDoc?.client.interfaces.length).toBe(1); +}); diff --git a/src/dev/build_api_docs/mdx/write_plugin_split_by_folder.ts b/src/dev/build_api_docs/mdx/write_plugin_split_by_folder.ts new file mode 100644 index 000000000000000..6fc37f6de97404a --- /dev/null +++ b/src/dev/build_api_docs/mdx/write_plugin_split_by_folder.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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { ToolingLog } from '@kbn/dev-utils'; +import { + addApiDeclarationToScope, + createEmptyScope, + getServiceForPath, + mergeScopeApi, + 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); + + mergeScopeApi(pluginDoc.client).forEach((dec: ApiDeclaration) => { + addSection(dec, 'client', mainPluginDocDef, pluginDocDefsByFolder, pluginDoc.serviceFolders!); + }); + mergeScopeApi(pluginDoc.server).forEach((dec: ApiDeclaration) => { + addSection(dec, 'server', mainPluginDocDef, pluginDocDefsByFolder, pluginDoc.serviceFolders!); + }); + mergeScopeApi(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 serviceFolderName = getServiceForPath(dec.source.path); + if (serviceFolderName && serviceFolders.find((f) => f === serviceFolderName)) { + const service = snakeToCamel(serviceFolderName); + if (!pluginServices[service]) { + pluginServices[service] = createServicePluginDocDef(mainPluginDocDef, service); + } + addApiDeclarationToScope(dec, pluginServices[service][scope]); + } else { + addApiDeclarationToScope(dec, mainPluginDocDef[scope]); + } +} + +function createServicePluginDocDef(pluginDoc: PluginApi, service?: string): PluginApi { + return { + id: service ? pluginDoc.id + '.' + service : pluginDoc.id, + client: createEmptyScope(), + server: createEmptyScope(), + common: createEmptyScope(), + }; +} diff --git a/src/dev/build_api_docs/run.ts b/src/dev/build_api_docs/run.ts new file mode 100644 index 000000000000000..463337c708a814c --- /dev/null +++ b/src/dev/build_api_docs/run.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { buildApiDocs } from './build_api_docs'; + +buildApiDocs(); diff --git a/src/dev/build_api_docs/tests/__snapshots__/api_doc_suite.test.ts.snap b/src/dev/build_api_docs/tests/__snapshots__/api_doc_suite.test.ts.snap new file mode 100644 index 000000000000000..c2a020a91984bf8 --- /dev/null +++ b/src/dev/build_api_docs/tests/__snapshots__/api_doc_suite.test.ts.snap @@ -0,0 +1,139 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`functions arrow function is exported correctly: + Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e?: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + 1`] = ` +Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e?: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", +] +`; + +exports[`functions non arrow function is exported correctly: + Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + 1`] = ` +Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", +] +`; + +exports[`objects Exported object property which is a non arrow function is correct: + Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + 1`] = ` +Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", +] +`; diff --git a/src/dev/build_api_docs/tests/api_doc_suite.test.ts b/src/dev/build_api_docs/tests/api_doc_suite.test.ts new file mode 100644 index 000000000000000..eaca272b6ba4d2e --- /dev/null +++ b/src/dev/build_api_docs/tests/api_doc_suite.test.ts @@ -0,0 +1,360 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import fs from 'fs'; +import Path from 'path'; +import { Project } from 'ts-morph'; +import { REPO_ROOT } from '@kbn/utils'; +import { ToolingLog, KibanaPlatformPlugin } from '@kbn/dev-utils'; + +import { writePluginDocs } from '../mdx/write_plugin_mdx_docs'; +import { ApiDeclaration, PluginApi, TextWithLinks, TypeKind } from '../types'; +import { getKibanaPlatformPlugin } from './kibana_platform_plugin_mock'; +import { getPluginApi } from '../get_plugin_api'; + +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, snapshot: string) { + 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!.signature!).toMatchSnapshot(snapshot); + + 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.String); + 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.Number); + 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.Array); + 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.CompoundType); + expect(p4!.signature?.length).toBeGreaterThan(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.String); + expect(p5!.signature?.length).toBe(1); + expect(linkCount(p5!.signature!)).toBe(0); +} + +beforeAll(() => { + const tsConfigFilePath = Path.resolve( + REPO_ROOT, + 'src', + 'dev', + 'build_api_docs', + 'tests', + 'src', + 'tsconfig.json' + ); + const project = new Project({ + tsConfigFilePath, + }); + + expect(project.getSourceFiles().length).toBeGreaterThan(0); + + const pluginA = getKibanaPlatformPlugin('pluginA', 'plugin_a'); + pluginA.manifest.serviceFolders = ['foo']; + const plugins: KibanaPlatformPlugin[] = [pluginA]; + + doc = getPluginApi(project, plugins[0], plugins, log); + mdxOutputFolder = Path.resolve(REPO_ROOT, 'src', 'dev', 'build_api_docs', 'tests', 'snapshots'); + writePluginDocs(mdxOutputFolder, doc, log); +}); + +it('Setup type is extracted', () => { + expect(doc.client.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', () => { + expect(doc.client.setup!.description).toBeDefined(); + expect(doc.client.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.misc.find((c) => c.label === 'commonFoo'); + expect(fooConst).toBeDefined(); + + expect(fooConst!.source.path.indexOf('src/plugin_a/common/foo/index.ts')).toBeGreaterThanOrEqual( + 0 + ); + expect(fooConst!.signature![0]).toBe('"COMMON VAR!"'); +}); + +describe('functions', () => { + it('arrow function is exported correctly', () => { + const fn = doc.client.functions.find((c) => c.label === 'arrowFn'); + // For some reason the arrow function signature uses "e?: string | undefined) => " while + // non arrow function signature shows up with "e: string | undefined) => ", hence the need to + // pass it in. + fnIsCorrect( + fn, + ` + Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e?: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + ` + ); + }); + + it('non arrow function is exported correctly', () => { + const fn = doc.client.functions.find((c) => c.label === 'notAnArrowFn'); + fnIsCorrect( + fn, + ` + Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + ` + ); + }); + + it('crazyFunction is typed correctly', () => { + const fn = doc.client.functions!.find((c) => c.label === 'crazyFunction'); + + expect(fn).toBeDefined(); + + const objParam = fn?.children?.find((c) => c.label === 'obj'); + expect(objParam).toBeDefined(); + }); +}); + +describe('objects', () => { + it('Exported object property which is a non arrow function is correct', () => { + const aNamespace = doc.client.objects.find((c) => c.label === 'aNamespace'); + expect(aNamespace).toBeDefined(); + + const fn = aNamespace?.children?.find((c) => c.label === 'notAnArrowFn'); + fnIsCorrect( + fn, + ` + Array [ + "(a: string, b: number | undefined, c: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + ", d: ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.ImAType", + "text": "ImAType", + }, + ", e: string | undefined) => ", + Object { + "docId": "kibPluginAPluginApi", + "section": "def-public.TypeWithGeneric", + "text": "TypeWithGeneric", + }, + "", + ] + ` + ); + }); +}); + +describe('Misc types', () => { + it('Explicitly typed array is returned with the correct type', () => { + const aStrArray = doc.client.misc.find((c) => c.label === 'aStrArray'); + expect(aStrArray).toBeDefined(); + expect(aStrArray?.type).toBe(TypeKind.Array); + }); + + it('Implicitly typed array is returned with the correct type', () => { + const aNumArray = doc.client.misc.find((c) => c.label === 'aNumArray'); + expect(aNumArray).toBeDefined(); + expect(aNumArray?.type).toBe(TypeKind.Array); + }); + + it('Explicitly typed string is returned with the correct type', () => { + const aStr = doc.client.misc.find((c) => c.label === 'aStr'); + expect(aStr).toBeDefined(); + expect(aStr?.type).toBe(TypeKind.String); + }); + + it('Implicitly typed number is returned with the correct type', () => { + const aNum = doc.client.misc.find((c) => c.label === 'aNum'); + expect(aNum).toBeDefined(); + expect(aNum?.type).toBe(TypeKind.Number); + }); + + it('aUnionProperty is exported as a CompoundType with a call signature', () => { + const prop = doc.client.misc.find((c) => c.label === 'aUnionProperty'); + expect(prop).toBeDefined(); + expect(prop?.type).toBe(TypeKind.CompoundType); + expect(linkCount(prop?.signature!)).toBe(1); + }); + + it('Function type is exported correctly', () => { + const fnType = doc.client.misc.find((c) => c.label === 'FnWithGeneric'); + expect(fnType).toBeDefined(); + expect(fnType?.type).toBe(TypeKind.TypeKind); + expect(fnType?.signature!).toMatchInlineSnapshot(` + Array [ + "(t: T) => TypeWithGeneric", + ] + `); + + // This is a known bug, links are not captured. https://github.com/dsherret/ts-morph/issues/923 + // TODO: if we can fix this bug, uncomment this line. + // expect(linkCount(fnType?.signature!)).toBe(1); + }); +}); + +describe('interfaces and classes', () => { + it('Interface exported correctly', () => { + const exampleInterface = doc.client.interfaces.find((c) => c.label === 'ExampleInterface'); + expect(exampleInterface).toBeDefined(); + expect(exampleInterface?.signature).toBeDefined(); + expect(exampleInterface?.type).toBe(TypeKind.InterfaceKind); + + expect(linkCount(exampleInterface?.signature!)).toBe(1); + + // 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", + // "section": "def-public.ExampleInterface", + // "text": "ExampleInterface", + // }, + // " extends AnotherInterface", + // ] + // `); + // expect(typeof exampleInterface!.signature![2]).toBe('Object'); + }); + + it('Non arrow function on interface is exported as function type', () => { + const exampleInterface = doc.client.interfaces.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.classes.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", + "section": "def-public.CrazyClass", + "text": "CrazyClass", + }, + "

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

extends ExampleClass>"],"children":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":51,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/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: ",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},", d: ",{"docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},", e: string | undefined) => ",{"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":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":22,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L22"}},{"type":"number","label":"b","isRequired":false,"signature":["number | undefined"],"description":["Feed me to the function"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":23,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L23"}},{"type":"Array","label":"c","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["So many params"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":24,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L24"}},{"type":"CompoundType","label":"d","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":["a great param"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":25,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L25"}},{"type":"string","label":"e","isRequired":false,"signature":["string | undefined"],"description":["Another comment"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L26"}}],"tags":[],"returnComment":["something!"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":21,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/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":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":42,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L42"}},{"type":"number","label":"b","isRequired":false,"signature":["number | undefined"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":43,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L43"}},{"type":"Array","label":"c","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":44,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L44"}},{"type":"CompoundType","label":"d","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":45,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L45"}},{"type":"string","label":"e","isRequired":false,"signature":["string | undefined"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":46,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L46"}}],"signature":["(a: string, b: number | undefined, c: ",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},", d: ",{"docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},", e?: string | undefined) => ",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["\nThis is an arrow function.\n"],"label":"arrowFn","source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":41,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/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":[{"type":"Function","id":"def-public.crazyFunction.obj.fn","label":"fn","signature":["(foo: { param: string; }) => number"],"description":[],"tags":[],"returnComment":[],"children":[{"id":"def-public.crazyFunction.obj.fn.foo","type":"Object","label":"foo","description":[],"children":[{"id":"def-public.crazyFunction.obj.fn.foo.param","type":"string","label":"param","signature":["string"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":59,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L59"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":59,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L59"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":59,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L59"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":59,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L59"}}],"signature":["(obj: { fn: (foo: { param: string; }) => number; }) => () => () => string"],"description":["\nWho would write such a complicated function?? Ew, how will the obj parameter appear in docs?\n"],"label":"crazyFunction","source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":59,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L59"},"returnComment":["I have no idea."],"initialIsOpen":false}],"interfaces":[{"id":"def-public.SearchSpec","type":"Interface","label":"SearchSpec","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.SearchSpec","text":"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","signature":["string"],"description":["\nStores the username. Duh,"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L26"}},{"id":"def-public.SearchSpec.password","type":"string","label":"password","signature":["string"],"description":["\nStores the password. I hope it's encrypted!"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":30,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L30"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":22,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L22"},"initialIsOpen":false},{"id":"def-public.WithGen","type":"Interface","label":"WithGen","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.WithGen","text":"WithGen"},""],"description":["\nAn interface with a generic."],"children":[{"id":"def-public.WithGen.t","type":"Unknown","label":"t","signature":["T"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":17,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L17"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":16,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L16"},"initialIsOpen":false},{"id":"def-public.AnotherInterface","type":"Interface","label":"AnotherInterface","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.AnotherInterface","text":"AnotherInterface"},""],"description":[],"children":[{"id":"def-public.AnotherInterface.t","type":"Unknown","label":"t","signature":["T"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":21,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L21"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":20,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L20"},"initialIsOpen":false},{"id":"def-public.ExampleInterface","type":"Interface","label":"ExampleInterface","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.ExampleInterface","text":"ExampleInterface"}," extends AnotherInterface"],"description":["\nThis is an example interface so we can see how it appears inside the API\ndocumentation system."],"children":[{"type":"Function","id":"def-public.ExampleInterface.getAPromiseThatResolvesToString","label":"getAPromiseThatResolvesToString","signature":["() => Promise"],"description":["\nThis gets a promise that resolves to a string."],"tags":[],"returnComment":[],"children":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":61,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L61"}},{"type":"Function","id":"def-public.ExampleInterface.aFnWithGen","label":"aFnWithGen","signature":["(t: T) => void"],"description":["\nThis function takes a generic. It was sometimes being tripped on\nand returned as an unknown type with no signature."],"tags":[],"returnComment":[],"children":[{"type":"Unknown","label":"t","isRequired":true,"signature":["T"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":67,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L67"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":67,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L67"}},{"id":"def-public.ExampleInterface.aFn","type":"Function","label":"aFn","signature":["() => void"],"description":["\nThese are not coming back properly."],"children":[],"tags":[],"returnComment":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":72,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L72"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":57,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L57"},"initialIsOpen":false},{"id":"def-public.IReturnAReactComponent","type":"Interface","label":"IReturnAReactComponent","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.IReturnAReactComponent","text":"IReturnAReactComponent"}],"description":["\nAn interface that has a react component."],"children":[{"id":"def-public.IReturnAReactComponent.component","type":"CompoundType","label":"component","signature":["React.ComponentType<{}>"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":79,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L79"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts","lineNumber":78,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts#L78"},"initialIsOpen":false}],"enums":[],"misc":[{"id":"def-public.aUnionProperty","type":"CompoundType","label":"aUnionProperty","description":["\nThis is a complicated union type"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts","lineNumber":27,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts#L27"},"signature":["string | number | (() => string) | ",{"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":"/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts","lineNumber":32,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts#L32"},"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":"/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts","lineNumber":37,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts#L37"},"signature":["number[]"],"initialIsOpen":false},{"id":"def-public.aStr","type":"string","label":"aStr","description":["\nA string that says hi to you!"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts","lineNumber":42,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts#L42"},"signature":["string"],"initialIsOpen":false},{"id":"def-public.aNum","type":"number","label":"aNum","description":["\nIt's a number. A special number."],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts","lineNumber":47,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts#L47"},"signature":["10"],"initialIsOpen":false},{"id":"def-public.StringOrUndefinedType","type":"Type","label":"StringOrUndefinedType","description":["\nHow should a potentially undefined type show up."],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts","lineNumber":12,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts#L12"},"signature":["string | undefined"],"initialIsOpen":false},{"id":"def-public.TypeWithGeneric","type":"Type","label":"TypeWithGeneric","description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts","lineNumber":14,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts#L14"},"signature":["T[]"],"initialIsOpen":false},{"id":"def-public.ImAType","type":"Type","label":"ImAType","description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts","lineNumber":16,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts#L16"},"signature":["string | number | TypeWithGeneric"],"initialIsOpen":false},{"id":"def-public.FnWithGeneric","type":"Type","label":"FnWithGeneric","description":["\nThis is a type that defines a function.\n"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts","lineNumber":23,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts#L23"},"signature":["(t: T) => TypeWithGeneric"],"initialIsOpen":false}],"objects":[{"id":"def-public.aNamespace","type":"Object","children":[{"id":"def-public.aNamespace.notAnArrowFn","type":"Function","label":"notAnArrowFn","signature":["(a: string, b: number | undefined, c: ",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},", d: ",{"docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"},", e: string | undefined) => ",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["/**\n * Will this comment show up in the docs? Or the one on the definition of\n * notAnArrowFn?\n */\n"],"children":[{"type":"string","label":"a","isRequired":true,"signature":["string"],"description":["The letter A"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":22,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L22"}},{"type":"number","label":"b","isRequired":false,"signature":["number | undefined"],"description":["Feed me to the function"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":23,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L23"}},{"type":"Array","label":"c","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.TypeWithGeneric","text":"TypeWithGeneric"},""],"description":["So many params"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":24,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L24"}},{"type":"CompoundType","label":"d","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.ImAType","text":"ImAType"}],"description":["a great param"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":25,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L25"}},{"type":"string","label":"e","isRequired":false,"signature":["string | undefined"],"description":["Another comment"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":26,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L26"}}],"tags":[],"returnComment":["something!"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts","lineNumber":21,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts#L21"}}],"description":["\nSome of the plugins wrap static exports in an object to create\na namespace like this."],"label":"aNamespace","source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts","lineNumber":16,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts#L16"},"initialIsOpen":false}],"start":{"id":"def-public.Start","type":"Interface","label":"Start","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.Start","text":"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":[{"type":"Function","id":"def-public.Start.getSearchLanguage","label":"getSearchLanguage","signature":["() => ",{"docId":"kibPluginAPluginApi","section":"def-public.SearchLanguage","text":"SearchLanguage"}],"description":[],"tags":[],"returnComment":["The currently selected {@link SearchLanguage}"],"children":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":68,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L68"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":64,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L64"},"lifecycle":"start","initialIsOpen":true},"setup":{"id":"def-public.Setup","type":"Interface","label":"Setup","signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.Setup","text":"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":[{"type":"Function","id":"def-public.Setup.getSearchService","label":"getSearchService","signature":["(searchSpec: ",{"docId":"kibPluginAPluginApi","section":"def-public.SearchSpec","text":"SearchSpec"},") => string"],"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"],"tags":["beta"],"returnComment":["the id of the search service."],"children":[{"type":"Object","label":"searchSpec","isRequired":true,"signature":["",{"docId":"kibPluginAPluginApi","section":"def-public.SearchSpec","text":"SearchSpec"}],"description":["Provide the settings neccessary to create a new Search Service"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":96,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L96"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":96,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L96"}},{"type":"Function","id":"def-public.Setup.getSearchService2","label":"getSearchService2","signature":["(searchSpec: { username: string; password: string; }) => string"],"description":["\nThis uses an inlined object type rather than referencing an exported type, which is discouraged.\nprefer the way { getSearchService} is typed.\n"],"tags":[],"returnComment":[],"children":[{"id":"def-public.Setup.getSearchService2.searchSpec","type":"Object","label":"searchSpec","description":[],"children":[{"id":"def-public.Setup.getSearchService2.searchSpec.username","type":"string","label":"username","signature":["string"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":104,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L104"}},{"id":"def-public.Setup.getSearchService2.searchSpec.password","type":"string","label":"password","signature":["string"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":104,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L104"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":104,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L104"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":104,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L104"}},{"type":"Function","id":"def-public.Setup.doTheThing","label":"doTheThing","signature":["(thingOne: number, thingTwo: string, thingThree: { nestedVar: number; }) => void"],"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"],"tags":["deprecated"],"returnComment":[],"children":[{"type":"number","label":"thingOne","isRequired":true,"signature":["number"],"description":["Thing one comment"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":117,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L117"}},{"type":"string","label":"thingTwo","isRequired":true,"signature":["string"],"description":["ThingTwo comment"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":117,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L117"}},{"id":"def-public.Setup.doTheThing.thingThree","type":"Object","label":"thingThree","description":[],"children":[{"id":"def-public.Setup.doTheThing.thingThree.nestedVar","type":"number","label":"nestedVar","signature":["number"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":117,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L117"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":117,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L117"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":117,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L117"}},{"type":"Function","id":"def-public.Setup.fnWithInlineParams","label":"fnWithInlineParams","signature":["(obj: { fn: (foo: { param: string; }) => number; }) => () => { retFoo: () => string; }"],"description":["\nWho would write such a complicated function?? Ew, how will the obj parameter appear in docs?\n"],"tags":[],"returnComment":["It's hard to tell but I think this returns a function that returns an object with a\nproperty that is a function that returns a string. Whoa."],"children":[{"id":"def-public.Setup.fnWithInlineParams.obj","type":"Object","label":"obj","description":[],"children":[{"type":"Function","id":"def-public.Setup.fnWithInlineParams.obj.fn","label":"fn","signature":["(foo: { param: string; }) => number"],"description":[],"tags":[],"returnComment":[],"children":[{"id":"def-public.Setup.fnWithInlineParams.obj.fn.foo","type":"Object","label":"foo","description":[],"children":[{"id":"def-public.Setup.fnWithInlineParams.obj.fn.foo.param","type":"string","label":"param","signature":["string"],"description":[],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":129,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L129"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":129,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L129"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":129,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L129"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":128,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L128"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":128,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L128"}},{"id":"def-public.Setup.id","type":"string","label":"id","signature":["string"],"description":["\nHi, I'm a comment for an id string!"],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":135,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L135"}}],"source":{"path":"/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts","lineNumber":84,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts#L84"},"lifecycle":"setup","initialIsOpen":true}},"server":{"classes":[],"functions":[],"interfaces":[],"enums":[],"misc":[],"objects":[]},"common":{"classes":[],"functions":[],"interfaces":[],"enums":[],"misc":[],"objects":[]}} \ No newline at end of file diff --git a/src/dev/build_api_docs/tests/snapshots/plugin_a.mdx b/src/dev/build_api_docs/tests/snapshots/plugin_a.mdx new file mode 100644 index 000000000000000..c9b18ebaa6847ac --- /dev/null +++ b/src/dev/build_api_docs/tests/snapshots/plugin_a.mdx @@ -0,0 +1,28 @@ +--- +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 + +### Consts, variables and types + diff --git a/src/dev/build_api_docs/tests/snapshots/plugin_a_foo.json b/src/dev/build_api_docs/tests/snapshots/plugin_a_foo.json new file mode 100644 index 000000000000000..2bbb661c62ae72b --- /dev/null +++ b/src/dev/build_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":"/src/dev/build_api_docs/tests/src/plugin_a/public/foo/index.ts","lineNumber":9,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/public/foo/index.ts#L9"},"returnComment":[],"initialIsOpen":false}],"interfaces":[],"enums":[],"misc":[],"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":"/src/dev/build_api_docs/tests/src/plugin_a/common/foo/index.ts","lineNumber":9,"link":"https://github.com/elastic/kibana/tree/master/src/dev/build_api_docs/tests/src/plugin_a/common/foo/index.ts#L9"},"signature":["\"COMMON VAR!\""],"initialIsOpen":false}],"objects":[]}} \ No newline at end of file diff --git a/src/dev/build_api_docs/tests/snapshots/plugin_a_foo.mdx b/src/dev/build_api_docs/tests/snapshots/plugin_a_foo.mdx new file mode 100644 index 000000000000000..22337eb1c4213ad --- /dev/null +++ b/src/dev/build_api_docs/tests/snapshots/plugin_a_foo.mdx @@ -0,0 +1,20 @@ +--- +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 + +## Common + +### Consts, variables and types + diff --git a/src/dev/build_api_docs/tests/src/plugin_a/common/foo/index.ts b/src/dev/build_api_docs/tests/src/plugin_a/common/foo/index.ts new file mode 100644 index 000000000000000..925c100117d19e2 --- /dev/null +++ b/src/dev/build_api_docs/tests/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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +export const commonFoo = 'COMMON VAR!'; diff --git a/src/dev/build_api_docs/tests/src/plugin_a/common/index.ts b/src/dev/build_api_docs/tests/src/plugin_a/common/index.ts new file mode 100644 index 000000000000000..73a602a5e883265 --- /dev/null +++ b/src/dev/build_api_docs/tests/src/plugin_a/common/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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +export { commonFoo } from './foo'; diff --git a/src/dev/build_api_docs/tests/src/plugin_a/kibana.json b/src/dev/build_api_docs/tests/src/plugin_a/kibana.json new file mode 100644 index 000000000000000..84b46caa7080211 --- /dev/null +++ b/src/dev/build_api_docs/tests/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/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/classes.ts new file mode 100644 index 000000000000000..686d6062458705f --- /dev/null +++ b/src/dev/build_api_docs/tests/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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.ts new file mode 100644 index 000000000000000..f88fa04bf198e57 --- /dev/null +++ b/src/dev/build_api_docs/tests/src/plugin_a/public/const_vars.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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { CrazyClass } from './classes'; +import { notAnArrowFn } from './fns'; + +/** + * Some of the plugins wrap static exports in an object to create + * a namespace like this. + */ +export const aNamespace = { + /** + * Will this comment show up in the docs? Or the one on the definition of + * notAnArrowFn? + */ + notAnArrowFn, +}; + +/** + * 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; diff --git a/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts new file mode 100644 index 000000000000000..7799f97e2f24f98 --- /dev/null +++ b/src/dev/build_api_docs/tests/src/plugin_a/public/fns.ts @@ -0,0 +1,59 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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?? Ew, how will the obj parameter appear in docs? + * + * @param obj A very crazy parameter. + * + * @returns I have no idea. + * + */ +export const crazyFunction = (obj: { fn: (foo: { param: string }) => number }) => () => () => 'hi'; diff --git a/src/dev/build_api_docs/tests/src/plugin_a/public/foo/index.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/foo/index.ts new file mode 100644 index 000000000000000..23727a50583b131 --- /dev/null +++ b/src/dev/build_api_docs/tests/src/plugin_a/public/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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +export const doTheFooFnThing = () => {}; diff --git a/src/dev/build_api_docs/tests/src/plugin_a/public/index.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/index.ts new file mode 100644 index 000000000000000..679384a58800fe2 --- /dev/null +++ b/src/dev/build_api_docs/tests/src/plugin_a/public/index.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { PluginA, Setup, Start, SearchSpec } from './plugin'; +export { Setup, Start, SearchSpec }; + +export { doTheFooFnThing } from './foo'; + +export * from './fns'; +export * from './classes'; +export * from './const_vars'; +export * from './types'; + +export function plugin() { + return new PluginA(); +} diff --git a/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/plugin.ts new file mode 100644 index 000000000000000..d49a7bbc550268f --- /dev/null +++ b/src/dev/build_api_docs/tests/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 + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts b/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts new file mode 100644 index 000000000000000..3991ed9e7b9c4ec --- /dev/null +++ b/src/dev/build_api_docs/tests/src/plugin_a/public/types.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +/** + * How should a potentially undefined type show up. + */ +export type StringOrUndefinedType = string | undefined; + +export type TypeWithGeneric = T[]; + +export type ImAType = string | number | TypeWithGeneric; + +/** + * 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; diff --git a/src/dev/build_api_docs/tests/src/tsconfig.json b/src/dev/build_api_docs/tests/src/tsconfig.json new file mode 100644 index 000000000000000..57353d8847ae135 --- /dev/null +++ b/src/dev/build_api_docs/tests/src/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "incremental": false, + "strictNullChecks": true, + }, + "include": ["./**/*"] +} \ No newline at end of file diff --git a/src/dev/build_api_docs/tsmorph_utils.ts b/src/dev/build_api_docs/tsmorph_utils.ts new file mode 100644 index 000000000000000..f151d6fcc9018e3 --- /dev/null +++ b/src/dev/build_api_docs/tsmorph_utils.ts @@ -0,0 +1,77 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { Node, JSDocableNode, SourceFile, Project } from 'ts-morph'; +import { getTextWithLinks } from './build_api_declarations/get_text_with_links'; +import { TextWithLinks } from './types'; + +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; +} + +export function getNodeName(node: Node): string { + return isNamedNode(node) ? node.getName() : ''; +} + +/** + * There appears to be no built-in support for @link tags in ts-morph when they are inside + * brackets, which is how they should be used. Hence this is manually parsing the information + * out. + * + * @param node + */ +export function getCommentsFromNode(node: Node): TextWithLinks | undefined { + let comments: TextWithLinks | undefined; + if (Node.isJSDocableNode(node)) { + comments = getCommentsFromJsDocableNode(node); + } else if (Node.isVariableDeclaration(node)) { + const gparent = node.getParent()?.getParent(); + if (Node.isJSDocableNode(gparent)) { + comments = getCommentsFromJsDocableNode(gparent); + } + } else { + comments = getTextWithLinks( + node + .getLeadingCommentRanges() + .map((c) => c.getText() + '\n') + .join('\n') + ); + } + + return comments; +} + +function getCommentsFromJsDocableNode(node: JSDocableNode): TextWithLinks | undefined { + return getTextWithLinks( + node + .getJsDocs() + .map((jsDocs) => { + const comments = jsDocs.getDescription(); + + return `${comments.replace(/@link/g, '')}`; + }) + .join('\n') + ); +} + +export function getSourceFileMatching( + project: Project, + relativePath: string +): SourceFile | undefined { + return project.getSourceFiles().find((file) => { + return file.getFilePath().indexOf(relativePath) >= 0; + }); +} diff --git a/src/dev/build_api_docs/types.ts b/src/dev/build_api_docs/types.ts new file mode 100644 index 000000000000000..f7547dd4fd812ec --- /dev/null +++ b/src/dev/build_api_docs/types.ts @@ -0,0 +1,196 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License 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`. + */ + TypeKind = 'Type', + /** + * Unknown is used if a type is encountered that isn't handled. + */ + Unknown = 'Unknown', + String = 'string', + Number = 'number', + Boolean = 'boolean', + Array = 'Array', + + /** + * This will cover things like string | number, or A & B, for lack of something better to put here. + */ + CompoundType = '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: ScopeApi; + server: ScopeApi; + common: ScopeApi; +} + +/** + * 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 { + 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/src/dev/build_api_docs/utils.test.ts b/src/dev/build_api_docs/utils.test.ts new file mode 100644 index 000000000000000..24f75fda7e17d3e --- /dev/null +++ b/src/dev/build_api_docs/utils.test.ts @@ -0,0 +1,49 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { findPlugins } from '../plugin_discovery'; +import { getPluginForPath, getServiceForPath } from './utils'; + +it('test getPluginForPath', () => { + const plugins: KibanaPlatformPlugin[] = Array.from( + findPlugins({ + oss: false, + examples: false, + extraPluginScanDirs: [], + }).values() + ); + expect( + getPluginForPath('/Users/auser/kibana/src/plugins/embeddable/public/service/file.ts', plugins) + ).toBeDefined(); +}); + +it('test getServiceForPath', () => { + expect(getServiceForPath('src/plugins/embed/public/service/file.ts')).toBe('service'); + expect(getServiceForPath('src/plugins/embed/public/service/subfolder/file.ts')).toBe('service'); + expect(getServiceForPath('src/plugins/embed/public/file.ts')).toBeUndefined(); + expect(getServiceForPath('src/plugins/embed/server/another_service/file.ts')).toBe( + 'another_service' + ); + expect(getServiceForPath('src/plugins/embed/server/f.ts')).toBeUndefined(); +}); + +// it('getRelativeKibanaPath', () => { +// let relativePath = getRelativeKibanaPath( +// '/tmp/tmp-5631-rv2QP2a7ISWH/x-pack/plugins/server/authorization/ui' +// ); +// expect(relativePath).toBe('x-pack/plugins/server/authorization/ui'); + +// relativePath = getRelativeKibanaPath( +// '/tmp/tmp-5631-rv2QP2a7ISWH/src/plugins/server/authorization/ui' +// ); +// expect(relativePath).toBe('src/plugins/server/authorization/ui'); + +// relativePath = getRelativeKibanaPath('/tmp/tmp-5631-rv2QP2a7ISWH/examples/test'); +// expect(relativePath).toBe('examples/test'); +// }); diff --git a/src/dev/build_api_docs/utils.ts b/src/dev/build_api_docs/utils.ts new file mode 100644 index 000000000000000..7dcea6b4661f548 --- /dev/null +++ b/src/dev/build_api_docs/utils.ts @@ -0,0 +1,207 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * and the Server Side Public License, v 1; you may not use this file except in + * compliance with, at your election, the Elastic License or the Server Side + * Public License, v 1. + */ + +import { KibanaPlatformPlugin } from '@kbn/dev-utils'; +import { Type } from 'ts-morph'; +import { AnchorLink, ApiDeclaration, ScopeApi, TypeKind, Lifecycle } 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') + .split(' ') + .join('_') + .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 is 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.includes(plugin.relativeDirectory)); +} + +/** + * 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): string | undefined { + const publicMatchGroups = path.match(/.*\/public\/(.*?)\/.*.ts/); + const serverMatchGroups = path.match(/.*\/server\/(.*?)\/.*.ts/); + const commonMatchGroups = path.match(/.*\/common\/(.*?)\/.*.ts/); + 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 mergeScopeApi(scope: ScopeApi): ApiDeclaration[] { + const api: ApiDeclaration[] = []; + if (scope.start) api.push(scope.start); + if (scope.setup) api.push(scope.setup); + + api.push( + ...scope.classes, + ...scope.functions, + ...scope.interfaces, + ...scope.objects, + ...scope.enums, + ...scope.misc + ); + + return api; +} + +export function getPluginApiDocId( + id: string, + serviceFolders?: readonly string[], + apiPath?: string +) { + let service = ''; + const cleanName = id.replace('.', '_'); + if (apiPath) { + const serviceName = getServiceForPath(apiPath); + const serviceFolder = 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 getIsTypeOptional(type: Type): boolean { + if (type.isUnion()) { + const unions = type.getUnionTypes(); + return unions.find((u) => u.isUndefined()) !== undefined; + } else { + return false; + } +} + +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 getPropertyTypeKind(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.String; + } else if (type.isNumber() || type.isNumberLiteral()) { + return TypeKind.Number; + + // 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.Array; + } else if (type.isObject()) { + return TypeKind.ObjectKind; + } else if (type.isBoolean()) { + return TypeKind.Boolean; + } 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 getPropertyTypeKind(otherType); + } + } + } + + if (type.isUnionOrIntersection()) { + return TypeKind.CompoundType; + } + + return TypeKind.Unknown; +} + +export function createEmptyScope(): ScopeApi { + return { + classes: [], + functions: [], + interfaces: [], + enums: [], + misc: [], + objects: [], + }; +} + +export function groupPluginApi(declarations: ApiDeclaration[]): ScopeApi { + const scope = createEmptyScope(); + + declarations.forEach((declaration) => { + addApiDeclarationToScope(declaration, scope); + }); + + return scope; +} + +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); + } + } +} diff --git a/src/plugins/data/kibana.json b/src/plugins/data/kibana.json index a09ab12f0c6f093..504ee3d45ba0e72 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"], "optionalPlugins": ["usageCollection"], "extraPublicDirs": ["common"], "requiredBundles": [ diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index fc8c44e8d1870d5..c50557a1ad38810 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -6,6 +6,10 @@ * Public License, v 1. */ +/** + * @serviceFolder search SearchServices + */ + import { PluginInitializerContext } from '../../../core/public'; import { ConfigSchema } from '../config'; diff --git a/src/plugins/data/public/search/types.ts b/src/plugins/data/public/search/types.ts index d1d65ba387ac527..5f7047754b0af23 100644 --- a/src/plugins/data/public/search/types.ts +++ b/src/plugins/data/public/search/types.ts @@ -26,6 +26,9 @@ export interface SearchEnhancements { * point. */ export interface ISearchSetup { + test?: { + aggs: AggsSetup; + }; aggs: AggsSetup; usageCollector?: SearchUsageCollector; /** diff --git a/src/plugins/data/public/types.ts b/src/plugins/data/public/types.ts index 02a26e4834fcce6..a8e453f64eb92a3 100644 --- a/src/plugins/data/public/types.ts +++ b/src/plugins/data/public/types.ts @@ -40,7 +40,8 @@ export interface DataStartDependencies { } /** - * Data plugin public Setup contract + * Data plugin public Setup contract. Add the `data` plugin as a dependency, and you can have + * access to this functionality within your own plugin's setup method. */ export interface DataPublicPluginSetup { autocomplete: AutocompleteSetup; diff --git a/src/plugins/embeddable/public/lib/containers/container.ts b/src/plugins/embeddable/public/lib/containers/container.ts index 8fd086113f98c64..f3da8bbd4e76ae5 100644 --- a/src/plugins/embeddable/public/lib/containers/container.ts +++ b/src/plugins/embeddable/public/lib/containers/container.ts @@ -24,6 +24,10 @@ import { isSavedObjectEmbeddableInput } from '../../../common/lib/saved_object_e const getKeys = (o: T): Array => Object.keys(o) as Array; +/** + * Extend the Container class to create custom dashboard-like + * embeddable renderers. + */ export abstract class Container< TChildInput extends Partial = {}, TContainerInput extends ContainerInput = ContainerInput, diff --git a/tsconfig.json b/tsconfig.json index 334a3febfddda46..119c3afb017f929 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "incremental": false + "incremental": false, }, "include": ["kibana.d.ts", "src/**/*", "typings/**/*"], "exclude": [ diff --git a/x-pack/plugins/infra/public/utils/data_search/data_search.stories.mdx b/x-pack/plugins/infra/public/utils/data_search/data_search.stories.mdx deleted file mode 100644 index a698b806b4cd704..000000000000000 --- a/x-pack/plugins/infra/public/utils/data_search/data_search.stories.mdx +++ /dev/null @@ -1,140 +0,0 @@ -import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks'; - - - -# The `data` plugin and `SearchStrategies` - -The search functionality abstraction provided by the `search` service of the -`data` plugin is pretty powerful: - -- The execution of the request is delegated to a search strategy, which is - executed on the Kibana server side. -- Any plugin can register custom search strategies with custom parameters and - response shapes. -- Search requests can be cancelled via an `AbortSignal`. -- Search requests are decoupled from the transport layer. The service will poll - for new results transparently. -- Partial responses can be returned as they become available if the search - takes longer. - -# Working with `data.search.search()` in the Browser - -The following chapters describe a set of React components and hooks that aim to -make it easy to take advantage of these characteristics from client-side React -code. They implement a producer/consumer pattern that decouples the craeation -of search requests from the consumption of the responses. This keeps each -code-path small and encourages the use of reactive processing, which in turn -reduces the risk of race conditions and incorrect assumptions about the -response timing. - -## Issuing new requests - -The main API to issue new requests is the `data.search.search()` function. It -returns an `Observable` representing the stream of partial and final results -without the consumer having to know the underlying transport mechanisms. -Besides receiving a search-strategy-specific parameter object, it supports -selection of the search strategy as well an `AbortSignal` used for request -cancellation. - -The hook `useDataSearch()` is designed to ease the integration between the -`Observable` world and the React world. It uses the function it is given to -derive the parameters to use for the next search request. The request can then -be issued by calling the returned `search()` function. For each new request the -hook emits an object describing the request and its state in the `requests$` -`Observable`. - -```typescript -const { search, requests$ } = useDataSearch({ - getRequest: useCallback((searchTerm: string) => ({ - request: { - params: { - searchTerm - } - } - }), []); -}); -``` - -## Executing requests and consuming the responses - -The response `Observable`s emitted by `data.search.search()` is "cold", so it -won't be executed unless a subscriber subscribes to it. And in order to cleanly -cancel and garbage collect the subscription it should be integrated with the -React component life-cycle. - -The `useLatestPartialDataSearchResponse()` does that in such a way that the -newest response observable is subscribed to and that any previous response -observables are unsubscribed from for proper cancellation if a new request has -been created. This uses RxJS's `switchMap()` operator under the hood. The hook -also makes sure that all observables are unsubscribed from on unmount. - -Since the specific response shape depends on the data strategy used, the hook -takes a projection function, that is responsible for decoding the response in -an appropriate way. - -A request can fail due to various reasons that include servers-side errors, -Elasticsearch shard failures and network failures. The intention is to map all -of them to a common `SearchStrategyError` interface. While the -`useLatestPartialDataSearchResponse()` hook does that for errors emitted -natively by the response `Observable`, it's the responsibility of the -projection function to handle errors that are encoded in the response body, -which includes most server-side errors. Note that errors and partial results in -a response are not mutually exclusive. - -The request status (running, partial, etc), the response -and the errors are turned in to React component state so they can be used in -the usual rendering cycle: - -```typescript -const { - cancelRequest, - isRequestRunning, - isResponsePartial, - latestResponseData, - latestResponseErrors, - loaded, - total, -} = useLatestPartialDataSearchResponse( - requests$, - 'initialValue', - useMemo(() => decodeOrThrow(mySearchStrategyResponsePayloadRT), []), -); -``` - -## Representing the request state to the user - -After the values have been made available to the React rendering process using -the `useLatestPartialDataSearchResponse()` hook, normal component hierarchies -can be used to make the request state and result available to the user. The -following utility components can make that even easier. - -### Undetermined progress - -If `total` and `loaded` are not (yet) known, we can show an undetermined -progress bar. - - - - - -### Known progress - -If `total` and `loaded` are returned by the search strategy, they can be used -to show a progress bar with the option to cancel the request if it takes too -long. - - - - - -### Failed requests - -Assuming the errors are represented as an array of `SearchStrategyError`s in -the `latestResponseErrors` return value, they can be rendered as appropriate -for the respective part of the UI. For many cases a `EuiCallout` is suitable, -so the `DataSearchErrorCallout` can serve as a starting point: - - - - - diff --git a/yarn.lock b/yarn.lock index ed861b58773b9f5..6d6a4671718a1b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2110,6 +2110,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" @@ -5134,6 +5142,18 @@ dependencies: "@babel/runtime" "^7.10.2" +"@ts-morph/common@~0.7.0": + version "0.7.2" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.7.2.tgz#b937d13376695146735aecec6af4573cee513a56" + integrity sha512-XyUPLf1UHtteP5C5FEgVJqgIEOcmaSEoJyU/jQ1gTBKlz/lb1Uss4ix+D2e5qRwPFiBMqM/jwJpna0yVDE5V/g== + 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" @@ -10538,6 +10558,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" @@ -21112,6 +21137,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" @@ -28400,6 +28436,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" @@ -28594,7 +28639,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==