feat: extract set_fields rule forces Int fields on gff_json merge targets
build-binaries / build-binaries (pull_request) Successful in 2m41s
test-image / build-image (pull_request) Successful in 42s
test / test (pull_request) Successful in 1m34s

Glob targets now match via matchPathPattern, so one rule can cover
areas/*.are.json. set_fields runs after preserve/merge so the forced
value always wins.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 18:11:33 +02:00
co-authored by Claude Fable 5
parent 5ebef57160
commit 3f532e43d2
3 changed files with 148 additions and 14 deletions
+94
View File
@@ -3503,6 +3503,100 @@ extract:
}
}
func TestExtractSetsConfiguredGFFJSONFields(t *testing.T) {
root := t.TempDir()
mustMkdir(t, filepath.Join(root, "src", "module"))
mustMkdir(t, filepath.Join(root, "src", "areas"))
mustMkdir(t, filepath.Join(root, "assets"))
mustMkdir(t, filepath.Join(root, "build"))
mustWriteFile(t, filepath.Join(root, "nwn-tool.yaml"), `
module:
name: Test Module
resref: testmod
paths:
source: src
assets: assets
build: build
extract:
merge:
gff_json:
- target: areas/*.are.json
set_fields:
- field: ChanceRain
value: 0
- field: ChanceSnow
value: 0
`)
mustWriteFile(t, filepath.Join(root, "src", "module", "module.ifo.json"), `{
"file_type": "IFO ",
"file_version": "V3.2",
"root": {
"struct_type": 0,
"fields": [
{
"label": "Mod_Name",
"type": "CExoString",
"value": "Test Module"
}
]
}
}
`)
mustWriteFile(t, filepath.Join(root, "src", "areas", "area_a.are.json"), `{
"file_type": "ARE ",
"file_version": "V3.2",
"root": {
"struct_type": 0,
"fields": [
{
"label": "ChanceRain",
"type": "Int",
"value": 40
},
{
"label": "WindPower",
"type": "Int",
"value": 2
}
]
}
}
`)
p, err := project.Load(root)
if err != nil {
t.Fatalf("load project: %v", err)
}
if err := p.ValidateLayout(); err != nil {
t.Fatalf("validate layout: %v", err)
}
if err := p.Scan(); err != nil {
t.Fatalf("scan: %v", err)
}
if _, err := BuildModule(p); err != nil {
t.Fatalf("build module: %v", err)
}
if err := p.Scan(); err != nil {
t.Fatalf("rescan before extract: %v", err)
}
if _, err := Extract(p); err != nil {
t.Fatalf("extract: %v", err)
}
document := readGFFJSON(t, filepath.Join(root, "src", "areas", "area_a.are.json"))
if got, want := fieldValue(t, document.Root, "ChanceRain"), gff.IntValue(0); got != want {
t.Fatalf("expected forced ChanceRain %#v, got %#v", want, got)
}
if got, want := fieldValue(t, document.Root, "WindPower"), gff.IntValue(2); got != want {
t.Fatalf("expected untouched WindPower %#v, got %#v", want, got)
}
if _, ok := gffField(document.Root, "ChanceSnow"); ok {
t.Fatalf("expected absent ChanceSnow to stay absent")
}
}
func TestExtractNormalizesResourceNamesToLowercase(t *testing.T) {
root := t.TempDir()
mustMkdir(t, filepath.Join(root, "src", "blueprints", "items"))