From e2038e061488aa001ed0ef17ea66f69f5e68450c Mon Sep 17 00:00:00 2001 From: Marcus Andersson Date: Tue, 25 Feb 2020 13:59:11 +0100 Subject: [PATCH] Docs: adding API reference documentation support for the packages libraries. (#21931) * trying out api-extractor. * works with our setup of build. * wip. * changed the packages so it works better with the api-extractor. * Changes to make the api-extractor to work. * cleaned up the api-extractor config files. * added some more documentation. * added tsdoc-metadata to gitignore. * removed the generated docs (will do that in another PR). * added execute permission to script for generating dosc. * added so we will push generated docs to branch. * will clean packages_api on abort. * Fixed failing tests. * fixed formatting issue with typedoc comment. * temporarily disabled tslint rules about namespace until https://github.com/microsoft/rushstack/issues/1029 is resolved * temporary enabled bable namespaces. * updated build script. * updated script. * updated script with some colors. * changed to camelCase. * removed spacing. * Starting to add documentation guidelines. * added examples headline. * added parameters and return values. * Fixed merge error. * changed so we use the eslint ignore syntax. * changed to correct eslint ingnore comment. * fixed some spelling errors reported by codespell. * added script to generate docs in current folder. * lerna bootstrap. * removed file that should be ignored. * updated locKFILE. * referenced the code comments guidelines. * updated packages. * updated deps. --- .gitignore | 1 + api-extractor.json | 34 ++ contribute/style-guides/code-comments.md | 209 ++++++++++++ contribute/style-guides/frontend.md | 1 + package.json | 6 +- packages/grafana-data/api-extractor.json | 3 + packages/grafana-data/package.json | 3 +- .../src/dataframe/DataFrameView.ts | 41 ++- .../src/datetime/datemath.test.ts | 2 +- .../grafana-data/src/datetime/datemath.ts | 251 +++++++-------- packages/grafana-data/src/datetime/index.ts | 5 +- .../grafana-data/src/datetime/rangeutil.ts | 299 +++++++++--------- packages/grafana-data/src/index.ts | 5 + packages/grafana-data/src/text/text.ts | 2 +- packages/grafana-data/src/types/appEvents.ts | 11 +- packages/grafana-data/src/types/datasource.ts | 4 +- packages/grafana-data/src/types/index.ts | 8 +- packages/grafana-data/src/types/panel.ts | 2 +- .../grafana-data/src/types/panelEvents.ts | 46 +-- packages/grafana-data/src/types/vector.ts | 2 +- packages/grafana-e2e/api-extractor.json | 3 + packages/grafana-e2e/package.json | 3 +- packages/grafana-e2e/src/index.ts | 9 +- packages/grafana-runtime/api-extractor.json | 3 + packages/grafana-runtime/package.json | 3 +- packages/grafana-runtime/src/index.ts | 6 +- .../src/utils/DataSourceWithBackend.ts | 2 +- packages/grafana-ui/api-extractor.json | 3 + packages/grafana-ui/package.json | 3 +- .../src/components/Cascader/Cascader.tsx | 2 +- .../ThresholdsEditor.test.tsx | 2 +- packages/grafana-ui/src/index.ts | 5 + packages/grafana-ui/src/themes/index.ts | 4 +- packages/grafana-ui/src/themes/mixins.ts | 25 +- packages/grafana-ui/src/utils/dom.ts | 71 +++-- packages/grafana-ui/src/utils/index.ts | 3 +- scripts/build_api_docs.sh | 27 ++ scripts/generate_api_docs.sh | 61 ++++ yarn.lock | 118 ++++++- 39 files changed, 899 insertions(+), 389 deletions(-) create mode 100644 api-extractor.json create mode 100644 contribute/style-guides/code-comments.md create mode 100644 packages/grafana-data/api-extractor.json create mode 100644 packages/grafana-e2e/api-extractor.json create mode 100644 packages/grafana-runtime/api-extractor.json create mode 100644 packages/grafana-ui/api-extractor.json create mode 100755 scripts/build_api_docs.sh create mode 100755 scripts/generate_api_docs.sh diff --git a/.gitignore b/.gitignore index 40ba75b1092..62e21230059 100644 --- a/.gitignore +++ b/.gitignore @@ -91,6 +91,7 @@ debug.test /packages/**/dist /packages/**/compiled /packages/**/.rpt2_cache +/packages/**/tsdoc-metadata.json # Ignore go local build dependencies /scripts/go/bin/** diff --git a/api-extractor.json b/api-extractor.json new file mode 100644 index 00000000000..2751721e9d5 --- /dev/null +++ b/api-extractor.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "mainEntryPointFilePath": "/dist/index.d.ts", + "bundledPackages": [], + "compiler": {}, + "apiReport": { + "enabled": false + }, + "docModel": { + "enabled": true, + "apiJsonFilePath": "/../../reports/docs/.api.json" + }, + "dtsRollup": { + "enabled": false + }, + "tsdocMetadata": {}, + "messages": { + "compilerMessageReporting": { + "default": { + "logLevel": "warning" + } + }, + "extractorMessageReporting": { + "default": { + "logLevel": "warning" + } + }, + "tsdocMessageReporting": { + "default": { + "logLevel": "warning" + } + } + } +} diff --git a/contribute/style-guides/code-comments.md b/contribute/style-guides/code-comments.md new file mode 100644 index 00000000000..216939291f9 --- /dev/null +++ b/contribute/style-guides/code-comments.md @@ -0,0 +1,209 @@ +# Guidelines for code comments in grafana-* packages + +This document aims to give you some recommendation on how to add code comments to the exported code in the grafana packages. + +## Table of Contents + +1. [Add package description](#add-package-description) +1. [Set stability of an API](#set-stability-of-an-api) +1. [Deprecate an API](#deprecate-an-api) +1. [Specify parameters](#specify-parameters) +1. [Set return values](#set-return-values) +____ + + ## Add package description + +Each package has an overview explaining the overall responsibility and usage of the package. + +You can document this description with [`@packageDocumentation`](https://api-extractor.com/pages/tsdoc/tag_packagedocumentation/) tag. + +Add this tag to the `/src/index.ts` entry file to have one place for the package description. + +## Set stability of an API + +All `exported` apis from the package should have a release tag to indicate its stability. + +- [`@alpha`](https://api-extractor.com/pages/tsdoc/tag_alpha/) - early draft of api and will probably change. +- [`@beta`](https://api-extractor.com/pages/tsdoc/tag_beta/) - close to being stable but might change. +- [`@public`](https://api-extractor.com/pages/tsdoc/tag_public/) - ready for useage in production. +- [`@internal`](https://api-extractor.com/pages/tsdoc/tag_internal/) - for internal use only. + +### Main stability of APIs + +Add a tag to mark the stability of the whole exported `class/interface/function/type` etc. + +Please place the `release tag` at the bottom of the comment to make it consistent among files and easier to read. + +**Do:** + +```typescript +/** + * Will help to create DataFrame objects and handle + * the heavy lifting of creating a complex object. + * + * @example + * ```typescript + * const dataFrame = factory.create(); + * ``` + * + * @public + **/ +export class DataFrameFactory { + create(): DataFrame { } +} +``` + +**Don't** +```typescript +/** + * Will help to create DataFrame objects and handle + * the heavy lifting of creating a complex object. + * + * @public + * @example + * ```typescript + * const dataFrame = factory.create(); + * ``` + **/ +export class DataFrameFactory { + create(): DataFrame { } +} +``` + +### Partial stability of APIs + +Add the main stability of the API at the top according to [Main stability of API](#main-stability-of-api). + +Then override the non-stable parts of the API with the proper [release tag](#release-tags). This should also be place at the bottom of the comment block. + +**Do:** + +```typescript +/** + * Will help to create DataFrame objects and handle + * the heavy lifting of creating a complex object. + * + * @example + * ```typescript + * const dataFrame = factory.create(); + * ``` + * + * @public + **/ +export class DataFrameFactory { + create(): DataFrame { } + + /** + * @beta + **/ + createMany(): DataFrames[] {} +} +``` + +**Don't** + +```typescript +/** + * Will help to create DataFrame objects and handle + * the heavy lifting of creating a complex object. + * + * @example + * ```typescript + * const dataFrame = factory.create(); + * ``` + **/ +export class DataFrameFactory { + /** + * @public + **/ + create(): DataFrame { } + + /** + * @beta + **/ + createMany(): DataFrame[] {} +} +``` + +## Deprecate an API +If you want to mark an API as deprecated to signal that this API will be removed in the future, then add the [`@deprecated`](https://api-extractor.com/pages/tsdoc/tag_deprecated/) tag. + +If applicable add a reason why the API is deprecated directly after the `@deprecated tag`. + +## Specify parameters +If you want to specify the possible parameters that can be passed to an API, then add the [`@param`](https://api-extractor.com/pages/tsdoc/tag_param/) tag. + +This attribute can be skipped if the type provided by `typescript` and the function comment or the function name is enough to explain what the parameters are. + +**Do:** + +```typescript +/** + * Will help to create a resource resovler depending + * on the current execution context. + * + * @param context - The current execution context. + * @returns FileResolver if executed on the server otherwise a HttpResolver. + * @public + **/ +export const factory = (context: Context): IResolver => { + if (context.isServer) { + return new FileResolver(); + } + return new HttpResolver(); +} +``` + +**Don't** + +```typescript +/** + * Will compare two numbers to see if they are equal to each others. + * + * @param x - The first number + * @param y - The second number + * @public + **/ +export const isEqual = (x: number, y: number): boolean => { + return x === y; +} +``` + + +## Set return values +If you want to specify the return value from a function you can use the [`@returns`](https://api-extractor.com/pages/tsdoc/tag_returns/) tag. + +This attribute can be skipped if the type provided by `typescript` and the function comment or the function name is enough to explain what the function returns. + +**Do:** + +```typescript +/** + * Will help to create a resource resovler depending + * on the current execution context. + * + * @param context - The current execution context. + * @returns FileResolver if executed on the server otherwise a HttpResolver. + * @public + **/ +export const factory = (context: Context): IResolver => { + if (context.isServer) { + return new FileResolver(); + } + return new HttpResolver(); +} +``` + +**Don't** + +```typescript +/** + * Will compare two numbers to see if they are equal to each others. + * + * @returns true if values are equal + * @public + **/ +export const isEqual = (x: number, y: number): boolean => { + return x === y; +} +``` \ No newline at end of file diff --git a/contribute/style-guides/frontend.md b/contribute/style-guides/frontend.md index c73cce4e09a..d4628eda1c7 100644 --- a/contribute/style-guides/frontend.md +++ b/contribute/style-guides/frontend.md @@ -214,6 +214,7 @@ For code that needs to be used by external plugin: - Use [TSDoc](https://github.com/microsoft/tsdoc) comments to document your code. - Use [react-docgen](https://github.com/reactjs/react-docgen) comments (`/** ... */`) for props documentation. - Use inline comments for comments inside functions, classes etc. +- Please try to follow the [code comment guidelines](./code-comments.md) when adding comments. ### Linting diff --git a/package.json b/package.json index ea095591f4b..46f90990140 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,8 @@ "@babel/preset-react": "7.8.3", "@babel/preset-typescript": "7.8.3", "@emotion/core": "10.0.10", + "@grafana/api-documenter": "0.9.3", + "@microsoft/api-extractor": "7.7.8", "@rtsao/plugin-proposal-class-properties": "7.0.1-patch.1", "@testing-library/react-hooks": "^3.2.1", "@types/angular": "1.6.56", @@ -183,7 +185,9 @@ "packages:publish": "lerna publish from-package --contents dist", "packages:publishLatest": "lerna publish from-package --contents dist --yes", "packages:publishNext": "lerna publish from-package --contents dist --dist-tag next --yes", - "packages:publishCanary": "lerna publish from-package --contents dist --dist-tag canary --yes" + "packages:publishCanary": "lerna publish from-package --contents dist --dist-tag canary --yes", + "packages:docsExtract": "rm -rf ./scripts/docs && lerna run docsExtract", + "packages:docsToMarkdown": "api-documenter markdown --input-folder ./reports/docs/ --output-folder ./docs/sources/packages_api/ --hugo --draft" }, "husky": { "hooks": { diff --git a/packages/grafana-data/api-extractor.json b/packages/grafana-data/api-extractor.json new file mode 100644 index 00000000000..5e96b3b0b3c --- /dev/null +++ b/packages/grafana-data/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.json" +} diff --git a/packages/grafana-data/package.json b/packages/grafana-data/package.json index cd880c4c55e..f5f72df9aba 100644 --- a/packages/grafana-data/package.json +++ b/packages/grafana-data/package.json @@ -18,7 +18,8 @@ "typecheck": "tsc --noEmit", "clean": "rimraf ./dist ./compiled", "bundle": "rollup -c rollup.config.ts", - "build": "grafana-toolkit package:build --scope=data" + "build": "grafana-toolkit package:build --scope=data", + "docsExtract": "api-extractor run 2>&1 | tee ../../reports/docs/$(basename $(pwd)).log" }, "dependencies": { "apache-arrow": "0.15.1", diff --git a/packages/grafana-data/src/dataframe/DataFrameView.ts b/packages/grafana-data/src/dataframe/DataFrameView.ts index 88e3969b17b..bf304e2f539 100644 --- a/packages/grafana-data/src/dataframe/DataFrameView.ts +++ b/packages/grafana-data/src/dataframe/DataFrameView.ts @@ -6,20 +6,12 @@ import { DisplayProcessor } from '../types'; * This abstraction will present the contents of a DataFrame as if * it were a well typed javascript object Vector. * - * NOTE: The contents of the object returned from `view.get(index)` - * are optimized for use in a loop. All calls return the same object - * but the index has changed. + * @remarks + * The {@link DataFrameView.get} is optimized for use in a loop and will return same object. + * See function for more details. * - * For example, the three objects: - * const first = view.get(0); - * const second = view.get(1); - * const third = view.get(2); - * will point to the contents at index 2 - * - * If you need three different objects, consider something like: - * const first = { ... view.get(0) }; - * const second = { ... view.get(1) }; - * const third = { ... view.get(2) }; + * @typeParam T - Type of object stored in the DataFrame. + * @beta */ export class DataFrameView implements Vector { private index = 0; @@ -56,6 +48,10 @@ export class DataFrameView implements Vector { return this.data.length; } + /** + * Helper function to return the {@link DisplayProcessor} for a given field column. + * @param colIndex - the field column index for the data frame. + */ getFieldDisplayProcessor(colIndex: number): DisplayProcessor | null { if (!this.dataFrame || !this.dataFrame.fields) { return null; @@ -70,6 +66,25 @@ export class DataFrameView implements Vector { return field.display; } + /** + * The contents of the object returned from this function + * are optimized for use in a loop. All calls return the same object + * but the index has changed. + * + * @example + * ```typescript + * // `first`, `second` and `third` will all point to the same contents at index 2: + * const first = view.get(0); + * const second = view.get(1); + * const third = view.get(2); + * + * // If you need three different objects, consider something like: + * const first = { ...view.get(0) }; + * const second = { ...view.get(1) }; + * const third = { ...view.get(2) }; + * ``` + * @param idx - The index of the object you currently are inspecting + */ get(idx: number) { this.index = idx; return this.obj; diff --git a/packages/grafana-data/src/datetime/datemath.test.ts b/packages/grafana-data/src/datetime/datemath.test.ts index 3443eea2d17..70bf399ea3c 100644 --- a/packages/grafana-data/src/datetime/datemath.test.ts +++ b/packages/grafana-data/src/datetime/datemath.test.ts @@ -1,7 +1,7 @@ import sinon, { SinonFakeTimers } from 'sinon'; import each from 'lodash/each'; -import * as dateMath from './datemath'; +import { dateMath } from './datemath'; import { dateTime, DurationUnit, DateTime } from './moment_wrapper'; describe('DateMath', () => { diff --git a/packages/grafana-data/src/datetime/datemath.ts b/packages/grafana-data/src/datetime/datemath.ts index 29747e15bc7..d8c850c9746 100644 --- a/packages/grafana-data/src/datetime/datemath.ts +++ b/packages/grafana-data/src/datetime/datemath.ts @@ -5,154 +5,157 @@ import { TimeZone } from '../types/index'; const units: DurationUnit[] = ['y', 'M', 'w', 'd', 'h', 'm', 's']; -export function isMathString(text: string | DateTime | Date): boolean { - if (!text) { - return false; - } - - if (typeof text === 'string' && (text.substring(0, 3) === 'now' || text.includes('||'))) { - return true; - } else { - return false; - } -} +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace dateMath { + export function isMathString(text: string | DateTime | Date): boolean { + if (!text) { + return false; + } -/** - * Parses different types input to a moment instance. There is a specific formatting language that can be used - * if text arg is string. See unit tests for examples. - * @param text - * @param roundUp See parseDateMath function. - * @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used. - */ -export function parse(text: string | DateTime | Date, roundUp?: boolean, timezone?: TimeZone): DateTime | undefined { - if (!text) { - return undefined; + if (typeof text === 'string' && (text.substring(0, 3) === 'now' || text.includes('||'))) { + return true; + } else { + return false; + } } - if (typeof text !== 'string') { - if (isDateTime(text)) { - return text; - } - if (isDate(text)) { - return dateTime(text); + /** + * Parses different types input to a moment instance. There is a specific formatting language that can be used + * if text arg is string. See unit tests for examples. + * @param text + * @param roundUp See parseDateMath function. + * @param timezone Only string 'utc' is acceptable here, for anything else, local timezone is used. + */ + export function parse(text: string | DateTime | Date, roundUp?: boolean, timezone?: TimeZone): DateTime | undefined { + if (!text) { + return undefined; } - // We got some non string which is not a moment nor Date. TS should be able to check for that but not always. - return undefined; - } else { - let time; - let mathString = ''; - let index; - let parseString; - - if (text.substring(0, 3) === 'now') { - time = dateTimeForTimeZone(timezone); - mathString = text.substring('now'.length); + + if (typeof text !== 'string') { + if (isDateTime(text)) { + return text; + } + if (isDate(text)) { + return dateTime(text); + } + // We got some non string which is not a moment nor Date. TS should be able to check for that but not always. + return undefined; } else { - index = text.indexOf('||'); - if (index === -1) { - parseString = text; - mathString = ''; // nothing else + let time; + let mathString = ''; + let index; + let parseString; + + if (text.substring(0, 3) === 'now') { + time = dateTimeForTimeZone(timezone); + mathString = text.substring('now'.length); } else { - parseString = text.substring(0, index); - mathString = text.substring(index + 2); + index = text.indexOf('||'); + if (index === -1) { + parseString = text; + mathString = ''; // nothing else + } else { + parseString = text.substring(0, index); + mathString = text.substring(index + 2); + } + // We're going to just require ISO8601 timestamps, k? + time = dateTime(parseString, ISO_8601); + } + + if (!mathString.length) { + return time; } - // We're going to just require ISO8601 timestamps, k? - time = dateTime(parseString, ISO_8601); + + return parseDateMath(mathString, time, roundUp); } + } - if (!mathString.length) { - return time; + /** + * Checks if text is a valid date which in this context means that it is either a Moment instance or it can be parsed + * by parse function. See parse function to see what is considered acceptable. + * @param text + */ + export function isValid(text: string | DateTime): boolean { + const date = parse(text); + if (!date) { + return false; } - return parseDateMath(mathString, time, roundUp); - } -} + if (isDateTime(date)) { + return date.isValid(); + } -/** - * Checks if text is a valid date which in this context means that it is either a Moment instance or it can be parsed - * by parse function. See parse function to see what is considered acceptable. - * @param text - */ -export function isValid(text: string | DateTime): boolean { - const date = parse(text); - if (!date) { return false; } - if (isDateTime(date)) { - return date.isValid(); - } - - return false; -} + /** + * Parses math part of the time string and shifts supplied time according to that math. See unit tests for examples. + * @param mathString + * @param time + * @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit. + */ + // TODO: Had to revert Andrejs `time: moment.Moment` to `time: any` + export function parseDateMath(mathString: string, time: any, roundUp?: boolean): DateTime | undefined { + const strippedMathString = mathString.replace(/\s/g, ''); + const dateTime = time; + let i = 0; + const len = strippedMathString.length; + + while (i < len) { + const c = strippedMathString.charAt(i++); + let type; + let num; + let unit; + + if (c === '/') { + type = 0; + } else if (c === '+') { + type = 1; + } else if (c === '-') { + type = 2; + } else { + return undefined; + } -/** - * Parses math part of the time string and shifts supplied time according to that math. See unit tests for examples. - * @param mathString - * @param time - * @param roundUp If true it will round the time to endOf time unit, otherwise to startOf time unit. - */ -// TODO: Had to revert Andrejs `time: moment.Moment` to `time: any` -export function parseDateMath(mathString: string, time: any, roundUp?: boolean): DateTime | undefined { - const strippedMathString = mathString.replace(/\s/g, ''); - const dateTime = time; - let i = 0; - const len = strippedMathString.length; - - while (i < len) { - const c = strippedMathString.charAt(i++); - let type; - let num; - let unit; - - if (c === '/') { - type = 0; - } else if (c === '+') { - type = 1; - } else if (c === '-') { - type = 2; - } else { - return undefined; - } + if (isNaN(parseInt(strippedMathString.charAt(i), 10))) { + num = 1; + } else if (strippedMathString.length === 2) { + num = strippedMathString.charAt(i); + } else { + const numFrom = i; + while (!isNaN(parseInt(strippedMathString.charAt(i), 10))) { + i++; + if (i > 10) { + return undefined; + } + } + num = parseInt(strippedMathString.substring(numFrom, i), 10); + } - if (isNaN(parseInt(strippedMathString.charAt(i), 10))) { - num = 1; - } else if (strippedMathString.length === 2) { - num = strippedMathString.charAt(i); - } else { - const numFrom = i; - while (!isNaN(parseInt(strippedMathString.charAt(i), 10))) { - i++; - if (i > 10) { + if (type === 0) { + // rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M) + if (num !== 1) { return undefined; } } - num = parseInt(strippedMathString.substring(numFrom, i), 10); - } + unit = strippedMathString.charAt(i++); - if (type === 0) { - // rounding is only allowed on whole, single, units (eg M or 1M, not 0.5M or 2M) - if (num !== 1) { + if (!includes(units, unit)) { return undefined; - } - } - unit = strippedMathString.charAt(i++); - - if (!includes(units, unit)) { - return undefined; - } else { - if (type === 0) { - if (roundUp) { - dateTime.endOf(unit); - } else { - dateTime.startOf(unit); + } else { + if (type === 0) { + if (roundUp) { + dateTime.endOf(unit); + } else { + dateTime.startOf(unit); + } + } else if (type === 1) { + dateTime.add(num, unit); + } else if (type === 2) { + dateTime.subtract(num, unit); } - } else if (type === 1) { - dateTime.add(num, unit); - } else if (type === 2) { - dateTime.subtract(num, unit); } } + return dateTime; } - return dateTime; } diff --git a/packages/grafana-data/src/datetime/index.ts b/packages/grafana-data/src/datetime/index.ts index 51b32326f58..444433da32a 100644 --- a/packages/grafana-data/src/datetime/index.ts +++ b/packages/grafana-data/src/datetime/index.ts @@ -1,7 +1,6 @@ // Names are too general to export globally -import * as dateMath from './datemath'; -import * as rangeUtil from './rangeutil'; +export { dateMath } from './datemath'; +export { rangeUtil } from './rangeutil'; export * from './moment_wrapper'; export * from './timezones'; export * from './formats'; -export { dateMath, rangeUtil }; diff --git a/packages/grafana-data/src/datetime/rangeutil.ts b/packages/grafana-data/src/datetime/rangeutil.ts index fcf55b37f4d..799893371ed 100644 --- a/packages/grafana-data/src/datetime/rangeutil.ts +++ b/packages/grafana-data/src/datetime/rangeutil.ts @@ -3,168 +3,183 @@ import groupBy from 'lodash/groupBy'; import { RawTimeRange } from '../types/time'; -import * as dateMath from './datemath'; +import { dateMath } from './datemath'; import { isDateTime, DateTime } from './moment_wrapper'; -const spans: { [key: string]: { display: string; section?: number } } = { - s: { display: 'second' }, - m: { display: 'minute' }, - h: { display: 'hour' }, - d: { display: 'day' }, - w: { display: 'week' }, - M: { display: 'month' }, - y: { display: 'year' }, -}; - -const rangeOptions = [ - { from: 'now/d', to: 'now/d', display: 'Today', section: 2 }, - { from: 'now/d', to: 'now', display: 'Today so far', section: 2 }, - { from: 'now/w', to: 'now/w', display: 'This week', section: 2 }, - { from: 'now/w', to: 'now', display: 'This week so far', section: 2 }, - { from: 'now/M', to: 'now/M', display: 'This month', section: 2 }, - { from: 'now/M', to: 'now', display: 'This month so far', section: 2 }, - { from: 'now/y', to: 'now/y', display: 'This year', section: 2 }, - { from: 'now/y', to: 'now', display: 'This year so far', section: 2 }, - - { from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday', section: 1 }, - { - from: 'now-2d/d', - to: 'now-2d/d', - display: 'Day before yesterday', - section: 1, - }, - { - from: 'now-7d/d', - to: 'now-7d/d', - display: 'This day last week', - section: 1, - }, - { from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week', section: 1 }, - { from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month', section: 1 }, - { from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year', section: 1 }, - - { from: 'now-5m', to: 'now', display: 'Last 5 minutes', section: 3 }, - { from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 3 }, - { from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 3 }, - { from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 3 }, - { from: 'now-3h', to: 'now', display: 'Last 3 hours', section: 3 }, - { from: 'now-6h', to: 'now', display: 'Last 6 hours', section: 3 }, - { from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 3 }, - { from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 3 }, - { from: 'now-2d', to: 'now', display: 'Last 2 days', section: 0 }, - { from: 'now-7d', to: 'now', display: 'Last 7 days', section: 0 }, - { from: 'now-30d', to: 'now', display: 'Last 30 days', section: 0 }, - { from: 'now-90d', to: 'now', display: 'Last 90 days', section: 0 }, - { from: 'now-6M', to: 'now', display: 'Last 6 months', section: 0 }, - { from: 'now-1y', to: 'now', display: 'Last 1 year', section: 0 }, - { from: 'now-2y', to: 'now', display: 'Last 2 years', section: 0 }, - { from: 'now-5y', to: 'now', display: 'Last 5 years', section: 0 }, -]; - -const absoluteFormat = 'YYYY-MM-DD HH:mm:ss'; - -const rangeIndex: any = {}; -each(rangeOptions, (frame: any) => { - rangeIndex[frame.from + ' to ' + frame.to] = frame; -}); - -export function getRelativeTimesList(timepickerSettings: any, currentDisplay: any) { - const groups = groupBy(rangeOptions, (option: any) => { - option.active = option.display === currentDisplay; - return option.section; +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace rangeUtil { + const spans: { [key: string]: { display: string; section?: number } } = { + s: { display: 'second' }, + m: { display: 'minute' }, + h: { display: 'hour' }, + d: { display: 'day' }, + w: { display: 'week' }, + M: { display: 'month' }, + y: { display: 'year' }, + }; + + const rangeOptions = [ + { from: 'now/d', to: 'now/d', display: 'Today', section: 2 }, + { from: 'now/d', to: 'now', display: 'Today so far', section: 2 }, + { from: 'now/w', to: 'now/w', display: 'This week', section: 2 }, + { from: 'now/w', to: 'now', display: 'This week so far', section: 2 }, + { from: 'now/M', to: 'now/M', display: 'This month', section: 2 }, + { from: 'now/M', to: 'now', display: 'This month so far', section: 2 }, + { from: 'now/y', to: 'now/y', display: 'This year', section: 2 }, + { from: 'now/y', to: 'now', display: 'This year so far', section: 2 }, + + { from: 'now-1d/d', to: 'now-1d/d', display: 'Yesterday', section: 1 }, + { + from: 'now-2d/d', + to: 'now-2d/d', + display: 'Day before yesterday', + section: 1, + }, + { + from: 'now-7d/d', + to: 'now-7d/d', + display: 'This day last week', + section: 1, + }, + { from: 'now-1w/w', to: 'now-1w/w', display: 'Previous week', section: 1 }, + { from: 'now-1M/M', to: 'now-1M/M', display: 'Previous month', section: 1 }, + { from: 'now-1y/y', to: 'now-1y/y', display: 'Previous year', section: 1 }, + + { from: 'now-5m', to: 'now', display: 'Last 5 minutes', section: 3 }, + { from: 'now-15m', to: 'now', display: 'Last 15 minutes', section: 3 }, + { from: 'now-30m', to: 'now', display: 'Last 30 minutes', section: 3 }, + { from: 'now-1h', to: 'now', display: 'Last 1 hour', section: 3 }, + { from: 'now-3h', to: 'now', display: 'Last 3 hours', section: 3 }, + { from: 'now-6h', to: 'now', display: 'Last 6 hours', section: 3 }, + { from: 'now-12h', to: 'now', display: 'Last 12 hours', section: 3 }, + { from: 'now-24h', to: 'now', display: 'Last 24 hours', section: 3 }, + { from: 'now-2d', to: 'now', display: 'Last 2 days', section: 0 }, + { from: 'now-7d', to: 'now', display: 'Last 7 days', section: 0 }, + { from: 'now-30d', to: 'now', display: 'Last 30 days', section: 0 }, + { from: 'now-90d', to: 'now', display: 'Last 90 days', section: 0 }, + { from: 'now-6M', to: 'now', display: 'Last 6 months', section: 0 }, + { from: 'now-1y', to: 'now', display: 'Last 1 year', section: 0 }, + { from: 'now-2y', to: 'now', display: 'Last 2 years', section: 0 }, + { from: 'now-5y', to: 'now', display: 'Last 5 years', section: 0 }, + ]; + + const absoluteFormat = 'YYYY-MM-DD HH:mm:ss'; + + const rangeIndex: any = {}; + each(rangeOptions, (frame: any) => { + rangeIndex[frame.from + ' to ' + frame.to] = frame; }); - // _.each(timepickerSettings.time_options, (duration: string) => { - // let info = describeTextRange(duration); - // if (info.section) { - // groups[info.section].push(info); - // } - // }); + export function getRelativeTimesList(timepickerSettings: any, currentDisplay: any) { + const groups = groupBy(rangeOptions, (option: any) => { + option.active = option.display === currentDisplay; + return option.section; + }); - return groups; -} - -function formatDate(date: DateTime) { - return date.format(absoluteFormat); -} + // _.each(timepickerSettings.time_options, (duration: string) => { + // let info = describeTextRange(duration); + // if (info.section) { + // groups[info.section].push(info); + // } + // }); -// handles expressions like -// 5m -// 5m to now/d -// now/d to now -// now/d -// if no to then to now is assumed -export function describeTextRange(expr: any) { - const isLast = expr.indexOf('+') !== 0; - if (expr.indexOf('now') === -1) { - expr = (isLast ? 'now-' : 'now') + expr; + return groups; } - let opt = rangeIndex[expr + ' to now']; - if (opt) { - return opt; + function formatDate(date: DateTime) { + return date.format(absoluteFormat); } - if (isLast) { - opt = { from: expr, to: 'now' }; - } else { - opt = { from: 'now', to: expr }; - } + // handles expressions like + // 5m + // 5m to now/d + // now/d to now + // now/d + // if no to then to now is assumed + export function describeTextRange(expr: any) { + const isLast = expr.indexOf('+') !== 0; + if (expr.indexOf('now') === -1) { + expr = (isLast ? 'now-' : 'now') + expr; + } - const parts = /^now([-+])(\d+)(\w)/.exec(expr); - if (parts) { - const unit = parts[3]; - const amount = parseInt(parts[2], 10); - const span = spans[unit]; - if (span) { - opt.display = isLast ? 'Last ' : 'Next '; - opt.display += amount + ' ' + span.display; - opt.section = span.section; - if (amount > 1) { - opt.display += 's'; - } + let opt = rangeIndex[expr + ' to now']; + if (opt) { + return opt; } - } else { - opt.display = opt.from + ' to ' + opt.to; - opt.invalid = true; - } - return opt; -} + if (isLast) { + opt = { from: expr, to: 'now' }; + } else { + opt = { from: 'now', to: expr }; + } -export function describeTimeRange(range: RawTimeRange): string { - const option = rangeIndex[range.from.toString() + ' to ' + range.to.toString()]; - if (option) { - return option.display; - } + const parts = /^now([-+])(\d+)(\w)/.exec(expr); + if (parts) { + const unit = parts[3]; + const amount = parseInt(parts[2], 10); + const span = spans[unit]; + if (span) { + opt.display = isLast ? 'Last ' : 'Next '; + opt.display += amount + ' ' + span.display; + opt.section = span.section; + if (amount > 1) { + opt.display += 's'; + } + } + } else { + opt.display = opt.from + ' to ' + opt.to; + opt.invalid = true; + } - if (isDateTime(range.from) && isDateTime(range.to)) { - return formatDate(range.from) + ' to ' + formatDate(range.to); + return opt; } - if (isDateTime(range.from)) { - const toMoment = dateMath.parse(range.to, true); - return toMoment ? formatDate(range.from) + ' to ' + toMoment.fromNow() : ''; - } + /** + * Use this function to get a properly formatted string representation of a {@link @grafana/data:RawTimeRange | range}. + * + * @example + * ``` + * // Prints "2": + * console.log(add(1,1)); + * ``` + * @category TimeUtils + * @param range - a time range (usually specified by the TimePicker) + * @alpha + */ + export function describeTimeRange(range: RawTimeRange): string { + const option = rangeIndex[range.from.toString() + ' to ' + range.to.toString()]; + if (option) { + return option.display; + } - if (isDateTime(range.to)) { - const from = dateMath.parse(range.from, false); - return from ? from.fromNow() + ' to ' + formatDate(range.to) : ''; - } + if (isDateTime(range.from) && isDateTime(range.to)) { + return formatDate(range.from) + ' to ' + formatDate(range.to); + } - if (range.to.toString() === 'now') { - const res = describeTextRange(range.from); - return res.display; - } + if (isDateTime(range.from)) { + const toMoment = dateMath.parse(range.to, true); + return toMoment ? formatDate(range.from) + ' to ' + toMoment.fromNow() : ''; + } - return range.from.toString() + ' to ' + range.to.toString(); -} + if (isDateTime(range.to)) { + const from = dateMath.parse(range.from, false); + return from ? from.fromNow() + ' to ' + formatDate(range.to) : ''; + } + + if (range.to.toString() === 'now') { + const res = describeTextRange(range.from); + return res.display; + } -export const isValidTimeSpan = (value: string) => { - if (value.indexOf('$') === 0 || value.indexOf('+$') === 0) { - return true; + return range.from.toString() + ' to ' + range.to.toString(); } - const info = describeTextRange(value); - return info.invalid !== true; -}; + export const isValidTimeSpan = (value: string) => { + if (value.indexOf('$') === 0 || value.indexOf('+$') === 0) { + return true; + } + + const info = describeTextRange(value); + return info.invalid !== true; + }; +} diff --git a/packages/grafana-data/src/index.ts b/packages/grafana-data/src/index.ts index fab26964da0..9d6a1a6c4ed 100644 --- a/packages/grafana-data/src/index.ts +++ b/packages/grafana-data/src/index.ts @@ -1,3 +1,8 @@ +/** + * A library containing most of the core functionality and data types used in Grafana. + * + * @packageDocumentation + */ export * from './utils'; export * from './types'; export * from './vector'; diff --git a/packages/grafana-data/src/text/text.ts b/packages/grafana-data/src/text/text.ts index f05a019720f..567b85094f1 100644 --- a/packages/grafana-data/src/text/text.ts +++ b/packages/grafana-data/src/text/text.ts @@ -58,7 +58,7 @@ const CLEAR_FLAG = '-'; const FLAGS_REGEXP = /\(\?([ims-]+)\)/g; /** - * Converts any mode modifers in the text to the Javascript equivalent flag + * Converts any mode modifiers in the text to the Javascript equivalent flag */ export function parseFlags(text: string): { cleaned: string; flags: string } { const flags: Set = new Set(['g']); diff --git a/packages/grafana-data/src/types/appEvents.ts b/packages/grafana-data/src/types/appEvents.ts index 9f87c1ea204..567440ab16b 100644 --- a/packages/grafana-data/src/types/appEvents.ts +++ b/packages/grafana-data/src/types/appEvents.ts @@ -5,8 +5,11 @@ export interface AppEvent { payload?: T; } -export type AlertPayload = [string, string?]; +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace AppEvents { + export type AlertPayload = [string, string?]; -export const alertSuccess = eventFactory('alert-success'); -export const alertWarning = eventFactory('alert-warning'); -export const alertError = eventFactory('alert-error'); + export const alertSuccess = eventFactory('alert-success'); + export const alertWarning = eventFactory('alert-warning'); + export const alertError = eventFactory('alert-error'); +} diff --git a/packages/grafana-data/src/types/datasource.ts b/packages/grafana-data/src/types/datasource.ts index c52f1c04c79..57a47c3f809 100644 --- a/packages/grafana-data/src/types/datasource.ts +++ b/packages/grafana-data/src/types/datasource.ts @@ -506,9 +506,9 @@ export interface DataSourceInstanceSettings { export type PanelMigrationHandler = (panel: PanelModel) => Partial; /** - * Called before a panel is initalized + * Called before a panel is initialized */ export type PanelTypeChangedHandler = ( options: Partial, diff --git a/packages/grafana-data/src/types/panelEvents.ts b/packages/grafana-data/src/types/panelEvents.ts index e64119c2862..f4b5255981b 100644 --- a/packages/grafana-data/src/types/panelEvents.ts +++ b/packages/grafana-data/src/types/panelEvents.ts @@ -2,26 +2,28 @@ import { eventFactory } from './utils'; import { DataQueryError, DataQueryResponseData } from './datasource'; import { AngularPanelMenuItem } from './panel'; -/** Payloads */ -export interface PanelChangeViewPayload { - fullscreen?: boolean; - edit?: boolean; - panelId?: number; - toggle?: boolean; -} - -/** Events */ +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace PanelEvents { + /** Payloads */ + export interface PanelChangeViewPayload { + fullscreen?: boolean; + edit?: boolean; + panelId?: number; + toggle?: boolean; + } -export const refresh = eventFactory('refresh'); -export const componentDidMount = eventFactory('component-did-mount'); -export const dataError = eventFactory('data-error'); -export const dataReceived = eventFactory('data-received'); -export const dataSnapshotLoad = eventFactory('data-snapshot-load'); -export const editModeInitialized = eventFactory('init-edit-mode'); -export const initPanelActions = eventFactory('init-panel-actions'); -export const panelChangeView = eventFactory('panel-change-view'); -export const panelInitialized = eventFactory('panel-initialized'); -export const panelSizeChanged = eventFactory('panel-size-changed'); -export const panelTeardown = eventFactory('panel-teardown'); -export const render = eventFactory('render'); -export const viewModeChanged = eventFactory('view-mode-changed'); + /** Events */ + export const refresh = eventFactory('refresh'); + export const componentDidMount = eventFactory('component-did-mount'); + export const dataError = eventFactory('data-error'); + export const dataReceived = eventFactory('data-received'); + export const dataSnapshotLoad = eventFactory('data-snapshot-load'); + export const editModeInitialized = eventFactory('init-edit-mode'); + export const initPanelActions = eventFactory('init-panel-actions'); + export const panelChangeView = eventFactory('panel-change-view'); + export const panelInitialized = eventFactory('panel-initialized'); + export const panelSizeChanged = eventFactory('panel-size-changed'); + export const panelTeardown = eventFactory('panel-teardown'); + export const render = eventFactory('render'); + export const viewModeChanged = eventFactory('view-mode-changed'); +} diff --git a/packages/grafana-data/src/types/vector.ts b/packages/grafana-data/src/types/vector.ts index d4e231b51d0..cf5b8563710 100644 --- a/packages/grafana-data/src/types/vector.ts +++ b/packages/grafana-data/src/types/vector.ts @@ -29,7 +29,7 @@ export interface MutableVector extends ReadWriteVector { add: (value: T) => void; /** - * modifies the vector so it is now the oposite order + * modifies the vector so it is now the opposite order */ reverse: () => void; } diff --git a/packages/grafana-e2e/api-extractor.json b/packages/grafana-e2e/api-extractor.json new file mode 100644 index 00000000000..5e96b3b0b3c --- /dev/null +++ b/packages/grafana-e2e/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.json" +} diff --git a/packages/grafana-e2e/package.json b/packages/grafana-e2e/package.json index ff8f25accbf..78fbd725087 100644 --- a/packages/grafana-e2e/package.json +++ b/packages/grafana-e2e/package.json @@ -21,7 +21,8 @@ "bundle": "rollup -c rollup.config.ts", "build": "grafana-toolkit package:build --scope=e2e", "open": "cypress open", - "start": "cypress run" + "start": "cypress run", + "docsExtract": "api-extractor run 2>&1 | tee ../../reports/docs/$(basename $(pwd)).log" }, "devDependencies": { "@cypress/webpack-preprocessor": "4.1.1", diff --git a/packages/grafana-e2e/src/index.ts b/packages/grafana-e2e/src/index.ts index 1865a55a8bc..d1000985f06 100644 --- a/packages/grafana-e2e/src/index.ts +++ b/packages/grafana-e2e/src/index.ts @@ -1,3 +1,6 @@ -import { e2e } from './noTypeCheck'; - -export { e2e }; +/** + * A library for writing end-to-end tests for Grafana and its ecosystem. + * + * @packageDocumentation + */ +export { e2e } from './noTypeCheck'; diff --git a/packages/grafana-runtime/api-extractor.json b/packages/grafana-runtime/api-extractor.json new file mode 100644 index 00000000000..5e96b3b0b3c --- /dev/null +++ b/packages/grafana-runtime/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.json" +} diff --git a/packages/grafana-runtime/package.json b/packages/grafana-runtime/package.json index 0e5ea01b7c6..1cf736ddd60 100644 --- a/packages/grafana-runtime/package.json +++ b/packages/grafana-runtime/package.json @@ -18,7 +18,8 @@ "typecheck": "tsc --noEmit", "clean": "rimraf ./dist ./compiled", "bundle": "rollup -c rollup.config.ts", - "build": "grafana-toolkit package:build --scope=runtime" + "build": "grafana-toolkit package:build --scope=runtime", + "docsExtract": "api-extractor run 2>&1 | tee ../../reports/docs/$(basename $(pwd)).log" }, "dependencies": { "@grafana/data": "6.7.0-pre", diff --git a/packages/grafana-runtime/src/index.ts b/packages/grafana-runtime/src/index.ts index 95520e1985d..347e4df40d2 100644 --- a/packages/grafana-runtime/src/index.ts +++ b/packages/grafana-runtime/src/index.ts @@ -1,7 +1,11 @@ +/** + * A library containing services, configurations etc. used to interact with the Grafana engine. + * + * @packageDocumentation + */ export * from './services'; export * from './config'; export * from './types'; export { loadPluginCss, SystemJS } from './utils/plugin'; export { reportMetaAnalytics } from './utils/analytics'; - export { DataSourceWithBackend } from './utils/DataSourceWithBackend'; diff --git a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts index 85d57014106..9761f75ac50 100644 --- a/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts +++ b/packages/grafana-runtime/src/utils/DataSourceWithBackend.ts @@ -71,7 +71,7 @@ export class DataSourceWithBackend< } /** - * This makes the arrow libary loading async. + * This makes the arrow library loading async. */ async toDataQueryResponse(rsp: any): Promise { const { resultsToDataFrames } = await import( diff --git a/packages/grafana-ui/api-extractor.json b/packages/grafana-ui/api-extractor.json new file mode 100644 index 00000000000..5e96b3b0b3c --- /dev/null +++ b/packages/grafana-ui/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.json" +} diff --git a/packages/grafana-ui/package.json b/packages/grafana-ui/package.json index c2714116694..8bfea0f3900 100644 --- a/packages/grafana-ui/package.json +++ b/packages/grafana-ui/package.json @@ -22,7 +22,8 @@ "storybook:build": "build-storybook -o ./dist/storybook -c .storybook -s .storybook/static", "clean": "rimraf ./dist ./compiled", "bundle": "rollup -c rollup.config.ts", - "build": "grafana-toolkit package:build --scope=ui" + "build": "grafana-toolkit package:build --scope=ui", + "docsExtract": "api-extractor run 2>&1 | tee ../../reports/docs/$(basename $(pwd)).log" }, "dependencies": { "@grafana/data": "6.7.0-pre", diff --git a/packages/grafana-ui/src/components/Cascader/Cascader.tsx b/packages/grafana-ui/src/components/Cascader/Cascader.tsx index 43f7b6ffb94..4a19adfb964 100644 --- a/packages/grafana-ui/src/components/Cascader/Cascader.tsx +++ b/packages/grafana-ui/src/components/Cascader/Cascader.tsx @@ -37,7 +37,7 @@ export interface CascaderOption { items?: CascaderOption[]; disabled?: boolean; title?: string; - /** Children will be shown in a submenu. Use 'items' instead, as 'children' exist to ensure backwards compability.*/ + /** Children will be shown in a submenu. Use 'items' instead, as 'children' exist to ensure backwards compatibility.*/ children?: CascaderOption[]; } diff --git a/packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.test.tsx b/packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.test.tsx index 98e822ea074..1b76e062c8b 100644 --- a/packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.test.tsx +++ b/packages/grafana-ui/src/components/ThresholdsEditor/ThresholdsEditor.test.tsx @@ -2,7 +2,7 @@ import React, { ChangeEvent } from 'react'; import { mount } from 'enzyme'; import { GrafanaThemeType, ThresholdsMode } from '@grafana/data'; import { ThresholdsEditor, Props, thresholdsWithoutKey } from './ThresholdsEditor'; -import { colors } from '../../utils'; +import { colors } from '../../utils/colors'; import { mockThemeContext } from '../../themes/ThemeContext'; const setup = (propOverrides?: Partial) => { diff --git a/packages/grafana-ui/src/index.ts b/packages/grafana-ui/src/index.ts index 3d10e00504f..2b378a6822c 100644 --- a/packages/grafana-ui/src/index.ts +++ b/packages/grafana-ui/src/index.ts @@ -1,3 +1,8 @@ +/** + * A library containing the different design components of the Grafana ecosystem. + * + * @packageDocumentation + */ export * from './components'; export * from './types'; export * from './utils'; diff --git a/packages/grafana-ui/src/themes/index.ts b/packages/grafana-ui/src/themes/index.ts index d1e0ea0295f..f88298f181e 100644 --- a/packages/grafana-ui/src/themes/index.ts +++ b/packages/grafana-ui/src/themes/index.ts @@ -3,6 +3,4 @@ import { getTheme, mockTheme } from './getTheme'; import { selectThemeVariant } from './selectThemeVariant'; export { stylesFactory } from './stylesFactory'; export { ThemeContext, withTheme, mockTheme, getTheme, selectThemeVariant, useTheme, mockThemeContext }; - -import * as styleMixins from './mixins'; -export { styleMixins }; +export { styleMixins } from './mixins'; diff --git a/packages/grafana-ui/src/themes/mixins.ts b/packages/grafana-ui/src/themes/mixins.ts index 727d08d74cf..d7f9ee20520 100644 --- a/packages/grafana-ui/src/themes/mixins.ts +++ b/packages/grafana-ui/src/themes/mixins.ts @@ -1,8 +1,10 @@ import { GrafanaTheme } from '@grafana/data'; -export function cardChrome(theme: GrafanaTheme): string { - if (theme.isDark) { - return ` +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace styleMixins { + export function cardChrome(theme: GrafanaTheme): string { + if (theme.isDark) { + return ` background: linear-gradient(135deg, ${theme.colors.dark8}, ${theme.colors.dark6}); &:hover { background: linear-gradient(135deg, ${theme.colors.dark9}, ${theme.colors.dark6}); @@ -10,9 +12,9 @@ export function cardChrome(theme: GrafanaTheme): string { box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3); border-radius: ${theme.border.radius.md}; `; - } + } - return ` + return ` background: linear-gradient(135deg, ${theme.colors.gray6}, ${theme.colors.gray7}); &:hover { background: linear-gradient(135deg, ${theme.colors.gray7}, ${theme.colors.gray6}); @@ -20,11 +22,11 @@ export function cardChrome(theme: GrafanaTheme): string { box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1); border-radius: ${theme.border.radius.md}; `; -} + } -export function listItem(theme: GrafanaTheme): string { - if (theme.isDark) { - return ` + export function listItem(theme: GrafanaTheme): string { + if (theme.isDark) { + return ` background: ${theme.colors.dark7}; &:hover { background: ${theme.colors.dark9}; @@ -32,9 +34,9 @@ export function listItem(theme: GrafanaTheme): string { box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.3); border-radius: ${theme.border.radius.md}; `; - } + } - return ` + return ` background: ${theme.colors.gray7}; &:hover { background: ${theme.colors.gray6}; @@ -42,4 +44,5 @@ export function listItem(theme: GrafanaTheme): string { box-shadow: -1px -1px 0 0 hsla(0, 0%, 100%, 0.1), 1px 1px 0 0 rgba(0, 0, 0, 0.1); border-radius: ${theme.border.radius.md}; `; + } } diff --git a/packages/grafana-ui/src/utils/dom.ts b/packages/grafana-ui/src/utils/dom.ts index 13f48764e73..b8fa192dbf5 100644 --- a/packages/grafana-ui/src/utils/dom.ts +++ b/packages/grafana-ui/src/utils/dom.ts @@ -1,41 +1,44 @@ -// Node.closest() polyfill -if ('Element' in window && !Element.prototype.closest) { - Element.prototype.closest = function(this: any, s: string) { - const matches = (this.document || this.ownerDocument).querySelectorAll(s); - let el = this; - let i; - // eslint-disable-next-line - do { - i = matches.length; +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace DOMUtil { + // Node.closest() polyfill + if ('Element' in window && !Element.prototype.closest) { + Element.prototype.closest = function(this: any, s: string) { + const matches = (this.document || this.ownerDocument).querySelectorAll(s); + let el = this; + let i; // eslint-disable-next-line - while (--i >= 0 && matches.item(i) !== el) {} - el = el.parentElement; - } while (i < 0 && el); - return el; - }; -} - -export function getPreviousCousin(node: any, selector: string) { - let sibling = node.parentElement.previousSibling; - let el; - while (sibling) { - el = sibling.querySelector(selector); - if (el) { + do { + i = matches.length; + // eslint-disable-next-line + while (--i >= 0 && matches.item(i) !== el) {} + el = el.parentElement; + } while (i < 0 && el); return el; - } - sibling = sibling.previousSibling; + }; } - return undefined; -} -export function getNextCharacter(global?: any) { - const selection = (global || window).getSelection(); - if (!selection || !selection.anchorNode) { - return null; + export function getPreviousCousin(node: any, selector: string) { + let sibling = node.parentElement.previousSibling; + let el; + while (sibling) { + el = sibling.querySelector(selector); + if (el) { + return el; + } + sibling = sibling.previousSibling; + } + return undefined; } - const range = selection.getRangeAt(0); - const text = selection.anchorNode.textContent; - const offset = range.startOffset; - return text!.substr(offset, 1); + export function getNextCharacter(global?: any) { + const selection = (global || window).getSelection(); + if (!selection || !selection.anchorNode) { + return null; + } + + const range = selection.getRangeAt(0); + const text = selection.anchorNode.textContent; + const offset = range.startOffset; + return text!.substr(offset, 1); + } } diff --git a/packages/grafana-ui/src/utils/index.ts b/packages/grafana-ui/src/utils/index.ts index a9e1c7328db..b3979e27e59 100644 --- a/packages/grafana-ui/src/utils/index.ts +++ b/packages/grafana-ui/src/utils/index.ts @@ -7,5 +7,4 @@ export * from './measureText'; export { default as ansicolor } from './ansicolor'; // Export with a namespace -import * as DOMUtil from './dom'; // includes Element.closest polyfil -export { DOMUtil }; +export { DOMUtil } from './dom'; // includes Element.closest polyfil diff --git a/scripts/build_api_docs.sh b/scripts/build_api_docs.sh new file mode 100755 index 00000000000..d1eac2c7c3a --- /dev/null +++ b/scripts/build_api_docs.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# abort if we get any error +set -e + +# always make sure we have a clean workspace +if ! git diff-index --quiet HEAD --; then + echo -e "\033[91mgit workspace is dirty and contains changes\033[0" + echo -e "\033[91mmake sure you have a clean workspace before running this script\033[0m" + exit 1 +fi + +# building grafana packages +echo "bulding grafana packages..." +yarn packages:build + +# extract packages api documentation json +echo "extracting packages documentation data..." +yarn packages:docsExtract + +# generating api documentation markdown +echo "generating markdown from documentation data..." +yarn packages:docsToMarkdown + +# cleaning packages +echo "cleaning up packages build files..." +lerna run clean diff --git a/scripts/generate_api_docs.sh b/scripts/generate_api_docs.sh new file mode 100755 index 00000000000..bc09c927e00 --- /dev/null +++ b/scripts/generate_api_docs.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash + +# abort if we get any error +set -e + +_current="$(git rev-parse --abbrev-ref HEAD)" +_branch="${_current}-docs" + +if [ "${_current}" == "master" ]; then + echo -e "\033[91myou cannot generate api docs from the master branch\033[0m" + echo "please checkout the release branch" + echo "ex 'git checkout v5.1.x'" + exit 1 +fi + +# always make sure we have a clean workspace +if ! git diff-index --quiet HEAD --; then + echo -e "\033[91mgit workspace is dirty and contains changes\033[0" + echo -e "\033[91mmake sure you have a clean workspace before running this script\033[0m" + exit 1 +fi + +# always make sure to pull latest changes from origin +echo "pulling latest changes from ${_current}" +git pull origin "${_current}" + +# creating new branch for docs update +echo "creating new branch ${_branch}" +git checkout -b "${_branch}" + +# building grafana packages +echo "bulding grafana packages..." +yarn packages:build + +# extract packages api documentation json +echo "extracting packages documentation data..." +yarn packages:docsExtract + +# generating api documentation markdown +echo "generating markdown from documentation data..." +yarn packages:docsToMarkdown + +echo "updated files:" +git status --porcelain | sed s/^...// + +echo "press [y] to commit documentation update" +read -n 1 confirm + +if [ "${confirm}" == "y" ]; then + git add --all docs/sources/packages_api + git commit -m "docs: updated packages api documentation" + git push origin "${_branch}" + git checkout "${_current}" + echo -e "\033[92mPackages docs successfully updated. Please open a PR from ${_branch} to master.\033[0m" +else + git checkout -- . + git clean -f docs/sources/packages_api + git checkout "${_current}" + git branch -d "${_branch}" + echo -e "\033[91mAbort!\033[0m" +fi diff --git a/yarn.lock b/yarn.lock index 83bcde27430..684beb936ed 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2867,6 +2867,19 @@ unique-filename "^1.1.1" which "^1.3.1" +"@grafana/api-documenter@0.9.3": + version "0.9.3" + resolved "https://registry.yarnpkg.com/@grafana/api-documenter/-/api-documenter-0.9.3.tgz#543d0a973157541dd8870d67fb29c3209c52292b" + integrity sha512-irYVzjmBQnJ8WEM7WECFhnaAy9b3jzfFbLbiWkTqpxNT1l4RzMycJyjBGdUVUhQjIvg/HbpF8Vqf1utNkrJdxA== + dependencies: + "@microsoft/api-extractor-model" "7.7.7" + "@microsoft/node-core-library" "3.19.3" + "@microsoft/ts-command-line" "4.3.10" + "@microsoft/tsdoc" "0.12.14" + colors "~1.2.1" + js-yaml "~3.13.1" + resolve "1.8.1" + "@grafana/eslint-config@^1.0.0-rc1": version "1.0.0-rc1" resolved "https://registry.yarnpkg.com/@grafana/eslint-config/-/eslint-config-1.0.0-rc1.tgz#3b0a1abddfea900a57abc9526ad31abb1da2d42c" @@ -3792,6 +3805,56 @@ resolved "https://registry.yarnpkg.com/@mdx-js/util/-/util-1.5.5.tgz#6f88bcb847ebd0117fc81bcd26b83220062fd881" integrity sha512-IudQkyZuM8T1CrSX9r0ShPXCABjtEtyrV4lxQqhKAwFqw1aYpy/5LOZhitMLoJTybZPVdPotuh+zjqYy9ZOSbA== +"@microsoft/api-extractor-model@7.7.7": + version "7.7.7" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.7.7.tgz#1d15eae7a19b72abbfca9053f200fe79b6f9d755" + integrity sha512-822kyHMEx2sl+KnBioEiFoTIXuz/4pYBo94nQ4AMqb9BFvY9I1AZUPtC4HFh2zcXQqpFLpKKC55s/o8UOze2wQ== + dependencies: + "@microsoft/node-core-library" "3.19.3" + "@microsoft/tsdoc" "0.12.14" + +"@microsoft/api-extractor@7.7.8": + version "7.7.8" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.7.8.tgz#19b0bca8a2113d4ded55a270266bc2b802de1a43" + integrity sha512-XNO6Dk6ByfJq24Cn1/j0B0F16ZtwYnEC/sxgB/M0wTphBdBlHjRXZmxofmjirBBj9f7vG4UJ18IOIZRLbhGFPw== + dependencies: + "@microsoft/api-extractor-model" "7.7.7" + "@microsoft/node-core-library" "3.19.3" + "@microsoft/ts-command-line" "4.3.10" + "@microsoft/tsdoc" "0.12.14" + colors "~1.2.1" + lodash "~4.17.15" + resolve "1.8.1" + source-map "~0.6.1" + typescript "~3.7.2" + +"@microsoft/node-core-library@3.19.3": + version "3.19.3" + resolved "https://registry.yarnpkg.com/@microsoft/node-core-library/-/node-core-library-3.19.3.tgz#cf09ddb2905a29b32956d4a88f9d035a00637be9" + integrity sha512-rJ+hT6+XK5AESbhn31YBnHKpZSFKCmqHCRZyK9+jyWwav1HXv0qzuXnFvnyrO0MZyJ6rH0seWOZVWbU5KGv1tg== + dependencies: + "@types/node" "10.17.13" + colors "~1.2.1" + fs-extra "~7.0.1" + jju "~1.4.0" + semver "~5.3.0" + timsort "~0.3.0" + z-schema "~3.18.3" + +"@microsoft/ts-command-line@4.3.10": + version "4.3.10" + resolved "https://registry.yarnpkg.com/@microsoft/ts-command-line/-/ts-command-line-4.3.10.tgz#fcb4f5ea43c93d17db6cc810bbee39ea32b2a86d" + integrity sha512-AgxArGqPt0H5WTo3fxNFP3Blm3obkCCopVG9kwIo+/mMdXaj6qMDn6+8Bv8+5Nke3CvvXpKAZtu3IaGY5cV1Hg== + dependencies: + "@types/argparse" "1.0.33" + argparse "~1.0.9" + colors "~1.2.1" + +"@microsoft/tsdoc@0.12.14": + version "0.12.14" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.12.14.tgz#0e0810a0a174e50e22dfe8edb30599840712f22d" + integrity sha512-518yewjSga1jLdiLrcmpMFlaba5P+50b0TWNFUpC+SL9Yzf0kMi57qw+bMl+rQ08cGqH1vLx4eg9YFUbZXgZ0Q== + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -4509,6 +4572,11 @@ resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== +"@types/argparse@1.0.33": + version "1.0.33" + resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.33.tgz#2728669427cdd74a99e53c9f457ca2866a37c52d" + integrity sha512-VQgHxyPMTj3hIlq9SY1mctqx+Jj8kpQfoLvDlVSDNOyuYs8JYfkuY3OW/4+dO657yPmNhHpePRx0/Tje5ImNVQ== + "@types/babel-types@*", "@types/babel-types@^7.0.0": version "7.0.7" resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3" @@ -5157,6 +5225,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.1.tgz#8701cd760acc20beba5ffe0b7a1b879f39cb8c41" integrity sha512-Rymt08vh1GaW4vYB6QP61/5m/CFLGnFZP++bJpWbiNxceNa6RBipDmb413jvtSf/R1gg5a/jQVl2jY4XVRscEA== +"@types/node@10.17.13": + version "10.17.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.13.tgz#ccebcdb990bd6139cd16e84c39dc2fb1023ca90c" + integrity sha512-pMCcqU2zT4TjqYFrWtYHKal7Sl30Ims6ulZ4UFXxI4xbtQqK/qqKwkDoBFCfooRqqmRu9vY3xaJRwxSh673aYg== + "@types/node@13.7.0": version "13.7.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4" @@ -6417,7 +6490,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.1.tgz#485f8e7c390ce4c5f78257dbea80d4be11feda4c" integrity sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw== -argparse@^1.0.7: +argparse@^1.0.7, argparse@~1.0.9: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -8445,6 +8518,11 @@ colors@~1.1.2: resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" integrity sha1-FopHAXVran9RoSzgyXv6KMCE7WM= +colors@~1.2.1: + version "1.2.5" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.5.tgz#89c7ad9a374bc030df8013241f68136ed8835afc" + integrity sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg== + columnify@^1.5.4, columnify@~1.5.4: version "1.5.4" resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" @@ -8491,7 +8569,7 @@ command-line-usage@5.0.5: table-layout "^0.4.3" typical "^2.6.1" -commander@2, commander@^2.14.1, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.8.1, commander@^2.9.0: +commander@2, commander@^2.14.1, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@^2.7.1, commander@^2.8.1, commander@^2.9.0: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -12006,7 +12084,7 @@ fs-extra@5.0.0: jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@7.0.1: +fs-extra@7.0.1, fs-extra@~7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== @@ -14910,6 +14988,11 @@ jest@24.8.0: import-local "^2.0.0" jest-cli "^24.8.0" +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha1-o6vicYryQaKykE+EpiWXDzia4yo= + jquery@3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2" @@ -14945,7 +15028,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.13.1, js-yaml@^3.13.1, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4, js-yaml@~3.13.0: +js-yaml@3.13.1, js-yaml@^3.13.1, js-yaml@^3.4.6, js-yaml@^3.5.1, js-yaml@^3.5.4, js-yaml@~3.13.0, js-yaml@~3.13.1: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -15813,7 +15896,7 @@ lodash.flattendeep@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2" integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI= -lodash.get@^4.4.2: +lodash.get@^4.0.0, lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= @@ -15922,7 +16005,7 @@ lodash.without@~4.4.0: resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" integrity sha1-PNRXSgC2e643OpS3SHcmQFB7eqw= -lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.1.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.7.0, lodash@^4.8.0, lodash@~4.17.10, lodash@~4.17.5: +lodash@4.17.15, lodash@>4.17.4, lodash@^4.0.0, lodash@^4.0.1, lodash@^4.1.1, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.7.0, lodash@^4.8.0, lodash@~4.17.10, lodash@~4.17.15, lodash@~4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -23659,7 +23742,7 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" -timsort@^0.3.0: +timsort@^0.3.0, timsort@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= @@ -24067,6 +24150,11 @@ typescript@3.7.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.2.tgz#27e489b95fa5909445e9fef5ee48d81697ad18fb" integrity sha512-ml7V7JfiN2Xwvcer+XAf2csGO1bPBdRbFCkYBczNZggrBZ9c7G3riSUeJmqEU5uOtXNPMhE3n+R4FA/3YOAWOQ== +typescript@~3.7.2: + version "3.7.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" + integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== + typical@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" @@ -24597,6 +24685,11 @@ validate-npm-package-name@^3.0.0, validate-npm-package-name@~3.0.0: dependencies: builtins "^1.0.3" +validator@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" + integrity sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -25559,6 +25652,17 @@ yup@^0.26.10: synchronous-promise "^2.0.5" toposort "^2.0.2" +z-schema@~3.18.3: + version "3.18.4" + resolved "https://registry.yarnpkg.com/z-schema/-/z-schema-3.18.4.tgz#ea8132b279533ee60be2485a02f7e3e42541a9a2" + integrity sha512-DUOKC/IhbkdLKKiV89gw9DUauTV8U/8yJl1sjf6MtDmzevLKOF2duNJ495S3MFVjqZarr+qNGCPbkg4mu4PpLw== + dependencies: + lodash.get "^4.0.0" + lodash.isequal "^4.0.0" + validator "^8.0.0" + optionalDependencies: + commander "^2.7.1" + zip-stream@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04"