Skip to content

Commit

Permalink
inoxjs: add Golang function that parses client-side interpolations
Browse files Browse the repository at this point in the history
  • Loading branch information
GraphR00t committed May 6, 2024
1 parent f35f40c commit 63a1961
Show file tree
Hide file tree
Showing 3 changed files with 217 additions and 20 deletions.
20 changes: 0 additions & 20 deletions internal/inoxjs/inox-component.go

This file was deleted.

90 changes: 90 additions & 0 deletions internal/inoxjs/inox_component.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package inoxjs

import (
"context"
"strings"

"github.com/inoxlang/inox/internal/hyperscript/hscode"
"github.com/inoxlang/inox/internal/hyperscript/hsparse"
"github.com/inoxlang/inox/internal/utils"
)

const (
TEXT_INTERPOLATION_OPENING_DELIMITER = "(("
TEXT_INTERPOLATION_CLOSING_DELIMITER = "))"
CONDITIONAL_DISPLAY_ATTR_NAME = "x-if"
FOR_LOOP_ATTR_NAME = "x-for"
INIT_COMPONENT_FN_NAME = "initComponent"
)

func ContainsClientSideInterpolation(s string) bool {
openingDelimIndex := strings.Index(s, TEXT_INTERPOLATION_OPENING_DELIMITER)
if openingDelimIndex < 0 {
return false
}
closingDelimIndex := strings.Index(s, TEXT_INTERPOLATION_CLOSING_DELIMITER)
return closingDelimIndex > openingDelimIndex
}

type ClientSideInterpolation struct {
Expression string
ParsingResult *hscode.ParsingResult
ParsingError *hscode.ParsingError
}

func ParseClientSideInterpolations(ctx context.Context, s string) (interpolations []ClientSideInterpolation, criticalErr error) {
if len(s) <= 1 {
return
}

runes := []rune(s)

i := 1
inInterpolation := false
interpolationStart := -1

//Find interpolations.

for i < len(runes) {
if !inInterpolation && runes[i] == '(' && runes[i-1] == '(' {
i++
inInterpolation = true
interpolationStart = i
continue
}
if inInterpolation && runes[i] == ')' && runes[i-1] == ')' {
interpolations = append(interpolations, ClientSideInterpolation{
Expression: string(runes[interpolationStart : i-1]),
})
interpolationStart = -1
inInterpolation = false

i++
continue
}

i++
}

//Parse Hyperscript expressions.

for interpIndex, interp := range interpolations {
if utils.IsContextDone(ctx) {
interpolations = nil
criticalErr = ctx.Err()
return
}

result, parsingErr, err := hsparse.ParseHyperScriptExpression(ctx, interp.Expression)
if err != nil {
criticalErr = err
return
}

interp.ParsingResult = result
interp.ParsingError = parsingErr
interpolations[interpIndex] = interp
}

return
}
127 changes: 127 additions & 0 deletions internal/inoxjs/inox_component_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package inoxjs

import (
"context"
"testing"

"github.com/inoxlang/inox/internal/hyperscript/hscode"
"github.com/stretchr/testify/assert"
)

func TestParseClientSideInterpolations(t *testing.T) {

t.Run("empty", func(t *testing.T) {
interpolations, err := ParseClientSideInterpolations(context.Background(), "")
if !assert.NoError(t, err) {
return
}
assert.Empty(t, interpolations)
})

t.Run("empty leading interpolation: length 0", func(t *testing.T) {
interpolations, err := ParseClientSideInterpolations(context.Background(), "(())end")
if !assert.NoError(t, err) {
return
}
if !assert.Len(t, interpolations, 1) {
return
}
interp := interpolations[0]

assert.Empty(t, interp.Expression)
if !assert.NotNil(t, interp.ParsingError) {
return
}
assert.Nil(t, interp.ParsingResult)
})

t.Run("empty leading interpolation: one space", func(t *testing.T) {
interpolations, err := ParseClientSideInterpolations(context.Background(), "(( ))end")
if !assert.NoError(t, err) {
return
}
if !assert.Len(t, interpolations, 1) {
return
}
interp := interpolations[0]

assert.Equal(t, " ", interp.Expression)
if !assert.NotNil(t, interp.ParsingError) {
return
}
assert.Nil(t, interp.ParsingResult)
})

t.Run("non-empty leading interpolation", func(t *testing.T) {
interpolations, err := ParseClientSideInterpolations(context.Background(), "((:count))end")
if !assert.NoError(t, err) {
return
}
if !assert.Len(t, interpolations, 1) {
return
}
interp := interpolations[0]

assert.Equal(t, ":count", interp.Expression)
if !assert.Nil(t, interp.ParsingError) {
return
}
if !assert.NotNil(t, interp.ParsingResult) {
return
}
assert.True(t, hscode.IsSymbolWithName(interp.ParsingResult.NodeData, ":count"))
})

t.Run("non-empty trailing interpolations", func(t *testing.T) {
interpolations, err := ParseClientSideInterpolations(context.Background(), "start((:count))")
if !assert.NoError(t, err) {
return
}
if !assert.Len(t, interpolations, 1) {
return
}
interp := interpolations[0]

assert.Equal(t, ":count", interp.Expression)
if !assert.Nil(t, interp.ParsingError) {
return
}
if !assert.NotNil(t, interp.ParsingResult) {
return
}
assert.True(t, hscode.IsSymbolWithName(interp.ParsingResult.NodeData, ":count"))
})

t.Run("two interpolations", func(t *testing.T) {
interpolations, err := ParseClientSideInterpolations(context.Background(), "((a))/((:count))")
if !assert.NoError(t, err) {
return
}
if !assert.Len(t, interpolations, 2) {
return
}

interp0 := interpolations[0]

assert.Equal(t, "a", interp0.Expression)
if !assert.Nil(t, interp0.ParsingError) {
return
}
if !assert.NotNil(t, interp0.ParsingResult) {
return
}
assert.True(t, hscode.IsSymbolWithName(interp0.ParsingResult.NodeData, "a"))

interp2 := interpolations[1]

assert.Equal(t, ":count", interp2.Expression)
if !assert.Nil(t, interp2.ParsingError) {
return
}
if !assert.NotNil(t, interp2.ParsingResult) {
return
}
assert.True(t, hscode.IsSymbolWithName(interp2.ParsingResult.NodeData, ":count"))
})

}

0 comments on commit 63a1961

Please sign in to comment.