Skip to content

Commit

Permalink
fix: parse common computed types (#131)
Browse files Browse the repository at this point in the history
* parse basic types from computed properties

* add note about computed property types

* only build once

* new snapshot w/ type info

* more specific documentation on parsing

* simplify BuildVars arguments

* use build int bool parser

* build vars tests
  • Loading branch information
hay-kot committed May 11, 2024
1 parent fb10bda commit f9ada30
Show file tree
Hide file tree
Showing 13 changed files with 175 additions and 20 deletions.
19 changes: 19 additions & 0 deletions .examples/types/scaffold.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
questions:
- name: langs
prompt:
multi: true
message: "Languages to be used in the project"
options:
- JavaScript & TypeScript
- Python

computed:
javascript: '{{ has "JavaScript & TypeScript" .Scaffold.langs }}'
python: '{{ has "Python" .Scaffold.langs }}'
int: "1"
basicint: "{{ add 1 2 }}"

presets:
default:
Project: "scaffold-test-defaults"
langs: ["Python"]
8 changes: 8 additions & 0 deletions .examples/types/{{ .ProjectKebab }}/types.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Has Javascript
{{ .Computed.javascript }} (type={{ typeOf .Computed.javascript }})
Has Python
{{ .Computed.python }} (type={{ typeOf .Computed.python }})
Should Be Int
{{ .Computed.int }} (type={{ typeOf .Computed.int }})
Basic Int
{{ .Computed.basicint }} (type={{ typeOf .Computed.basicint }})
2 changes: 1 addition & 1 deletion app/commands/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func (ctrl *Controller) runscaffold(cfg runconf) error {
WriteFS: cfg.outputfs,
}

vars, err = scaffold.BuildVars(ctrl.engine, args, vars)
vars, err = scaffold.BuildVars(ctrl.engine, args.Project, vars)
if err != nil {
return err
}
Expand Down
30 changes: 21 additions & 9 deletions app/scaffold/render_funcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,26 +150,38 @@ func guardFeatureFlag(e *engine.Engine, args *RWFSArgs, vars engine.Vars) filepa

// BuildVars builds the vars for the engine by setting the provided vars
// under the "Scaffold" key and adding the project name and computed vars.
func BuildVars(eng *engine.Engine, args *RWFSArgs, vars engine.Vars) (engine.Vars, error) {
func BuildVars(eng *engine.Engine, project *Project, vars engine.Vars) (engine.Vars, error) {
iVars := engine.Vars{
"Project": args.Project.Name,
"ProjectSnake": xstrings.ToSnakeCase(args.Project.Name),
"ProjectKebab": xstrings.ToKebabCase(args.Project.Name),
"ProjectCamel": xstrings.ToCamelCase(args.Project.Name),
"Project": project.Name,
"ProjectSnake": xstrings.ToSnakeCase(project.Name),
"ProjectKebab": xstrings.ToKebabCase(project.Name),
"ProjectCamel": xstrings.ToCamelCase(project.Name),
"Scaffold": vars,
}

mp := make(map[string]any, len(args.Project.Conf.Computed))
for k, v := range args.Project.Conf.Computed {
computed := make(map[string]any, len(project.Conf.Computed))
for k, v := range project.Conf.Computed {
out, err := eng.TmplString(v, iVars)
if err != nil {
return nil, err
}

mp[k] = out
// We must parse the integer first to avoid incorrectly parsing a '0'
// as a boolean.
if i, err := strconv.Atoi(out); err == nil {
computed[k] = i
continue
}

if b, err := strconv.ParseBool(out); err == nil {
computed[k] = b
continue
}

computed[k] = out
}

iVars["Computed"] = mp
iVars["Computed"] = computed

return iVars, nil
}
Expand Down
78 changes: 78 additions & 0 deletions app/scaffold/render_funcs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package scaffold

import (
"testing"

"github.com/hay-kot/scaffold/app/core/engine"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_BuildVars(t *testing.T) {
project := &Project{
Name: "test",
Conf: &ProjectScaffoldFile{
Computed: map[string]string{
"Bool": "true",
"Int": "{{ add 1 2 }}",
"ZeroInt": "0",
"UsesVars": "Computed: {{ .Scaffold.key }}",
},
},
}

vars := engine.Vars{
"key": "value",
}

eng := engine.New()

got, err := BuildVars(eng, project, vars)
require.NoError(t, err)

//
// Assert Top Level Keys
//

requiredStringKeys := []string{
"Project",
"ProjectSnake",
"ProjectKebab",
"ProjectCamel",
}

for _, key := range requiredStringKeys {
assert.NotNil(t, got[key])
assert.IsType(t, "", got[key])
}

assert.NotNil(t, got["Scaffold"])
assert.IsType(t, engine.Vars{}, got["Scaffold"])

//
// Assert Passed in Vars live under Scaffold
//

scaffold := got["Scaffold"].(engine.Vars)
assert.NotNil(t, scaffold["key"])

//
// Assert Computed Properties are Typed and Computed
//

require.NotNil(t, got["Computed"])
computed := got["Computed"].(map[string]any)

assert.NotNil(t, computed["Bool"])
assert.IsType(t, true, computed["Bool"])

assert.NotNil(t, computed["Int"])
assert.IsType(t, 3, computed["Int"])

assert.NotNil(t, computed["ZeroInt"])
assert.IsType(t, 0, computed["ZeroInt"])

assert.NotNil(t, computed["UsesVars"])
assert.IsType(t, "", computed["UsesVars"])
assert.Equal(t, "Computed: value", computed["UsesVars"])
}
2 changes: 1 addition & 1 deletion app/scaffold/snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func Test_RenderRWFileSystem(t *testing.T) {
Path: "ROOT_NODE",
}

vars, err := BuildVars(tEngine, args, vars)
vars, err := BuildVars(tEngine, args.Project, vars)
require.NoError(t, err)

err = RenderRWFS(tEngine, args, vars)
Expand Down
7 changes: 6 additions & 1 deletion docs/docs/scaffold-file.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@ You can reference computed variables like so
{{ .Computed.shuffled }}
```

!!! tip
Computed variables are generally of type string however, there are special cases for boolean and integer types. Scaffold will attempt to parse the computed string value into an integer, and then a boolean. If any are successful, that value will be used in-place of the string.



### Rewrites

Rewrites working with the [template scaffolds](./index.md#terminology) to perform a path rewrite to another directory. The following example defines a rewrite that will render the `templates/defaults.yaml` file to the `roles/{{ .ProjectKebab }}/defaults/main.yaml` path.
Expand Down Expand Up @@ -242,4 +247,4 @@ presets:
```

!!! tip "Presets and Testing"
Presets can be used in conjunction with the `new` command for testing purposes. See [Testing Scaffolds](./testing-scaffolds.md) for more information.
Presets can be used in conjunction with the `new` command for testing purposes. See [Testing Scaffolds](./testing-scaffolds.md) for more information.
4 changes: 2 additions & 2 deletions tests/cli-snapshot.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
source tests/assert.sh

# Your script continues as before...
output=$(go run main.go --log-level="error" \
output=$($1 --log-level="error" \
new \
--preset="default" \
--no-prompt \
--snapshot="stdout" \
cli)

# Call the function to assert the snapshot
assert_snapshot "cli.snapshot.txt" "$output"
assert_snapshot "cli.snapshot.txt" "$output"
4 changes: 2 additions & 2 deletions tests/cli.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# Source the assertions file
source tests/assert.sh

go run main.go --log-level="error" \
$1 --log-level="error" \
new \
--preset="default" \
--no-prompt \
Expand All @@ -16,4 +16,4 @@ output=$(go run ./gen/scaffold-test*/main.go hello)
expected_output="colors=red, green description=This is a test description"

# Call the function to compare output with expected output
assert_output "$output" "$expected_output"
assert_output "$output" "$expected_output"
8 changes: 6 additions & 2 deletions tests/nested-snapshot.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
# Source the assert_snapshot function
source tests/assert.sh

# accept bin as first argument


# Your script continues as before...
output=$(go run main.go --log-level="error" \
output=$($1 --log-level="error" \
--output-dir=":memory:" \
new \
--preset="default" \
--no-prompt \
--snapshot="stdout" \
nested)

# Call the function to assert the snapshot
assert_snapshot "nested.snapshot.txt" "$output"
assert_snapshot "nested.snapshot.txt" "$output"
7 changes: 5 additions & 2 deletions tests/runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ export SCAFFOLD_DIR=".scaffold,.examples"
checkmark=""
crossmark=""

# build main.go into random temp path
go build -o /tmp/scaffold-test ./main.go

echo "Running Script Tests"
# run each test script in the tests directory
for test_script in tests/*.test.sh; do
rm -rf ./gen

# if exit code of script is 0, print checkmark, else print crossmark
# and the output indented by 4 spaces
output=$($test_script 2>&1)
output=$($test_script /tmp/scaffold-test 2>&1)

if [ $? -eq 0 ]; then
echo " $checkmark $test_script"
Expand All @@ -22,4 +25,4 @@ for test_script in tests/*.test.sh; do
# Print each line of the output indented by 4 spaces
echo "$output" | sed 's/^/ /'
fi
done
done
11 changes: 11 additions & 0 deletions tests/snapshots/types.snapshot.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
scaffold-test-defaults: (type=dir)
types.txt: (type=file)
Has Javascript
false (type=bool)
Has Python
true (type=bool)
Should Be Int
1 (type=int)
Basic Int
3 (type=int)

15 changes: 15 additions & 0 deletions tests/types-snapshot.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash

# Source the assert_snapshot function
source tests/assert.sh

# Your script continues as before...
output=$($1 --log-level="error" \
new \
--preset="default" \
--no-prompt \
--snapshot="stdout" \
types)

# Call the function to assert the snapshot
assert_snapshot "types.snapshot.txt" "$output"

0 comments on commit f9ada30

Please sign in to comment.