11/* eslint-disable @typescript-eslint/no-var-requires */
2-
3- //TODO:
4- console . warn (
5- '----------------------\nCurrently there are two tag-names missing or faulty: "ui5-notification-overflow-action" and "ui5-timeline-item"\nThese have to be adjusted manually!\n----------------------'
6- ) ;
7-
8- // To only create a single component, replace "false" with the component (module) name
9- // or execute the following command: "yarn create-webcomponents-wrapper [name]"
10- const CREATE_SINGLE_COMPONENT = process . argv [ 2 ] || false ;
11-
12- const EXCLUDE_LIST = [ 'NotificationListItem' ] ;
13-
142import mainWebComponentsSpec from '@ui5/webcomponents/dist/api.json' ;
153import fioriWebComponentsSpec from '@ui5/webcomponents-fiori/dist/api.json' ;
164import dedent from 'dedent' ;
@@ -19,6 +7,19 @@ import prettierConfigRaw from '../../../prettier.config.cjs';
197import path from 'path' ;
208import PATHS from '../../../config/paths.js' ;
219import fs from 'fs' ;
10+ import TurndownService from 'turndown' ;
11+
12+ const turndownService = new TurndownService ( {
13+ headingStyle : 'atx' ,
14+ codeBlockStyle : 'fenced'
15+ } ) ;
16+ turndownService . keep ( [ 'ui5-link' ] ) ;
17+
18+ // To only create a single component, replace "false" with the component (module) name
19+ // or execute the following command: "yarn create-webcomponents-wrapper [name]"
20+ const CREATE_SINGLE_COMPONENT = process . argv [ 2 ] || false ;
21+
22+ const EXCLUDE_LIST = [ 'NotificationListItem' ] ;
2223
2324const prettierConfig = {
2425 ...prettierConfigRaw ,
@@ -102,26 +103,44 @@ COMPONENTS_WITHOUT_DEMOS.add('SideNavigationSubItem');
102103COMPONENTS_WITHOUT_DEMOS . add ( 'SuggestionItem' ) ;
103104COMPONENTS_WITHOUT_DEMOS . add ( 'UploadCollectionItem' ) ;
104105COMPONENTS_WITHOUT_DEMOS . add ( 'NotificationOverflowAction' ) ;
106+ COMPONENTS_WITHOUT_DEMOS . add ( 'WizardStep' ) ;
105107
106108const componentsFromFioriPackage = new Set ( fioriWebComponentsSpec . symbols . map ( ( componentSpec ) => componentSpec . module ) ) ;
107109
110+ const allWebComponents = [
111+ ...mainWebComponentsSpec . symbols . filter ( ( spec ) => ! spec . module . startsWith ( 'types/' ) ) ,
112+ ...fioriWebComponentsSpec . symbols . filter ( ( spec ) => ! spec . module . startsWith ( 'types/' ) )
113+ ] ;
114+
115+ const htmlTagToModuleNameMap = new Map ( ) ;
116+ for ( const spec of allWebComponents ) {
117+ htmlTagToModuleNameMap . set ( spec . tagname , spec . module ) ;
118+ }
119+
108120const capitalizeFirstLetter = ( s ) => s . charAt ( 0 ) . toUpperCase ( ) + s . slice ( 1 ) ;
109121const snakeToCamel = ( str ) => str . replace ( / ( [ - _ ] \w ) / g, ( g ) => g [ 1 ] . toUpperCase ( ) ) ;
110122const filterNonPublicAttributes = ( prop ) =>
111123 prop . visibility === 'public' && prop . readonly !== 'true' && prop . static !== true ;
112124
113125const replaceTagNameWithModuleName = ( description ) => {
126+ let parsedDescription = description . replace ( / ( u i 5 - [ \w - ] + ) / g, ( fullMatch , tag , ...args ) => {
127+ if ( tag === 'ui5-link' ) return tag ;
128+ return htmlTagToModuleNameMap . get ( tag ) ;
129+ } ) ;
130+
131+ parsedDescription = parsedDescription . replace ( / ` u i 5 - l i n k / g, `\`${ htmlTagToModuleNameMap . get ( 'ui5-link' ) } ` ) ;
132+
114133 // replace all tag occurrences in description with module name
115- [ ...description . matchAll ( new RegExp ( `<code>ui5-` , 'g' ) ) ] . forEach ( ( ) => {
134+ [ ...parsedDescription . matchAll ( new RegExp ( `<code>ui5-` , 'g' ) ) ] . forEach ( ( ) => {
116135 const start = description . indexOf ( `<code>ui5-` ) + 6 ;
117136 const end = description . indexOf ( `</code>` , start ) ;
118137 const tagName = description . slice ( start , end ) ;
119- const webComponentWithTagName = allWebComponents . find ( ( item ) => item . tagname === tagName ) ;
120- if ( webComponentWithTagName ) {
121- description = description . replace ( webComponentWithTagName . tagname , webComponentWithTagName . module ) ;
138+ if ( htmlTagToModuleNameMap . has ( tagName ) ) {
139+ description = description . replace ( tagName , htmlTagToModuleNameMap . get ( tagName ) ) ;
122140 }
123141 } ) ;
124- return description ;
142+
143+ return parsedDescription ;
125144} ;
126145
127146const getTypeScriptTypeForProperty = ( property ) => {
@@ -407,31 +426,45 @@ const createWebComponentWrapper = (
407426 }
408427 let componentDescription ;
409428 try {
410- componentDescription = prettier
411- . format ( description , {
412- ...prettierConfigRaw ,
413- parser : 'html'
414- } )
415- . replace ( / \s \s + / g, ' ' ) ;
429+ componentDescription = turndownService . turndown ( description ) . replace ( / \n / g, '\n * ' ) ;
416430 } catch ( e ) {
417431 console . warn (
418432 `----------------------\nHeader description of ${ name } couldn't be generated. \nThere is probably a syntax error in the associated description that can't be fixed automatically.\n----------------------`
419433 ) ;
420434 componentDescription = '' ;
421435 }
436+
437+ const regularImports = importStatements
438+ . filter ( ( imp ) => ! imp . includes ( "from 'react'" ) )
439+ . sort ( ( a , b ) => {
440+ const importNameA = / i m p o r t \{ ( \w + ) \} / . exec ( a ) [ 1 ] ;
441+ const importNameB = / i m p o r t \{ ( \w + ) \} / . exec ( b ) [ 1 ] ;
442+ return importNameA . localeCompare ( importNameB ) ;
443+ } ) ;
444+ const reactImports = [
445+ 'FC' ,
446+ ...importStatements
447+ . filter ( ( imp ) => imp . includes ( "from 'react'" ) )
448+ . map ( ( imp ) => {
449+ const match = / i m p o r t \{ ( \w + ) \} / . exec ( imp ) ;
450+ return match [ 1 ] ;
451+ } )
452+ ] . sort ( ( a , b ) => a . localeCompare ( b ) ) ;
453+
422454 return prettier . format (
423455 `
456+ ${ regularImports . join ( '\n' ) }
424457 import { withWebComponent, WithWebComponentPropTypes } from '@ui5/webcomponents-react/lib/withWebComponent';
425458 import '@ui5/webcomponents${ componentsFromFioriPackage . has ( name ) ? '-fiori' : '' } /dist/${ name } ';
426- import { FC } from 'react';
427- ${ importStatements . join ( '\n' ) }
459+ import { ${ reactImports . join ( ', ' ) } } from 'react';
428460
429461 export interface ${ name } PropTypes extends ${ tsExtendsStatement } {
430462 ${ types . join ( '\n' ) }
431463 }
432464
433465 /**
434466 * ${ componentDescription }
467+ *
435468 * <a href="https://sap.github.io/ui5-webcomponents/playground/components/${ name } " target="_blank">UI5 Web Components Playground</a>
436469 */
437470 const ${ name } : FC<${ name } PropTypes> = withWebComponent<${ name } PropTypes>(
@@ -494,7 +527,7 @@ const createWebComponentDemo = (componentSpec, componentProps, description) => {
494527 enumImports . push ( prop . importStatement ) ;
495528 }
496529 if ( componentSpec . module === 'Icon' && prop . name === 'name' ) {
497- enumImports . push ( `import "@ui5/webcomponents-icons/dist/icons/ employee.js";` ) ;
530+ enumImports . push ( `import "@ui5/webcomponents-icons/dist/employee.js";` ) ;
498531 args . push ( `name: 'employee'` ) ;
499532 }
500533 if ( prop . name === 'primaryCalendarType' ) {
@@ -516,7 +549,7 @@ const createWebComponentDemo = (componentSpec, componentProps, description) => {
516549 customArgTypes . push ( `children: {control: {disable:true}}` ) ;
517550 }
518551 } else if ( prop . name === 'icon' ) {
519- enumImports . push ( `import "@ui5/webcomponents-icons/dist/icons/ employee.js";` ) ;
552+ enumImports . push ( `import "@ui5/webcomponents-icons/dist/employee.js";` ) ;
520553 enumImports . push ( `import { Icon } from '@ui5/webcomponents-react/lib/Icon';` ) ;
521554 if ( prop . tsType === 'string' ) {
522555 args . push ( `icon: 'employee'` ) ;
@@ -613,11 +646,6 @@ const createWebComponentDemo = (componentSpec, componentProps, description) => {
613646 ) } ${ formattedDescription } `;
614647} ;
615648
616- const allWebComponents = [
617- ...mainWebComponentsSpec . symbols . filter ( ( spec ) => ! spec . module . startsWith ( 'types/' ) ) ,
618- ...fioriWebComponentsSpec . symbols . filter ( ( spec ) => ! spec . module . startsWith ( 'types/' ) )
619- ] ;
620-
621649const assignComponentPropertiesToMaps = ( componentSpec , { properties, slots, events } ) => {
622650 ( componentSpec . properties || [ ] ) . forEach ( ( prop ) => {
623651 if ( ! properties . has ( prop . name ) ) {
@@ -699,10 +727,9 @@ resolvedWebComponents.forEach((componentSpec) => {
699727 if ( ! componentSpec . tagname ) {
700728 return property . description || '' ;
701729 }
702- let formattedDescription = ( property . description || '' )
703- . replace ( / \n \n < b r > < b r > / g, '<br/><br/>\n *\n * ' )
704- . replace ( / \n \n / g, '<br/><br/>\n *\n * ' )
705- . replace ( new RegExp ( componentSpec . tagname , 'g' ) , `${ componentSpec . module } ` ) ;
730+ let formattedDescription = turndownService
731+ . turndown ( ( property . description || '' ) . trim ( ) )
732+ . replace ( / \n / g, '\n * ' ) ;
706733
707734 const customDescriptionReplace = CUSTOM_DESCRIPTION_REPLACE [ componentSpec . module ] ;
708735 if ( customDescriptionReplace && customDescriptionReplace [ property . name ] ) {
@@ -746,7 +773,9 @@ resolvedWebComponents.forEach((componentSpec) => {
746773 importStatements . push ( ...eventParameters . importStatements ) ;
747774 propTypes . push ( dedent `
748775 /**
749- * ${ replaceTagNameWithModuleName ( eventSpec . description ) }
776+ * ${ replaceTagNameWithModuleName (
777+ turndownService . turndown ( ( eventSpec . description || '' ) . trim ( ) ) . replace ( / \n / g, '\n * ' )
778+ ) }
750779 */
751780 on${ capitalizeFirstLetter ( snakeToCamel ( eventSpec . name ) ) } ?: ${ eventParameters . tsType } ;
752781 ` ) ;
0 commit comments