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,
},
},
'!',
],
});
});
});