diff --git a/CHANGELOG.md b/CHANGELOG.md index d0211997ee5b..500c02f9c09b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,42 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + + +### Bug Fixes + +* declare webpackChunkName in generated dynamic imports for readable runtime bundle names ([#7835](https://github.com/SAP/ui5-webcomponents/issues/7835)) ([592a10b](https://github.com/SAP/ui5-webcomponents/commit/592a10b25a14da89885874c40c5c7a192b8b4d85)) +* **ui5-list:** shift+tab navigation in List ([#7728](https://github.com/SAP/ui5-webcomponents/issues/7728)) ([399b941](https://github.com/SAP/ui5-webcomponents/commit/399b941ebeae7b44f6dba9cd4e8ec7ebb6f283c6)) + + +### Features + +* **ui5-illustrated-message:** titleLevel property added ([#7771](https://github.com/SAP/ui5-webcomponents/issues/7771)) ([2883c58](https://github.com/SAP/ui5-webcomponents/commit/2883c587f367e51e0f08065498b990f86e60e88c)), closes [#7037](https://github.com/SAP/ui5-webcomponents/issues/7037) + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + + +### Bug Fixes + +* **ItemNavigation:** more than 1 ItemNavigation per component allowed ([#7798](https://github.com/SAP/ui5-webcomponents/issues/7798)) ([b1019af](https://github.com/SAP/ui5-webcomponents/commit/b1019aff6c4aced61458c1b718ffe0a3a7802ae2)) +* **ui5-segmented-button:** check for items before applying settings ([#7792](https://github.com/SAP/ui5-webcomponents/issues/7792)) ([7f11274](https://github.com/SAP/ui5-webcomponents/commit/7f112746d50381474ec86da5e428df79c17c6499)), closes [#7788](https://github.com/SAP/ui5-webcomponents/issues/7788) +* **ui5-time-picker:** check value before formatting ([#7793](https://github.com/SAP/ui5-webcomponents/issues/7793)) ([70deda8](https://github.com/SAP/ui5-webcomponents/commit/70deda85293d5e62e99530c9dc0747071d9ee59c)), closes [#7790](https://github.com/SAP/ui5-webcomponents/issues/7790) + + +### Features + +* **ui5-illustrated-message:** added new TNT illustrations ([#7773](https://github.com/SAP/ui5-webcomponents/issues/7773)) ([03f28b9](https://github.com/SAP/ui5-webcomponents/commit/03f28b90df0b2a28c0f09f67caaa0a5a1e63c4f3)) +* **ui5-side-navigation:** added href and target properties ([#7682](https://github.com/SAP/ui5-webcomponents/issues/7682)) ([7530f00](https://github.com/SAP/ui5-webcomponents/commit/7530f00b589d0b95dcbee49f6ed980e9d36ba58b)) + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package ui5-webcomponents diff --git a/docs/1-getting-started/06-using-features.md b/docs/1-getting-started/06-using-features.md index 3c4b30b3e74b..2f48a83032af 100644 --- a/docs/1-getting-started/06-using-features.md +++ b/docs/1-getting-started/06-using-features.md @@ -16,7 +16,7 @@ Import the feature file from the respective NPM package: `import "@ui5//dist/features/.js` -## Component features +## Component features Currently, only a few components offer additional features: @@ -31,22 +31,28 @@ Currently, only a few components offer additional features: | `localization` | Multiple (`ui5-date-picker`, etc...) | `@ui5/webcomponents-localization/dist/features/calendar/Japanese.js` | Japanese calendar support | | `localization` | Multiple (`ui5-date-picker`, etc...) | `@ui5/webcomponents-localization/dist/features/calendar/Persian.js` | Persian calendar support | +Note: Features must be imported before all components modules, +so that the feature is enabled before the components' definition. + For example: ```js import "@ui5/webcomponents/dist/features/ColorPaletteMoreColors.js;"; + +import "@ui5/webcomponents/dist/Button.js"; +import "@ui5/webcomponents/dist/Link.js"; +import "@ui5/webcomponents/dist/Input.js"; ``` -## Framework features +## Framework features | Package | Affects | Feature Import | Description | |----------------|---------------------------------------------------|----------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------| | `base` | Framework | `@ui5/webcomponents-base/dist/features/OpenUI5Support.js` | Integration with the OpenUI5 framework, allowing synchronization and resources re-use | | `base` | Multiple components within all libraries | `@ui5/webcomponents-base/dist/features/F6Navigation.js` | Support for F6 fast groups navigation | | `base` | Date related components | `@ui5/webcomponents-base/dist/features/LegacyDateFormats.js` | Support for legacy date formats | -| -Framework-level features must be imported before all components modules, +Note: Framework-level features must be imported before all components modules, so that the feature is enabled upon framework boot, before the components' definition. For example: diff --git a/docs/4-frameworks/01-React.md b/docs/4-frameworks/01-React.md index f8fcf353bc6c..a9a6472e878d 100644 --- a/docs/4-frameworks/01-React.md +++ b/docs/4-frameworks/01-React.md @@ -2,7 +2,7 @@ In this tutorial, you will learn how to add UI5 Web Components to your application. You can add UI5 Web Components both to new React applications and to already existing ones. -**Important:** The get the best development experience, we recommend using the [UI5 Web Components for React](https://github.com/SAP/ui5-webcomponents-react) and follow the [UI5 Web Components for React Тutorial](https://developers.sap.com/mission.react-spa.html). UI5 Web Components for React library is a React implementation of UI5 Web Components which overcomes several limitations of React in handling web components in general, explained in the "Additional Info" section below. +**Important:** To get the best development experience, we recommend using the [UI5 Web Components for React](https://github.com/SAP/ui5-webcomponents-react) and follow the [UI5 Web Components for React Тutorial](https://developers.sap.com/mission.react-spa.html). UI5 Web Components for React library is a React implementation of UI5 Web Components which overcomes several limitations of React in handling web components in general, explained in the "Additional Info" section below. Here are the steps to use pure UI5 Web Components in React: diff --git a/docs/4-frameworks/02-Angular.md b/docs/4-frameworks/02-Angular.md index abc4af553272..62d5697d9177 100644 --- a/docs/4-frameworks/02-Angular.md +++ b/docs/4-frameworks/02-Angular.md @@ -1,6 +1,10 @@ # Get Started with UI5 Web Components & Angular -In this tutorial, you will learn how to add UI5 Web Components to your application. The UI5 Web Components can be added both to new Angular applications and to already existing ones. +In this tutorial, you will learn how to use `UI5 Web Components` in an Angular application. In the second part, we will introduce `UI5 Web Components for Angular` - wrapper library for UI5 Web Components, improving their integration with Angular. + +**Note:** To get the best development experience, we recommend using the [UI5 Web Components for Angular](https://ui5-webcomponents-ngx.netlify.app). The library removes the need for `CUSTOM_ELEMENTS_SCHEMA` and `NO_ERRORS_SCHEMA` schemas, and supports all Angular-specific features out-of-the-box. + +## UI5 Web Components ### Step 1. Install Angular CLI. @@ -10,26 +14,30 @@ npm install -g @angular/cli ### Step 2. Create a new Angular application. +Use the standard path to setup a new Angular app. + ```bash ng new ui5-web-components-application cd ui5-web-components-application ``` -### Step 3. Add UI5 Web Components. +### Step 3. Install UI5 Web Components. ```bash -npm install @ui5/webcomponents --save +npm install @ui5/webcomponents ``` -### Step 4. Allow the use of custom elements in Angular. +### Step 4. Allow Custom Elements in Angular. -Before using UI5 Web Components, you have to allow the use of custom elements in Angular. To do so, import CUSTOM_ELEMENTS_SCHEMA in ```app.module.ts``` : +Before using UI5 Web Components, you have to allow the use of custom elements via the `CUSTOM_ELEMENTS_SCHEMA`. This allows an NgModule to contain Non-Angular elements named with dash. + +- Import `CUSTOM_ELEMENTS_SCHEMA` in `app.module.ts`: ```js import { ..., CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; ``` -After importing it, add it to the schemas array: +- Add `CUSTOM_ELEMENTS_SCHEMA` to the schemas array: ```js imports: [ @@ -40,13 +48,30 @@ schemas: [ ] ``` -### Step 5. Import the components you are going to use. +### Step 5. Import UI5 Web Components. + +Import the components you are going to use. + +Let's import the Button in `app.component.ts`: ```js -import "@ui5/webcomponents/dist/Button.js"; +import { Component } from '@angular/core'; + +import '@ui5/webcomponents/dist/Button.js'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', +}) +export class AppComponent { +} ``` -### Step 6. Use the imported elements in your application. +### Step 6. Use UI5 Web Components. + +Use the imported components in your application by their tag names - as any other HTML element. + +Let's add the button into the `app.component.html` template: ```html Hello world! @@ -58,73 +83,181 @@ import "@ui5/webcomponents/dist/Button.js"; ng serve -o ``` -## Additional Info +After the development server starts, the UI5 Web Components Button will be rendered in the test page. Now that you've seen how easy it is to use the UI5 Web Components, you can continue with adding more components in the same manner. + + +## UI5 Web Components For Angular + +UI5 Web Components for Angular is a wrapper library for UI5 Web Components. This means that for every UI5 Web Component, there is a corresponding Angular wrapper component available. -### Two-Way Data Binding +**For Example:** -You can use two-way data binding with the following components: CheckBox, RadioButton, Input, DatePicker, Switch, TextArea. -In order to use it, you have to use a library called [Origami](https://github.com/hotforfeature/origami) that provides advanced support for two-way data binding of custom elements. +- The native Button web component +```js +import '@ui5/webcomponents/dist/Button.js'; +``` + +- The "ngx" Button wrapper component +```js +import { ButtonComponent } from '@ui5/webcomponents-ngx/main/button'; +``` -Example: +These wrappers supports all Angular-specific features out-of-the-box, f.e. two-way data binding with `NgModel`, as they are native to Angular. + +### Angular Form with `NgModel` + +The following section demonstrates how to build template-driven Angular form (following the oficial [Angular documentation](https://angular.io/guide/forms)) with UI5 Web Components For Angular. It illustrates the usage of two-way data binding to update the data model in the component as changes are made in the template and vice versa. + +### Step 1. Setup Angular project + +```bash +npm install -g @angular/cli +ng new ui5-web-components-ngx-application +cd ui5-web-components-ngx-application +``` + +### Step 2. Install UI5 Web Components for Angular. -#### 1. Install Origami. ```bash -npm install @codebakery/origami +npm install @ui5/webcomponents-ngx ``` -#### 2. Import the OrigamiFormsModule from Origami. +### Step 3. Build Angular form. + +To build an Angular Form, we will include the required infrastructure such as the `FormsModule`, track input validity and status using `ngModel` and make use of some form components from `@ui5/webcomponents-ngx`. + + +- Import `FormsModule` in `app.module.ts` and add it to the imports array. ```js -import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; import { BrowserModule } from '@angular/platform-browser'; -import { OrigamiFormsModule } from '@codebakery/origami/forms'; + import { AppComponent } from './app.component'; @NgModule({ - imports: [BrowserModule, OrigamiFormsModule], - declarations: [AppComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], + declarations: [ + AppComponent + ], + imports: [ + BrowserModule, + FormsModule, + ], + providers: [], bootstrap: [AppComponent] }) -export class AppModule {} -``` - -#### 3. Use Origami in your template. - -```html - +export class AppModule { +} ``` -#### 4. Make Angular boot after UI5 Web Components are defined. +- Import `Label`, `Input` and `Button` components from `@ui5/webcomponents-ngx` in `app.module.ts` and add them to the imports array. -Add the ```APP_INITIALIZER``` provider to the module where you are using UI5 Web Components. In order to do so, import ```APP_INITIALIZER``` and add it to the providers array like this (in this example we will add it to the ```app.module.ts```): ```js -import { ..., APP_INITIALIZER } from '@angular/core'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; -import CheckBox from "@ui5/webcomponents/dist/CheckBox"; +import { AppComponent } from './app.component'; -function onAppInit(): () => Promise { - return (): Promise => { - return CheckBox.define(); - }; -} +// UI5 Web Components For Angular +import { LabelComponent } from '@ui5/webcomponents-ngx/main/label'; +import { ButtonComponent } from '@ui5/webcomponents-ngx/main/button'; +import { InputComponent } from '@ui5/webcomponents-ngx/main/input'; @NgModule({ declarations: [ - ... + AppComponent ], imports: [ - ... - ], - providers: [ - { - provide: APP_INITIALIZER, - useFactory: onAppInit, - multi: true - }, + BrowserModule, + FormsModule, + LabelComponent, + InputComponent, + ButtonComponent ], - schemas: [ CUSTOM_ELEMENTS_SCHEMA ], + providers: [], bootstrap: [AppComponent] }) +export class AppModule { +} +``` + +### Step 4. Define a Data Model. + +- Add the following object, that will serve as a data model, to the `AppComponent`: + +```js +// app.component.ts +import { Component } from '@angular/core'; + +export class AppComponent { + model = { + firstName: "", + lastName: "" + }; +} +``` + +### Step 5. Create the Form UI. + +- Add the following inline template to the `AppComponent`. +- Bind form components to data properties using the `ngModel` directive and two-way data-binding syntax. +- Name form controls (e.g. add `name` attribute) to make them accessible to `ngModel`. + +```js +// app.component.ts +import { Component } from '@angular/core'; + +@Component({ + selector: 'app-root', + template: `

Form Works!

+ +
+
+ First Name: + +
+ +
+ Last Name: + +
+ + Submit + + Form Value: {{heroForm.value | json}} + Form Status: {{heroForm.status}} +
`, +}) +export class AppComponent { + model = { + firstName: "", + lastName: "" + }; +} +``` + +### Step 5. Launch the application. + +```bash +ng serve -o ``` + +After the development server starts, a simple form will be rendered in the test page. + +Initially, the model is empty and the form is invalid: + +```js +// Form Value: { "firstName": "", "lastName": "" } +// Form Status: "Invalid" +``` + +Start typing in the input fields and you will notice how the form model and form status are updated. + +Good job, the Form works! + +## Summary + +Angular provides good support of web components and `UI5 Web Components` are working perfectly in the majority of use-cases. However, for an enhanced development experience and better support for both template-driven and Reactive forms, the `UI5 Web Components for Angular` is the recommended choice. \ No newline at end of file diff --git a/docs/6-contributing/04-writing-samples.md b/docs/6-contributing/04-writing-samples.md index 003d96d48c6c..e9b42420d53b 100644 --- a/docs/6-contributing/04-writing-samples.md +++ b/docs/6-contributing/04-writing-samples.md @@ -115,7 +115,7 @@ The above example includes only the `indeterminate`, `checked` properties in the ## Documentation -The documentation for each component is automatically produced using the `custom-elements.json` file. Additionally, there is an `argTypes.ts` file located beside each `.stories.ts` file. It is generated during build time and contains extra properties that enhance the documentation beyond what is available in the `custom-elements.json` file. This file should not be edited directly, as it can only be modified by the `packages/playground/build-scripts-storybook/samples-prepare.js` script. +The documentation for each component is automatically produced using the `custom-elements.json` file. Additionally, there is an `argTypes.ts` file located beside each `.stories.ts` file. It is generated during build time and contains extra properties that enhance the documentation beyond what is available in the `custom-elements.json` file. This file should not be edited directly, as it can only be modified by the `packages/playground/build-scripts-storybook/samples-prepare.ts` script. ### Docs page Every story has a `docs` page in the storybook's sidebar. Usually, this page is generated automatically by storybook but it can be customized by adding a `docs` property to the story parameters. diff --git a/lerna.json b/lerna.json index 5d6aa2a5d997..4bc6b7e7b3c3 100644 --- a/lerna.json +++ b/lerna.json @@ -12,7 +12,7 @@ "packages/playground", "packages/create-package" ], - "version": "1.19.0", + "version": "1.20.0-rc.1", "command": { "publish": { "allowBranch": "*", diff --git a/packages/base/CHANGELOG.md b/packages/base/CHANGELOG.md index f821abc49282..3b94cd5fdba2 100644 --- a/packages/base/CHANGELOG.md +++ b/packages/base/CHANGELOG.md @@ -3,6 +3,30 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + +**Note:** Version bump only for package @ui5/webcomponents-base + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + + +### Bug Fixes + +* **ItemNavigation:** more than 1 ItemNavigation per component allowed ([#7798](https://github.com/SAP/ui5-webcomponents/issues/7798)) ([b1019af](https://github.com/SAP/ui5-webcomponents/commit/b1019aff6c4aced61458c1b718ffe0a3a7802ae2)) + + +### Features + +* **ui5-side-navigation:** added href and target properties ([#7682](https://github.com/SAP/ui5-webcomponents/issues/7682)) ([7530f00](https://github.com/SAP/ui5-webcomponents/commit/7530f00b589d0b95dcbee49f6ed980e9d36ba58b)) + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package @ui5/webcomponents-base diff --git a/packages/base/package-scripts.cjs b/packages/base/package-scripts.cjs index 86d93d9dc24b..d24d6111c819 100644 --- a/packages/base/package-scripts.cjs +++ b/packages/base/package-scripts.cjs @@ -43,6 +43,8 @@ const scripts = { generateTemplates: `mkdirp src/generated/templates && cross-env UI5_BASE=true UI5_TS=true node "${LIB}/hbs2ui5/index.js" -d test/elements -o src/generated/templates`, generateAPI: { default: "nps generateAPI.prepare generateAPI.preprocess generateAPI.jsdoc generateAPI.cleanup", + generateCEM: `cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"`, + validateCEM: `node "${LIB}/cem/validate.js"`, prepare: `copy-and-watch "dist/**/*.js" jsdoc-dist/`, preprocess: `node "${preprocessJSDocScript}" jsdoc-dist/`, jsdoc: `jsdoc -c "${LIB}/jsdoc/configTypescript.json"`, diff --git a/packages/base/package.json b/packages/base/package.json index 3cf7f12e6fc8..3553351160bb 100644 --- a/packages/base/package.json +++ b/packages/base/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-base", - "version": "1.19.0", + "version": "1.20.0-rc.1", "description": "UI5 Web Components: webcomponents.base", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -37,8 +37,8 @@ "devDependencies": { "@buxlabs/amd-to-es6": "0.16.1", "@openui5/sap.ui.core": "1.116.0", - "@ui5/webcomponents-tools": "1.19.0", - "chromedriver": "117.0.3", + "@ui5/webcomponents-tools": "1.20.0-rc.1", + "chromedriver": "119.0.1", "clean-css": "^5.2.2", "copy-and-watch": "^0.1.5", "cross-env": "^7.0.3", diff --git a/packages/base/src/ManagedStyles.ts b/packages/base/src/ManagedStyles.ts index 37312ea007d2..299470ba2a80 100644 --- a/packages/base/src/ManagedStyles.ts +++ b/packages/base/src/ManagedStyles.ts @@ -105,16 +105,18 @@ const updateStyle = (data: StyleData, name: string, value = "", theme?: string) } }; -const hasStyle = (name: string, value = "") => { +const hasStyle = (name: string, value = ""): boolean => { if (shouldUseLinks()) { return !!document.querySelector(`head>link[${name}="${value}"]`); } + const styleElement = document.querySelector(`head>style[${name}="${value}"]`); + if (document.adoptedStyleSheets && !isSafari()) { - return !!document.adoptedStyleSheets.find(sh => (sh as Record)._ui5StyleId === getStyleId(name, value)); + return !!styleElement || !!document.adoptedStyleSheets.find(sh => (sh as Record)._ui5StyleId === getStyleId(name, value)); } - return !!document.querySelector(`head>style[${name}="${value}"]`); + return !!styleElement; }; const removeStyle = (name: string, value = "") => { diff --git a/packages/base/src/features/OpenUI5Support.ts b/packages/base/src/features/OpenUI5Support.ts index 7e6d59c4e747..b634d78017ce 100644 --- a/packages/base/src/features/OpenUI5Support.ts +++ b/packages/base/src/features/OpenUI5Support.ts @@ -54,6 +54,7 @@ type Theming = { type Formatting = { getCalendarType: () => string, getLegacyDateCalendarCustomizing: () => LegacyDateCalendarCustomizing, + getCustomIslamicCalendarData?: () => LegacyDateCalendarCustomizing, } type CalendarUtils = { @@ -137,7 +138,8 @@ class OpenUI5Support { calendarType: Formatting.getCalendarType(), formatSettings: { firstDayOfWeek: CalendarUtils.getWeekConfigurationValues().firstDayOfWeek, - legacyDateCalendarCustomizing: Formatting.getLegacyDateCalendarCustomizing(), + legacyDateCalendarCustomizing: Formatting.getCustomIslamicCalendarData?.() + ?? Formatting.getLegacyDateCalendarCustomizing?.(), }, }; } diff --git a/packages/create-package/CHANGELOG.md b/packages/create-package/CHANGELOG.md index 2beee3019a1b..9da7efc03271 100644 --- a/packages/create-package/CHANGELOG.md +++ b/packages/create-package/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + +**Note:** Version bump only for package @ui5/create-webcomponents-package + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + +**Note:** Version bump only for package @ui5/create-webcomponents-package + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package @ui5/create-webcomponents-package diff --git a/packages/create-package/package.json b/packages/create-package/package.json index 950cd9da2c44..4cfbcf189f8f 100644 --- a/packages/create-package/package.json +++ b/packages/create-package/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/create-webcomponents-package", - "version": "1.19.0", + "version": "1.20.0-rc.1", "description": "UI5 Web Components: create package", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", diff --git a/packages/fiori/CHANGELOG.md b/packages/fiori/CHANGELOG.md index 1d0562ca2fcc..5981f94b21ff 100644 --- a/packages/fiori/CHANGELOG.md +++ b/packages/fiori/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + + +### Features + +* **ui5-illustrated-message:** titleLevel property added ([#7771](https://github.com/SAP/ui5-webcomponents/issues/7771)) ([2883c58](https://github.com/SAP/ui5-webcomponents/commit/2883c587f367e51e0f08065498b990f86e60e88c)), closes [#7037](https://github.com/SAP/ui5-webcomponents/issues/7037) + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + + +### Features + +* **ui5-illustrated-message:** added new TNT illustrations ([#7773](https://github.com/SAP/ui5-webcomponents/issues/7773)) ([03f28b9](https://github.com/SAP/ui5-webcomponents/commit/03f28b90df0b2a28c0f09f67caaa0a5a1e63c4f3)) +* **ui5-side-navigation:** added href and target properties ([#7682](https://github.com/SAP/ui5-webcomponents/issues/7682)) ([7530f00](https://github.com/SAP/ui5-webcomponents/commit/7530f00b589d0b95dcbee49f6ed980e9d36ba58b)) + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package @ui5/webcomponents-fiori diff --git a/packages/fiori/package.json b/packages/fiori/package.json index 412ab794df89..87d9188ee4be 100644 --- a/packages/fiori/package.json +++ b/packages/fiori/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-fiori", - "version": "1.19.0", + "version": "1.20.0-rc.1", "description": "UI5 Web Components: webcomponents.fiori", "ui5": { "webComponentsPackage": true @@ -41,14 +41,14 @@ "directory": "packages/fiori" }, "dependencies": { - "@ui5/webcomponents": "1.19.0", - "@ui5/webcomponents-base": "1.19.0", - "@ui5/webcomponents-icons": "1.19.0", - "@ui5/webcomponents-theming": "1.19.0", + "@ui5/webcomponents": "1.20.0-rc.1", + "@ui5/webcomponents-base": "1.20.0-rc.1", + "@ui5/webcomponents-icons": "1.20.0-rc.1", + "@ui5/webcomponents-theming": "1.20.0-rc.1", "@zxing/library": "^0.17.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "1.19.0", - "chromedriver": "117.0.3" + "@ui5/webcomponents-tools": "1.20.0-rc.1", + "chromedriver": "119.0.1" } } diff --git a/packages/fiori/src/IllustratedMessage.hbs b/packages/fiori/src/IllustratedMessage.hbs index 7871e6c49f3c..14a36b98b7e7 100644 --- a/packages/fiori/src/IllustratedMessage.hbs +++ b/packages/fiori/src/IllustratedMessage.hbs @@ -6,7 +6,7 @@ {{#if hasFormattedTitle}} {{else}} - {{effectiveTitleText}} + {{effectiveTitleText}} {{/if}} {{/if}} diff --git a/packages/fiori/src/IllustratedMessage.ts b/packages/fiori/src/IllustratedMessage.ts index c4167028d412..30832e3e8691 100644 --- a/packages/fiori/src/IllustratedMessage.ts +++ b/packages/fiori/src/IllustratedMessage.ts @@ -9,6 +9,7 @@ import { getEffectiveAriaLabelText } from "@ui5/webcomponents-base/dist/util/Ari import { getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import type I18nBundle from "@ui5/webcomponents-base/dist/i18nBundle.js"; import Title from "@ui5/webcomponents/dist/Title.js"; +import TitleLevel from "@ui5/webcomponents/dist/types/TitleLevel.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import IllustrationMessageSize from "./types/IllustrationMessageSize.js"; import IllustrationMessageType from "./types/IllustrationMessageType.js"; @@ -153,6 +154,20 @@ class IllustratedMessage extends UI5Element { @property({ defaultValue: "" }) accessibleNameRef!: string; + /** + * Defines the semantic level of the title. + * + * Note: Used for accessibility purposes only. + * + * @type {sap.ui.webc.main.types.TitleLevel} + * @defaultvalue "H2" + * @name sap.ui.webc.fiori.IllustratedMessage.prototype.titleLevel + * @public + * @since 1.20.0 + */ + @property({ type: TitleLevel, defaultValue: TitleLevel.H2 }) + titleLevel!: `${TitleLevel}`; + /** * Illustration breakpoint variant for the Spot size. * diff --git a/packages/fiori/src/ShellBar.ts b/packages/fiori/src/ShellBar.ts index 97bd0defd60a..9c25c5a9b06d 100644 --- a/packages/fiori/src/ShellBar.ts +++ b/packages/fiori/src/ShellBar.ts @@ -139,15 +139,6 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms *
  • product-switch
  • * * - *

    CSS Shadow Parts

    - * - * CSS Shadow Parts allow developers to style elements inside the Shadow DOM. - *
    - * The ui5-shellbar exposes the following CSS Shadow Parts: - *
      - *
    • root - Used to style the outermost wrapper of the ui5-shellbar
    • - *
    - * *

    Keyboard Handling

    * *

    Fast Navigation

    @@ -159,12 +150,10 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms *

    ES6 Module Import

    * import "@ui5/webcomponents-fiori/dist/ShellBar"; * + * @csspart root - Used to style the outermost wrapper of the ui5-shellbar + * * @constructor - * @author SAP SE - * @alias sap.ui.webc.fiori.ShellBar - * @extends sap.ui.webc.base.UI5Element - * @tagname ui5-shellbar - * @appenddocs sap.ui.webc.fiori.ShellBarItem + * @extends UI5Element * @public * @since 0.8.0 */ @@ -189,13 +178,15 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * * Fired, when the notification icon is activated. * - * @event sap.ui.webc.fiori.ShellBar#notifications-click * @allowPreventDefault * @param {HTMLElement} targetRef dom ref of the activated element * @public */ @event("notifications-click", { detail: { + /** + * @public + */ targetRef: { type: HTMLElement }, }, }) @@ -203,12 +194,14 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms /** * Fired, when the profile slot is present. * - * @event sap.ui.webc.fiori.ShellBar#profile-click * @param {HTMLElement} targetRef dom ref of the activated element * @public */ @event("profile-click", { detail: { + /** + * @public + */ targetRef: { type: HTMLElement }, }, }) @@ -217,13 +210,15 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * Fired, when the product switch icon is activated. * Note: You can prevent closing of overflow popover by calling event.preventDefault(). * - * @event sap.ui.webc.fiori.ShellBar#product-switch-click * @allowPreventDefault * @param {HTMLElement} targetRef dom ref of the activated element * @public */ @event("product-switch-click", { detail: { + /** + * @public + */ targetRef: { type: HTMLElement }, }, }) @@ -231,13 +226,15 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms /** * Fired, when the logo is activated. * - * @event sap.ui.webc.fiori.ShellBar#logo-click * @param {HTMLElement} targetRef dom ref of the activated element * @since 0.10 * @public */ @event("logo-click", { detail: { + /** + * @public + */ targetRef: { type: HTMLElement }, }, }) @@ -245,13 +242,15 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms /** * Fired, when the co pilot is activated. * - * @event sap.ui.webc.fiori.ShellBar#co-pilot-click * @param {HTMLElement} targetRef dom ref of the activated element * @since 0.10 * @public */ @event("co-pilot-click", { detail: { + /** + * @public + */ targetRef: { type: HTMLElement }, }, }) @@ -260,13 +259,15 @@ const HANDLE_RESIZE_DEBOUNCE_RATE = 200; // ms * Fired, when a menu item is activated * Note: You can prevent closing of overflow popover by calling event.preventDefault(). * - * @event sap.ui.webc.fiori.ShellBar#menu-item-click * @param {HTMLElement} item DOM ref of the activated list item * @since 0.10 * @public */ @event("menu-item-click", { detail: { + /** + * @public + */ item: { type: HTMLElement }, }, }) @@ -276,9 +277,7 @@ class ShellBar extends UI5Element { * Defines the primaryTitle. *

    * Note: The primaryTitle would be hidden on S screen size (less than approx. 700px). - * @type {string} - * @defaultvalue "" - * @name sap.ui.webc.fiori.ShellBar.prototype.primaryTitle + * @default "" * @public */ @property() @@ -288,9 +287,7 @@ class ShellBar extends UI5Element { * Defines the secondaryTitle. *

    * Note: The secondaryTitle would be hidden on S and M screen sizes (less than approx. 1300px). - * @type {string} - * @defaultvalue "" - * @name sap.ui.webc.fiori.ShellBar.prototype.secondaryTitle + * @default "" * @public */ @property() @@ -299,9 +296,7 @@ class ShellBar extends UI5Element { /** * Defines the notificationsCount, * displayed in the notification icon top-right corner. - * @type {string} - * @defaultvalue "" - * @name sap.ui.webc.fiori.ShellBar.prototype.notificationsCount + * @default "" * @public */ @property() @@ -309,9 +304,7 @@ class ShellBar extends UI5Element { /** * Defines, if the notification icon would be displayed. - * @type {boolean} - * @defaultvalue false - * @name sap.ui.webc.fiori.ShellBar.prototype.showNotifications + * @default false * @public */ @property({ type: Boolean }) @@ -319,9 +312,7 @@ class ShellBar extends UI5Element { /** * Defines, if the product switch icon would be displayed. - * @type {boolean} - * @defaultvalue false - * @name sap.ui.webc.fiori.ShellBar.prototype.showProductSwitch + * @default false * @public */ @property({ type: Boolean }) @@ -331,9 +322,7 @@ class ShellBar extends UI5Element { * Defines, if the product CoPilot icon would be displayed. *
    Note: By default the co-pilot is displayed as static SVG. * If you need an animated co-pilot, you can import the "@ui5/webcomponents-fiori/dist/features/CoPilotAnimation.js" module as add-on feature. - * @type {boolean} - * @defaultvalue false - * @name sap.ui.webc.fiori.ShellBar.prototype.showCoPilot + * @default false * @public */ @property({ type: Boolean }) @@ -342,9 +331,7 @@ class ShellBar extends UI5Element { /** * Defines, if the Search Field would be displayed when there is a valid searchField slot. *
    Note: By default the Search Field is not displayed. - * @type {boolean} - * @defaultvalue false - * @name sap.ui.webc.fiori.ShellBar.prototype.showSearchField + * @default false * @public */ @property({ type: Boolean }) @@ -355,9 +342,7 @@ class ShellBar extends UI5Element { * * It supports the following fields: * - logoRole: the accessibility role for the logo - * - * @type {object} - * @name sap.ui.webc.fiori.ShellBar.prototype.accessibilityRoles + * @default {} * @public * @since 1.6.0 */ @@ -372,8 +357,7 @@ class ShellBar extends UI5Element { * - profileButtonTitle: defines the tooltip for the profile button * - logoTitle: defines the tooltip for the logo * - * @type {object} - * @name sap.ui.webc.fiori.ShellBar.prototype.accessibilityTexts + * @default {} * @public * @since 1.1.0 */ @@ -403,8 +387,7 @@ class ShellBar extends UI5Element { * * * - * @type {object} - * @name sap.ui.webc.fiori.ShellBar.prototype.accessibilityAttributes + * @default {} * @public * @since 1.10.0 */ @@ -450,9 +433,6 @@ class ShellBar extends UI5Element { * Note: * You can use the  <ui5-shellbar-item></ui5-shellbar-item>. * - * @type {sap.ui.webc.fiori.IShellBarItem[]} - * @name sap.ui.webc.fiori.ShellBar.prototype.default - * @slot items * @public */ @slot({ type: HTMLElement, "default": true, invalidateOnChildChange: true }) @@ -464,9 +444,6 @@ class ShellBar extends UI5Element { * * Note: We recommend not using the size attribute of ui5-avatar because * it should have specific size by design in the context of ui5-shellbar profile. - * @type {sap.ui.webc.main.IAvatar} - * @name sap.ui.webc.fiori.ShellBar.prototype.profile - * @slot profile * @since 1.0.0-rc.6 * @public */ @@ -476,9 +453,6 @@ class ShellBar extends UI5Element { /** * Defines the logo of the ui5-shellbar. * For example, you can use ui5-avatar or img elements as logo. - * @type {sap.ui.webc.main.IAvatar} - * @name sap.ui.webc.fiori.ShellBar.prototype.logo - * @slot * @since 1.0.0-rc.8 * @public */ @@ -491,9 +465,6 @@ class ShellBar extends UI5Element { * Note: * You can use the  <ui5-li></ui5-li> and its ancestors. * - * @type {sap.ui.webc.main.IListItem[]} - * @name sap.ui.webc.fiori.ShellBar.prototype.menuItems - * @slot * @since 0.10 * @public */ @@ -503,9 +474,6 @@ class ShellBar extends UI5Element { /** * Defines the ui5-input, that will be used as a search field. * - * @type {sap.ui.webc.main.IInput} - * @name sap.ui.webc.fiori.ShellBar.prototype.searchField - * @slot * @public */ @slot() @@ -516,9 +484,6 @@ class ShellBar extends UI5Element { * We encourage this slot to be used for a back or home button. * It gets overstyled to match ShellBar's styling. * - * @type {sap.ui.webc.main.IButton} - * @name sap.ui.webc.fiori.ShellBar.prototype.startButton - * @slot * @public */ @slot() @@ -706,10 +671,8 @@ class ShellBar extends UI5Element { * Closes the overflow area. * Useful to manually close the overflow after having suppressed automatic closing with preventDefault() of ShellbarItem's press event * @public - * @method - * @name sap.ui.webc.fiori.ShellBar#closeOverflow */ - closeOverflow() { + closeOverflow(): void { if (this.overflowPopover) { this.overflowPopover.close(); } @@ -907,79 +870,61 @@ class ShellBar extends UI5Element { /** * Returns the logo DOM ref. - * @type {HTMLElement} - * @name sap.ui.webc.fiori.ShellBar.prototype.logoDomRef * @public - * @readonly * @since 1.0.0-rc.16 */ - get logoDomRef() { - return this.shadowRoot!.querySelector + + + + + + +
    diff --git a/packages/main/test/specs/ComboBox.spec.js b/packages/main/test/specs/ComboBox.spec.js index 13cbd8a25b6d..286eac952d18 100644 --- a/packages/main/test/specs/ComboBox.spec.js +++ b/packages/main/test/specs/ComboBox.spec.js @@ -180,6 +180,10 @@ describe("General interaction", () => { // act await arrow.click(); + + assert.ok(await popover.getProperty("opened"), "Popover should be displayed") + + listItems = await popover.$("ui5-list").$$("ui5-li"); await listItems[0].click(); // assert diff --git a/packages/main/test/specs/DayPicker.spec.js b/packages/main/test/specs/DayPicker.spec.js index d77e7513826f..91ed16148656 100644 --- a/packages/main/test/specs/DayPicker.spec.js +++ b/packages/main/test/specs/DayPicker.spec.js @@ -45,4 +45,20 @@ describe("Day Picker Tests", () => { assert.strictEqual(selectedDate, new Date(Date.now() + 24 * 3600 * 1000).getDate(), "Dates are equal"); }); + + it("Day names are correctly displayed when length is less than 3", async () => { + const dayPickerFirstDayName = await browser.$(`#${daypicker._sut}`).shadow$(".ui5-dp-firstday"); + const dayPickerFirstDayNameText = await dayPickerFirstDayName.getProperty("textContent"); + + assert.strictEqual(dayPickerFirstDayNameText, "Sun", "Name is rendered correctly"); + }); + + it("Day names are correctly displayed when length is more than 3", async () => { + browser.url(`test/pages/DayPicker.html?sap-ui-language=pt_PT`); + + const dayPickerFirstDayName = await browser.$(`#${daypicker._sut}`).shadow$(".ui5-dp-firstday"); + const dayPickerFirstDayNameText = await dayPickerFirstDayName.getProperty("textContent"); + + assert.strictEqual(dayPickerFirstDayNameText, "D", "Name is rendered correctly"); + }); }); diff --git a/packages/main/test/specs/List.spec.js b/packages/main/test/specs/List.spec.js index e790dc1d2bcf..ae40832a45af 100644 --- a/packages/main/test/specs/List.spec.js +++ b/packages/main/test/specs/List.spec.js @@ -576,4 +576,17 @@ describe("List Tests", () => { assert.strictEqual(await itemCloseResult.getProperty("value"), "0", "item-close event is not fired when the button is pressed."); }); + + it("List item fires _request-tabindex-change event and updates tabindex when inner element receives focus", async () => { + const innerElement = await browser.$("#effectiveTabindexChange #country11 button"); + const listItem = await browser.$("#effectiveTabindexChange #country11"); + const rootItemElement = await listItem.shadow$(".ui5-li-root"); + + // Focus on the target list item + await innerElement.click(); + + const newTabIndex = await rootItemElement.getAttribute("tabindex"); + + assert.equal(newTabIndex , "0", "The tabIndex of the list item root should be '0' when inner element receives focus."); + }); }); diff --git a/packages/main/test/specs/Menu.spec.js b/packages/main/test/specs/Menu.spec.js index 3dcd37530564..69d255036728 100644 --- a/packages/main/test/specs/Menu.spec.js +++ b/packages/main/test/specs/Menu.spec.js @@ -52,18 +52,30 @@ describe("Menu interaction", () => { openButton.click(); const staticAreaItemClassName = await browser.getStaticAreaItemClassName("#menu"); - const popover = await browser.$(`.${staticAreaItemClassName}`).shadow$("ui5-responsive-popover"); + const staticAreaItem = await browser.$(`.${staticAreaItemClassName}`); + const popover = staticAreaItem.shadow$("ui5-responsive-popover"); const listItems = await popover.$("ui5-list").$$("ui5-li"); + const submenuList = await staticAreaItem.shadow$(".ui5-menu-submenus"); listItems[3].click(); // open sub-menu - assert.ok(await browser.$(`.${staticAreaItemClassName}`).shadow$(".ui5-menu-submenus").$("ui5-menu"), - "The second level sub-menu is being created"); // new ui5-menu element is created for the sub-menu + await submenuList.$("ui5-menu").waitForExist({ + timeout: 1000, + timeoutMsg: "The second level sub-menu is should be created" + }) + + assert.ok(await submenuList.$("ui5-menu"), "The second level sub-menu is being created"); // new ui5-menu element is created for the sub-menu await browser.keys("ArrowLeft"); // back to main menu await browser.keys("ArrowDown"); // go to the next menu item (close sub-menu) - assert.strictEqual(await browser.$(`.${staticAreaItemClassName}`).shadow$(".ui5-menu-submenus").$$("ui5-menu").length, 0, + await submenuList.$("ui5-menu").waitForExist({ + reverse: true, + timeout: 1000, + timeoutMsg: "The second level sub-menu is should be destroyed" + }) + + assert.strictEqual(await submenuList.$$("ui5-menu").length, 0, "The second level sub-menu is being destroyed"); // sub-menu ui5-menu element is destroyed }); diff --git a/packages/playground/.storybook/args/enhanceArgTypes.ts b/packages/playground/.storybook/args/enhanceArgTypes.ts index 7426fb784800..8da8f412dfb8 100644 --- a/packages/playground/.storybook/args/enhanceArgTypes.ts +++ b/packages/playground/.storybook/args/enhanceArgTypes.ts @@ -25,6 +25,14 @@ export const enhanceArgTypes = ( ) as typeof userArgTypes) : userArgTypes; + Object.keys(withExtractedTypes) + .filter(key => key.startsWith("_ui5")) + .forEach(argType => { + withExtractedTypes[argType].name = withExtractedTypes[argType].name.replace("_ui5", ""); + + withExtractedTypes[argType].control = "text" + }) + // enhance descriptions enhanceArgTypesDescriptions(withExtractedTypes); return withExtractedTypes; diff --git a/packages/playground/.storybook/args/enhancers/description/event/EventDescriptionRenderer.tsx b/packages/playground/.storybook/args/enhancers/description/event/EventDescriptionRenderer.tsx index 302e4e3e94f5..4ab4bcbf8521 100644 --- a/packages/playground/.storybook/args/enhancers/description/event/EventDescriptionRenderer.tsx +++ b/packages/playground/.storybook/args/enhancers/description/event/EventDescriptionRenderer.tsx @@ -7,7 +7,7 @@ export class EventDescriptionRenderer implements IDescriptionRenderer { {p.name}
      -
    • type: {p.type}
    • +
    • type: {p.type.text}
    • description: {p.description}
    diff --git a/packages/playground/.storybook/args/enhancers/description/method/MethodDescriptionRenderer.tsx b/packages/playground/.storybook/args/enhancers/description/method/MethodDescriptionRenderer.tsx index 56c65efeee65..1a9b50c7a1fb 100644 --- a/packages/playground/.storybook/args/enhancers/description/method/MethodDescriptionRenderer.tsx +++ b/packages/playground/.storybook/args/enhancers/description/method/MethodDescriptionRenderer.tsx @@ -8,7 +8,7 @@ export class MethodDescriptionRenderer implements IDescriptionRenderer { {p.name}
      -
    • type: {p.type}
    • +
    • type: {p.type.text}
    • description: {p.description}
    @@ -31,7 +31,7 @@ export class MethodDescriptionRenderer implements IDescriptionRenderer { <>

    Return Value:

      -
    • type: {returnValue?.type}
    • +
    • type: {returnValue?.type?.text}
    • description: {returnValue?.description}
    diff --git a/packages/playground/.storybook/args/types.ts b/packages/playground/.storybook/args/types.ts index 099202cbd080..dbdd3e628fa6 100644 --- a/packages/playground/.storybook/args/types.ts +++ b/packages/playground/.storybook/args/types.ts @@ -8,13 +8,17 @@ export interface IArgTypeEnhancer { } export type ReturnValue = { - type: string; + type: { + text: string, + }; description: string; }; export type Parameter = { name: string; - type: string; + type: { + text: string + }; description: string; }; diff --git a/packages/playground/.storybook/sbTheme.ts b/packages/playground/.storybook/sbTheme.ts index 3dcfa3cb99b5..dec5ceddbaea 100644 --- a/packages/playground/.storybook/sbTheme.ts +++ b/packages/playground/.storybook/sbTheme.ts @@ -4,6 +4,6 @@ export default create({ base: "light", brandTitle: "UI5 Web Components", brandImage: `../assets/images/sb-logo.png`, - brandUrl: './', + brandUrl: '../', brandTarget: "_self", }); diff --git a/packages/playground/CHANGELOG.md b/packages/playground/CHANGELOG.md index 43abb2777734..8d3211c29c70 100644 --- a/packages/playground/CHANGELOG.md +++ b/packages/playground/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + + +### Features + +* **ui5-illustrated-message:** titleLevel property added ([#7771](https://github.com/SAP/ui5-webcomponents/issues/7771)) ([2883c58](https://github.com/SAP/ui5-webcomponents/commit/2883c587f367e51e0f08065498b990f86e60e88c)), closes [#7037](https://github.com/SAP/ui5-webcomponents/issues/7037) + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + +**Note:** Version bump only for package @ui5/webcomponents-playground + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package @ui5/webcomponents-playground diff --git a/packages/playground/_stories/fiori/IllustratedMessage/IllustratedMessage.stories.ts b/packages/playground/_stories/fiori/IllustratedMessage/IllustratedMessage.stories.ts index a96f1c22bd53..628055d79ca6 100644 --- a/packages/playground/_stories/fiori/IllustratedMessage/IllustratedMessage.stories.ts +++ b/packages/playground/_stories/fiori/IllustratedMessage/IllustratedMessage.stories.ts @@ -33,8 +33,9 @@ const Template: UI5StoryArgs = ( subtitle-text="${ifDefined(args.subtitleText)}" title-text="${ifDefined(args.titleText)}" accessible-name-ref="${ifDefined(args.accessibleNameRef)}" + title-level="${ifDefined(args.titleLevel)}" > - ${unsafeHTML(args.title)} + ${unsafeHTML(args.title)} ${unsafeHTML(args.subtitle)} ${unsafeHTML(args.default)} `; diff --git a/packages/playground/build-scripts-storybook/parse-manifest.js b/packages/playground/build-scripts-storybook/parse-manifest.js index 6b114a134a5d..9e35df3a8aea 100644 --- a/packages/playground/build-scripts-storybook/parse-manifest.js +++ b/packages/playground/build-scripts-storybook/parse-manifest.js @@ -28,26 +28,33 @@ const EXCLUDE_LIST = [ ]; const loadManifest = () => { - try { - const customElementsMain = require("@ui5/webcomponents/custom-elements.json"); - const customElementsFiori = require("@ui5/webcomponents-fiori/custom-elements.json"); + let customElementsMain = {}; + let customElementsFiori = {}; + let customElementsBase = {}; - return { - customElementsMain, - customElementsFiori, - }; + try { + customElementsMain = require("@ui5/webcomponents/custom-elements.json"); } catch (error) { - console.log("Error while loading manifests. Did you run 'yarn build'?"); + console.error("Did you run `yarn build` for packages/main?") + } - if (process.env.NODE_ENV !== "production") { - return { - customElementsMain: {}, - customElementsFiori: {}, - }; - } + try { + customElementsFiori = require("@ui5/webcomponents-fiori/custom-elements.json"); + } catch (error) { + console.error("Did you run `yarn build` for packages/main?") + } - throw error; + try { + customElementsBase = require("@ui5/webcomponents-base/custom-elements.json"); + } catch (error) { + console.error("Did you run `yarn build` for packages/main?") } + + return { + customElementsMain, + customElementsFiori, + customElementsBase, + }; }; const parseMembers = (members) => { @@ -56,10 +63,6 @@ const parseMembers = (members) => { if (EXCLUDE_LIST.indexOf(member.name) > -1) { return; } - if (member.kind === "method") { - // change kind to property as Storybook does not show methods from the custom-elements.json - member.kind = "field"; - } parsed.push(member); }); return parsed; @@ -76,6 +79,15 @@ const parseModule = (module) => { if (declaration.members) { declaration.members = parseMembers(declaration.members); } + // Storybook remove slots/css parts/properties/events with duplicate names so we add suffix to css parts in order to avoid duplicates. + // It can't happen to slots and properties since you can't have duplicate accessors. + if (declaration.cssParts) { + declaration.cssParts.forEach(part => { + if (!part.name.startsWith("_ui5") ) { + part.name = `_ui5${part.name}`; + } + }); + } return declaration; }); @@ -98,7 +110,7 @@ const flattenAPIsHierarchicalStructure = module => { const declarations = module.declarations; declarations.forEach(declaration => { - let superclassDeclaration = processedDeclarations.get(declaration.superclass.name); + let superclassDeclaration = processedDeclarations.get(declaration.superclass?.name); if (!superclassDeclaration) { superclassDeclaration = customElements.modules.find(_m => _m.declarations.find(_d => _d.name === declaration.superclass?.name )); @@ -109,7 +121,7 @@ const flattenAPIsHierarchicalStructure = module => { } if (superclassDeclaration) { - processedDeclarations.set(declaration.name, mergeClassMembers(declaration, processedDeclarations.get(declaration.superclass.name))); + processedDeclarations.set(declaration.name, mergeClassMembers(declaration, processedDeclarations.get(declaration.superclass?.name))); } else { processedDeclarations.set(declaration.name, declaration); } @@ -117,7 +129,7 @@ const flattenAPIsHierarchicalStructure = module => { } const mergeClassMembers = (declaration, superclassDeclaration) => { - const props = ["members", "slots", "events"]; + const props = ["members", "slots", "events", "cssParts"]; props.forEach(prop => { if (declaration[prop]?.length) { @@ -139,11 +151,11 @@ const mergeArraysWithoutDuplicates = (currentValues, newValue) => { } -const { customElementsMain, customElementsFiori } = loadManifest(); -const customElements = mergeManifests(customElementsMain, customElementsFiori ); +const { customElementsMain, customElementsFiori, customElementsBase } = loadManifest(); +let customElements = mergeManifests(mergeManifests(customElementsMain, customElementsFiori), customElementsBase ); const processedDeclarations = new Map(); -customElements.modules.forEach(flattenAPIsHierarchicalStructure) +customElements.modules?.forEach(flattenAPIsHierarchicalStructure); fs.writeFileSync( path.join(__dirname, "../.storybook/custom-elements.json"), diff --git a/packages/playground/build-scripts-storybook/samples-prepare.js b/packages/playground/build-scripts-storybook/samples-prepare.js deleted file mode 100644 index 48f605ecacaa..000000000000 --- a/packages/playground/build-scripts-storybook/samples-prepare.js +++ /dev/null @@ -1,142 +0,0 @@ -const fs = require('fs/promises'); -const path = require('path'); - -const STORIES_ROOT_FOLDER_NAME = '../_stories'; - -// run the script to generate the argTypes for the stories available in the _stories folder -const main = async () => { - - const baseAPI = JSON.parse((await fs.readFile(`../base/dist/api.json`)).toString()); - - // read all directories inside _stories folder and create a list of components - const packages = await fs.readdir(path.join(__dirname, STORIES_ROOT_FOLDER_NAME)); - for (const package of packages) { - // packages [main, fiori] - const api = JSON.parse((await fs.readFile(`../${package}/dist/api.json`)).toString()); - - const packagePath = path.join(__dirname, STORIES_ROOT_FOLDER_NAME, package); - const packageStats = await fs.stat(packagePath); - if (packageStats.isDirectory()) { - const componentsInPackage = await fs.readdir(packagePath); - for (const component of componentsInPackage) { - // components [Button, Card, ...] - const componentPath = path.join(packagePath, component); - const componentStats = await fs.stat(componentPath); - if (componentStats.isDirectory()) { - generateStoryDoc(componentPath, component, api, package); - } - } - } - } - - async function generateStoryDoc(componentPath, component, api, package) { - console.log(`Generating argTypes for story ${component}`); - const apiData = getAPIData(api, component, package); - const { storyArgsTypes, slotNames, info } = apiData; - - await fs.writeFile(componentPath + '/argTypes.ts', `export default ${storyArgsTypes}; -export const componentInfo = ${JSON.stringify(info, null, 4)}; -export type StoryArgsSlots = { - ${slotNames.map(slotName => `${slotName}: string;`).join('\n ')} -}`); - }; - - function getAPIData(api, module, package) { - const moduleAPI = api.symbols.find(s => s.module === module); - const data = getArgsTypes(api, moduleAPI); - - return { - info: { - package: `@ui5/webcomponents${package !== 'main' ? `-${package}` : ''}`, - since: moduleAPI.since - }, - slotNames: data.slotNames, - storyArgsTypes: JSON.stringify(data.args, null, "\t") - }; - } - - function getArgsTypes(api, moduleAPI) { - let args = {}; - let slotNames = []; - - moduleAPI?.properties?.forEach(prop => { - if (prop.visibility === 'public') { - const typeEnum = api.symbols.find(s => s.name === prop.type) || baseAPI.symbols.find(s => s.name === prop.type); - if (prop.readonly) { - args[prop.name] = { - control: { - type: false - }, - }; - } else if (Array.isArray(typeEnum?.properties)) { - args[prop.name] = { - control: "select", - options: typeEnum.properties.map(a => a.type), - }; - } - } - }); - - moduleAPI?.slots?.forEach(prop => { - if (prop.visibility === 'public') { - args[prop.name] = { - control: { - type: "text" - } - }; - slotNames.push(prop.name); - } - }); - - // methods parsing because Storybook does not include them in the args by default from the custom-elements.json - // only changing the category to Methods so they are not displayed in the Properties tab - moduleAPI?.methods?.forEach((prop) => { - if (prop.visibility === "public") { - args[prop.name] = { - description: prop.description, - table: { - category: "methods", - }, - }; - - // methods can have custom descriptions with parameters and return value - if (prop.parameters || prop.returnValue) { - args[prop.name].UI5CustomData = { - parameters: prop.parameters, - returnValue: prop.returnValue, - } - } - } - }); - - // events also have custom descriptions with parameters of their detail object - moduleAPI?.events?.forEach((prop) => { - if (prop.visibility === "public" && prop.parameters) { - args[prop.name] = { - description: prop.description, - table: { - category: "events", - }, - UI5CustomData: { - parameters: prop.parameters, - }, - }; - } - }); - - // recursively merging the args from the parent/parents - const moduleAPIBeingExtended = api.symbols.find(s => s.name === moduleAPI.extends) || baseAPI.symbols.find(s => s.module === moduleAPI.extends); - if (moduleAPIBeingExtended) { - const { args: nextArgs, slotNames: nextSlotNames } = getArgsTypes(api, moduleAPIBeingExtended); - args = { ...args, ...nextArgs }; - slotNames = [...slotNames, ...nextSlotNames].filter((v, i, a) => a.indexOf(v) === i); - } - - return { - args, - slotNames - }; - } -}; - -main(); diff --git a/packages/playground/build-scripts-storybook/samples-prepare.ts b/packages/playground/build-scripts-storybook/samples-prepare.ts new file mode 100644 index 000000000000..47ead0ffa790 --- /dev/null +++ b/packages/playground/build-scripts-storybook/samples-prepare.ts @@ -0,0 +1,240 @@ +import fs from "fs/promises"; +import path from "path"; +import type { + ClassDeclaration, + CustomElementDeclaration, + MySchema, + Parameter, + Type, + ClassField, + ClassMethod, + EnumDeclaration, + InterfaceDeclaration, + FunctionDeclaration, + CustomElementMixinDeclaration, + MixinDeclaration, + VariableDeclaration +} from "@ui5/webcomponents-tools/lib/cem/types.js"; + +const STORIES_ROOT_FOLDER_NAME = '../_stories'; + +const isCustomElementDeclaration = (object: any): object is CustomElementDeclaration => { + return "customElement" in object && object.customElement; +}; + +type Declaration = CustomElementDeclaration | EnumDeclaration | ClassDeclaration | InterfaceDeclaration | FunctionDeclaration | MixinDeclaration | VariableDeclaration | CustomElementMixinDeclaration + +type ControlType = "text" | "select" | "multi-select" | boolean; + +type ArgsTypes = Record>; + name?: string; + options?: string[]; + table?: { + category?: string; + defaultValue?: { summary: string; detail?: string }; + subcategory?: string; + type?: { summary?: string; detail?: string }; + }; + UI5CustomData?: { + parameters?: Array; + returnValue?: { + description?: string; + summary?: string; + type?: Type; + }; + }; +}>; + +type APIData = { + info: { + package: string; + since: string | undefined; + }; + slotNames: Array; + storyArgsTypes: string; +}; + +// run the script to generate the argTypes for the stories available in the _stories folder +const main = async () => { + const api: MySchema = JSON.parse((await fs.readFile(`./.storybook/custom-elements.json`)).toString()); + + // read all directories inside _stories folder and create a list of components + const packages = await fs.readdir(path.join(__dirname, STORIES_ROOT_FOLDER_NAME)); + for (const currPackage of packages) { + // packages [main, fiori] + const packagePath = path.join(__dirname, STORIES_ROOT_FOLDER_NAME, currPackage); + const packageStats = await fs.stat(packagePath); + if (packageStats.isDirectory()) { + const componentsInPackage = await fs.readdir(packagePath); + for (const component of componentsInPackage) { + // components [Button, Card, ...] + const componentPath = path.join(packagePath, component); + const componentStats = await fs.stat(componentPath); + if (componentStats.isDirectory()) { + generateStoryDoc(componentPath, component, api, currPackage); + } + } + } + } +}; + +const generateStoryDoc = async (componentPath: string, component: string, api: MySchema, componentPackage: string) => { + console.log(`Generating argTypes for story ${component}`); + const apiData = getAPIData(api, component, componentPackage); + + if (!apiData) { + return; + } + + const { storyArgsTypes, slotNames, info } = apiData; + + await fs.writeFile(componentPath + '/argTypes.ts', `export default ${storyArgsTypes}; +export const componentInfo = ${JSON.stringify(info, null, 4)}; +export type StoryArgsSlots = { + ${slotNames.map(slotName => `${slotName}: string;`).join('\n ')} +}`); +}; + +const getAPIData = (api: MySchema, module: string, componentPackage: string): APIData | undefined => { + const moduleAPI = api.modules?.find(currModule => currModule.declarations?.find(s => s._ui5reference?.name === module && s._ui5reference?.package === `@ui5/webcomponents${componentPackage !== 'main' ? `-${componentPackage}` : ''}`)); + const declaration = moduleAPI?.declarations?.find(s => s._ui5reference?.name === module && s._ui5reference?.package === `@ui5/webcomponents${componentPackage !== 'main' ? `-${componentPackage}` : ''}`); + + if (!declaration) { + return; + } + + const data = getArgsTypes(api, declaration as CustomElementDeclaration); + + return { + info: { + package: `@ui5/webcomponents${componentPackage !== 'main' ? `-${componentPackage}` : ''}`, + since: declaration?._ui5since + }, + slotNames: data.slotNames, + storyArgsTypes: JSON.stringify(data.args, null, "\t") + }; +}; + +const getArgsTypes = (api: MySchema, moduleAPI: CustomElementDeclaration | ClassDeclaration) => { + let args: ArgsTypes = {}; + let slotNames: string[] = []; + + moduleAPI.members + ?.filter((member): member is ClassField => "kind" in member && member.kind === "field") + .forEach(prop => { + let typeEnum: EnumDeclaration | undefined; + + if (prop.type?.references?.length) { + for (const currModule of api.modules) { + if (!currModule.declarations) { + continue; + } + + for (const s of currModule.declarations) { + if (s?._ui5reference?.name === prop.type?.references[0].name && s._ui5reference?.package === prop.type?.references[0].package && s.kind === "enum") { + typeEnum = s; + break; + } + } + } + } + + if (prop.readonly) { + args[prop.name] = { + control: { + type: false + }, + }; + } else if (typeEnum && Array.isArray(typeEnum.members)) { + args[prop.name] = { + control: "select", + options: typeEnum.members.map(a => a.name), + }; + } + }); + + if (isCustomElementDeclaration(moduleAPI)) { + moduleAPI.slots?.forEach(prop => { + args[prop.name] = { + control: { + type: "text" + } + }; + slotNames.push(prop.name); + }); + } + + moduleAPI.members + ?.filter((member): member is ClassMethod => "kind" in member && member.kind === "method") + .forEach((prop) => { + args[prop.name] = { + description: prop.description, + table: { + category: "methods", + }, + }; + + if (prop.parameters || prop.return) { + args[prop.name].UI5CustomData = { + parameters: prop.parameters, + returnValue: prop.return, + }; + } + + (prop as unknown as ClassField).kind = "field"; + }); + + // events also have custom descriptions with parameters of their detail objec + if (isCustomElementDeclaration(moduleAPI)) { + moduleAPI.events?.forEach((prop) => { + if (prop.privacy === "public" && prop.params?.length) { + args[prop.name] = { + description: prop.description, + table: { + category: "events", + }, + UI5CustomData: { + parameters: prop.params, + }, + }; + } + }); + } + + const packages = ["@ui5/webcomponents", "@ui5/webcomponents-fiori"]; + + // recursively merging the args from the parent/parents + let moduleAPIBeingExtended; + + if (moduleAPI.superclass && api.modules) { + for (const currModule of api.modules) { + if (!currModule.declarations || !moduleAPI.superclass?.name || !moduleAPI.superclass?.package) { + continue; + } + + moduleAPIBeingExtended = findReference(currModule.declarations, moduleAPI.superclass?.name, moduleAPI.superclass.package); + } + } + + const referencePackage = moduleAPIBeingExtended?._ui5reference?.package; + + if (moduleAPIBeingExtended && referencePackage && packages.includes(referencePackage)) { + const { args: nextArgs, slotNames: nextSlotNames } = getArgsTypes(api, moduleAPIBeingExtended as ClassDeclaration); + args = { ...args, ...nextArgs }; + slotNames = [...slotNames, ...nextSlotNames].filter((v, i, a) => a.indexOf(v) === i); + } + + return { + args, + slotNames + }; +}; + +const findReference = (something: Array, componentName: string, componentPackage: string): Declaration | undefined => { + return something.find(s => s._ui5reference?.name === componentName && s._ui5reference?.package === componentPackage) +} + +main(); diff --git a/packages/playground/package.json b/packages/playground/package.json index 4be93e5d7d19..06954d4dbc82 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -1,7 +1,7 @@ { "name": "@ui5/webcomponents-playground", "private": true, - "version": "1.19.0", + "version": "1.20.0-rc.1", "description": "UI5 Web Components Playground", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -51,7 +51,7 @@ "prepare:build:nojekyll": "copy-and-watch \"./.nojekyll\" \"./dist\"", "prepare:build:pages": "npm run clean:pages && vite-node ./build-scripts-storybook/pages-prepare.ts", "prepare:assets": "npm run clean:assets && npm run copy:assets", - "prepare:samples": "node ./build-scripts-storybook/samples-prepare.js", + "prepare:samples": "vite-node ./build-scripts-storybook/samples-prepare.ts", "prepare:manifest": "node ./build-scripts-storybook/parse-manifest.js", "prepare:documentation": "vite-node ./build-scripts-storybook/documentation-prepare.ts", "storybook": "npm-run-all --parallel prepare:* && storybook dev -p 6006", diff --git a/packages/theming/CHANGELOG.md b/packages/theming/CHANGELOG.md index 932394920814..0e4e2a4d0df6 100644 --- a/packages/theming/CHANGELOG.md +++ b/packages/theming/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + +**Note:** Version bump only for package @ui5/webcomponents-theming + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + +**Note:** Version bump only for package @ui5/webcomponents-theming + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package @ui5/webcomponents-theming diff --git a/packages/theming/package.json b/packages/theming/package.json index 93118191883c..ec314c4ead61 100644 --- a/packages/theming/package.json +++ b/packages/theming/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-theming", - "version": "1.19.0", + "version": "1.20.0-rc.1", "description": "UI5 Web Components: webcomponents.theming", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -29,11 +29,11 @@ "directory": "packages/theming" }, "dependencies": { - "@sap-theming/theming-base-content": "11.6.8", - "@ui5/webcomponents-base": "1.19.0" + "@sap-theming/theming-base-content": "11.9.0", + "@ui5/webcomponents-base": "1.20.0-rc.1" }, "devDependencies": { - "@ui5/webcomponents-tools": "1.19.0", + "@ui5/webcomponents-tools": "1.20.0-rc.1", "cssnano": "^6.0.1", "globby": "^13.1.1", "json-beautify": "^1.1.1", diff --git a/packages/tools/CHANGELOG.md b/packages/tools/CHANGELOG.md index cbfe5195ae38..e62ef63ccc5a 100644 --- a/packages/tools/CHANGELOG.md +++ b/packages/tools/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [1.20.0-rc.1](https://github.com/SAP/ui5-webcomponents/compare/v1.20.0-rc.0...v1.20.0-rc.1) (2023-11-16) + + +### Bug Fixes + +* declare webpackChunkName in generated dynamic imports for readable runtime bundle names ([#7835](https://github.com/SAP/ui5-webcomponents/issues/7835)) ([592a10b](https://github.com/SAP/ui5-webcomponents/commit/592a10b25a14da89885874c40c5c7a192b8b4d85)) + + + + + +# [1.20.0-rc.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0...v1.20.0-rc.0) (2023-11-09) + +**Note:** Version bump only for package @ui5/webcomponents-tools + + + + + # [1.19.0](https://github.com/SAP/ui5-webcomponents/compare/v1.19.0-rc.3...v1.19.0) (2023-11-02) **Note:** Version bump only for package @ui5/webcomponents-tools diff --git a/packages/tools/components-package/eslint.js b/packages/tools/components-package/eslint.js index 47c39bcd9cc2..47445d08c7a1 100644 --- a/packages/tools/components-package/eslint.js +++ b/packages/tools/components-package/eslint.js @@ -27,6 +27,7 @@ const overrides = tsMode ? [{ "@typescript-eslint/no-unsafe-call": "off", "@typescript-eslint/no-non-null-assertion": "off", "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-empty-interface": "off", "lines-between-class-members": "off", } }] : []; diff --git a/packages/tools/components-package/nps.js b/packages/tools/components-package/nps.js index 5200860880a3..69588fdc40a5 100644 --- a/packages/tools/components-package/nps.js +++ b/packages/tools/components-package/nps.js @@ -131,6 +131,8 @@ const getScripts = (options) => { }, generateAPI: { default: "nps generateAPI.prepare generateAPI.preprocess generateAPI.jsdoc generateAPI.cleanup generateAPI.prepareManifest", + generateCEM: `cem analyze --config "${LIB}/cem/custom-elements-manifest.config.mjs"`, + validateCEM: `node "${LIB}/cem/validate.js"`, prepare: `node "${LIB}/copy-and-watch/index.js" --silent "dist/**/*.js" jsdoc-dist/`, prepareManifest: `node "${LIB}/generate-custom-elements-manifest/index.js" dist dist`, preprocess: `node "${preprocessJSDocScript}" jsdoc-dist/ src`, diff --git a/packages/tools/lib/cem/custom-elements-manifest.config.mjs b/packages/tools/lib/cem/custom-elements-manifest.config.mjs new file mode 100644 index 000000000000..e27a682eadf6 --- /dev/null +++ b/packages/tools/lib/cem/custom-elements-manifest.config.mjs @@ -0,0 +1,355 @@ +import { parse } from "comment-parser"; +import processEvent from "./event.mjs"; +import { + getDeprecatedStatus, + getSinceStatus, + getPrivacyStatus, + getReference, + validateJSDocComment, + findDecorator, + findAllDecorators, + hasTag, + findTag, + findAllTags, + getJSDocErrors, + getTypeRefs, +} from "./utils.mjs"; + +function processClass(ts, classNode, moduleDoc) { + const className = classNode?.name?.text; + const currClass = moduleDoc?.declarations?.find(declaration => declaration?.name === className); + const currClassJSdoc = classNode?.jsDoc?.[0] || classNode?.jsDoc?.find(jsDoc => jsDoc?.[0]?.getText?.()?.includes("@class")); + + if (!currClassJSdoc) return; + + const customElementDecorator = findDecorator(classNode, "customElement"); + const classParsedJsDoc = parse(currClassJSdoc?.getText())[0]; + + validateJSDocComment("class", classParsedJsDoc, classNode.name?.text, moduleDoc); + + const decoratorArg = customElementDecorator?.expression?.arguments[0]; + currClass.tagName = decoratorArg?.text || (decoratorArg?.properties.find(property => property.name.text === "tag")?.initializer?.text); + currClass.customElement = !!decoratorArg; + currClass.kind = "class"; + currClass.deprecated = getDeprecatedStatus(classParsedJsDoc); + currClass._ui5since = getSinceStatus(classParsedJsDoc); + currClass._ui5privacy = getPrivacyStatus(classParsedJsDoc); + currClass._ui5abstract = hasTag(classParsedJsDoc, "abstract") ? true : undefined; + currClass.description = classParsedJsDoc.description || findTag(classParsedJsDoc, "class")?.description; + currClass._ui5implements = findAllTags(classParsedJsDoc, "implements") + .map(tag => getReference(ts, tag.type, classNode, moduleDoc.path)) + .filter(Boolean); + + + if (hasTag(classParsedJsDoc, "extends")) { + const superclassTag = findTag(classParsedJsDoc, "extends"); + currClass.superclass = getReference(ts, superclassTag.name, classNode, moduleDoc.path); + } + + if (!currClass._ui5implements.length) delete currClass._ui5implements; + + // Slots + + // Slots without accessort (defined in class comment) + if (hasTag(classParsedJsDoc, "slot") && currClass.slots) { + const slotTags = findAllTags(classParsedJsDoc, "slot"); + + currClass.slots.forEach(slot => { + const tag = slotTags.find(tag => tag.name === slot.name); + + const typeRefs = (tag.type + ?.replaceAll(/Array<|>|\[\]/g, "") + ?.split("|") + ?.map(e => getReference(ts, e.trim(), classNode, moduleDoc.path)).filter(Boolean)); + + slot._ui5privacy = "public"; + slot._ui5type = { text: tag.type }; + + if (typeRefs && typeRefs.length) { + slot._ui5type.references = typeRefs; + } + + delete slot.type + }) + } + + // Events + currClass.events = findAllDecorators(classNode, "event") + ?.map(event => processEvent(ts, event, classNode, moduleDoc)); + + // Slots (with accessor), methods and fields + for (let i = 0; i < (currClass.members?.length || 0); i++) { + const member = currClass.members[i]; + const classNodeMember = classNode.members?.find(nodeMember => nodeMember.name?.text === member?.name); + const classNodeMemberJSdoc = classNodeMember?.jsDoc?.[0]; + + if (!classNodeMember || !classNodeMemberJSdoc) continue; + + const memberParsedJsDoc = parse(classNodeMemberJSdoc?.getText())[0]; + + member._ui5since = getSinceStatus(memberParsedJsDoc); + member.deprecated === "true" && (member.deprecated = true) + + // Slots with accessors are treated like fields by the tool, so we have to convert them into slots. + if (member.kind === "field") { + const slotDecorator = findDecorator(classNodeMember, "slot"); + validateJSDocComment(slotDecorator ? "slot" : (member.readonly ? "getter" : "field" ), memberParsedJsDoc, classNodeMember.name?.text, moduleDoc); + + const typeRefs = (getTypeRefs(ts, classNodeMember, member) + ?.map(e => getReference(ts, e, classNodeMember, moduleDoc.path)).filter(Boolean)) || []; + + if (member.type && typeRefs.length) { + member.type.references = typeRefs; + } + + if (slotDecorator) { + if (!currClass.slots) currClass.slots = []; + + const slot = currClass.members.splice(i, 1)[0]; + const defaultProperty = slotDecorator.expression?.arguments?.[0]?.properties?.find(property => property.name.text === "default"); + + // name of the default slot declared with decorator will be overriden so we to provide it's accessor name + if (defaultProperty && defaultProperty.initializer?.kind === ts.SyntaxKind.TrueKeyword) { + slot._ui5propertyName = slot.name; + slot.name = "default"; + } + + // Slots don't have type, privacy and kind, so we have do convert them and to clean unused props + member._ui5type = member.type; + member._ui5privacy = member.privacy; + delete member.type; + delete member.privacy; + delete slot.kind; + + currClass.slots.push(slot); + i--; + } else { + if (hasTag(memberParsedJsDoc, "formProperty")) { + member._ui5formProperty = true; + } + + const formEventsTag = findTag(memberParsedJsDoc, "formEvents"); + if (formEventsTag) { + const tagValue = formEventsTag.description ? `${formEventsTag.name} ${formEventsTag.description}` : formEventsTag.name; + member._ui5formEvents = tagValue.trim().replaceAll(/\s+/g, ","); + } + + const defaultTag = findTag(memberParsedJsDoc, "default"); + if (defaultTag) { + const tagValue = defaultTag.source?.[0]?.tokens?.name || defaultTag.source?.[0]?.tokens?.description || defaultTag.source?.[0]?.tokens?.type || ""; + member.default = tagValue; + } + + if (member.privacy === "public") { + const JSDocErrors = getJSDocErrors(); + if (member.readonly && !member.type) { + JSDocErrors.push( + `=== ERROR: Problem found with ${member.name}'s JSDoc comment in ${moduleDoc.path}: Missing return type` + ); + } + + if (!member.default) { + JSDocErrors.push( + `=== ERROR: Problem found with ${member.name}'s JSDoc comment in ${moduleDoc.path}: Default value is missing` + ); + } + } + + // Getters are treated as fields so they should not have return, instead of return they should have default value defined with @default + if (member.readonly) { + if (member.privacy === "public" && !member.type) { + const JSDocErrors = getJSDocErrors(); + + JSDocErrors.push( + `=== ERROR: Problem found with ${member.name}'s JSDoc comment in ${moduleDoc.path}: Missing return type` + ); + } + + delete member.return; + } + } + } else if (member.kind === "method") { + validateJSDocComment("method", memberParsedJsDoc, classNodeMember.name?.text, moduleDoc); + + member.parameters?.forEach(param => { + // Treat every parameter that has respective @param tag as public + param._ui5privacy = findAllTags(memberParsedJsDoc, "param").some(tag => tag.name === param.name) ? "public" : "private"; + const paramNode = classNodeMember.parameters?.find(parameter => parameter.name?.text === param.name); + + const typeRefs = (getTypeRefs(ts, paramNode, param) + ?.map(typeRef => getReference(ts, typeRef, classNodeMember, moduleDoc.path)).filter(Boolean)) || []; + + if (typeRefs.length) { + param.type.references = typeRefs; + } + }); + + if (member.return) { + const returnTag = findTag(memberParsedJsDoc, "returns"); + member.return.description = returnTag?.description ? `${returnTag.name} ${returnTag.description}` : returnTag?.name; + member.return.type.text = classNodeMember?.type?.getFullText?.()?.trim(); + const typeRefs = (getTypeRefs(ts, classNodeMember, member.return) + ?.map(typeRef => getReference(ts, typeRef, classNodeMember, moduleDoc.path)).filter(Boolean)) || []; + + if (typeRefs.length) { + member.return.type.references = typeRefs; + } + } + + if (member.privacy === "public" && !member.return) { + const JSDocErrors = getJSDocErrors(); + + JSDocErrors.push( + `=== ERROR: Problem found with ${member.name}'s JSDoc comment in ${moduleDoc.path}: Missing return type` + ); + } + } + } +} + +function processInterface(ts, interfaceNode, moduleDoc) { + const interfaceJSdoc = interfaceNode?.jsDoc?.[0]; + const interfaceName = interfaceNode?.name?.text; + + if (!interfaceJSdoc) return; + + const interfaceParsedJsDoc = parse(interfaceJSdoc?.getText())[0]; + + validateJSDocComment("interface", interfaceParsedJsDoc, interfaceNode.name?.text, moduleDoc); + + moduleDoc.declarations.push({ + kind: "interface", + name: interfaceName, + description: interfaceParsedJsDoc?.description, + _ui5privacy: getPrivacyStatus(interfaceParsedJsDoc), + _ui5since: getSinceStatus(interfaceParsedJsDoc), + deprecated: getDeprecatedStatus(interfaceParsedJsDoc), + }); +} + +function processEnum(ts, enumNode, moduleDoc) { + const enumJSdoc = enumNode?.jsDoc?.[0]; + const enumName = enumNode?.name?.text; + + if (!enumJSdoc) return; + + const enumParsedJsDoc = parse(enumJSdoc?.getText())[0]; + + validateJSDocComment("enum", enumParsedJsDoc, enumNode.name?.text, moduleDoc); + + const result = { + kind: "enum", + name: enumName, + description: enumJSdoc?.comment, + _ui5privacy: getPrivacyStatus(enumParsedJsDoc), + _ui5since: getSinceStatus(enumParsedJsDoc), + deprecated: getDeprecatedStatus(enumParsedJsDoc) || undefined, + members: (enumNode?.members || []).map(member => { + const memberJSdoc = member?.jsDoc?.[0]; + + if (!memberJSdoc) return; + + const memberParsedJsDoc = parse(memberJSdoc?.getText())[0]; + + validateJSDocComment("enum", memberParsedJsDoc, member.name?.text, moduleDoc); + + return { + kind: "field", + static: true, + privacy: getPrivacyStatus(memberParsedJsDoc), + _ui5since: getSinceStatus(memberParsedJsDoc), + description: memberJSdoc?.comment, + default: member.initializer?.text, + deprecated: getDeprecatedStatus(memberParsedJsDoc), + name: member.name?.text, + readonly: true, + }; + }).filter(Boolean), + }; + + moduleDoc.declarations.push(result); +} + +const processPublicAPI = object => { + if (!object) { + return true; + } + const keys = Object.keys(object); + if (!keys.includes("privacy") && !keys.includes("_ui5privacy")) { + return true; + } + for (const key of keys) { + if ((key === "privacy" && object[key] !== "public") || (key === "_ui5privacy" && object[key] !== "public")) { + return true; + } else if (typeof object[key] === "object") { + if (key === "cssParts" || key === "_ui5implements") { + continue; + } + + if (Array.isArray(object[key])) { + for (let i = 0; i < object[key].length; i++) { + const shouldRemove = processPublicAPI(object[key][i]); + if (shouldRemove) { + object[key].splice(i, 1); + i--; + } + } + if (object[key].length === 0) { + delete object[key]; + } else { + object[key].sort(function (a, b) { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + } + } + } + } + return false; +}; + +export default { + globs: ["src/!(*generated)/*.ts", "src/*.ts"], + outdir: 'dist', + plugins: [ + { + name: 'my-plugin', + analyzePhase({ ts, node, moduleDoc }) { + switch (node.kind) { + case ts.SyntaxKind.ClassDeclaration: + processClass(ts, node, moduleDoc); + break; + case ts.SyntaxKind.EnumDeclaration: + processEnum(ts, node, moduleDoc); + break; + case ts.SyntaxKind.InterfaceDeclaration: + processInterface(ts, node, moduleDoc); + break; + } + }, + moduleLinkPhase({ moduleDoc }) { + for (let i = 0; i < moduleDoc.declarations.length; i++) { + const shouldRemove = processPublicAPI(moduleDoc.declarations[i]) || ["function", "variable"].includes(moduleDoc.declarations[i].kind) + if (shouldRemove) { + moduleDoc.declarations.splice(i, 1); + i--; + } + } + }, + packageLinkPhase() { + // Uncomment and handle errors appropriately + const JSDocErrors = getJSDocErrors(); + if (JSDocErrors.length > 0) { + console.log(JSDocErrors.join("\n")); + console.log(`Invalid JSDoc. ${JSDocErrors.length} were found.`); + throw new Error(`Invalid JSDoc.`); + } + } + }, + ], +}; diff --git a/packages/tools/lib/cem/event.mjs b/packages/tools/lib/cem/event.mjs new file mode 100644 index 000000000000..1bf7eb2fe1f2 --- /dev/null +++ b/packages/tools/lib/cem/event.mjs @@ -0,0 +1,112 @@ +import { parse } from "comment-parser"; +import { + getPrivacyStatus, + getDeprecatedStatus, + getSinceStatus, + getType, + validateJSDocComment, + hasTag, + findTag, + findAllTags, + getReference +} from "./utils.mjs"; + +const jsDocRegExp = /\/\*\*(.|\n)+?\s+\*\//; + +const getParams = (ts, eventDetails, commentParams, classNode, moduleDoc) => { + return commentParams?.map(commentParam => { + const decoratorParam = eventDetails?.find(prop => prop?.name?.text === commentParam?.name); + + if (!decoratorParam || !decoratorParam?.jsDoc?.[0]) { + return; + } + + const decoratorParamParsedComment = parse(decoratorParam?.jsDoc?.[0]?.getText?.())[0]; + + validateJSDocComment("eventParam", decoratorParamParsedComment, decoratorParam.name?.text, moduleDoc); + + const { typeName, name } = getType(commentParam?.type); + let type; + + if (typeName) { + type = { text: typeName }; + + let typeRefs = name?.split("|") + ?.map(e => getReference(ts, e.trim(), classNode, moduleDoc.path)) + .filter(Boolean); + + if (typeRefs?.length) { + type.references = typeRefs; + } + } + + return { + type, + name: commentParam?.name, + _ui5privacy: getPrivacyStatus(decoratorParamParsedComment), + description: commentParam?.description, + _ui5since: getSinceStatus(decoratorParamParsedComment), + deprecated: getDeprecatedStatus(decoratorParamParsedComment), + }; + }).filter(pair => !!pair); +}; + +function processEvent(ts, event, classNode, moduleDoc) { + const result = { + name: event?.expression?.arguments?.[0]?.text, + _ui5privacy: "private", + type: { text: "CustomEvent" } + }; + + const comment = event.getFullText?.().match(jsDocRegExp)?.[0]; + + if (!comment) { + return result; + } + + const eventParsedComment = parse(comment)[0]; + + validateJSDocComment("event", eventParsedComment, event?.expression?.arguments?.[0]?.text, moduleDoc); + + const deprecatedTag = findTag(eventParsedComment, "deprecated"); + const privacy = findTag(eventParsedComment, ["public", "private", "protected"])?.tag || "private"; + const sinceTag = findTag(eventParsedComment, "since"); + const commentParams = findAllTags(eventParsedComment, "param"); + const allowPreventDefault = hasTag(eventParsedComment, "allowPreventDefault") || undefined; + const description = eventParsedComment?.description; + const native = hasTag(eventParsedComment, "native"); + const eventDetails = event?.expression?.arguments?.[1]?.properties?.find(prop => prop?.name?.text === "detail")?.initializer?.properties; + + result.description = description; + result._ui5allowPreventDefault = allowPreventDefault; + + if (native) { + result.type = { text: "Event" }; + } + + if (privacy) { + result._ui5privacy = privacy; + } + + if (deprecatedTag?.name) { + result.deprecated = deprecatedTag.description + ? `${deprecatedTag.name} ${deprecatedTag.description}` + : deprecatedTag.name; + } else if (deprecatedTag) { + result.deprecated = true; + } + + if (sinceTag?.name) { + result._ui5since = sinceTag?.description + ? `${sinceTag.name} ${sinceTag.description}` + : sinceTag.name; + } + + if (commentParams && eventDetails) { + result._ui5parameters = getParams(ts, eventDetails, commentParams, classNode, moduleDoc); + } + + return result; +} + +export default processEvent; diff --git a/packages/tools/lib/cem/schema-internal.json b/packages/tools/lib/cem/schema-internal.json new file mode 100644 index 000000000000..0acb3b7c932c --- /dev/null +++ b/packages/tools/lib/cem/schema-internal.json @@ -0,0 +1,1352 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "Attribute": { + "properties": { + "default": { + "description": "The default value of the attribute, if any.\n\nAs attributes are always strings, this is the actual value, not a human\nreadable description.", + "type": "string" + }, + "deprecated": { + "description": "Whether the attribute is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "fieldName": { + "description": "The name of the field this attribute is associated with, if any.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "name": { + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The type that the attribute will be serialized/deserialized as." + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "ClassDeclaration": { + "properties": { + "_ui5implements": { + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5since": { + "description": "Marks when the field was", + "type": "string" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "kind": { + "enum": [ + "class" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "EnumDeclaration": { + "properties": { + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "kind": { + "enum": [ + "enum" + ], + "type": "string" + }, + "members": { + "items": { + "$ref": "#/definitions/EnumField" + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "InterfaceDeclaration": { + "properties": { + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "kind": { + "enum": [ + "interface" + ], + "type": "string" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "ClassField": { + "properties": { + "_ui5formProperty": { + "type": "boolean" + }, + "_ui5formEvents": { + "type": "string" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "kind": { + "enum": [ + "field" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "privacy": { + "$ref": "#/definitions/Privacy" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "static": { + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "EnumField": { + "properties": { + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "kind": { + "enum": [ + "field" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "privacy": { + "$ref": "#/definitions/Privacy" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "static": { + "type": "boolean" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "ClassMethod": { + "properties": { + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the function is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "kind": { + "enum": [ + "method" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "privacy": { + "$ref": "#/definitions/Privacy" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "static": { + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "CssCustomProperty": { + "properties": { + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the CSS custom property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "name": { + "description": "The name of the property, including leading `--`.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "syntax": { + "description": "The expected syntax of the defined property. Defaults to \"*\".\n\nThe syntax must be a valid CSS [syntax string](https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax)\nas defined in the CSS Properties and Values API.\n\nExamples:\n\n\"\": accepts a color\n\" | \": accepts lengths or percentages but not calc expressions with a combination of the two\n\"small | medium | large\": accepts one of these values set as custom idents.\n\"*\": any valid token", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CssPart": { + "description": "The description of a CSS Part", + "properties": { + "deprecated": { + "description": "Whether the CSS shadow part is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "name": { + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CustomElementDeclaration": { + "description": "A description of a custom element class.\n\nCustom elements are JavaScript classes, so this extends from\n`ClassDeclaration` and adds custom-element-specific features like\nattributes, events, and slots.\n\nNote that `tagName` in this interface is optional. Tag names are not\nneccessarily part of a custom element class, but belong to the definition\n(often called the \"registration\") or the `customElements.define()` call.\n\nBecause classes and tag names can only be registered once, there's a\none-to-one relationship between classes and tag names. For ease of use,\nwe allow the tag name here.\n\nSome packages define and register custom elements in separate modules. In\nthese cases one `Module` should contain the `CustomElement` without a\ntagName, and another `Module` should contain the\n`CustomElementExport`.", + "properties": { + "_ui5implements": { + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "_ui5abstract": { + "type": "boolean" + }, + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "attributes": { + "description": "The attributes that this element is known to understand.", + "items": { + "$ref": "#/definitions/Attribute" + }, + "type": "array" + }, + "cssParts": { + "items": { + "$ref": "#/definitions/CssPart" + }, + "type": "array" + }, + "cssProperties": { + "items": { + "$ref": "#/definitions/CssCustomProperty" + }, + "type": "array" + }, + "customElement": { + "description": "Distinguishes a regular JavaScript class from a\ncustom element class", + "enum": [ + true + ], + "type": "boolean" + }, + "demos": { + "items": { + "$ref": "#/definitions/Demo" + }, + "type": "array" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "events": { + "description": "The events that this element fires.", + "items": { + "$ref": "#/definitions/Event" + }, + "type": "array" + }, + "kind": { + "enum": [ + "class" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "slots": { + "description": "The shadow dom content slots that this element accepts.", + "items": { + "$ref": "#/definitions/Slot" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + }, + "tagName": { + "description": "An optional tag name that should be specified if this is a\nself-registering element.\n\nSelf-registering elements must also include a CustomElementExport\nin the module's exports.", + "type": "string" + } + }, + "required": [ + "customElement", + "kind", + "name" + ], + "type": "object" + }, + "CustomElementExport": { + "description": "A global custom element defintion, ie the result of a\n`customElements.define()` call.\n\nThis is represented as an export because a definition makes the element\navailable outside of the module it's defined it.", + "properties": { + "declaration": { + "$ref": "#/definitions/Reference", + "description": "A reference to the class or other declaration that implements the\ncustom element." + }, + "deprecated": { + "description": "Whether the custom-element export is deprecated.\nFor example, a future version will not register the custom element in this file.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "kind": { + "enum": [ + "custom-element-definition" + ], + "type": "string" + }, + "name": { + "description": "The tag name of the custom element.", + "type": "string" + } + }, + "required": [ + "declaration", + "kind", + "name" + ], + "type": "object" + }, + "CustomElementMixinDeclaration": { + "description": "A class mixin that also adds custom element related properties.", + "properties": { + "attributes": { + "description": "The attributes that this element is known to understand.", + "items": { + "$ref": "#/definitions/Attribute" + }, + "type": "array" + }, + "cssParts": { + "items": { + "$ref": "#/definitions/CssPart" + }, + "type": "array" + }, + "cssProperties": { + "items": { + "$ref": "#/definitions/CssCustomProperty" + }, + "type": "array" + }, + "customElement": { + "description": "Distinguishes a regular JavaScript class from a\ncustom element class", + "enum": [ + true + ], + "type": "boolean" + }, + "demos": { + "items": { + "$ref": "#/definitions/Demo" + }, + "type": "array" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "events": { + "description": "The events that this element fires.", + "items": { + "$ref": "#/definitions/Event" + }, + "type": "array" + }, + "kind": { + "enum": [ + "mixin" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "slots": { + "description": "The shadow dom content slots that this element accepts.", + "items": { + "$ref": "#/definitions/Slot" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + }, + "tagName": { + "description": "An optional tag name that should be specified if this is a\nself-registering element.\n\nSelf-registering elements must also include a CustomElementExport\nin the module's exports.", + "type": "string" + } + }, + "required": [ + "customElement", + "kind", + "name" + ], + "type": "object" + }, + "Demo": { + "properties": { + "description": { + "description": "A markdown description of the demo.", + "type": "string" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "url": { + "description": "Relative URL of the demo if it's published with the package. Absolute URL\nif it's hosted.", + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + }, + "Event": { + "properties": { + "_ui5parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5allowPreventDefault": { + "description": "Whether the parameter is optional. Undefined implies non-optional.", + "type": "boolean" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the event is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "name": { + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The type of the event object that's fired." + } + }, + "required": [ + "name", + "type" + ], + "type": "object" + }, + "FunctionDeclaration": { + "properties": { + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the function is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "kind": { + "enum": [ + "function" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "JavaScriptExport": { + "properties": { + "declaration": { + "$ref": "#/definitions/Reference", + "description": "A reference to the exported declaration.\n\nIn the case of aggregating exports, the reference's `module` field must be\ndefined and the `name` field must be `\"*\"`." + }, + "deprecated": { + "description": "Whether the export is deprecated. For example, the name of the export was changed.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "kind": { + "enum": [ + "js" + ], + "type": "string" + }, + "name": { + "description": "The name of the exported symbol.\n\nJavaScript has a number of ways to export objects which determine the\ncorrect name to use.\n\n- Default exports must use the name \"default\".\n- Named exports use the name that is exported. If the export is renamed\n with the \"as\" clause, use the exported name.\n- Aggregating exports (`* from`) should use the name `*`", + "type": "string" + } + }, + "required": [ + "declaration", + "kind", + "name" + ], + "type": "object" + }, + "JavaScriptModule": { + "properties": { + "declarations": { + "description": "The declarations of a module.\n\nFor documentation purposes, all declarations that are reachable from\nexports should be described here. Ie, functions and objects that may be\nproperties of exported objects, or passed as arguments to functions.", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassDeclaration" + }, + { + "$ref": "#/definitions/EnumDeclaration" + }, + { + "$ref": "#/definitions/InterfaceDeclaration" + }, + { + "$ref": "#/definitions/FunctionDeclaration" + }, + { + "$ref": "#/definitions/MixinDeclaration" + }, + { + "$ref": "#/definitions/VariableDeclaration" + }, + { + "$ref": "#/definitions/CustomElementDeclaration" + }, + { + "$ref": "#/definitions/CustomElementMixinDeclaration" + } + ] + }, + "type": "array" + }, + "deprecated": { + "description": "Whether the module is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the module.", + "type": "string" + }, + "exports": { + "description": "The exports of a module. This includes JavaScript exports and\ncustom element definitions.", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/JavaScriptExport" + }, + { + "$ref": "#/definitions/CustomElementExport" + } + ] + }, + "type": "array" + }, + "kind": { + "enum": [ + "javascript-module" + ], + "type": "string" + }, + "path": { + "description": "Path to the javascript file needed to be imported. \n(not the path for example to a typescript file.)", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + }, + "MixinDeclaration": { + "description": "A description of a class mixin.\n\nMixins are functions which generate a new subclass of a given superclass.\nThis interfaces describes the class and custom element features that\nare added by the mixin. As such, it extends the CustomElement interface and\nClassLike interface.\n\nSince mixins are functions, it also extends the FunctionLike interface. This\nmeans a mixin is callable, and has parameters and a return type.\n\nThe return type is often hard or impossible to accurately describe in type\nsystems like TypeScript. It requires generics and an `extends` operator\nthat TypeScript lacks. Therefore it's recommended that the return type is\nleft empty. The most common form of a mixin function takes a single\nargument, so consumers of this interface should assume that the return type\nis the single argument subclassed by this declaration.\n\nA mixin should not have a superclass. If a mixins composes other mixins,\nthey should be listed in the `mixins` field.\n\nSee [this article]{@link https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/}\nfor more information on the classmixin pattern in JavaScript.", + "properties": { + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "kind": { + "enum": [ + "mixin" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "Parameter": { + "properties": { + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "description": "Whether the parameter is optional. Undefined implies non-optional.", + "type": "boolean" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "rest": { + "description": "Whether the parameter is a rest parameter. Only the last parameter may be a rest parameter.\nUndefined implies single parameter.", + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "Privacy": { + "enum": [ + "private", + "protected", + "public" + ], + "type": "string" + }, + "Reference": { + "description": "A reference to an export of a module.\n\nAll references are required to be publically accessible, so the canonical\nrepresentation of a reference is the export it's available from.\n\n`package` should generally refer to an npm package name. If `package` is\nundefined then the reference is local to this package. If `module` is\nundefined the reference is local to the containing module.\n\nReferences to global symbols like `Array`, `HTMLElement`, or `Event` should\nuse a `package` name of `\"global:\"`.", + "properties": { + "module": { + "type": "string" + }, + "name": { + "type": "string" + }, + "package": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "Slot": { + "properties": { + "_ui5type": { + "$ref": "#/definitions/Type" + }, + "_ui5privacy": { + "$ref": "#/definitions/Privacy" + }, + "_ui5since": { + "description": "Marks when the field was introduced", + "type": "string" + }, + "deprecated": { + "description": "Whether the slot is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "name": { + "description": "The slot name, or the empty string for an unnamed slot.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SourceReference": { + "description": "A reference to the source of a declaration or member.", + "properties": { + "href": { + "description": "An absolute URL to the source (ie. a GitHub URL).", + "type": "string" + } + }, + "required": [ + "href" + ], + "type": "object" + }, + "Type": { + "properties": { + "references": { + "description": "An array of references to the types in the type string.\n\nThese references have optional indices into the type string so that tools\ncan understand the references in the type string independently of the type\nsystem and syntax. For example, a documentation viewer could display the\ntype `Array` with cross-references to `FooElement`\nand `BarElement` without understanding arrays, generics, or union types.", + "items": { + "$ref": "#/definitions/TypeReference" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "text": { + "description": "The full string representation of the type, in whatever type syntax is\nused, such as JSDoc, Closure, or TypeScript.", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "TypeReference": { + "description": "A reference that is associated with a type string and optionally a range\nwithin the string.\n\nStart and end must both be present or not present. If they're present, they\nare indices into the associated type string. If they are missing, the entire\ntype string is the symbol referenced and the name should match the type\nstring.", + "properties": { + "end": { + "type": "number" + }, + "module": { + "type": "string" + }, + "name": { + "type": "string" + }, + "package": { + "type": "string" + }, + "start": { + "type": "number" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "VariableDeclaration": { + "properties": { + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "kind": { + "enum": [ + "variable" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + } + }, + "description": "The top-level interface of a custom elements manifest file.\n\nBecause custom elements are JavaScript classes, describing a custom element\nmay require describing arbitrary JavaScript concepts like modules, classes,\nfunctions, etc. So custom elements manifests are capable of documenting\nthe elements in a package, as well as those JavaScript concepts.\n\nThe modules described in a package should be the public entrypoints that\nother packages may import from. Multiple modules may export the same object\nvia re-exports, but in most cases a package should document the single\ncanonical export that should be used.", + "properties": { + "deprecated": { + "description": "Whether the package is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "modules": { + "description": "An array of the modules this package contains.", + "items": { + "$ref": "#/definitions/JavaScriptModule" + }, + "type": "array" + }, + "readme": { + "description": "The Markdown to use for the main readme of this package.\n\nThis can be used to override the readme used by Github or npm if that\nfile contains information irrelevant to custom element catalogs and\ndocumentation viewers.", + "type": "string" + }, + "schemaVersion": { + "description": "The version of the schema used in this file.", + "type": "string" + } + }, + "required": [ + "modules", + "schemaVersion" + ], + "type": "object" +} \ No newline at end of file diff --git a/packages/tools/lib/cem/schema.json b/packages/tools/lib/cem/schema.json new file mode 100644 index 000000000000..963c8ce7351d --- /dev/null +++ b/packages/tools/lib/cem/schema.json @@ -0,0 +1,1098 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "Attribute": { + "properties": { + "default": { + "description": "The default value of the attribute, if any.\n\nAs attributes are always strings, this is the actual value, not a human\nreadable description.", + "type": "string" + }, + "deprecated": { + "description": "Whether the attribute is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "fieldName": { + "description": "The name of the field this attribute is associated with, if any.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "name": { + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The type that the attribute will be serialized/deserialized as." + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "ClassDeclaration": { + "properties": { + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "kind": { + "enum": [ + "class" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "ClassField": { + "properties": { + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "kind": { + "enum": [ + "field" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "privacy": { + "$ref": "#/definitions/Privacy" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "static": { + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "ClassMethod": { + "properties": { + "deprecated": { + "description": "Whether the function is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "kind": { + "enum": [ + "method" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "privacy": { + "$ref": "#/definitions/Privacy" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "static": { + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "CssCustomProperty": { + "properties": { + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the CSS custom property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "name": { + "description": "The name of the property, including leading `--`.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "syntax": { + "description": "The expected syntax of the defined property. Defaults to \"*\".\n\nThe syntax must be a valid CSS [syntax string](https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax)\nas defined in the CSS Properties and Values API.\n\nExamples:\n\n\"\": accepts a color\n\" | \": accepts lengths or percentages but not calc expressions with a combination of the two\n\"small | medium | large\": accepts one of these values set as custom idents.\n\"*\": any valid token", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CssPart": { + "description": "The description of a CSS Part", + "properties": { + "deprecated": { + "description": "Whether the CSS shadow part is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "name": { + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CustomElementDeclaration": { + "description": "A description of a custom element class.\n\nCustom elements are JavaScript classes, so this extends from\n`ClassDeclaration` and adds custom-element-specific features like\nattributes, events, and slots.\n\nNote that `tagName` in this interface is optional. Tag names are not\nneccessarily part of a custom element class, but belong to the definition\n(often called the \"registration\") or the `customElements.define()` call.\n\nBecause classes and tag names can only be registered once, there's a\none-to-one relationship between classes and tag names. For ease of use,\nwe allow the tag name here.\n\nSome packages define and register custom elements in separate modules. In\nthese cases one `Module` should contain the `CustomElement` without a\ntagName, and another `Module` should contain the\n`CustomElementExport`.", + "properties": { + "attributes": { + "description": "The attributes that this element is known to understand.", + "items": { + "$ref": "#/definitions/Attribute" + }, + "type": "array" + }, + "cssParts": { + "items": { + "$ref": "#/definitions/CssPart" + }, + "type": "array" + }, + "cssProperties": { + "items": { + "$ref": "#/definitions/CssCustomProperty" + }, + "type": "array" + }, + "customElement": { + "description": "Distinguishes a regular JavaScript class from a\ncustom element class", + "enum": [ + true + ], + "type": "boolean" + }, + "demos": { + "items": { + "$ref": "#/definitions/Demo" + }, + "type": "array" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "events": { + "description": "The events that this element fires.", + "items": { + "$ref": "#/definitions/Event" + }, + "type": "array" + }, + "kind": { + "enum": [ + "class" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "slots": { + "description": "The shadow dom content slots that this element accepts.", + "items": { + "$ref": "#/definitions/Slot" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + }, + "tagName": { + "description": "An optional tag name that should be specified if this is a\nself-registering element.\n\nSelf-registering elements must also include a CustomElementExport\nin the module's exports.", + "type": "string" + } + }, + "required": [ + "customElement", + "kind", + "name" + ], + "type": "object" + }, + "CustomElementExport": { + "description": "A global custom element defintion, ie the result of a\n`customElements.define()` call.\n\nThis is represented as an export because a definition makes the element\navailable outside of the module it's defined it.", + "properties": { + "declaration": { + "$ref": "#/definitions/Reference", + "description": "A reference to the class or other declaration that implements the\ncustom element." + }, + "deprecated": { + "description": "Whether the custom-element export is deprecated.\nFor example, a future version will not register the custom element in this file.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "kind": { + "enum": [ + "custom-element-definition" + ], + "type": "string" + }, + "name": { + "description": "The tag name of the custom element.", + "type": "string" + } + }, + "required": [ + "declaration", + "kind", + "name" + ], + "type": "object" + }, + "CustomElementMixinDeclaration": { + "description": "A class mixin that also adds custom element related properties.", + "properties": { + "attributes": { + "description": "The attributes that this element is known to understand.", + "items": { + "$ref": "#/definitions/Attribute" + }, + "type": "array" + }, + "cssParts": { + "items": { + "$ref": "#/definitions/CssPart" + }, + "type": "array" + }, + "cssProperties": { + "items": { + "$ref": "#/definitions/CssCustomProperty" + }, + "type": "array" + }, + "customElement": { + "description": "Distinguishes a regular JavaScript class from a\ncustom element class", + "enum": [ + true + ], + "type": "boolean" + }, + "demos": { + "items": { + "$ref": "#/definitions/Demo" + }, + "type": "array" + }, + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "events": { + "description": "The events that this element fires.", + "items": { + "$ref": "#/definitions/Event" + }, + "type": "array" + }, + "kind": { + "enum": [ + "mixin" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "slots": { + "description": "The shadow dom content slots that this element accepts.", + "items": { + "$ref": "#/definitions/Slot" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + }, + "tagName": { + "description": "An optional tag name that should be specified if this is a\nself-registering element.\n\nSelf-registering elements must also include a CustomElementExport\nin the module's exports.", + "type": "string" + } + }, + "required": [ + "customElement", + "kind", + "name" + ], + "type": "object" + }, + "Demo": { + "properties": { + "description": { + "description": "A markdown description of the demo.", + "type": "string" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "url": { + "description": "Relative URL of the demo if it's published with the package. Absolute URL\nif it's hosted.", + "type": "string" + } + }, + "required": [ + "url" + ], + "type": "object" + }, + "Event": { + "properties": { + "deprecated": { + "description": "Whether the event is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "inheritedFrom": { + "$ref": "#/definitions/Reference" + }, + "name": { + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type", + "description": "The type of the event object that's fired." + } + }, + "required": [ + "name", + "type" + ], + "type": "object" + }, + "FunctionDeclaration": { + "properties": { + "deprecated": { + "description": "Whether the function is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "kind": { + "enum": [ + "function" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "JavaScriptExport": { + "properties": { + "declaration": { + "$ref": "#/definitions/Reference", + "description": "A reference to the exported declaration.\n\nIn the case of aggregating exports, the reference's `module` field must be\ndefined and the `name` field must be `\"*\"`." + }, + "deprecated": { + "description": "Whether the export is deprecated. For example, the name of the export was changed.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "kind": { + "enum": [ + "js" + ], + "type": "string" + }, + "name": { + "description": "The name of the exported symbol.\n\nJavaScript has a number of ways to export objects which determine the\ncorrect name to use.\n\n- Default exports must use the name \"default\".\n- Named exports use the name that is exported. If the export is renamed\n with the \"as\" clause, use the exported name.\n- Aggregating exports (`* from`) should use the name `*`", + "type": "string" + } + }, + "required": [ + "declaration", + "kind", + "name" + ], + "type": "object" + }, + "JavaScriptModule": { + "properties": { + "declarations": { + "description": "The declarations of a module.\n\nFor documentation purposes, all declarations that are reachable from\nexports should be described here. Ie, functions and objects that may be\nproperties of exported objects, or passed as arguments to functions.", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassDeclaration" + }, + { + "$ref": "#/definitions/FunctionDeclaration" + }, + { + "$ref": "#/definitions/MixinDeclaration" + }, + { + "$ref": "#/definitions/VariableDeclaration" + }, + { + "$ref": "#/definitions/CustomElementDeclaration" + }, + { + "$ref": "#/definitions/CustomElementMixinDeclaration" + } + ] + }, + "type": "array" + }, + "deprecated": { + "description": "Whether the module is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the module.", + "type": "string" + }, + "exports": { + "description": "The exports of a module. This includes JavaScript exports and\ncustom element definitions.", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/JavaScriptExport" + }, + { + "$ref": "#/definitions/CustomElementExport" + } + ] + }, + "type": "array" + }, + "kind": { + "enum": [ + "javascript-module" + ], + "type": "string" + }, + "path": { + "description": "Path to the javascript file needed to be imported. \n(not the path for example to a typescript file.)", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "kind", + "path" + ], + "type": "object" + }, + "MixinDeclaration": { + "description": "A description of a class mixin.\n\nMixins are functions which generate a new subclass of a given superclass.\nThis interfaces describes the class and custom element features that\nare added by the mixin. As such, it extends the CustomElement interface and\nClassLike interface.\n\nSince mixins are functions, it also extends the FunctionLike interface. This\nmeans a mixin is callable, and has parameters and a return type.\n\nThe return type is often hard or impossible to accurately describe in type\nsystems like TypeScript. It requires generics and an `extends` operator\nthat TypeScript lacks. Therefore it's recommended that the return type is\nleft empty. The most common form of a mixin function takes a single\nargument, so consumers of this interface should assume that the return type\nis the single argument subclassed by this declaration.\n\nA mixin should not have a superclass. If a mixins composes other mixins,\nthey should be listed in the `mixins` field.\n\nSee [this article]{@link https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/}\nfor more information on the classmixin pattern in JavaScript.", + "properties": { + "deprecated": { + "description": "Whether the class or mixin is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the class.", + "type": "string" + }, + "kind": { + "enum": [ + "mixin" + ], + "type": "string" + }, + "members": { + "items": { + "anyOf": [ + { + "$ref": "#/definitions/ClassField" + }, + { + "$ref": "#/definitions/ClassMethod" + } + ] + }, + "type": "array" + }, + "mixins": { + "description": "Any class mixins applied in the extends clause of this class.\n\nIf mixins are applied in the class definition, then the true superclass\nof this class is the result of applying mixins in order to the superclass.\n\nMixins must be listed in order of their application to the superclass or\nprevious mixin application. This means that the innermost mixin is listed\nfirst. This may read backwards from the common order in JavaScript, but\nmatches the order of language used to describe mixin application, like\n\"S with A, B\".", + "items": { + "$ref": "#/definitions/Reference" + }, + "type": "array" + }, + "name": { + "type": "string" + }, + "parameters": { + "items": { + "$ref": "#/definitions/Parameter" + }, + "type": "array" + }, + "return": { + "properties": { + "description": { + "description": "A markdown description.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "type": "object" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "superclass": { + "$ref": "#/definitions/Reference", + "description": "The superclass of this class.\n\nIf this class is defined with mixin applications, the prototype chain\nincludes the mixin applications and the true superclass is computed\nfrom them." + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + }, + "Parameter": { + "properties": { + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "name": { + "type": "string" + }, + "optional": { + "description": "Whether the parameter is optional. Undefined implies non-optional.", + "type": "boolean" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "rest": { + "description": "Whether the parameter is a rest parameter. Only the last parameter may be a rest parameter.\nUndefined implies single parameter.", + "type": "boolean" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "Privacy": { + "enum": [ + "private", + "protected", + "public" + ], + "type": "string" + }, + "Reference": { + "description": "A reference to an export of a module.\n\nAll references are required to be publically accessible, so the canonical\nrepresentation of a reference is the export it's available from.\n\n`package` should generally refer to an npm package name. If `package` is\nundefined then the reference is local to this package. If `module` is\nundefined the reference is local to the containing module.\n\nReferences to global symbols like `Array`, `HTMLElement`, or `Event` should\nuse a `package` name of `\"global:\"`.", + "properties": { + "module": { + "type": "string" + }, + "name": { + "type": "string" + }, + "package": { + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "Slot": { + "properties": { + "deprecated": { + "description": "Whether the slot is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description.", + "type": "string" + }, + "name": { + "description": "The slot name, or the empty string for an unnamed slot.", + "type": "string" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "SourceReference": { + "description": "A reference to the source of a declaration or member.", + "properties": { + "href": { + "description": "An absolute URL to the source (ie. a GitHub URL).", + "type": "string" + } + }, + "required": [ + "href" + ], + "type": "object" + }, + "Type": { + "properties": { + "references": { + "description": "An array of references to the types in the type string.\n\nThese references have optional indices into the type string so that tools\ncan understand the references in the type string independently of the type\nsystem and syntax. For example, a documentation viewer could display the\ntype `Array` with cross-references to `FooElement`\nand `BarElement` without understanding arrays, generics, or union types.", + "items": { + "$ref": "#/definitions/TypeReference" + }, + "type": "array" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "text": { + "description": "The full string representation of the type, in whatever type syntax is\nused, such as JSDoc, Closure, or TypeScript.", + "type": "string" + } + }, + "required": [ + "text" + ], + "type": "object" + }, + "TypeReference": { + "description": "A reference that is associated with a type string and optionally a range\nwithin the string.\n\nStart and end must both be present or not present. If they're present, they\nare indices into the associated type string. If they are missing, the entire\ntype string is the symbol referenced and the name should match the type\nstring.", + "properties": { + "end": { + "type": "number" + }, + "module": { + "type": "string" + }, + "name": { + "type": "string" + }, + "package": { + "type": "string" + }, + "start": { + "type": "number" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "VariableDeclaration": { + "properties": { + "default": { + "type": "string" + }, + "deprecated": { + "description": "Whether the property is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "description": { + "description": "A markdown description of the field.", + "type": "string" + }, + "kind": { + "enum": [ + "variable" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "readonly": { + "description": "Whether the property is read-only.", + "type": "boolean" + }, + "source": { + "$ref": "#/definitions/SourceReference" + }, + "summary": { + "description": "A markdown summary suitable for display in a listing.", + "type": "string" + }, + "type": { + "$ref": "#/definitions/Type" + } + }, + "required": [ + "kind", + "name" + ], + "type": "object" + } + }, + "description": "The top-level interface of a custom elements manifest file.\n\nBecause custom elements are JavaScript classes, describing a custom element\nmay require describing arbitrary JavaScript concepts like modules, classes,\nfunctions, etc. So custom elements manifests are capable of documenting\nthe elements in a package, as well as those JavaScript concepts.\n\nThe modules described in a package should be the public entrypoints that\nother packages may import from. Multiple modules may export the same object\nvia re-exports, but in most cases a package should document the single\ncanonical export that should be used.", + "properties": { + "deprecated": { + "description": "Whether the package is deprecated.\nIf the value is a string, it's the reason for the deprecation.", + "type": [ + "string", + "boolean" + ] + }, + "modules": { + "description": "An array of the modules this package contains.", + "items": { + "$ref": "#/definitions/JavaScriptModule" + }, + "type": "array" + }, + "readme": { + "description": "The Markdown to use for the main readme of this package.\n\nThis can be used to override the readme used by Github or npm if that\nfile contains information irrelevant to custom element catalogs and\ndocumentation viewers.", + "type": "string" + }, + "schemaVersion": { + "description": "The version of the schema used in this file.", + "type": "string" + } + }, + "required": [ + "modules", + "schemaVersion" + ], + "type": "object" +} \ No newline at end of file diff --git a/packages/tools/lib/cem/types-internal.d.ts b/packages/tools/lib/cem/types-internal.d.ts new file mode 100644 index 000000000000..916f8c5f2176 --- /dev/null +++ b/packages/tools/lib/cem/types-internal.d.ts @@ -0,0 +1,1061 @@ +export type Privacy = "private" | "protected" | "public" + +/** + * The top-level interface of a custom elements manifest file. + * + * Because custom elements are JavaScript classes, describing a custom element + * may require describing arbitrary JavaScript concepts like modules, classes, + * functions, etc. So custom elements manifests are capable of documenting + * the elements in a package, as well as those JavaScript concepts. + * + * The modules described in a package should be the public entrypoints that + * other packages may import from. Multiple modules may export the same object + * via re-exports, but in most cases a package should document the single + * canonical export that should be used. + */ +export interface Package { + /** + * Whether the package is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * An array of the modules this package contains. + */ + modules: JavaScriptModule[] + /** + * The Markdown to use for the main readme of this package. + * + * This can be used to override the readme used by Github or npm if that + * file contains information irrelevant to custom element catalogs and + * documentation viewers. + */ + readme?: string + /** + * The version of the schema used in this file. + */ + schemaVersion: string +} +export interface JavaScriptModule { + /** + * The declarations of a module. + * + * For documentation purposes, all declarations that are reachable from + * exports should be described here. Ie, functions and objects that may be + * properties of exported objects, or passed as arguments to functions. + */ + declarations?: ( + | ClassDeclaration + | EnumDeclaration + | InterfaceDeclaration + | FunctionDeclaration + | MixinDeclaration + | VariableDeclaration + | CustomElementDeclaration + | CustomElementMixinDeclaration + )[] + /** + * Whether the module is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the module. + */ + description?: string + /** + * The exports of a module. This includes JavaScript exports and + * custom element definitions. + */ + exports?: (JavaScriptExport | CustomElementExport)[] + kind: "javascript-module" + /** + * Path to the javascript file needed to be imported. + * (not the path for example to a typescript file.) + */ + path: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface ClassDeclaration { + _ui5implements?: Reference[] + _ui5privacy?: Privacy + /** + * Marks when the field was + */ + _ui5since?: string + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + kind: "class" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } +} +/** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ +export interface Reference { + module?: string + name: string + package?: string +} +export interface ClassField { + _ui5formProperty?: boolean + _ui5formEvents?: string + /** + * Marks when the field was introduced + */ + _ui5since?: string + default?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + inheritedFrom?: Reference + kind: "field" + name: string + privacy?: Privacy + /** + * Whether the property is read-only. + */ + readonly?: boolean + source?: SourceReference + static?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type +} +/** + * A reference to the source of a declaration or member. + */ +export interface SourceReference { + /** + * An absolute URL to the source (ie. a GitHub URL). + */ + href: string +} +export interface Type { + /** + * An array of references to the types in the type string. + * + * These references have optional indices into the type string so that tools + * can understand the references in the type string independently of the type + * system and syntax. For example, a documentation viewer could display the + * type `Array` with cross-references to `FooElement` + * and `BarElement` without understanding arrays, generics, or union types. + */ + references?: TypeReference[] + source?: SourceReference + /** + * The full string representation of the type, in whatever type syntax is + * used, such as JSDoc, Closure, or TypeScript. + */ + text: string +} +/** + * A reference that is associated with a type string and optionally a range + * within the string. + * + * Start and end must both be present or not present. If they're present, they + * are indices into the associated type string. If they are missing, the entire + * type string is the symbol referenced and the name should match the type + * string. + */ +export interface TypeReference { + end?: number + module?: string + name: string + package?: string + start?: number +} +export interface ClassMethod { + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the function is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + inheritedFrom?: Reference + kind: "method" + name: string + parameters?: Parameter[] + privacy?: Privacy + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + source?: SourceReference + static?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface Parameter { + _ui5privacy?: Privacy + /** + * Marks when the field was introduced + */ + _ui5since?: string + default?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + name: string + /** + * Whether the parameter is optional. Undefined implies non-optional. + */ + optional?: boolean + /** + * Whether the property is read-only. + */ + readonly?: boolean + /** + * Whether the parameter is a rest parameter. Only the last parameter may be a rest parameter. + * Undefined implies single parameter. + */ + rest?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type +} +export interface EnumDeclaration { + _ui5privacy?: Privacy + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + kind: "enum" + members?: EnumField[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } +} +export interface EnumField { + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + inheritedFrom?: Reference + kind: "field" + name: string + privacy?: Privacy + source?: SourceReference + static?: boolean + /** + * Whether the property is read-only. + */ + readonly?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface InterfaceDeclaration { + _ui5privacy?: Privacy + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + kind: "interface" + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } +} +export interface FunctionDeclaration { + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the function is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + kind: "function" + name: string + parameters?: Parameter[] + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +/** + * A description of a class mixin. + * + * Mixins are functions which generate a new subclass of a given superclass. + * This interfaces describes the class and custom element features that + * are added by the mixin. As such, it extends the CustomElement interface and + * ClassLike interface. + * + * Since mixins are functions, it also extends the FunctionLike interface. This + * means a mixin is callable, and has parameters and a return type. + * + * The return type is often hard or impossible to accurately describe in type + * systems like TypeScript. It requires generics and an `extends` operator + * that TypeScript lacks. Therefore it's recommended that the return type is + * left empty. The most common form of a mixin function takes a single + * argument, so consumers of this interface should assume that the return type + * is the single argument subclassed by this declaration. + * + * A mixin should not have a superclass. If a mixins composes other mixins, + * they should be listed in the `mixins` field. + * + * See [this article]{@link https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/} + * for more information on the classmixin pattern in JavaScript. + */ +export interface MixinDeclaration { + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + kind: "mixin" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + parameters?: Parameter[] + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } +} +export interface VariableDeclaration { + default?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + kind: "variable" + name: string + /** + * Whether the property is read-only. + */ + readonly?: boolean + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type +} +/** + * A description of a custom element class. + * + * Custom elements are JavaScript classes, so this extends from + * `ClassDeclaration` and adds custom-element-specific features like + * attributes, events, and slots. + * + * Note that `tagName` in this interface is optional. Tag names are not + * neccessarily part of a custom element class, but belong to the definition + * (often called the "registration") or the `customElements.define()` call. + * + * Because classes and tag names can only be registered once, there's a + * one-to-one relationship between classes and tag names. For ease of use, + * we allow the tag name here. + * + * Some packages define and register custom elements in separate modules. In + * these cases one `Module` should contain the `CustomElement` without a + * tagName, and another `Module` should contain the + * `CustomElementExport`. + */ +export interface CustomElementDeclaration { + _ui5implements?: Reference[] + _ui5abstract?: boolean + _ui5privacy?: Privacy + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * The attributes that this element is known to understand. + */ + attributes?: Attribute[] + cssParts?: CssPart[] + cssProperties?: CssCustomProperty[] + /** + * Distinguishes a regular JavaScript class from a + * custom element class + */ + customElement: true + demos?: Demo[] + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + /** + * The events that this element fires. + */ + events?: Event[] + kind: "class" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + /** + * The shadow dom content slots that this element accepts. + */ + slots?: Slot[] + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * An optional tag name that should be specified if this is a + * self-registering element. + * + * Self-registering elements must also include a CustomElementExport + * in the module's exports. + */ + tagName?: string +} +export interface Attribute { + /** + * The default value of the attribute, if any. + * + * As attributes are always strings, this is the actual value, not a human + * readable description. + */ + default?: string + /** + * Whether the attribute is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + /** + * The name of the field this attribute is associated with, if any. + */ + fieldName?: string + inheritedFrom?: Reference + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * The type that the attribute will be serialized/deserialized as. + */ + type?: { + /** + * An array of references to the types in the type string. + * + * These references have optional indices into the type string so that tools + * can understand the references in the type string independently of the type + * system and syntax. For example, a documentation viewer could display the + * type `Array` with cross-references to `FooElement` + * and `BarElement` without understanding arrays, generics, or union types. + */ + references?: TypeReference[] + source?: SourceReference + /** + * The full string representation of the type, in whatever type syntax is + * used, such as JSDoc, Closure, or TypeScript. + */ + text: string + [k: string]: unknown + } +} +/** + * The description of a CSS Part + */ +export interface CssPart { + /** + * Whether the CSS shadow part is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface CssCustomProperty { + default?: string + /** + * Whether the CSS custom property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + /** + * The name of the property, including leading `--`. + */ + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * The expected syntax of the defined property. Defaults to "*". + * + * The syntax must be a valid CSS [syntax string](https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax) + * as defined in the CSS Properties and Values API. + * + * Examples: + * + * "": accepts a color + * " | ": accepts lengths or percentages but not calc expressions with a combination of the two + * "small | medium | large": accepts one of these values set as custom idents. + * "*": any valid token + */ + syntax?: string +} +export interface Demo { + /** + * A markdown description of the demo. + */ + description?: string + source?: SourceReference + /** + * Relative URL of the demo if it's published with the package. Absolute URL + * if it's hosted. + */ + url: string +} +export interface Event { + _ui5parameters?: Parameter[] + _ui5privacy?: Privacy + /** + * Whether the parameter is optional. Undefined implies non-optional. + */ + _ui5allowPreventDefault?: boolean + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the event is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + inheritedFrom?: Reference + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * The type of the event object that's fired. + */ + type: { + /** + * An array of references to the types in the type string. + * + * These references have optional indices into the type string so that tools + * can understand the references in the type string independently of the type + * system and syntax. For example, a documentation viewer could display the + * type `Array` with cross-references to `FooElement` + * and `BarElement` without understanding arrays, generics, or union types. + */ + references?: TypeReference[] + source?: SourceReference + /** + * The full string representation of the type, in whatever type syntax is + * used, such as JSDoc, Closure, or TypeScript. + */ + text: string + [k: string]: unknown + } +} +export interface Slot { + _ui5type?: Type + _ui5privacy?: Privacy + /** + * Marks when the field was introduced + */ + _ui5since?: string + /** + * Whether the slot is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + /** + * The slot name, or the empty string for an unnamed slot. + */ + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +/** + * A class mixin that also adds custom element related properties. + */ +export interface CustomElementMixinDeclaration { + /** + * The attributes that this element is known to understand. + */ + attributes?: Attribute[] + cssParts?: CssPart[] + cssProperties?: CssCustomProperty[] + /** + * Distinguishes a regular JavaScript class from a + * custom element class + */ + customElement: true + demos?: Demo[] + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + /** + * The events that this element fires. + */ + events?: Event[] + kind: "mixin" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + parameters?: Parameter[] + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + /** + * The shadow dom content slots that this element accepts. + */ + slots?: Slot[] + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * An optional tag name that should be specified if this is a + * self-registering element. + * + * Self-registering elements must also include a CustomElementExport + * in the module's exports. + */ + tagName?: string +} +export interface JavaScriptExport { + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + declaration: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * Whether the export is deprecated. For example, the name of the export was changed. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + kind: "js" + /** + * The name of the exported symbol. + * + * JavaScript has a number of ways to export objects which determine the + * correct name to use. + * + * - Default exports must use the name "default". + * - Named exports use the name that is exported. If the export is renamed + * with the "as" clause, use the exported name. + * - Aggregating exports (`* from`) should use the name `*` + */ + name: string +} +/** + * A global custom element defintion, ie the result of a + * `customElements.define()` call. + * + * This is represented as an export because a definition makes the element + * available outside of the module it's defined it. + */ +export interface CustomElementExport { + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + declaration: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * Whether the custom-element export is deprecated. + * For example, a future version will not register the custom element in this file. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + kind: "custom-element-definition" + /** + * The tag name of the custom element. + */ + name: string +} diff --git a/packages/tools/lib/cem/types.d.ts b/packages/tools/lib/cem/types.d.ts new file mode 100644 index 000000000000..20fb70847b07 --- /dev/null +++ b/packages/tools/lib/cem/types.d.ts @@ -0,0 +1,871 @@ +export type Privacy = "private" | "protected" | "public" + +/** + * The top-level interface of a custom elements manifest file. + * + * Because custom elements are JavaScript classes, describing a custom element + * may require describing arbitrary JavaScript concepts like modules, classes, + * functions, etc. So custom elements manifests are capable of documenting + * the elements in a package, as well as those JavaScript concepts. + * + * The modules described in a package should be the public entrypoints that + * other packages may import from. Multiple modules may export the same object + * via re-exports, but in most cases a package should document the single + * canonical export that should be used. + */ +export interface Package { + /** + * Whether the package is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * An array of the modules this package contains. + */ + modules: JavaScriptModule[] + /** + * The Markdown to use for the main readme of this package. + * + * This can be used to override the readme used by Github or npm if that + * file contains information irrelevant to custom element catalogs and + * documentation viewers. + */ + readme?: string + /** + * The version of the schema used in this file. + */ + schemaVersion: string +} +export interface JavaScriptModule { + /** + * The declarations of a module. + * + * For documentation purposes, all declarations that are reachable from + * exports should be described here. Ie, functions and objects that may be + * properties of exported objects, or passed as arguments to functions. + */ + declarations?: ( + | ClassDeclaration + | FunctionDeclaration + | MixinDeclaration + | VariableDeclaration + | CustomElementDeclaration + | CustomElementMixinDeclaration + )[] + /** + * Whether the module is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the module. + */ + description?: string + /** + * The exports of a module. This includes JavaScript exports and + * custom element definitions. + */ + exports?: (JavaScriptExport | CustomElementExport)[] + kind: "javascript-module" + /** + * Path to the javascript file needed to be imported. + * (not the path for example to a typescript file.) + */ + path: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface ClassDeclaration { + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + kind: "class" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } +} +export interface ClassField { + default?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + inheritedFrom?: Reference + kind: "field" + name: string + privacy?: Privacy + /** + * Whether the property is read-only. + */ + readonly?: boolean + source?: SourceReference + static?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type +} +/** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ +export interface Reference { + module?: string + name: string + package?: string +} +/** + * A reference to the source of a declaration or member. + */ +export interface SourceReference { + /** + * An absolute URL to the source (ie. a GitHub URL). + */ + href: string +} +export interface Type { + /** + * An array of references to the types in the type string. + * + * These references have optional indices into the type string so that tools + * can understand the references in the type string independently of the type + * system and syntax. For example, a documentation viewer could display the + * type `Array` with cross-references to `FooElement` + * and `BarElement` without understanding arrays, generics, or union types. + */ + references?: TypeReference[] + source?: SourceReference + /** + * The full string representation of the type, in whatever type syntax is + * used, such as JSDoc, Closure, or TypeScript. + */ + text: string +} +/** + * A reference that is associated with a type string and optionally a range + * within the string. + * + * Start and end must both be present or not present. If they're present, they + * are indices into the associated type string. If they are missing, the entire + * type string is the symbol referenced and the name should match the type + * string. + */ +export interface TypeReference { + end?: number + module?: string + name: string + package?: string + start?: number +} +export interface ClassMethod { + /** + * Whether the function is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + inheritedFrom?: Reference + kind: "method" + name: string + parameters?: Parameter[] + privacy?: Privacy + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + source?: SourceReference + static?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface Parameter { + default?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + name: string + /** + * Whether the parameter is optional. Undefined implies non-optional. + */ + optional?: boolean + /** + * Whether the property is read-only. + */ + readonly?: boolean + /** + * Whether the parameter is a rest parameter. Only the last parameter may be a rest parameter. + * Undefined implies single parameter. + */ + rest?: boolean + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type +} +export interface FunctionDeclaration { + /** + * Whether the function is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + kind: "function" + name: string + parameters?: Parameter[] + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +/** + * A description of a class mixin. + * + * Mixins are functions which generate a new subclass of a given superclass. + * This interfaces describes the class and custom element features that + * are added by the mixin. As such, it extends the CustomElement interface and + * ClassLike interface. + * + * Since mixins are functions, it also extends the FunctionLike interface. This + * means a mixin is callable, and has parameters and a return type. + * + * The return type is often hard or impossible to accurately describe in type + * systems like TypeScript. It requires generics and an `extends` operator + * that TypeScript lacks. Therefore it's recommended that the return type is + * left empty. The most common form of a mixin function takes a single + * argument, so consumers of this interface should assume that the return type + * is the single argument subclassed by this declaration. + * + * A mixin should not have a superclass. If a mixins composes other mixins, + * they should be listed in the `mixins` field. + * + * See [this article]{@link https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/} + * for more information on the classmixin pattern in JavaScript. + */ +export interface MixinDeclaration { + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + kind: "mixin" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + parameters?: Parameter[] + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } +} +export interface VariableDeclaration { + default?: string + /** + * Whether the property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the field. + */ + description?: string + kind: "variable" + name: string + /** + * Whether the property is read-only. + */ + readonly?: boolean + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type +} +/** + * A description of a custom element class. + * + * Custom elements are JavaScript classes, so this extends from + * `ClassDeclaration` and adds custom-element-specific features like + * attributes, events, and slots. + * + * Note that `tagName` in this interface is optional. Tag names are not + * neccessarily part of a custom element class, but belong to the definition + * (often called the "registration") or the `customElements.define()` call. + * + * Because classes and tag names can only be registered once, there's a + * one-to-one relationship between classes and tag names. For ease of use, + * we allow the tag name here. + * + * Some packages define and register custom elements in separate modules. In + * these cases one `Module` should contain the `CustomElement` without a + * tagName, and another `Module` should contain the + * `CustomElementExport`. + */ +export interface CustomElementDeclaration { + /** + * The attributes that this element is known to understand. + */ + attributes?: Attribute[] + cssParts?: CssPart[] + cssProperties?: CssCustomProperty[] + /** + * Distinguishes a regular JavaScript class from a + * custom element class + */ + customElement: true + demos?: Demo[] + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + /** + * The events that this element fires. + */ + events?: Event[] + kind: "class" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + /** + * The shadow dom content slots that this element accepts. + */ + slots?: Slot[] + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * An optional tag name that should be specified if this is a + * self-registering element. + * + * Self-registering elements must also include a CustomElementExport + * in the module's exports. + */ + tagName?: string +} +export interface Attribute { + /** + * The default value of the attribute, if any. + * + * As attributes are always strings, this is the actual value, not a human + * readable description. + */ + default?: string + /** + * Whether the attribute is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + /** + * The name of the field this attribute is associated with, if any. + */ + fieldName?: string + inheritedFrom?: Reference + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * The type that the attribute will be serialized/deserialized as. + */ + type?: { + /** + * An array of references to the types in the type string. + * + * These references have optional indices into the type string so that tools + * can understand the references in the type string independently of the type + * system and syntax. For example, a documentation viewer could display the + * type `Array` with cross-references to `FooElement` + * and `BarElement` without understanding arrays, generics, or union types. + */ + references?: TypeReference[] + source?: SourceReference + /** + * The full string representation of the type, in whatever type syntax is + * used, such as JSDoc, Closure, or TypeScript. + */ + text: string + [k: string]: unknown + } +} +/** + * The description of a CSS Part + */ +export interface CssPart { + /** + * Whether the CSS shadow part is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +export interface CssCustomProperty { + default?: string + /** + * Whether the CSS custom property is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + /** + * The name of the property, including leading `--`. + */ + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * The expected syntax of the defined property. Defaults to "*". + * + * The syntax must be a valid CSS [syntax string](https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax) + * as defined in the CSS Properties and Values API. + * + * Examples: + * + * "": accepts a color + * " | ": accepts lengths or percentages but not calc expressions with a combination of the two + * "small | medium | large": accepts one of these values set as custom idents. + * "*": any valid token + */ + syntax?: string +} +export interface Demo { + /** + * A markdown description of the demo. + */ + description?: string + source?: SourceReference + /** + * Relative URL of the demo if it's published with the package. Absolute URL + * if it's hosted. + */ + url: string +} +export interface Event { + /** + * Whether the event is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + inheritedFrom?: Reference + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * The type of the event object that's fired. + */ + type: { + /** + * An array of references to the types in the type string. + * + * These references have optional indices into the type string so that tools + * can understand the references in the type string independently of the type + * system and syntax. For example, a documentation viewer could display the + * type `Array` with cross-references to `FooElement` + * and `BarElement` without understanding arrays, generics, or union types. + */ + references?: TypeReference[] + source?: SourceReference + /** + * The full string representation of the type, in whatever type syntax is + * used, such as JSDoc, Closure, or TypeScript. + */ + text: string + [k: string]: unknown + } +} +export interface Slot { + /** + * Whether the slot is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description. + */ + description?: string + /** + * The slot name, or the empty string for an unnamed slot. + */ + name: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string +} +/** + * A class mixin that also adds custom element related properties. + */ +export interface CustomElementMixinDeclaration { + /** + * The attributes that this element is known to understand. + */ + attributes?: Attribute[] + cssParts?: CssPart[] + cssProperties?: CssCustomProperty[] + /** + * Distinguishes a regular JavaScript class from a + * custom element class + */ + customElement: true + demos?: Demo[] + /** + * Whether the class or mixin is deprecated. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + /** + * A markdown description of the class. + */ + description?: string + /** + * The events that this element fires. + */ + events?: Event[] + kind: "mixin" + members?: (ClassField | ClassMethod)[] + /** + * Any class mixins applied in the extends clause of this class. + * + * If mixins are applied in the class definition, then the true superclass + * of this class is the result of applying mixins in order to the superclass. + * + * Mixins must be listed in order of their application to the superclass or + * previous mixin application. This means that the innermost mixin is listed + * first. This may read backwards from the common order in JavaScript, but + * matches the order of language used to describe mixin application, like + * "S with A, B". + */ + mixins?: Reference[] + name: string + parameters?: Parameter[] + return?: { + /** + * A markdown description. + */ + description?: string + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + type?: Type + [k: string]: unknown + } + /** + * The shadow dom content slots that this element accepts. + */ + slots?: Slot[] + source?: SourceReference + /** + * A markdown summary suitable for display in a listing. + */ + summary?: string + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + superclass?: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * An optional tag name that should be specified if this is a + * self-registering element. + * + * Self-registering elements must also include a CustomElementExport + * in the module's exports. + */ + tagName?: string +} +export interface JavaScriptExport { + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + declaration: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * Whether the export is deprecated. For example, the name of the export was changed. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + kind: "js" + /** + * The name of the exported symbol. + * + * JavaScript has a number of ways to export objects which determine the + * correct name to use. + * + * - Default exports must use the name "default". + * - Named exports use the name that is exported. If the export is renamed + * with the "as" clause, use the exported name. + * - Aggregating exports (`* from`) should use the name `*` + */ + name: string +} +/** + * A global custom element defintion, ie the result of a + * `customElements.define()` call. + * + * This is represented as an export because a definition makes the element + * available outside of the module it's defined it. + */ +export interface CustomElementExport { + /** + * A reference to an export of a module. + * + * All references are required to be publically accessible, so the canonical + * representation of a reference is the export it's available from. + * + * `package` should generally refer to an npm package name. If `package` is + * undefined then the reference is local to this package. If `module` is + * undefined the reference is local to the containing module. + * + * References to global symbols like `Array`, `HTMLElement`, or `Event` should + * use a `package` name of `"global:"`. + */ + declaration: { + module?: string + name: string + package?: string + [k: string]: unknown + } + /** + * Whether the custom-element export is deprecated. + * For example, a future version will not register the custom element in this file. + * If the value is a string, it's the reason for the deprecation. + */ + deprecated?: string | boolean + kind: "custom-element-definition" + /** + * The tag name of the custom element. + */ + name: string +} diff --git a/packages/tools/lib/cem/utils.mjs b/packages/tools/lib/cem/utils.mjs new file mode 100644 index 000000000000..b5b8370586df --- /dev/null +++ b/packages/tools/lib/cem/utils.mjs @@ -0,0 +1,334 @@ +import fs from "fs"; +import path from "path"; + +let JSDocErrors = []; + +const getDeprecatedStatus = (jsdocComment) => { + const deprecatedTag = findTag(jsdocComment, "deprecated"); + return deprecatedTag?.name + ? deprecatedTag.description + ? `${deprecatedTag.name} ${deprecatedTag.description}` + : deprecatedTag.name + : deprecatedTag + ? true + : undefined; +}; + +const getTypeRefs = (ts, classNodeMember, member) => { + const extractTypeRefs = (type) => { + if (type?.kind === ts.SyntaxKind.TypeReference) { + return type.typeArguments?.length + ? type.typeArguments.map((typeRef) => typeRef.typeName?.text) + : [type.typeName?.text]; + } else if (type?.kind === ts.SyntaxKind.UnionType) { + return type.types + .map((type) => extractTypeRefs(type)) + .flat(1); + } else if (type?.kind === ts.SyntaxKind.TemplateLiteralType) { + if (member.type) { + member.type.text = member.type.text.replaceAll?.(/`|\${|}/g, ""); + } + + return type.templateSpans?.length + ? type.templateSpans.map((typeRef) => typeRef.type?.typeName?.text) + : [type.typeName?.text]; + } + }; + + let typeRefs = extractTypeRefs(classNodeMember.type); + + if (typeRefs) { + typeRefs = typeRefs.filter((e) => !!e); + } + + return typeRefs?.length ? typeRefs : undefined; +}; + +const getSinceStatus = (jsdocComment) => { + const sinceTag = findTag(jsdocComment, "since"); + return sinceTag + ? sinceTag.description + ? `${sinceTag.name} ${sinceTag.description}` + : sinceTag.name + : undefined; +}; + +const getPrivacyStatus = (jsdocComment) => { + const privacyTag = findTag(jsdocComment, ["public", "private", "protected"]); + return privacyTag?.tag || "private"; +}; + +const findPackageName = (ts, sourceFile, typeName, packageJSON) => { + const localStatements = [ + ts.SyntaxKind.EnumDeclaration, + ts.SyntaxKind.InterfaceDeclaration, + ts.SyntaxKind.ClassDeclaration, + ts.SyntaxKind.TypeAliasDeclaration, + ]; + + const isLocalDeclared = sourceFile.statements.some( + (statement) => + localStatements.includes(statement.kind) && statement?.name?.text === typeName + ); + + if (isLocalDeclared) { + return packageJSON?.name; + } else { + const importStatements = sourceFile.statements?.filter( + (statement) => statement.kind === ts.SyntaxKind.ImportDeclaration + ); + const currentModuleSpecifier = importStatements.find((statement) => { + if (statement.importClause?.name?.text === typeName) { + return true; + } + + return statement.importClause?.namedBindings?.elements?.some( + (element) => element.name?.text === typeName + ); + })?.moduleSpecifier; + + if (currentModuleSpecifier?.text?.startsWith(".")) { + return packageJSON?.name; + } else { + return Object.keys(packageJSON?.dependencies || {}).find( + (dependency) => + currentModuleSpecifier?.text?.startsWith(dependency) + ); + } + } +}; + +const findImportPath = (ts, sourceFile, typeName, packageJSON, modulePath) => { + const localStatements = [ + ts.SyntaxKind.EnumDeclaration, + ts.SyntaxKind.InterfaceDeclaration, + ts.SyntaxKind.ClassDeclaration, + ts.SyntaxKind.TypeAliasDeclaration, + ]; + + const isLocalDeclared = sourceFile.statements.some( + (statement) => + localStatements.includes(statement.kind) && statement?.name?.text === typeName + ); + + if (isLocalDeclared) { + return ( + modulePath?.replace("src", "dist")?.replace(".ts", ".js") || undefined + ); + } else { + const importStatements = sourceFile.statements?.filter( + (statement) => statement.kind === ts.SyntaxKind.ImportDeclaration + ); + const currentModuleSpecifier = importStatements.find((statement) => { + if (statement.importClause?.name?.text === typeName) { + return true; + } + + return statement.importClause?.namedBindings?.elements?.some( + (element) => element.name?.text === typeName + ); + })?.moduleSpecifier; + + if (currentModuleSpecifier?.text?.startsWith(".")) { + return ( + path.join(path.dirname(modulePath), currentModuleSpecifier.text) + ?.replace("src", "dist")?.replace(".ts", ".js") || undefined + ); + } else { + const packageName = Object.keys(packageJSON?.dependencies || {}).find( + (dependency) => + currentModuleSpecifier?.text?.startsWith(dependency) + ); + return currentModuleSpecifier?.text + ?.replace(`${packageName}/`, "") || undefined; + } + } +}; + +const getReference = (ts, type, classNode, modulePath) => { + let sourceFile = classNode.parent; + + while (sourceFile && sourceFile.kind !== ts.SyntaxKind.SourceFile) { + sourceFile = sourceFile.parent; + } + + const packageJSON = JSON.parse(fs.readFileSync("./package.json")); + + const typeName = + typeof type === "string" + ? type + : type.class?.expression?.text || + type.typeExpression?.type?.getText() || + type.typeExpression?.type?.elementType?.typeName?.text; + const packageName = findPackageName(ts, sourceFile, typeName, packageJSON); + const importPath = findImportPath( + ts, + sourceFile, + typeName, + packageJSON, + modulePath + ); + + return packageName && { + name: typeName, + package: packageName, + module: importPath, + }; +}; + +const getType = (type) => { + const typeName = typeof type === "string" ? type : type?.type; + + const multiple = + typeName?.endsWith("[]") || typeName?.startsWith("Array<"); + const name = multiple + ? typeName?.replace("[]", "")?.replace("Array<", "")?.replace(">", "") + : typeName; + + return typeName ? { typeName: multiple ? `Array<${name}>` : typeName, name, multiple } : undefined; +}; + +const commonTags = ["public", "protected", "private", "since", "deprecated"]; + +const allowedTags = { + field: [...commonTags, "formEvents", "formProperty", "default"], + slot: [...commonTags, "default"], + event: [...commonTags, "param", "allowPreventDefault", "native"], + eventParam: [...commonTags], + method: [...commonTags, "param", "returns", "override"], + class: [...commonTags, "constructor", "class", "abstract", "implements", "extends", "slot", "csspart"], + enum: [...commonTags], + enumMember: [...commonTags], + interface: [...commonTags], +}; +allowedTags.getter = [...allowedTags.field, "override"] + +const tagMatchCallback = (tag, tagName) => { + const currentTagName = tag.tag; + + return typeof tagName === "string" + ? currentTagName === tagName + : tagName.includes(currentTagName); +}; + +const findDecorator = (node, decoratorName) => { + return node?.decorators?.find( + (decorator) => + decorator?.expression?.expression?.text === decoratorName + ); +}; + +const findAllDecorators = (node, decoratorName) => { + return ( + node?.decorators?.filter( + (decorator) => + decorator?.expression?.expression?.text === decoratorName + ) || [] + ); +}; + +const hasTag = (jsDoc, tagName) => { + if (!jsDoc) { + return; + } + + return jsDoc?.tags?.some((tag) => tagMatchCallback(tag, tagName)); +}; + +const findTag = (jsDoc, tagName) => { + if (!jsDoc) { + return; + } + + return jsDoc?.tags?.find((tag) => tagMatchCallback(tag, tagName)); +}; + +const findAllTags = (jsDoc, tagName) => { + if (!jsDoc) { + return []; + } + + const foundTags = jsDoc?.tags?.filter((tag) => tagMatchCallback(tag, tagName)); + + return foundTags || []; +}; + +const validateJSDocTag = (tag) => { + const booleanTags = ["private", "protected", "public", "abstract", "allowPreventDefault", "native", "formProperty", "constructor", "override"]; + let tagName = tag.tag; + + if (booleanTags.includes(tag.tag)) { + tagName = "boolean"; + } + + switch (tagName) { + case "boolean": + return !tag.name && !tag.type && !tag.description; + case "deprecated": + return !tag.type; + case "extends": + return !tag.type && tag.name && !tag.description; + case "implements": + return tag.type && !tag.name && !tag.description; + case "slot": + return tag.type && tag.name && tag.description; + case "csspart": + return !tag.type && tag.name && tag.description; + case "since": + return !tag.type && tag.name; + case "returns": + return !tag.type && tag.name; + case "default": + return !tag.type && !tag.description; + case "class": + return !tag.type; + case "param": + return !tag.type && tag.name; + case "eventparam": + return tag.type && tag.name; + case "formEvents": + return !tag.type && tag.name; + default: + return false; + } +}; + +const validateJSDocComment = (fieldType, jsdocComment, node, moduleDoc) => { + return !!jsdocComment?.tags?.every((tag) => { + let isValid = false + + if (fieldType === "event" && tag?.tag === "param") { + isValid = allowedTags[fieldType]?.includes(tag.tag) && validateJSDocTag({...tag, tag: "eventparam"}); + } else { + isValid = allowedTags[fieldType]?.includes(tag.tag) && validateJSDocTag(tag); + } + + if (!isValid) { + JSDocErrors.push( + `=== ERROR: Problem found with ${node}'s JSDoc comment in ${moduleDoc.path}: \n\t- @${tag.tag} tag is being used wrong or it's not part of ${fieldType} JSDoc tags` + ); + } + + return !!isValid; + }); +}; + +const getJSDocErrors = () => { + return JSDocErrors; +}; + +export { + getPrivacyStatus, + getSinceStatus, + getDeprecatedStatus, + getType, + getReference, + validateJSDocComment, + findDecorator, + findAllDecorators, + hasTag, + findTag, + findAllTags, + getJSDocErrors, + getTypeRefs, +}; diff --git a/packages/tools/lib/cem/validate.js b/packages/tools/lib/cem/validate.js new file mode 100644 index 000000000000..b46f2ae29e5a --- /dev/null +++ b/packages/tools/lib/cem/validate.js @@ -0,0 +1,63 @@ +const fs = require('fs'); +const Ajv = require('ajv'); +const path = require('path'); + +// Load your JSON schema +const extenalSchema = require('./schema.json'); +const internalSchema = require('./schema-internal.json'); + +// Load your JSON data from the input file +const inputFilePath = path.join(process.cwd(), "dist/custom-elements.json"); // Update with your file path +const customManifest = fs.readFileSync(inputFilePath, 'utf8'); +const inputDataInternal = JSON.parse(customManifest); + +const clearProps = (data) => { + if (Array.isArray(data)) { + for (let i = 0; i < data.length; i++) { + if (typeof data[i] === "object") { + if (["enum", "interface"].includes(data[i].kind)) { + data.splice(i, 1); + i--; + } else { + clearProps(data[i]); + } + } + } + } else if (typeof data === "object") { + Object.keys(data).forEach(prop => { + if (prop.startsWith("_ui5")) { + delete data[prop]; + } else if (typeof data[prop] === "object") { + clearProps(data[prop]); + } + }); + } + + return data; +} + +const inputDataExternal = clearProps(JSON.parse(JSON.stringify(inputDataInternal))); + +const ajv = new Ajv({ allowUnionTypes: true, allError: true }) + +let validate = ajv.compile(internalSchema) + +// Validate the JSON data against the schema +if (validate(inputDataInternal)) { + console.log('Validation internal custom-elements successful'); +} else { + console.error('Validation of internal custom-elements failed:', ajv.errorsText(validate.errors)); + throw new Error("Validation of internal custom-elements failed"); +} + +validate = ajv.compile(extenalSchema) + +// Validate the JSON data against the schema +if (validate(inputDataExternal)) { + console.log('Validation external custom-elements successful'); + fs.writeFileSync(inputFilePath, JSON.stringify(inputDataExternal, null, 2), 'utf8'); + fs.writeFileSync(inputFilePath.replace("custom-elements", "custom-elements-internal"), JSON.stringify(inputDataInternal, null, 2), 'utf8'); +} else { + console.error('Validation of external custom-elements failed:', ajv.errorsText(validate.errors)); + throw new Error("Validation of external custom-elements failed"); +} \ No newline at end of file diff --git a/packages/tools/lib/generate-json-imports/i18n.js b/packages/tools/lib/generate-json-imports/i18n.js index 0e262ecdd3f5..b6d01139c5f9 100644 --- a/packages/tools/lib/generate-json-imports/i18n.js +++ b/packages/tools/lib/generate-json-imports/i18n.js @@ -56,7 +56,7 @@ localeIds.forEach(localeId => { `; // Actual imports for json assets - const dynamicImportsString = languages.map(key => ` case "${key}": return (await import("../assets/i18n/messagebundle_${key}.json")).default;`).join("\n"); + const dynamicImportsString = languages.map(key => ` case "${key}": return (await import(/* webpackChunkName: "${packageName.replace("@", "").replace("/", "-")}-messagebundle-${key}" */ "../assets/i18n/messagebundle_${key}.json")).default;`).join("\n"); // Resulting file content contentDynamic = `import { registerI18nLoader } from "@ui5/webcomponents-base/dist/asset-registries/i18n.js"; diff --git a/packages/tools/lib/generate-json-imports/themes.js b/packages/tools/lib/generate-json-imports/themes.js index 03fed6e8daeb..90e5edfbaf09 100644 --- a/packages/tools/lib/generate-json-imports/themes.js +++ b/packages/tools/lib/generate-json-imports/themes.js @@ -22,7 +22,7 @@ const generate = async () => { const importLines = themesOnFileSystem.map(theme => `import ${theme} from "../assets/themes/${theme}/parameters-bundle.css.json";`).join("\n"); const themeUrlsByName = "{\n" + themesOnFileSystem.join(",\n") + "\n}"; const availableThemesArray = `[${themesOnFileSystem.map(theme => `"${theme}"`).join(", ")}]`; - const dynamicImportLines = themesOnFileSystem.map(theme => `\t\tcase "${theme}": return (await import("../assets/themes/${theme}/parameters-bundle.css.json")).default;`).join("\n"); + const dynamicImportLines = themesOnFileSystem.map(theme => `\t\tcase "${theme}": return (await import(/* webpackChunkName: "${packageName.replace("@", "").replace("/", "-")}-${theme.replace("_", "-")}-parameters-bundle" */"../assets/themes/${theme}/parameters-bundle.css.json")).default;`).join("\n"); // static imports file content diff --git a/packages/tools/package.json b/packages/tools/package.json index 4378d50cf9a3..95bc3594edae 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -1,6 +1,6 @@ { "name": "@ui5/webcomponents-tools", - "version": "1.19.0", + "version": "1.20.0-rc.1", "description": "UI5 Web Components: webcomponents.tools", "author": "SAP SE (https://www.sap.com)", "license": "Apache-2.0", @@ -21,6 +21,7 @@ "directory": "packages/tools" }, "dependencies": { + "@custom-elements-manifest/analyzer": "^0.8.4", "@typescript-eslint/eslint-plugin": "^5.42.1", "@typescript-eslint/parser": "^5.42.1", "@wdio/cli": "^7.19.7", @@ -29,11 +30,13 @@ "@wdio/mocha-framework": "^7.19.7", "@wdio/spec-reporter": "^7.19.7", "@wdio/static-server-service": "^7.19.5", + "ajv": "^8.12.0", "chai": "^4.3.4", "child_process": "^1.0.2", "chokidar": "^3.5.1", "chokidar-cli": "^3.0.0", "command-line-args": "^5.1.1", + "comment-parser": "^1.4.0", "concurrently": "^6.0.0", "cross-env": "^7.0.3", "cssnano": "^6.0.1", @@ -50,6 +53,7 @@ "is-port-reachable": "^3.1.0", "jsdoc": "^3.6.6", "json-beautify": "^1.1.1", + "json-schema-to-typescript": "^13.1.1", "mkdirp": "^1.0.4", "nps": "^5.10.0", "postcss": "^8.4.5", diff --git a/yarn.lock b/yarn.lock index 3f762386ae11..06f03b8420a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1319,6 +1319,16 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@bcherny/json-schema-ref-parser@10.0.5-fork": + version "10.0.5-fork" + resolved "https://registry.yarnpkg.com/@bcherny/json-schema-ref-parser/-/json-schema-ref-parser-10.0.5-fork.tgz#9b5e1e7e07964ea61840174098e634edbe8197bc" + integrity sha512-E/jKbPoca1tfUPj3iSbitDZTGnq6FUFjkH6L8U2oDwSuwK1WhnnVtCG7oFOTg/DDnyoXbQYUiUiGOibHqaGVnw== + dependencies: + "@jsdevtools/ono" "^7.1.3" + "@types/json-schema" "^7.0.6" + call-me-maybe "^1.0.1" + js-yaml "^4.1.0" + "@buxlabs/amd-to-es6@0.16.1": version "0.16.1" resolved "https://registry.yarnpkg.com/@buxlabs/amd-to-es6/-/amd-to-es6-0.16.1.tgz#4baf5bc01af7d2306a8fe3ecb3fe3589688e7aa7" @@ -1494,6 +1504,29 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" +"@custom-elements-manifest/analyzer@^0.8.4": + version "0.8.4" + resolved "https://registry.yarnpkg.com/@custom-elements-manifest/analyzer/-/analyzer-0.8.4.tgz#34fce1158a44cb7a9d8c1c7415e8c9d03e25d95f" + integrity sha512-hibYFNoqPc/xSH9ySuotOllz3UtQnnbG912oC0RtRwHGilnOVT5zeL3Ip26swCjiuFAp8Y0uLN5DwnMpa/xXYQ== + dependencies: + "@custom-elements-manifest/find-dependencies" "^0.0.5" + "@github/catalyst" "^1.6.0" + "@web/config-loader" "0.1.3" + chokidar "3.5.2" + command-line-args "5.1.2" + comment-parser "1.2.4" + custom-elements-manifest "1.0.0" + debounce "1.2.1" + globby "11.0.4" + typescript "~4.3.2" + +"@custom-elements-manifest/find-dependencies@^0.0.5": + version "0.0.5" + resolved "https://registry.yarnpkg.com/@custom-elements-manifest/find-dependencies/-/find-dependencies-0.0.5.tgz#ebc11672019de3d52bb8f29f76efe510b8401fbd" + integrity sha512-fKIMMZCDFSoL2ySUoz8knWgpV4jpb0lUXgLOvdZQMQFHxgxz1PqOJpUIypwvEVyKk3nEHRY4f10gNol02HjeCg== + dependencies: + es-module-lexer "^0.9.3" + "@discoveryjs/json-ext@^0.5.3": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" @@ -1761,6 +1794,11 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@github/catalyst@^1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@github/catalyst/-/catalyst-1.6.0.tgz#378734d1d2b6a85af169d7e66c1a2a604bf1e82c" + integrity sha512-u8A+DameixqpeyHzvnJWTGj+wfiskQOYHzSiJscCWVfMkIT3rxnbHMtGh3lMthaRY21nbUOK71WcsCnCrXhBJQ== + "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.5.0.tgz#1407967d4c6eecd7388f83acf1eaf4d0c6e58ef9" @@ -1938,6 +1976,11 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jsdevtools/ono@^7.1.3": + version "7.1.3" + resolved "https://registry.yarnpkg.com/@jsdevtools/ono/-/ono-7.1.3.tgz#9df03bbd7c696a5c58885c34aa06da41c8543796" + integrity sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg== + "@juggle/resize-observer@^3.3.1": version "3.4.0" resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" @@ -2484,10 +2527,10 @@ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@sap-theming/theming-base-content@11.6.8": - version "11.6.8" - resolved "https://registry.yarnpkg.com/@sap-theming/theming-base-content/-/theming-base-content-11.6.8.tgz#3e70ddfe415f4492b3e37df2c642fbbf7cb8296d" - integrity sha512-LRYvqVeqFYCqhB4EMbFslQpgRLrYyOOsacWI0JZbWlnvRkbF4/pzKpr4ULyVPFp26CrwXhUZJeSSAa3/8KS6iw== +"@sap-theming/theming-base-content@11.9.0": + version "11.9.0" + resolved "https://registry.yarnpkg.com/@sap-theming/theming-base-content/-/theming-base-content-11.9.0.tgz#bd46458c7ed58cfb23e4e0ec620c9780a5711a5b" + integrity sha512-EOAYDx13SU9Wd18qgAR+FYTrywC5dk+IU3oM5NGAz0GxJLpiGQkSONYnAMJK/Gqk9QhU7uqWQsjrcnOcOl0fxA== "@sigstore/protobuf-specs@^0.1.0": version "0.1.0" @@ -3189,10 +3232,10 @@ dependencies: defer-to-connect "^2.0.0" -"@testim/chrome-version@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.3.tgz#fbb68696899d7b8c1b9b891eded9c04fe2cd5529" - integrity sha512-g697J3WxV/Zytemz8aTuKjTGYtta9+02kva3C1xc7KXB8GdbfE1akGJIsZLyY/FSh2QrnE+fiB7vmWU3XNcb6A== +"@testim/chrome-version@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@testim/chrome-version/-/chrome-version-1.1.4.tgz#86e04e677cd6c05fa230dd15ac223fa72d1d7090" + integrity sha512-kIhULpw9TrGYnHp/8VfdcneIcxKnLixmADtukQRtJUmsVlMg0niMkwV0xZmi8hqa57xqilIHjWFA0GKvEjVU5g== "@tootallnate/once@2": version "2.0.0" @@ -3372,6 +3415,14 @@ "@types/jsonfile" "*" "@types/node" "*" +"@types/glob@^7.1.3": + version "7.2.0" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" + integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + "@types/glob@^8.0.0", "@types/glob@^8.1.0": version "8.1.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-8.1.0.tgz#b63e70155391b0584dce44e7ea25190bbc38f2fc" @@ -3446,6 +3497,11 @@ dependencies: "@types/sizzle" "*" +"@types/json-schema@^7.0.11", "@types/json-schema@^7.0.6": + version "7.0.13" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" + integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== + "@types/json-schema@^7.0.9": version "7.0.12" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" @@ -3501,6 +3557,11 @@ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.195.tgz#bafc975b252eb6cea78882ce8a7b6bf22a6de632" integrity sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg== +"@types/lodash@^4.14.182": + version "4.14.199" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.199.tgz#c3edb5650149d847a277a8961a7ad360c474e9bf" + integrity sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg== + "@types/markdown-it@^12.2.3": version "12.2.3" resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" @@ -3541,16 +3602,16 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== +"@types/minimatch@*", "@types/minimatch@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + "@types/minimatch@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== -"@types/minimatch@^5.1.2": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" - integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== - "@types/minimist@^1.2.0", "@types/minimist@^1.2.2": version "1.2.2" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" @@ -3624,6 +3685,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/prettier@^2.6.1": + version "2.7.3" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" + integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== + "@types/pretty-hrtime@^1.0.0": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/pretty-hrtime/-/pretty-hrtime-1.0.1.tgz#72a26101dc567b0d68fd956cf42314556e42d601" @@ -4078,6 +4144,13 @@ "@wdio/types" "7.30.2" p-iteration "^1.1.8" +"@web/config-loader@0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@web/config-loader/-/config-loader-0.1.3.tgz#8325ea54f75ef2ee7166783e64e66936db25bff7" + integrity sha512-XVKH79pk4d3EHRhofete8eAnqto1e8mCRAqPV00KLNFzCWSe8sWmLnqKCqkPNARC6nksMaGrATnA5sPDRllMpQ== + dependencies: + semver "^7.3.4" + "@whitespace/storybook-addon-html@^5.1.0": version "5.1.6" resolved "https://registry.yarnpkg.com/@whitespace/storybook-addon-html/-/storybook-addon-html-5.1.6.tgz#9813a40a3e71e4afcb49069788e1120423e083f6" @@ -4238,7 +4311,7 @@ ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.6: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: +ajv@^8.0.1, ajv@^8.12.0: version "8.12.0" resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== @@ -4321,6 +4394,11 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -4421,6 +4499,11 @@ array-back@^3.0.1, array-back@^3.1.0: resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0" integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q== +array-back@^6.1.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/array-back/-/array-back-6.2.2.tgz#f567d99e9af88a6d3d2f9dfcc21db6f9ba9fd157" + integrity sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw== + array-buffer-byte-length@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" @@ -4593,10 +4676,10 @@ axe-core@4.2.3: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.2.3.tgz#2a3afc332f0031b42f602f4a3de03c211ca98f72" integrity sha512-pXnVMfJKSIWU2Ml4JHP7pZEPIrgBO1Fd3WGx+fPBsS+KRGhE4vxooD8XBGWbQOIVSZsVK7pUDBBkCicNu80yzQ== -axios@^1.0.0, axios@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" - integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== +axios@^1.0.0, axios@^1.6.0: + version "1.6.2" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" + integrity sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A== dependencies: follow-redirects "^1.15.0" form-data "^4.0.0" @@ -4993,6 +5076,11 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-me-maybe@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" + integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -5242,18 +5330,18 @@ chrome-launcher@^0.15.0: is-wsl "^2.2.0" lighthouse-logger "^1.0.0" -chromedriver@117.0.3: - version "117.0.3" - resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-117.0.3.tgz#4a14cc992d572367b99b53c772adcc4c19078e1e" - integrity sha512-c2rk2eGK5zZFBJMdviUlAJfQEBuPNIKfal4+rTFVYAmrWbMPYAqPozB+rIkc1lDP/Ryw44lPiqKglrI01ILhTQ== +chromedriver@119.0.1: + version "119.0.1" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-119.0.1.tgz#064f3650790ccea055e9bfd95c600f5ea60295e9" + integrity sha512-lpCFFLaXPpvElTaUOWKdP74pFb/sJhWtWqMjn7Ju1YriWn8dT5JBk84BGXMPvZQs70WfCYWecxdMmwfIu1Mupg== dependencies: - "@testim/chrome-version" "^1.1.3" - axios "^1.4.0" - compare-versions "^6.0.0" + "@testim/chrome-version" "^1.1.4" + axios "^1.6.0" + compare-versions "^6.1.0" extract-zip "^2.0.1" https-proxy-agent "^5.0.1" proxy-from-env "^1.1.0" - tcp-port-used "^1.0.1" + tcp-port-used "^1.0.2" ci-info@^2.0.0: version "2.0.0" @@ -5282,6 +5370,17 @@ cli-boxes@^2.2.0: resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== +cli-color@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.3.tgz#73769ba969080629670f3f2ef69a4bf4e7cc1879" + integrity sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ== + dependencies: + d "^1.0.1" + es5-ext "^0.10.61" + es6-iterator "^2.0.3" + memoizee "^0.4.15" + timers-ext "^0.1.7" + cli-cursor@3.1.0, cli-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" @@ -5442,6 +5541,16 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" integrity sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw== +command-line-args@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.1.2.tgz#25908e573d2214bc23a8437e3df853b02dffa425" + integrity sha512-fytTsbndLbl+pPWtS0CxLV3BEWw9wJayB8NnU2cbQqVPsNdYezQeT+uIQv009m+GShnMNyuoBrRo8DTmuTfSCA== + dependencies: + array-back "^6.1.2" + find-replace "^3.0.0" + lodash.camelcase "^4.3.0" + typical "^4.0.0" + command-line-args@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e" @@ -5467,6 +5576,16 @@ commander@^8.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +comment-parser@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.2.4.tgz#489f3ee55dfd184a6e4bffb31baba284453cb760" + integrity sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw== + +comment-parser@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.0.tgz#0f8c560f59698193854f12884c20c0e39a26d32c" + integrity sha512-QLyTNiZ2KDOibvFPlZ6ZngVsZ/0gYnE6uTXi5aoDg8ed3AkJAz4sEje3Y8a29hQ1s6A99MZXe47fLAXQ1rTqaw== + common-ancestor-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz#4f7d2d1394d91b7abdf51871c62f71eadb0182a7" @@ -5490,7 +5609,7 @@ compare-func@^2.0.0: array-ify "^1.0.0" dot-prop "^5.1.0" -compare-versions@^6.0.0: +compare-versions@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== @@ -5993,6 +6112,19 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" +custom-elements-manifest@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/custom-elements-manifest/-/custom-elements-manifest-1.0.0.tgz#b35c2129076a1dc9f95d720c6f7b5b71a857274b" + integrity sha512-j59k0ExGCKA8T6Mzaq+7axc+KVHwpEphEERU7VZ99260npu/p/9kd+Db+I3cGKxHkM5y6q5gnlXn00mzRQkX2A== + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + dargs@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" @@ -6015,6 +6147,11 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +debounce@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + debug@2.6.9, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -6574,11 +6711,47 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +es5-ext@^0.10.35, es5-ext@^0.10.46, es5-ext@^0.10.50, es5-ext@^0.10.53, es5-ext@^0.10.61, es5-ext@~0.10.14, es5-ext@~0.10.2, es5-ext@~0.10.46: + version "0.10.62" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + es6-object-assign@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c" integrity sha512-MEl9uirslVwqQU369iHNWZXsI8yaZYGg/D65aOgZkeyFJwHYSxilf7rQzXKI7DdDuBPrBXbfk3sl9hJhmd5AUw== +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +es6-weak-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.3.tgz#b6da1f16cc2cc0d9be43e6bdbfc5e7dfcdf31d53" + integrity sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA== + dependencies: + d "1" + es5-ext "^0.10.46" + es6-iterator "^2.0.3" + es6-symbol "^3.1.1" + esbuild-plugin-alias@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/esbuild-plugin-alias/-/esbuild-plugin-alias-0.2.1.tgz#45a86cb941e20e7c2bc68a2bea53562172494fcb" @@ -6863,6 +7036,14 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +event-emitter@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + integrity sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA== + dependencies: + d "1" + es5-ext "~0.10.14" + event-stream@=3.3.4: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" @@ -7010,6 +7191,13 @@ express@^4.14.0, express@^4.17.3: utils-merge "1.0.1" vary "~1.1.2" +ext@^1.1.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -7066,6 +7254,17 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^3.1.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + fast-glob@^3.2.7, fast-glob@^3.2.9, fast-glob@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.0.tgz#7c40cb491e1e2ed5664749e87bfb516dbe8727c0" @@ -7530,6 +7729,11 @@ get-stdin@^4.0.1: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" integrity sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw== +get-stdin@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" + integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== + get-stdin@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" @@ -7653,6 +7857,13 @@ glob-parent@6.0.2, glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" +glob-promise@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-4.2.2.tgz#15f44bcba0e14219cd93af36da6bb905ff007877" + integrity sha512-xcUzJ8NWN5bktoTIX7eOclO1Npxd/dyVqUJxlLIDasT4C7KZyqlPIwkdJ0Ypiy3p2ZKahTjK4M9uC3sNSfNMzw== + dependencies: + "@types/glob" "^7.1.3" + glob-promise@^6.0.2: version "6.0.3" resolved "https://registry.yarnpkg.com/glob-promise/-/glob-promise-6.0.3.tgz#e6b3ab02d350b3f4b3e15b57e4485986e41ba2fe" @@ -7778,6 +7989,18 @@ globalthis@^1.0.3: dependencies: define-properties "^1.1.3" +globby@11.0.4: + version "11.0.4" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globby@11.1.0, globby@^11.0.1, globby@^11.0.2, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -8161,7 +8384,7 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.0.4, ignore@^5.1.9, ignore@^5.2.0, ignore@^5.2.4: +ignore@^5.0.4, ignore@^5.1.4, ignore@^5.1.9, ignore@^5.2.0, ignore@^5.2.4: version "5.2.4" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== @@ -8595,6 +8818,11 @@ is-port-reachable@^3.1.0: resolved "https://registry.yarnpkg.com/is-port-reachable/-/is-port-reachable-3.1.0.tgz#f6668d3bca9c36b07f737c48a8f875ab0653cd2b" integrity sha512-vjc0SSRNZ32s9SbZBzGaiP6YVB+xglLShhgZD/FHMZUXBvQWaV9CtzgeVhjccFJrI6RAMV+LX7NYxueW/A8W5A== +is-promise@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" + integrity sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -9027,6 +9255,26 @@ json-parse-even-better-errors@^3.0.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz#2cb2ee33069a78870a0c7e3da560026b89669cf7" integrity sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA== +json-schema-to-typescript@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/json-schema-to-typescript/-/json-schema-to-typescript-13.1.1.tgz#8d1b28f93530d3b57730ee7272eec8e4400238e9" + integrity sha512-F3CYhtA7F3yPbb8vF7sFchk/2dnr1/yTKf8RcvoNpjnh67ZS/ZMH1ElLt5KHAtf2/bymiejLQQszszPWEeTdSw== + dependencies: + "@bcherny/json-schema-ref-parser" "10.0.5-fork" + "@types/json-schema" "^7.0.11" + "@types/lodash" "^4.14.182" + "@types/prettier" "^2.6.1" + cli-color "^2.0.2" + get-stdin "^8.0.0" + glob "^7.1.6" + glob-promise "^4.2.2" + is-glob "^4.0.3" + lodash "^4.17.21" + minimist "^1.2.6" + mkdirp "^1.0.4" + mz "^2.7.0" + prettier "^2.6.2" + json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" @@ -9643,6 +9891,13 @@ lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.0.0.tgz#b9e2a6a72a129d81ab317202d93c7691df727e61" integrity sha512-svTf/fzsKHffP42sujkO/Rjs37BCIsQVRCeNYIm9WN8rgT7ffoUnRtZCqU+6BqcSBdv8gwJeTz8knJpgACeQMw== +lru-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + integrity sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ== + dependencies: + es5-ext "~0.10.2" + magic-string@^0.27.0: version "0.27.0" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.27.0.tgz#e4a3413b4bab6d98d2becffd48b4a257effdbbf3" @@ -9937,6 +10192,20 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== +memoizee@^0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.15.tgz#e6f3d2da863f318d02225391829a6c5956555b72" + integrity sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ== + dependencies: + d "^1.0.1" + es5-ext "^0.10.53" + es6-weak-map "^2.0.3" + event-emitter "^0.3.5" + is-promise "^2.2.2" + lru-queue "^0.1.0" + next-tick "^1.1.0" + timers-ext "^0.1.7" + memoizerific@^1.11.3: version "1.11.3" resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" @@ -10618,6 +10887,15 @@ mute-stream@0.0.8, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mz@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + nanoid@3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" @@ -10648,6 +10926,11 @@ neo-async@^2.5.0, neo-async@^2.6.0: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +next-tick@1, next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -11950,7 +12233,7 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA== -prettier@^2.8.0, prettier@^2.8.1: +prettier@^2.6.2, prettier@^2.8.0, prettier@^2.8.1: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -13659,7 +13942,7 @@ tar@^6.1.11, tar@^6.1.13, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -tcp-port-used@^1.0.1: +tcp-port-used@^1.0.1, tcp-port-used@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/tcp-port-used/-/tcp-port-used-1.0.2.tgz#9652b7436eb1f4cfae111c79b558a25769f6faea" integrity sha512-l7ar8lLUD3XS1V2lfoJlCBaeoaWo/2xfYt81hM7VlvR4RrMVFqfmzfhLVk40hAb368uitje5gPtBRL1m/DGvLA== @@ -13742,6 +14025,20 @@ thenby@^1.3.4: resolved "https://registry.yarnpkg.com/thenby/-/thenby-1.3.4.tgz#81581f6e1bb324c6dedeae9bfc28e59b1a2201cc" integrity sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + third-party-web@^0.12.4: version "0.12.7" resolved "https://registry.yarnpkg.com/third-party-web/-/third-party-web-0.12.7.tgz#64445702379abf1a29066d636a965173e4e423c6" @@ -13777,6 +14074,14 @@ timed-out@4.0.1: resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== +timers-ext@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" + integrity sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ== + dependencies: + es5-ext "~0.10.46" + next-tick "1" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -13982,6 +14287,16 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + typed-array-buffer@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" @@ -14038,6 +14353,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript@~4.3.2: + version "4.3.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" + integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"