import * as t from '@rekajs/types'; import { Parser } from '../parser'; describe('Parser', () => { it('should be able to parse expressions', () => { expect(Parser.parseExpression('1+counter')).toMatchObject({ type: 'BinaryExpression', id: expect.any(String), left: { type: 'Literal', id: expect.any(String), value: 1, meta: {}, }, meta: {}, operator: '+', right: { type: 'Identifier', id: expect.any(String), name: 'counter', meta: {}, }, } as t.BinaryExpression); }); it('should be able to parse member expression', () => { expect(Parser.parseExpression(`obj.prop`)).toMatchObject({ type: 'MemberExpression', object: { type: 'Identifier', name: 'obj', external: false, }, property: { type: 'Literal', value: 'prop', }, }); expect(Parser.parseExpression(`obj.prop[0]`)).toMatchObject({ type: 'MemberExpression', object: { type: 'MemberExpression', object: { type: 'Identifier', name: 'obj', external: false, }, property: { type: 'Literal', value: 'prop', }, }, property: { type: 'Literal', value: 0, }, }); expect(Parser.parseExpression(`obj.prop[idx]`)).toMatchObject({ type: 'MemberExpression', object: { type: 'MemberExpression', object: { type: 'Identifier', name: 'obj', external: false, }, property: { type: 'Literal', value: 'prop', }, }, property: { type: 'Identifier', name: 'idx', }, }); expect(Parser.parseExpression(`$obj.prop`)).toMatchObject({ type: 'MemberExpression', object: { type: 'Identifier', name: 'obj', external: true, }, property: { type: 'Literal', value: 'prop', }, }); }); it('should be able to parse program', () => { expect( Parser.parseProgram(` component App(prop1="defaultValue") { val counter = 0; } => (
) `) ).toMatchObject({ type: 'Program', components: [ { type: 'RekaComponent', name: 'App', state: [ { type: 'Val', name: 'counter', init: { type: 'Literal', value: 0, }, }, ], props: [ { type: 'ComponentProp', name: 'prop1', init: { type: 'Literal', value: 'defaultValue', }, }, ], template: { type: 'TagTemplate', tag: 'div', props: {}, children: [ { type: 'ComponentTemplate', component: { type: 'Identifier', name: 'Button', }, props: { text: { type: 'Identifier', name: 'prop1' }, }, }, ], }, }, ], }); }); it('should be able to parse variable kind', () => { expect( Parser.parseProgram(` val color: string = "blue"; val colors: array = ["blue"]; val option: option<{blue: "Blue", red: "Red"}> = "red"; `) ).toMatchObject({ type: 'Program', globals: [ { type: 'Val', name: 'color', kind: { type: 'StringKind', }, init: { type: 'Literal', value: 'blue', }, }, { type: 'Val', name: 'colors', kind: { type: 'ArrayKind', elements: { type: 'StringKind', }, }, init: { type: 'ArrayExpression', elements: [{ type: 'Literal', value: 'blue' }], }, }, { type: 'Val', name: 'option', kind: { type: 'OptionKind', options: { blue: 'Blue', red: 'Red', }, }, init: { type: 'Literal', value: 'red', }, }, ], }); }); it('should be able to parse variable with number kind', () => { expect( Parser.parseProgram(` val num: number = 100; val numWithMinMax: number<1,2> = 1; val numWithMin: number<1> = 1; val numWithMax: number<_,2> = 1; `) ).toMatchObject({ type: 'Program', globals: [ { type: 'Val', name: 'num', kind: { type: 'NumberKind', }, }, { type: 'Val', name: 'numWithMinMax', kind: { type: 'NumberKind', min: 1, max: 2, }, }, { type: 'Val', name: 'numWithMin', kind: { type: 'NumberKind', min: 1, max: null, }, }, { type: 'Val', name: 'numWithMax', kind: { type: 'NumberKind', min: null, max: 2, }, }, ], }); }); it('should be able to parse variable with custom kind', () => { expect( Parser.parseProgram(` val color: Color = "#000"; `) ).toMatchObject({ type: 'Program', globals: [ { type: 'Val', name: 'color', init: { type: 'Literal', value: '#000', }, kind: { type: 'CustomKind', name: 'Color', }, }, ], }); }); it('should be able to parse negative values', () => { expect(Parser.parseExpression('-1')).toMatchObject({ operator: '-', argument: { type: 'Literal', value: 1, }, }); }); it('should be able to parse directives', () => { const parsed = Parser.parseProgram(`component Test(value) => ( )`); expect(parsed.components[0].template?.props['value']).toMatchObject({ identifier: { type: 'Identifier', name: 'value', }, }); }); it('should be able to parse identifier component props', () => { const parsed = Parser.parseProgram( `component Test(@value: string) => ()` ); expect(parsed.components[0].props[0]).toMatchObject({ type: 'ComponentProp', name: 'value', bindable: true, }); }); it('should be able to parse string type', () => { const parsed = Parser.parseExpression( '`Hello {{myVariable}} there {{1+2}}!`' ); expect(parsed).toMatchObject({ type: 'String', value: [ 'Hello ', { type: 'Identifier', name: 'myVariable', }, ' there ', { type: 'BinaryExpression', left: { type: 'Literal', value: 1, }, operator: '+', right: { type: 'Literal', value: 2, }, }, '!', ], }); }); });