Git Product home page Git Product logo

devextreme-renovation's Introduction

Devextreme Generators

This version are compatible with latest version of DevExtreme

Building

  • npm install
  • npm run build - build all generators and common modules (required for webpack, e2e tests and avoiding TS errors in generated tests)

Development

All changes should be merged in master branch. After that, these changes should be cherry-picked to the desired version of generator (branch releases/v*).

Testing

Unit tests

  • npm run test - run all test (unit and generated)
  • npm run test:with-replace - run all test and replace failed generated tests

e2e tests

Publishing

New version are published automatically by GitHub actions. For this, you need to create a special PR, prepared by script:

  • Checkout to version, which you will update (releases/v*)
  • Make sure that you have no release branch locally (could have stayed after previous release)
  • Run publish script based on changes since last release:
    • npm run publish:patch - fixes, improvements and refactor
    • npm run publish:minor - new features, probably after that you need to create a PR in DevExtreme repo (to use these features)
    • npm run publish:major - Breaking Changes or next version to continue development while code freeze
  • Make sure that all packages are updated. After that, changes will be committed to release branch and pushed
  • Go to GitHub and create a PR to right branch (releases/v*). Check name of PR, it should be v*.*.*

After merge, GihHub action will check that version updated in right branch and publish new version.

Using

Installing

Generators

These packages need to be installed for development

Generators:

  • npm install --save-dev @devextreme-generator/core
  • npm install --save-dev @devextreme-generator/angular
  • npm install --save-dev @devextreme-generator/inferno
  • npm install --save-dev @devextreme-generator/react
  • npm install --save-dev @devextreme-generator/vue

Declarations

  • npm install --save-dev @devextreme-generator/declarations

Build tools:

  • npm install --save-dev @devextreme-generator/build-helpers

Usage

With gulp

// gulpfile.js
const { generateComponents } = require('@devextreme-generator/build-helpers');
const generator = require('@devextreme-generator/inferno').default;
// const generator = require('@devextreme-generator/react').default;
// const generator = require('@devextreme-generator/angular').default;

// Optional set options
generator.options = {
    defaultOptionsModule: 'pathToYourModule',
    jqueryComponentRegistratorModule: 'path',
    jqueryBaseComponentModule: 'component_wrapper/component',
};

gulp.task('generate-components', function() {
    return gulp.src(SRC)
        .pipe(generateComponents(generator))
        .pipe(gulp.dest(DEST));
});

Generate component from file

const { compileCode } = require('@devextreme-generator/core');
const generator = require('@devextreme-generator/inferno').default;

const result = compileCode(generator, source, {
    path: path,
    dirname: dirname
});

With webpack

// webpack.config.js

module.exports = {
    // ...
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loaders: [
                    {
                        loader: 'babel-loader',
                    },
                    {
                        loader: '@devextreme-generator/build-helpers/dist/webpack-loader',
                        options: {
                            platform: 'inferno',
                            defaultOptionsModule: 'pathToYourModule',
                            jqueryComponentRegistratorModule: 'path',
                            jqueryBaseComponentModule: 'component_wrapper/component',
                            // ...
                            tsConfig: path.resolve('./inferno.tsconfig.json')
                        },
                    },
                ],
                exclude: ['/node_modules/'],
            },
            // ...
            ]
    },
    resolve: {
        extensions: ['.js', '.tsx', '.ts'],
    }
};

devextreme-renovation's People

Contributors

artem-kurchenko avatar bingorus avatar churkin avatar dependabot[bot] avatar dxvladislavvolkov avatar egaluza avatar eugeniykiyashko avatar ibat avatar ivanblinov2k17 avatar ksercs avatar lazylahtak avatar maximkudriavtsev avatar mikevitik avatar ovchinnikov avatar renovate[bot] avatar roman-simionov avatar selyankinfyodor avatar timbset avatar vconst avatar williamvinogradov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

devextreme-renovation's Issues

Angular Generator: empty ComponentBindings when props are exists

Get error when we have empty component binding, but use this.props in Effect:

@ComponentBindings()
class NumberBoxInput {
}

export default class NumberBox extends JSXComponent<NumberBoxInput> {
    @Ref()
    widgetRef!: HTMLDivElement;
    @Effect()
    setupWidget() {
        ($(this.widgetRef) as any).dxNumberBox(this.props as any);
    }
}

Get
TypeError: Cannot read property 'body' of undefined

In

internalStateDependency.forEach(name => {
    const setter = this.members.find(p => p.name === `_${name}`);
    setter.body.statements.push( /* ... */)
    //...
})

Can't pass method into jsx attribute

Declaration

function view(model: Widget) { 
    <div onClick={model.method1}></div>
}

@Component({
    view: view
})
export default class Widget extends JSXComponent<WidgetProps> {
    method1() { 
        return this.method2();
    }
}

React Generator: restAttributes works but application is compiled with errors

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

// view
function view(model: Widget) {
    return (
        <div {...model.restAttributes}>
        </div>
    );
}

App

 <Component
    style={{backgroundColor: "red"}}
 ></Component>

Additional Information

Property 'style' does not exist on type 'IntrinsicAttributes & ComponentPropsType & RefAttributes<...>'.

A version of the generator: 1.0.64

React Generator: Callback dependency should include dependency from other callback if the first one calls the second one

Declaration

export default class Widget extends JSXComponent<WidgetInput> {
    method1() { 
        return this.method2();
    }

    method2() { 
        return this.props.height;
    }
}

Result

const method1=useCallback(function method1(){
    return method2();
}, []);
const method2=useCallback(function method2(){
    return props.height;
}, [props.height]);

Expected Result

const method1=useCallback(function method1(){
    return method2();
}, [props.height]);
const method2=useCallback(function method2(){
    return props.height;
}, [props.height]);

Angular Generator: destructuring doesn't work sometimes

Declaration

export const viewFunction = ({ renderNavButtons, props }: PagerPageIndexSelector) => {
    const { rtlEnabled } = props;
    return (
        <Fragment>
            {renderNavButtons &&
            <PagerNavigationButton rtlEnabled={rtlEnabled} direction={'prev'} />}
            <Pages {...props}/>
            {renderNavButtons &&
            <PagerNavigationButton rtlEnabled={rtlEnabled} direction={'next'} />}
        </Fragment>);
};

Generated

PagerPageIndexSelector = __decorate([(0, _core.Component)({
  selector: "dx-pager-page-index-selector",
  template: "\n<dx-pager-navigation-button [rtlEnabled]=\"props.rtlEnabled\"\ndirection=\"prev\"\n*ngIf=\"__renderNavButtons\"></dx-pager-navigation-button>\n\n<dx-pages #_auto_ref_0></dx-pages>\n\n<dx-pager-navigation-button [rtlEnabled]=\"props.rtlEnabled\"\ndirection=\"next\"\n*ngIf=\"__renderNavButtons\"></dx-pager-navigation-button>\n"
})], PagerPageIndexSelector);
exports.default = PagerPageIndexSelector;

Error: props is undefined
image

The main problem in passing rtlEnabled property into PagerNavigationButton

AngularGenerator: map with destructorized object parameter parsed incorectly

Jsx

import { OneWay, JSXComponent, Component, ComponentBindings } from "../../../component_declaration/common";

function view(viewModel: Widget) { 
    return <div>
        {viewModel.props.items.map(({ p1, p2 }) => <div>{p1+p2}</div>)}
    </div>
}

@ComponentBindings()
export class WidgetProps { 
    @OneWay() items: Array<{p1: number, p2: number}> = []
}

@Component({
    view: view
})
export default class Widget extends JSXComponent<WidgetProps> {
}

Result

<div>
    <ng-container *ngFor="let {p1,p2} of items"><div >{{this.p1+this.p2}}</div></ng-container>
</div>

Expected Result

<div>
    <ng-container *ngFor="let item of items">
        <div>{{item.p1+item.p2}}</div>
    </ng-container>
</div>

Generator has incorrect createReturn API

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Current

createReturn(expression: Expression) {
    return new ReturnStatement(expression);
}

Expected

createReturn(expression?: Expression) {
    return new ReturnStatement(expression);
}

Additional Information

A version of the generator: 1.0.70

Add a way to tell effect to run only once or on every render

Current Behavior

Effects run only when its dependencies change.

Expected Behavior

Some scenarios require effect to run only once. Sometimes they should run on every render call.

Proposed Solution

  1. Run on dependencies change (list of dependencies is collected by generator)
    @Effect()

  2. Run only once on first render
    @Effect({ once: true })

  3. Run on every render
    @Effect({ always: true })

React Generator: Generator doesn't replace keyword `template` by `render` in some cases

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

export const viewFunction = () => (
  <div>
    <Button
      text="Use Template In"
      onClick={() => alert('Clicked')}
      icon="download"
      iconPosition="right"
      template={() => <div>Test</div>}
    />
  </div>
);

Current Generated File

React has render property in Button, but use template in this case

var viewFunction = exports.viewFunction = function viewFunction() {
  return _react2.default.createElement("div", null, _react2.default.createElement(_button2.default, {
    text: "Use Template In",
    onClick: function onClick() {
      return alert("Clicked");
    },
    icon: "download",
    iconPosition: "right",
    template: function template() {
      return _react2.default.createElement("div", null, "Test");
    }
  }));
};

Additional Information

A version of the generator: 1.0.61

Angular Generator: lost class in some components

Wrap some components/text into additional div

Angular
image

Info = __decorate([(0, _core.Component)({
  selector: "dx-info",
  template: "<div [class]=\"PAGER_INFO_CLASS\">{{__Text}}</div>"
})], Info);
exports.default = Info;

React
image

var viewFunction = exports.viewFunction = function viewFunction(_ref) {
  var Text = _ref.Text;
  return _react2.default.createElement("div", {
    className: PAGER_INFO_CLASS
  }, Text);
};

Angular Generator: doesn't work `template` property with other components

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

<Button
  text="Use Template In"
  icon="download"
  iconPosition="right"
  template={Button}
/>

Current Generated File

TestComponent = __decorate([(0, _core.Component)({
    selector: "dx-test-component",
    template: "<div >\n<dx-button text=\"Use Template In\"\nicon=\"download\"\niconPosition=\"right\"\n[template]=\"Button\"></dx-button>\n</div>"
  })], TestComponent);

Expected Generated File

One of possible generation:

TestComponent = __decorate([(0, _core.Component)({
    selector: "dx-test-component",
    template: "<div >\n<dx-button text=\"Use Template In\"\nicon=\"download\"\niconPosition=\"right\"\n[template]=\"Button\"></dx-button>\n</div><ng-template #Button let-text=\"text\" let-icon=\"icon\"><dx-button text={{text}} icon={{icon}}></dx-button></ng-template>"
  })], TestComponent);

Additional Information

A version of the generator: 1.0.61

`Maximum call stack size exceeded` occurs modules have cycle dependency

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

// module1.tsx
import "./module2"

// module2.tsx
import "./module1"

Additional Information

at Generator.generate (build/base-generator/index.js:1:88932)
at Object.compileCode (build/component-compiler.js:1:12155)
at Generator.createImportDeclaration (build/base-generator/index.js:1:73602)
at module.exports (eval at compileCode (build/component-compiler.js:1:12164), :32:6)

A version of the generator: 1.0.63

TypeError: Cannot read property 'toString' of undefined if empty JsxExpression

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@OneWay
<div>{/*comment*/}</div>

Additional Information

TypeError: Cannot read property 'toString' of undefined
    at JsxExpression.toString (/Users/romansimionov/work/DevExtreme/node_modules/devextreme-generator/base-generator/expressions/jsx.js:104:58)

A version of the generator: 1.0.64

Can't spread `props` in Angular template

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

export const viewFunction = ({ pageSizeSelectorProps, pageIndexSelectorProps, props }: Pager) => {
    return (<div className={PAGER_CLASS}>
        <PageSizeSelector {...pageSizeSelectorProps} />
        <div className={PAGER_PAGES_CLASS}>
            <Info {...props} />
            <PageIndexSelector {...pageIndexSelectorProps} />
        </div>
    </div>);
};

Current Generated File

Pager = __decorate([(0, _core.Component)({
  selector: "dx-pager",
  template: "<div [class]=\"'dx-pager'\">\n<dx-page-size-selector [isLargeDisplayMode]=\"__pageSizeSelectorProps.isLargeDisplayMode\"\n[pageSize]=\"__pageSizeSelectorProps.pageSize\"\n(pageSizeChanged)=\"__pageSizeSelectorProps.pageSizeChanged($event)\"\n[pageSizes]=\"__pageSizeSelectorProps.pageSizes\"></dx-page-size-selector>\n\n<div [class]=\"'dx-pages'\">\n<dx-info [infoTextMessageTemplate]=\"props.infoTextMessageTemplate\"\n[pageCount]=\"props.pageCount\"\n[pageIndex]=\"props.pageIndex\"\n[totalCount]=\"props.totalCount\"></dx-info>\n\n<dx-pager-page-index-selector [hasKnownLastPage]=\"__pageIndexSelectorProps.hasKnownLastPage\"\n[isLargeDisplayMode]=\"__pageIndexSelectorProps.isLargeDisplayMode\"\n[maxPagesCount]=\"__pageIndexSelectorProps.maxPagesCount\"\n[pageCount]=\"__pageIndexSelectorProps.pageCount\"\n[pageIndex]=\"__pageIndexSelectorProps.pageIndex\"\n(pageIndexChanged)=\"__pageIndexSelectorProps.pageIndexChanged($event)\"\n[pagesCountText]=\"__pageIndexSelectorProps.pagesCountText\"\n[rtlEnabled]=\"__pageIndexSelectorProps.rtlEnabled\"\n[showNavigationButtons]=\"__pageIndexSelectorProps.showNavigationButtons\"\n[totalCount]=\"__pageIndexSelectorProps.totalCount\"></dx-pager-page-index-selector>\n</div>\n</div>"
})], Pager);
exports.default = Pager;

Expected Generated File

Pager = __decorate([(0, _core.Component)({
  selector: "dx-pager",
  template: "<div [class]=\"'dx-pager'\">\n<dx-page-size-selector [isLargeDisplayMode]=\"__pageSizeSelectorProps.isLargeDisplayMode\"\n[pageSize]=\"__pageSizeSelectorProps.pageSize\"\n(pageSizeChanged)=\"__pageSizeSelectorProps.pageSizeChanged($event)\"\n[pageSizes]=\"__pageSizeSelectorProps.pageSizes\"></dx-page-size-selector>\n\n<div [class]=\"'dx-pages'\">\n<dx-info [infoTextMessageTemplate]=\"infoTextMessageTemplate\"\n[pageCount]=\"pageCount\"\n[pageIndex]=\"pageIndex\"\n[totalCount]=\"totalCount\"></dx-info>\n\n<dx-pager-page-index-selector [hasKnownLastPage]=\"__pageIndexSelectorProps.hasKnownLastPage\"\n[isLargeDisplayMode]=\"__pageIndexSelectorProps.isLargeDisplayMode\"\n[maxPagesCount]=\"__pageIndexSelectorProps.maxPagesCount\"\n[pageCount]=\"__pageIndexSelectorProps.pageCount\"\n[pageIndex]=\"__pageIndexSelectorProps.pageIndex\"\n(pageIndexChanged)=\"__pageIndexSelectorProps.pageIndexChanged($event)\"\n[pagesCountText]=\"__pageIndexSelectorProps.pagesCountText\"\n[rtlEnabled]=\"__pageIndexSelectorProps.rtlEnabled\"\n[showNavigationButtons]=\"__pageIndexSelectorProps.showNavigationButtons\"\n[totalCount]=\"__pageIndexSelectorProps.totalCount\"></dx-pager-page-index-selector>\n</div>\n</div>"
})], Pager);
exports.default = Pager;

Additional Information

A version of the generator: 1.0.56

Declaration Model doesn't extend external ts class

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

base-props.ts

export default class BaseProps {
 @OneWay() b: number = 100;
}
import BaseProps from './base-props'; // ts class file

widget.tsx
export class WidgetProps extends BaseProps {
    @OneWay() a?: number = 400;
}

Current Generated File

import BaseProps from './base-props'; // ts class file

export const WidgetProps = {
    ...BaseProps,
    a: 400,
};

Expected Generated File

export const WidgetProps = {
    b: 100,
    a: 400,
};

Additional Information

A version of the generator: 1.0.55

jQuery: API methods should return result

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@Method()
getHeight(p:number=10, p1: any): string { 
    return `${this.props.prop1} + ${this.props.prop2} + ${this.divRef.innerHTML} + ${p}`;
}

Current Generated File

getHeight(p:number=10, p1: any) {
    this.viewRef.current.getHeight(p, p1);
}

Expected Generated File

getHeight(p:number=10, p1: any) {
    return this.viewRef.current.getHeight(p, p1);
}

Additional Information

A version of the generator: 1.0.70

Can't export @ComponentBinding() class by default

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@ComponentBindings()
export default class BaseProps {}

Current Generated File

export default;
export BaseProps = {}

Expected Generated File

export default BaseProps = {}

Additional Information

A version of the generator: 1.0.57

Can't define component member with the same name as any prop name

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@ComponentBindings()
class WidgetInput { 
    @Event() onClick: (a:number) => null = () => null;
}

@Component({
    view: view
})
export default class Widget extends JSXComponent(WidgetInput) {
    onClick() { }
}

Current Generated File

export default {
    props: WidgetInput,
    methods: {
        onClick() {

        },
        __restAttributes() {
            return {}
        },
        props() {
            return {};
        }
    }
}

Expected Generated File

export default {
    props: WidgetInput,
    methods: {
        __onClick() {

        },
        __restAttributes() {
            return {}
        },
        props() {
            return { onClick: this.onClick };
        },
        onClick(...args) {
            this.$emit("on-click", ...args);
        }
    }
}

Additional Information

A version of the generator: 1.0.69

_this is undefined error occurs

Doesnt work because

export default class SelectBox extends JSXComponent<SelectBoxProps> {
    @Ref()
    widgetRef!: HTMLDivElement;
    @Effect()
    setupWidget() {
        // tslint:disable-next-line: no-unused-expression
        new dxSelectBox(this.widgetRef, {
            ...this.props as any,
            onValueChanged: (e) => {
                this.props.valueChange!(e.value);
            },
        });
    }
}

wrong generated code (I suppose props instead of _this.props )

    new _select_box2.default(widgetRef.current, _objectSpread({}, props, {
      onValueChanged: function onValueChanged(e) {
        _this.props.valueChange(e.value);
      }
    }));

Work properly

        const  { valueChange } = this.props;
        // tslint:disable-next-line: no-unused-expression
        new dxSelectBox(this.widgetRef, {
            ...this.props as any,
            onValueChanged: (e) => {
                valueChange!(e.value);
            },
        });
    }

Can't make method carrying

Declaration

    navigateToPrevPage = () => this.navigateToPage(this.props.rtlEnabled ? 'next' : 'prev');

    private navigateToPage(direction: 'next' | 'prev') {
        const canNavigate = this.canNavigateTo(this.props, direction);
        if (canNavigate) {
            this.props.pageIndexChange!(this.props.pageIndex! + this.getIncrement(direction));
        }
    }

Generator interprets navigateToPrevPage as InternalState Property

WA

navigateToPrevPage() {
   return this.navigateToPage(this.props.rtlEnabled ? 'next' : 'prev');
}

Generator doesn't apply `+=` or `-=` operators

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

export default class TestComp extends JSXComponent<TestCompProps> {
  counter = 123;

  @Effect()
  onLoadEffect() {
    this.counter += 1;
  }
}

Current Generated File

    const [__state_counter, __state_setCounter] = useState(123);

    useEffect(() => {
        __state_counter += 1;
    }, [__state_counter]);

Expected Generated File

    const [__state_counter, __state_setCounter] = useState(123);

    useEffect(() => {
        __state_setCounter(__state_counter + 1);
    }, [__state_counter]);

Additional Information

A version of the generator: X.X.X

Preact typescript compilation errors

Check what generator works wrong

  • Angular
  • React
  • Vue
  • Preact/jQuery

Steps to reproduce

Build pager in the main DevExtreme repository

Additional Information

js/renovation/pager/page-size-selector.p.tsx(11,89): error TS2322: Type '{ key: any; className: any; label: any; onClick: any; }' is not assignable to type 'LightButtonPropsType'.
  Property 'key' does not exist on type 'LightButtonPropsType'.
js/renovation/pager/pages-large.p.tsx(5,83): error TS2322: Type '{ key: any; index: any; selected: boolean; onClick: () => void; }' is not assignable to type 'PagePropsType'.
  Property 'key' does not exist on type 'PagePropsType'.
js/renovation/widget.p.tsx(8,32): error TS2307: Cannot find module '../events/utils'.
js/renovation/pager/page-size-selector.p.tsx(11,89): error TS2322: Type '{ key: any; className: any; label: any; onClick: any; }' is not assignable to type 'LightButtonPropsType'.
  Property 'key' does not exist on type 'LightButtonPropsType'.
js/renovation/pager/pages-large.p.tsx(5,83): error TS2322: Type '{ key: any; index: any; selected: boolean; onClick: () => void; }' is not assignable to type 'PagePropsType'.
  Property 'key' does not exist on type 'PagePropsType'.

A version of the generator: 1.0.72

Rename `default` slot

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Description

default slot should be renamed (default is keyword).
Possible variant: defaultSlot

A version of the generator: 1.0.73

Incorrect parsing parenthesis

Expression

function(){
    const {p} = this.props;
    ($(this.widgetRef) as any).dxNumberBox({})
}

Parses incorrectly

function(){
    const {p} = props($(this.widgetRef.current)).dxNumberBox({})
}

Meantime

$(this.widgetRef).dxNumberBox({})

Parses correctly

$(this.widgetRef.current).dxNumberBox({})

Type casting expression should be skipped in template

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

<div attr={value as number}>

Current Generated File

<div [attr]="value as number">

Expected Generated File

<div [attr]="value">

Additional Information

A version of the generator: 1.0.71

ts.createTypeOperatorNode is not a function

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

 type HTMLRefType = Record<keyof RefsType, HTMLElement>;

Additional Information

Can't use TypeOperatorNode expression

A version of the generator: 1.0.62

VueJS. Effects are not scheduled if state changed without virtual DOM modification

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Component watches for dependency change and schedule effect. But scheduled effect are called only on updated hook. So in the example below we never get effect called because we don't change Dom, we only update state.

Declaration File

export default class Effects extends JSXComponent<Props> {
    @InternalState() state1: number = 0;

    @Effect()
    someEffect() {
        console.log(this.state1);
    }
    
    onButtonClick() {
        this.state1 = this.state1 + 1;
    }
}

Current Generated File

export {
  watch: {
    state1: ["__schedule_setupData", "__schedule_alwaysEffect"]
  },
  someEffect() {
    console.log(this.state1);
  },
  onButtonClick() {
    this.state1 = this.state1 + 1;
  },
  __schedule_ someEffect() {
      this.__scheduleEffects[0] = () => {
        this.__destroyEffects[0] && this.__destroyEffects[0]();
        this.__destroyEffects[0] = this.someEffect();
      };
    }
  },
  created() {
    this.__destroyEffects = [];
    this.__scheduleEffects = [];
  },
  mounted() {
    this.__destroyEffects[0] = this.someEffect();
  },
  updated() {
    this.__scheduleEffects.forEach((_, i) => {
      this.__scheduleEffects[i] && this.__scheduleEffects[i]();
    });
  },
  destroyed() {
    this.__destroyEffects.forEach((_, i) => {
      this.__destroyEffects[i] && this.__destroyEffects[i]();
    });
    this.__destroyEffects = null;
  }
};

React Generator: required props are generated incorrectly

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@ComponentBindings()
export class LightButtonProps {
  @OneWay() keyboardContainerClassName!: string;
}

Current Generated File

export declare type LightButtonPropsType = {
    keyboardContainerClassName!: string
}
export const LightButtonProps: LightButtonPropsType = {

};

Expected Generated File

export declare type LightButtonPropsType = {
    keyboardContainerClassName: string
}
export const LightButtonProps: LightButtonPropsType = {
   
} as LightButtonPropsType;

Additional Information

A version of the generator: 1.0.60

Name collisions in generated components

Example

AngularGenerator Input

@ComponentBindings()
class Input { 
    @OneWay() prop1?: number;
}

Output

import {Input} from "@angular/core"
class Input  {
    @Input() prop1?:number;
}

Possible Solution

Generate a complex name for the imported modules

Example

import {Input as AngularCoreInput} from "@angular/core"

Ref can not be passed as prop to other components

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@Ref() divRef?: HTMLDivElement;

(<SomeComponent somePropForRef={viewModel.divRef} />)
@ComponentBindings()
class SomeProps {
  @OneWay() somePropForRef?: HTMLDivElement;
}

@Component()
class SomeComponent extends JSXElement<SomeProps> {
  @Effect()
  someEffect() {
    const html = this.props.somePropForRef?.outerHTML;
  }
}

Current Generated File

function SomeComponent(props) {
  useEffect(someEffect() {
    const html = props.somePropForRef?.outerHTML;
  }, [props.somePropForRef])
}

Expected Generated File

function SomeComponent(props) {
  useEffect(someEffect() {
    const html = props.somePropForRef?.current.outerHTML;
  }, [props.somePropForRef])
}

Angular Generator: unable to use functions that return components in viewFunction

function smallSelector(selectBoxProps) {
    return (<SelectBox {...selectBoxProps} />);
}

function largeSelector(pageSizesText: { className: string; click: () => void; text: string; }[]) {
    return pageSizesText.map(({ text, className }, key) => (
        <div key={key} className={className}>{text}</div>
    ));
}

export const viewFunction = ({ pageSizesText, selectBoxProps,
                               props: { isLargeDisplayMode } }: PageSizeSelector) => {

    // !!! Here is an error !!!
    const PageSizesComponent = isLargeDisplayMode ?
                largeSelector(pageSizesText) : smallSelector(selectBoxProps);

    return (
        <div className={PAGER_PAGE_SIZES_CLASS}>
            {PageSizesComponent}
        </div>);
};

Angular Generator ignores key attribute if map returns condition expression

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

items.map(item =>
        (item!==null?(<ListItem key={item.key} color={item.color || "red"} onClick={item.onClick} text={item.text} />): <div>empty</div>)
    );

Current Generated File

</ng-container><ng-container *ngFor="let item of __items;index as index">

Expected Generated File

</ng-container><ng-container *ngFor="let item of __items;index as index;trackBy: _trackBy___items_1">

Additional Information

A version of the generator: 1.0.72

Components do not support form input bindings

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@TwoWay() value: string = 'state';

Current Result

It's not possible to use model binding in Angular and Vue applications.

Vue

<my-component v-model="compValue"></my-component>

Angular

<my-component [(ngModel)]="compValue"></my-component>

Expected Result

Generated components should support model bindings in Angular and Vue.
All editors should support formControlName and ngModel binding. See current doc

Additional Info

https://vuejs.org/v2/guide/forms.html
https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components
https://vuejs.org/v2/guide/components-custom-events.html#Customizing-Component-v-model

https://angular.io/guide/reactive-forms
https://angular.io/guide/forms

Angular Generator: doesn't apply ng-if

The __renderNavButtons is false and passes into shownavigationbuttons correctly, but navigation buttons are rendered

export const viewFunction = ({ renderNavButtons, props }: PagerPageIndexSelector) => {
    const { rtlEnabled } = props;
    return (
        <Fragment>
            {renderNavButtons &&
            <PagerNavigationButton rtlEnabled={rtlEnabled} direction={'prev'} />}
            <Pages {...props}/>
            {renderNavButtons &&
            <PagerNavigationButton rtlEnabled={rtlEnabled} direction={'next'} />}
        </Fragment>);
};

export default class PagerPageIndexSelector extends JSXComponent<PagerPageIndexSelectorInput> {
    get renderNavButtons() {
        const
            { isLargeDisplayMode, showNavigationButtons } = this.props;
        return !isLargeDisplayMode || showNavigationButtons;
    }
}
PagerPageIndexSelector = __decorate([(0, _core.Component)({
  selector: "dx-pager-page-index-selector",
  template: "\n<dx-pager-navigation-button [rtlEnabled]=\"props.rtlEnabled\"\ndirection=\"prev\"\n*ngIf=\"__renderNavButtons\"></dx-pager-navigation-button>\n\n<dx-pages #_auto_ref_0></dx-pages>\n\n<dx-pager-navigation-button [rtlEnabled]=\"props.rtlEnabled\"\ndirection=\"next\"\n*ngIf=\"__renderNavButtons\"></dx-pager-navigation-button>\n"
})], PagerPageIndexSelector);
exports.default = PagerPageIndexSelector;

image

xxxRender (xxxTemplate) should work as render prop in React

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@Template() contentTemplate: any;

<div>
  {props.contentTemplate && (<props.contentTemplate {...props} />)}
<div>

Current Generated File

React.createElement('div', {}, 
  props.contentRender && React.createElement(props.contentRender, {props}))

Expected Generated File

React.createElement('div', {}, 
  props.contentRender && props.contentRender(props),
  props.contentComponent && React.createElement(props.contentComponent, {props}),
)

For every xxxTemplate prop we should add a xxxRender render prop and xxxComponent component prop.

Can't pass props in other component using spread

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

// view
<Info {...props} />
// component
get pageSizeSelectorProps(): PageSizeSelectorInput {
        return {
            isLargeDisplayMode: !this.props.lightModeEnabled,
            ...this.props as any,
        };
}

Current Generated File

//view
<Info v-bind="props" />
// component
 __pageSizeSelectorProps() {
      return { isLargeDisplayMode: !this.lightModeEnabled, ...{
        infoTextMessageTemplate: this.infoTextMessageTemplate,
        lightModeEnabled: this.lightModeEnabled,
        maxPagesCount: this.maxPagesCount,
        pageCount: this.pageCount,
        pageIndex:
          this.pageIndex !== undefined ? this.pageIndex : this.pageIndex_state,
        pagesCountText: this.pagesCountText,
        pageSize:
          this.pageSize !== undefined ? this.pageSize : this.pageSize_state,
        pageSizes: this.pageSizes,
        rtlEnabled: this.rtlEnabled,
        showNavigationButtons: this.showNavigationButtons,
        totalCount: this.totalCount,
        defaultPageIndex: this.defaultPageIndex,
        pageIndexChange: this.pageIndexChange,
        defaultPageSize: this.defaultPageSize,
        pageSizeChange: this.pageSizeChange
      } };
    },

Expected Generated File

//view
<Info v-bind="props()" />

__pageSizeSelectorProps() {
      return { isLargeDisplayMode: !this.lightModeEnabled, ...this.props() };
},

props() {
      return {
        infoTextMessageTemplate: this.infoTextMessageTemplate,
        lightModeEnabled: this.lightModeEnabled,
        maxPagesCount: this.maxPagesCount,
        pageCount: this.pageCount,
        pageIndex:
          this.pageIndex !== undefined ? this.pageIndex : this.pageIndex_state,
        pagesCountText: this.pagesCountText,
        pageSize:
          this.pageSize !== undefined ? this.pageSize : this.pageSize_state,
        pageSizes: this.pageSizes,
        rtlEnabled: this.rtlEnabled,
        showNavigationButtons: this.showNavigationButtons,
        totalCount: this.totalCount,
        pageIndexChange: this.pageIndexChange,
        pageSizeChange: this.pageSizeChange
      };
    },

Additional Information

A version of the generator: 1.0.63

Can't use implements for Component Bindings

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

export type TwoWayProps = {
    pageIndexChange?: (pageIndex: number) => void;
    pageSizeChange?: (pageSize: number) => void;
  };
  
  @ComponentBindings()
  export class PagerContentProps implements TwoWayProps {
    @Event() pageIndexChange!: (pageIndex: number) => void;
  
    @Event() pageSizeChange!: (pageSize: number) => void;
  }

Current Generated File

export type TwoWayProps = {
    pageIndexChange?: (pageIndex: number) => void,
    pageSizeChange?: (pageSize: number) => void
}
export declare type PagerContentPropsType = typeof TwoWayProps & {
    pageIndexChange: (pageIndex: number) => void;
    pageSizeChange: (pageSize: number) => void
}
export const PagerContentProps: PagerContentPropsType = {
    ...TwoWayProps
} as PagerContentPropsType;

Expected Generated File

export type TwoWayProps = {
    pageIndexChange?: (pageIndex: number) => void,
    pageSizeChange?: (pageSize: number) => void
}
export declare type PagerContentPropsType = {
    pageIndexChange: (pageIndex: number) => void;
    pageSizeChange: (pageSize: number) => void
}
export const PagerContentProps: PagerContentPropsType = {
} as PagerContentPropsType;

Additional Information

A version of the generator: 1.0.65

Can't make all props are required

Can't make all props are required using the following declaration:

export default class Widget extends JSXComponent<Required<WidgetInput>> {
    ...
}

Generators fail to process assignment to ref's property

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

class Comp extends JSXComponent(Props) {
    @Ref() divRef: HTMLDivElement;

    @Effect()
    changeRefEffect() {
        this.divRef.innerHTML = "Some value";
    }
}

Current Generated File

React

function Widget(props: {}) {
    const divRef=useRef<HTMLDivElement>();
    
    useEffect(function changeRefEffect(){
        __state_setInnerHTML("Some value");
    }, []);
}

Vue

methods: {
    changeRefEffect() {
        this.divRef = "Some value";
    }, []);
}

Angular

class Widget   {
    @ViewChild("divRef", {static: false}) divRef:ElementRef<HTMLDivElement>
    __changeRefEffect():any{
        this.divRef = "Some value";
    }
}

Expected Generated File

React

function Widget(props: {}) {
    const divRef=useRef<HTMLDivElement>();
    
    useEffect(function changeRefEffect(){
        divRef.current.innerHTML = "Some value";
    }, []);
}

Vue

methods: {
    changeRefEffect() {
        this.$refs.divRef.innerHTML = "Some value";
    }, []);
}

Angular

class Widget   {
    @ViewChild("divRef", {static: false}) divRef:ElementRef<HTMLDivElement>
    __changeRefEffect():any{
        this.divRef.nativeElement.innerHTML = "Some value";
    }
}

React Generator: Increment InternalState and TwoWay props works wrong

Check what generator works wrong

  • Angular
  • React
  • Vue
  • jQuery

Declaration File

@InternalState() counter
updateCounter(){
    this.counter++
}

Current Generated File

 const updateState=useCallback(function updateState(){
            __state_setCounter(__state_counter+1)
}, [__state_counter]);

Expected Generated File

 const updateState=useCallback(function updateState(){
            __state_setCounter((__state_counter)=>__state_counter+1)
}, [__state_counter]);

Additional Information

A version of the generator: 1.0.72

React. Generated state manipulation code may become incorrect

##Declaration

@Component({})
export default class Widget extends JSXComponent<WidgetInput> {
    updateState() {
        const cur = this.props.s; // s is TwoWay prop
        this.props.s = cur === true ? false : true;
    }
}

Actual ReactGenerator output

export default function Widget(props: WidgetInput) {
  const updateState = useCallback(function updateState() {
    const cur = (props.s !== undefined ? props.s : __state_s)(__state_setS(cur === true ? false : true), props.sChange!(cur === true ? false : true))
  }, [props.s, __state_s, props.sChange]);
}

The code above is treated as function call

Expected ReactGenerator output

export default function Widget(props: WidgetInput) {
  const updateState = useCallback(function updateState() {
    const cur = (props.s !== undefined ? props.s : __state_s);  // a new line and semicolon
    (__state_setS(cur === true ? false : true), props.sChange!(cur === true ? false : true))
  }, [props.s, __state_s, props.sChange]);
}

React. DefaultProps contains default values of TwoWay props

##Declaration

@ComponentBindings()
class WidgetInput { 
    @TwoWay() pressed?: boolean = false;
}

Actual ReactGenerator output

const WidgetInput: WidgetInput = {
  pressed: false,
  pressedChange: () => { }
};

export default function Widget(props: WidgetInput) {
  const [__state_pressed, __state_setPressed] = useState(() => (props.pressed !== undefined ? props.pressed : props.defaultPressed) || false);
}

Widget.defaultProps = {
  ...WidgetInput
}

Expected ReactGenerator output

const WidgetInput: WidgetInput = {
  pressedChange: () => { }
};

export default function Widget(props: WidgetInput) {
  const [__state_pressed, __state_setPressed] = useState(() => (props.pressed !== undefined ? props.pressed : props.defaultPressed) || false);
}

Widget.defaultProps = {
  ...WidgetInput
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.