Skip to content

Commit

Permalink
Angular | Autogen: Adding support for standalone components
Browse files Browse the repository at this point in the history
  • Loading branch information
reb-dev committed Apr 20, 2024
1 parent 015655d commit b9683b2
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 122 deletions.
42 changes: 30 additions & 12 deletions packages/angular/autogen/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,74 @@ function getJSDocComments (jsdocStringArray: string[]): string {
}).join('\n')
}

function checkGeneric (type: string, generics?: GenericParameter[]): string {
// Override the default generic with specified type from generics array
const isFound = type.search(/[<|\s](Datum)>/)
const isValid = generics?.find(t => t.name === 'Datum')
if (isFound !== -1 && !isValid) {
return `${type.slice(0, isFound + 1)}${generics[0].name}${type.slice(isFound + 6)}`
}
return type
}

export function getComponentCode (
componentName: string,
generics: GenericParameter[],
configProps: ConfigProperty[],
provide: string,
importStatements: { source: string; elements: string[] }[],
dataType = 'any',
kebabCaseName?: string
kebabCaseName?: string,
isStandAlone = false,
styles = []
): string {
const genericsStr = generics ? `<${generics?.map(g => g.name).join(', ')}>` : ''
const genericsDefStr = generics
? `<${generics?.map(g => g.name + (g.extends ? ` extends ${g.extends}` : '') + (g.default ? ` = ${g.default}` : '')).join(', ')}>`
: ''
const decoratorProps = isStandAlone ? `template: '<div #container class="${kebabCaseName ?? kebabCase(componentName)}-container"></div>',
styles: ['.${kebabCaseName ?? kebabCase(componentName)}-container { ${styles?.join('; ')} }']`
: 'template: \'\''
const constructorArgs = isStandAlone
? `this.containerRef.nativeElement, this.getConfig()${dataType ? ', this.data' : ''}`
: 'this.getConfig()'
// Override the default generic with specified type from generics array
return `// !!! This code was automatically generated. You should not change it !!!
import { Component, AfterViewInit, Input, SimpleChanges } from '@angular/core'
import { Component, AfterViewInit, Input, SimpleChanges${isStandAlone ? ', ViewChild, ElementRef' : ''} } from '@angular/core'
${importStatements.map(s => `import { ${s.elements.join(', ')} } from '${s.source}'`).join('\n')}
import { ${provide} } from '../../core'
@Component({
selector: 'vis-${kebabCaseName ?? kebabCase(componentName)}',
template: '',
${decoratorProps},
// eslint-disable-next-line no-use-before-define
providers: [{ provide: ${provide}, useExisting: Vis${componentName}Component }],
})
export class Vis${componentName}Component${genericsDefStr} implements ${componentName}ConfigInterface${genericsStr}, AfterViewInit {
${isStandAlone ? '@ViewChild(\'container\', { static: false }) containerRef: ElementRef' : ''}
${
configProps
.map((p: ConfigProperty) => `
${getJSDocComments(p.doc ?? [])}
@Input() ${p.name}${p.required ? '' : '?'}: ${p.type}`)
@Input() ${p.name}${p.required ? '' : '?'}: ${checkGeneric(p.type, generics)}`)
.join('\n')
}
${dataType ? `@Input() data: ${dataType}` : ''}
${dataType ? `@Input() data: ${dataType}\n` : ''}
component: ${componentName}${genericsStr} | undefined
public componentContainer: ContainerCore | undefined
${isStandAlone ? '' : 'public componentContainer: ContainerCore | undefined\n'}
ngAfterViewInit (): void {
this.component = new ${componentName}${genericsStr}(this.getConfig())
this.component = new ${componentName}${genericsStr}(${constructorArgs})
${dataType ? `
if (this.data) {
this.component.setData(this.data)
this.componentContainer?.render()
${isStandAlone ? '' : 'this.componentContainer?.render()'}
}` : ''}
}
ngOnChanges (changes: SimpleChanges): void {
${dataType ? 'if (changes.data) { this.component?.setData(this.data) }' : ''}
this.component?.setConfig(this.getConfig())
this.componentContainer?.render()
this.component?.${componentName === 'BulletLegend' ? 'update' : 'setConfig'}(this.getConfig())
${isStandAlone ? '' : 'this.componentContainer?.render()'}
}
private getConfig (): ${componentName}ConfigInterface${genericsStr} {
Expand Down
11 changes: 6 additions & 5 deletions packages/angular/autogen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,11 @@ import { getImportStatements, kebabCase, getConfigSummary } from '@unovis/shared
import { getComponentCode } from './component'
import { getModuleCode } from './module'

const skipProperties = ['width', 'height']
const components = getComponentList() as AngularComponentInput[]

for (const component of components) {
const { configProperties, configInterfaceMembers, generics, statements } = getConfigSummary(component, skipProperties, false)
const importStatements = getImportStatements(component.name, statements, configInterfaceMembers, generics, ['ContainerCore'])
const { configProperties, configInterfaceMembers, generics, statements } = getConfigSummary(component, [], false)
const importStatements = getImportStatements(component.name, statements, configInterfaceMembers, generics, component.isStandAlone ? [] : ['ContainerCore'])

const componentCode = getComponentCode(
component.name,
Expand All @@ -28,12 +27,14 @@ for (const component of components) {
component.angularProvide,
importStatements,
component.dataType,
component.kebabCaseName
component.kebabCaseName,
component.isStandAlone,
component.angularStyles
)
const moduleCode = getModuleCode(component.name, component.kebabCaseName)

const nameKebabCase = component.kebabCaseName ?? kebabCase(component.name)
const pathComponentBase = `src/components/${nameKebabCase}`
const pathComponentBase = `src/${component.isStandAlone ? 'html-' : ''}components/${nameKebabCase}`
const pathComponent = `${pathComponentBase}/${nameKebabCase}.component.ts`
const pathModule = `${pathComponentBase}/${nameKebabCase}.module.ts`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class VisNestedDonutComponent<Datum> implements NestedDonutConfigInterfac
/** Direction of hierarchy flow from root to leaf.
* `NestedDonutDirection.Inwards` starts from the outer most radius and works towards center
* `NestedDonutDirection.Outwards` starts from the inner most radius the consecutive layers outward.
* Default: `NestedDonutDirection.Inwards` */
* Default: `NestedDonutDirection.Inwards` */
@Input() direction?: NestedDonutDirection | string


Expand All @@ -105,7 +105,12 @@ export class VisNestedDonutComponent<Datum> implements NestedDonutConfigInterfac
/** Array of accessor functions to defined the nested groups */
@Input() layers: StringAccessor<Datum>[]


/** Configuration properties for individual layers. Accepts an accessor or constant of type:
* {
* backgroundColor?: string;
* labelAlignment?: NestedDonutSegmentLabelAlignment;
* width?: number | string;
* } */
@Input() layerSettings?: GenericAccessor<NestedDonutLayerSettings, number>


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,6 @@ export class VisTooltipComponent implements TooltipConfigInterface, AfterViewIni
[attr: string]: string | number | boolean;
}


component: Tooltip | undefined
public componentContainer: ContainerCore | undefined

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// !!! This code was automatically generated. You should not change it !!!
import { Component, AfterViewInit, Input, SimpleChanges, ViewChild, ElementRef } from '@angular/core'
import { BulletLegend, BulletLegendConfigInterface, BulletLegendItemInterface, BulletShape, GenericAccessor } from '@unovis/ts'
import { BulletLegend, BulletLegendConfigInterface, BulletLegendItemInterface, GenericAccessor, BulletShape } from '@unovis/ts'
import { VisGenericComponent } from '../../core'

@Component({
selector: 'vis-bullet-legend',
template: '<div #container class="bullet-legend-container"></div>',
styles: ['.bullet-legend-container { }'],
// eslint-disable-next-line no-use-before-define
providers: [{ provide: VisGenericComponent, useExisting: VisBulletLegendComponent }],
})
Expand All @@ -14,14 +16,15 @@ export class VisBulletLegendComponent implements BulletLegendConfigInterface, Af
/** Legend items. Array of `BulletLegendItemInterface`:
* ```
* {
* name: string | number;
* color?: string;
* inactive?: boolean;
* hidden?: boolean;
* pointer?: boolean;
* name: string | number;
* color?: string;
* shape?: BulletShape;
* inactive?: boolean;
* hidden?: boolean;
* pointer?: boolean;
* }
* ```
* Default: `[]` */
* Default: `[]` */
@Input() items: BulletLegendItemInterface[]

/** Apply a specific class to the labels. Default: `''` */
Expand All @@ -36,7 +39,7 @@ export class VisBulletLegendComponent implements BulletLegendConfigInterface, Af
/** Label text (<span> element) max-width CSS property. Default: `null` */
@Input() labelMaxWidth?: string | null

/** Bullet circle size, mapped to the width and height CSS properties. Default: `null` */
/** Bullet shape size, mapped to the width and height CSS properties. Default: `null` */
@Input() bulletSize?: string | null

/** Bullet shape enum value or accessor function. Default: `d => d.shape ?? BulletShape.Circle */
Expand All @@ -53,8 +56,8 @@ export class VisBulletLegendComponent implements BulletLegendConfigInterface, Af
}

private getConfig (): BulletLegendConfigInterface {
const { items, labelClassName, onLegendItemClick, labelFontSize, labelMaxWidth, bulletSize } = this
const config = { items, labelClassName, onLegendItemClick, labelFontSize, labelMaxWidth, bulletSize }
const { items, labelClassName, onLegendItemClick, labelFontSize, labelMaxWidth, bulletSize, bulletShape } = this
const config = { items, labelClassName, onLegendItemClick, labelFontSize, labelMaxWidth, bulletSize, bulletShape }
const keys = Object.keys(config) as (keyof BulletLegendConfigInterface)[]
keys.forEach(key => { if (config[key] === undefined) delete config[key] })

Expand Down
Loading

0 comments on commit b9683b2

Please sign in to comment.