Skip to content

Commit

Permalink
hyperscript/analysis: support install resolution and application
Browse files Browse the repository at this point in the history
  • Loading branch information
GraphR00t committed May 15, 2024
1 parent f1b8339 commit 6854d54
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 0 deletions.
1 change: 1 addition & 0 deletions internal/hyperscript/hsanalysis/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type Result struct {
Warnings []Warning
Behaviors []*Behavior
FunctionDefinitions []FunctionDefinition
Installs []InstallFeature
}

func Analyze(params Parameters) (*Result, error) {
Expand Down
4 changes: 4 additions & 0 deletions internal/hyperscript/hsanalysis/behavior.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ func MakeBehaviorFromNode(node hscode.JSONMap, location sourcecode.PositionRange

return &behavior
}

func (b *Behavior) ApplyResolvedInstalls() []Error {
return applyResolvedInstalls(b.Installs, &b.AppliedInstalls, &b.InitialElementScopeVarNames, &b.InitializedDataAttributeNames, &b.HandledEvents)
}
4 changes: 4 additions & 0 deletions internal/hyperscript/hsanalysis/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,7 @@ func PreanalyzeHyperscriptComponent(

return
}

func (c *Component) ApplyResolvedInstalls() []Error {
return applyResolvedInstalls(c.Installs, &c.AppliedInstalls, &c.InitialElementScopeVarNames, &c.InitializedDataAttributeNames, &c.HandledEvents)
}
55 changes: 55 additions & 0 deletions internal/hyperscript/hsanalysis/install_feature.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package hsanalysis

import (
"slices"

"github.com/inoxlang/inox/internal/hyperscript/hscode"
"github.com/inoxlang/inox/internal/sourcecode"
)

type InstallFeature struct {
BehaviorFullName string
ResolvedBehavior *Behavior
Fields []ArgListField

Location sourcecode.PositionRange
Expand Down Expand Up @@ -36,3 +39,55 @@ type ArgListField struct {
Name string
Value hscode.JSONMap
}

func (i *InstallFeature) Resolve(behaviors []*Behavior) (success bool) {
if i.ResolvedBehavior != nil {
return true
}

wantedBehaviorName := i.BehaviorFullName

for _, behavior := range behaviors {
if behavior.FullName != wantedBehaviorName {
continue
}
i.ResolvedBehavior = behavior
return true
}

return false
}

func applyResolvedInstalls(
installs []*InstallFeature,
appliedInstalls *[]*InstallFeature,
elementScopeVarNames *[]string,
dataAttrNames *[]string,
handledEvents *[]DOMEvent,
) []Error {
for _, install := range installs {
if install.ResolvedBehavior == nil || slices.Contains(*appliedInstalls, install) {
continue
}
*appliedInstalls = append(*appliedInstalls, install)
resolvedBehavior := install.ResolvedBehavior

for _, varName := range resolvedBehavior.InitialElementScopeVarNames {
if !slices.Contains(*elementScopeVarNames, varName) {
*elementScopeVarNames = append(*elementScopeVarNames, varName)
}
}
for _, attrName := range resolvedBehavior.InitializedDataAttributeNames {
if !slices.Contains(*dataAttrNames, attrName) {
*dataAttrNames = append(*dataAttrNames, attrName)
}
}
for _, event := range resolvedBehavior.HandledEvents {
if !slices.ContainsFunc(*handledEvents, func(e DOMEvent) bool { return e.Type == event.Type }) {
*handledEvents = append(*handledEvents, event)
}
}
}

return nil
}
103 changes: 103 additions & 0 deletions internal/hyperscript/hsanalysis/install_feature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package hsanalysis

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestApplyResolvedInstalls(t *testing.T) {
t.Run("base case", func(t *testing.T) {
resolvedBehavior := &Behavior{
Name: "A",
FullName: "A",
InitialElementScopeVarNames: []string{":a"},
InitializedDataAttributeNames: []string{"data-x"},
HandledEvents: []DOMEvent{{Type: "X"}},
}

installs := []*InstallFeature{{BehaviorFullName: "A", ResolvedBehavior: resolvedBehavior}}

var elementScopedVarNames []string
var dataAttributeNames []string
var handledEvents []DOMEvent

var appliedInstalls []*InstallFeature

errs := applyResolvedInstalls(installs, &appliedInstalls, &elementScopedVarNames, &dataAttributeNames, &handledEvents)

assert.Empty(t, errs)
if !assert.Equal(t, []*InstallFeature{installs[0]}, appliedInstalls) {
return
}
assert.Equal(t, []string{":a"}, elementScopedVarNames)
assert.Equal(t, []string{"data-x"}, dataAttributeNames)
assert.Equal(t, []DOMEvent{{Type: "X"}}, handledEvents)

//Calling the function again should have no effect since the installs are applied.

errs = applyResolvedInstalls(installs, &appliedInstalls, &elementScopedVarNames, &dataAttributeNames, &handledEvents)
assert.Empty(t, errs)
assert.Equal(t, []string{":a"}, elementScopedVarNames)
assert.Equal(t, []string{"data-x"}, dataAttributeNames)
assert.Equal(t, []DOMEvent{{Type: "X"}}, handledEvents)
})

t.Run("if some variables or data attributes or event types are common, no duplicate should appear", func(t *testing.T) {
resolvedBehavior := &Behavior{
Name: "A",
FullName: "A",
InitialElementScopeVarNames: []string{":a", ":b"},
InitializedDataAttributeNames: []string{"data-x", "data-y"},
HandledEvents: []DOMEvent{{Type: "X"}, {Type: "Y"}},
}

installs := []*InstallFeature{{BehaviorFullName: "A", ResolvedBehavior: resolvedBehavior}}

elementScopedVarNames := []string{":a"}
dataAttributeNames := []string{"data-x"}
handledEvents := []DOMEvent{{Type: "X"}}

var appliedInstalls []*InstallFeature

errs := applyResolvedInstalls(installs, &appliedInstalls, &elementScopedVarNames, &dataAttributeNames, &handledEvents)

assert.Empty(t, errs)
if !assert.Equal(t, []*InstallFeature{installs[0]}, appliedInstalls) {
return
}
assert.Equal(t, []string{":a", ":b"}, elementScopedVarNames)
assert.Equal(t, []string{"data-x", "data-y"}, dataAttributeNames)
assert.Equal(t, []DOMEvent{{Type: "X"}, {Type: "Y"}}, handledEvents)

//Calling the function again should have no effect since the installs are applied.

errs = applyResolvedInstalls(installs, &appliedInstalls, &elementScopedVarNames, &dataAttributeNames, &handledEvents)
assert.Empty(t, errs)
assert.Equal(t, []string{":a", ":b"}, elementScopedVarNames)
assert.Equal(t, []string{"data-x", "data-y"}, dataAttributeNames)
assert.Equal(t, []DOMEvent{{Type: "X"}, {Type: "Y"}}, handledEvents)
})

t.Run("passing an unresolved install should have no effect", func(t *testing.T) {

installs := []*InstallFeature{{BehaviorFullName: "A", ResolvedBehavior: nil}}

elementScopedVarNames := []string{":a"}
dataAttributeNames := []string{"data-x"}
handledEvents := []DOMEvent{{Type: "X"}}

var appliedInstalls []*InstallFeature

errs := applyResolvedInstalls(installs, &appliedInstalls, &elementScopedVarNames, &dataAttributeNames, &handledEvents)

assert.Empty(t, errs)
if !assert.Empty(t, appliedInstalls) {
return
}
assert.Empty(t, errs)
assert.Equal(t, []string{":a"}, elementScopedVarNames)
assert.Equal(t, []string{"data-x"}, dataAttributeNames)
assert.Equal(t, []DOMEvent{{Type: "X"}}, handledEvents)
})
}

0 comments on commit 6854d54

Please sign in to comment.