feat: simplified generated resources code customizations with yaml file config (#17)
* feat: simplified generated code customizations with yaml file config * chore: apply linting
This commit is contained in:
committed by
GitHub
parent
8c99b428d9
commit
5a403dbb39
73
codegen/customizations.yml
Normal file
73
codegen/customizations.yml
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
customizations:
|
||||
resources:
|
||||
Account:
|
||||
fields:
|
||||
IP:
|
||||
omitEmpty: true
|
||||
NetworkID:
|
||||
omitEmpty: true
|
||||
ChannelPlan:
|
||||
fields:
|
||||
Channel:
|
||||
ifFieldType: "string"
|
||||
customUnmarshalType: "numberOrString"
|
||||
BackupChannel:
|
||||
ifFieldType: "string"
|
||||
customUnmarshalType: "numberOrString"
|
||||
TxPower:
|
||||
ifFieldType: "string"
|
||||
customUnmarshalType: "numberOrString"
|
||||
Device:
|
||||
fields:
|
||||
_all:
|
||||
omitEmpty: true
|
||||
X:
|
||||
fieldType: "float64"
|
||||
Y:
|
||||
fieldType: "float64"
|
||||
StpPriority:
|
||||
fieldType: "string"
|
||||
customUnmarshalType: "numberOrString"
|
||||
Ht:
|
||||
fieldType: "int"
|
||||
Channel:
|
||||
customUnmarshalType: "numberOrString"
|
||||
ifFieldType: "string"
|
||||
BackupChannel:
|
||||
customUnmarshalType: "numberOrString"
|
||||
ifFieldType: "string"
|
||||
TxPower:
|
||||
customUnmarshalType: "numberOrString"
|
||||
ifFieldType: "string"
|
||||
LteExtAnt:
|
||||
customUnmarshalType: "booleanishString"
|
||||
LtePoe:
|
||||
customUnmarshalType: "booleanishString"
|
||||
PortOverrides:
|
||||
omitEmpty: false
|
||||
Network:
|
||||
fields:
|
||||
InternetAccessEnabled:
|
||||
ifFieldType: "bool"
|
||||
customUnmarshalType: "*bool"
|
||||
customUnmarshalFunc: "emptyBoolToTrue"
|
||||
IntraNetworkAccessEnabled:
|
||||
ifFieldType: "bool"
|
||||
customUnmarshalType: "*bool"
|
||||
customUnmarshalFunc: "emptyBoolToTrue"
|
||||
WANUsername:
|
||||
omitEmpty: true
|
||||
XWANPassword:
|
||||
omitEmpty: true
|
||||
User:
|
||||
fields:
|
||||
Blocked:
|
||||
fieldType: "bool"
|
||||
LastSeen:
|
||||
fieldType: "int"
|
||||
customUnmarshalType: "emptyStringInt"
|
||||
WLAN:
|
||||
fields:
|
||||
ScheduleWithDuration:
|
||||
omitEmpty: false
|
||||
157
codegen/customize.go
Normal file
157
codegen/customize.go
Normal file
@@ -0,0 +1,157 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
AllFieldsCustomizationKeyword = "_all"
|
||||
defaultCustomizationsPath = "customizations.yml"
|
||||
)
|
||||
|
||||
type Generate struct {
|
||||
Customizations struct {
|
||||
Resources map[string]*ResourceCustomization `yaml:"resources"`
|
||||
} `yaml:"customizations"`
|
||||
}
|
||||
|
||||
type ResourceCustomization struct {
|
||||
ResourceName string `yaml:"-"`
|
||||
Fields map[string]*FieldCustomization `yaml:"fields"`
|
||||
}
|
||||
|
||||
type FieldCustomization struct {
|
||||
FieldName string `yaml:"-"`
|
||||
Overrides *FieldInfoOverride `yaml:",inline"`
|
||||
IfFieldType string `yaml:"ifFieldType"`
|
||||
}
|
||||
|
||||
type FieldInfoOverride struct {
|
||||
FieldName *string `yaml:"fieldName"`
|
||||
FieldType *string `yaml:"fieldType"`
|
||||
OmitEmpty *bool `yaml:"omitEmpty"`
|
||||
CustomUnmarshalType *string `yaml:"customUnmarshalType"`
|
||||
CustomUnmarshalFunc *string `yaml:"customUnmarshalFunc"`
|
||||
}
|
||||
|
||||
func compositeCustomizationsProcessor(customizationsProcessor FieldProcessor) FieldProcessor {
|
||||
return func(name string, f *FieldInfo) error {
|
||||
err := customizationsProcessor(AllFieldsCustomizationKeyword, f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed applying all fields customization to %s field: %w", name, err)
|
||||
}
|
||||
err = customizationsProcessor(name, f)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed applying customization to %s fields: %w", name, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ResourceCustomization) ApplyTo(resource *Resource) {
|
||||
if resource.StructName == r.ResourceName {
|
||||
currentProcessor := resource.FieldProcessor
|
||||
customizationsProcessor := r.toFieldProcessor()
|
||||
if currentProcessor != nil {
|
||||
// create composite processor with existing processor, first running pre-defined customizations, then user-defined
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
err := compositeCustomizationsProcessor(customizationsProcessor)(name, f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return currentProcessor(name, f)
|
||||
}
|
||||
} else {
|
||||
resource.FieldProcessor = compositeCustomizationsProcessor(customizationsProcessor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ResourceCustomization) toFieldProcessor() FieldProcessor {
|
||||
return func(name string, f *FieldInfo) error {
|
||||
if fc, ok := r.Fields[name]; ok && fc.Overrides != nil && (fc.IfFieldType == "" || fc.IfFieldType == f.FieldType) {
|
||||
if fc.Overrides.FieldType != nil {
|
||||
f.FieldType = *fc.Overrides.FieldType
|
||||
}
|
||||
if fc.Overrides.CustomUnmarshalType != nil {
|
||||
f.CustomUnmarshalType = *fc.Overrides.CustomUnmarshalType
|
||||
}
|
||||
if fc.Overrides.OmitEmpty != nil {
|
||||
f.OmitEmpty = *fc.Overrides.OmitEmpty
|
||||
}
|
||||
if fc.Overrides.CustomUnmarshalFunc != nil {
|
||||
f.CustomUnmarshalFunc = *fc.Overrides.CustomUnmarshalFunc
|
||||
}
|
||||
if fc.Overrides.FieldName != nil {
|
||||
f.FieldName = *fc.Overrides.FieldName
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed customizations.yml
|
||||
var defaultCustomizationYml []byte
|
||||
|
||||
func readCustomizationsYml(customizationsPath string) ([]byte, error) {
|
||||
if customizationsPath == "" || customizationsPath == defaultCustomizationsPath {
|
||||
return defaultCustomizationYml, nil
|
||||
}
|
||||
customizations, err := os.ReadFile(customizationsPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed reading customizations file %s: %w", customizationsPath, err)
|
||||
}
|
||||
return customizations, nil
|
||||
}
|
||||
|
||||
func unmarshalCustomizationYaml(customizationsPath string) (*Generate, error) {
|
||||
var generate Generate
|
||||
customizationsYml, err := readCustomizationsYml(customizationsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = yaml.Unmarshal(customizationsYml, &generate)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed unmarshalling YAML to Generate structure: %w", err)
|
||||
}
|
||||
// Assign ResourceName and FieldName based on the map keys
|
||||
for resourceName, resource := range generate.Customizations.Resources {
|
||||
resource.ResourceName = resourceName
|
||||
for fieldName, field := range resource.Fields {
|
||||
field.FieldName = fieldName
|
||||
}
|
||||
}
|
||||
return &generate, nil
|
||||
}
|
||||
|
||||
type YamlConfigCodeCustomizer struct {
|
||||
Customizations map[string]*ResourceCustomization
|
||||
}
|
||||
|
||||
type CodeCustomizer interface {
|
||||
ApplyToResource(resource *Resource)
|
||||
}
|
||||
|
||||
type noopCustomizer struct{}
|
||||
|
||||
func (noopCustomizer) ApplyToResource(resource *Resource) {}
|
||||
|
||||
func NewCodeCustomizer(customizationsPath string) (CodeCustomizer, error) { //nolint: ireturn
|
||||
generate, err := unmarshalCustomizationYaml(customizationsPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &YamlConfigCodeCustomizer{generate.Customizations.Resources}, nil
|
||||
}
|
||||
|
||||
func (r *YamlConfigCodeCustomizer) ApplyToResource(resource *Resource) {
|
||||
for resourceName, resourceCustomization := range r.Customizations {
|
||||
if resource.StructName == resourceName {
|
||||
resourceCustomization.ApplyTo(resource)
|
||||
}
|
||||
}
|
||||
}
|
||||
199
codegen/customize_test.go
Normal file
199
codegen/customize_test.go
Normal file
@@ -0,0 +1,199 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// Removed dummy type declarations for FieldInfo and Resource since they are already defined in the package
|
||||
|
||||
func TestUnmarshalCustomizationYamlDefault(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := assert.New(t)
|
||||
|
||||
generate, err := unmarshalCustomizationYaml("")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, generate)
|
||||
|
||||
// Check that some expected resource customizations exist
|
||||
a.Contains(generate.Customizations.Resources, "Account")
|
||||
a.Contains(generate.Customizations.Resources, "Device")
|
||||
|
||||
dvc, ok := generate.Customizations.Resources["Device"]
|
||||
a.True(ok, "Device customization should exist")
|
||||
a.Contains(dvc.Fields, AllFieldsCustomizationKeyword)
|
||||
}
|
||||
|
||||
func TestNewCodeCustomizer_NonExistent(t *testing.T) {
|
||||
t.Parallel()
|
||||
cc, err := NewCodeCustomizer("nonexistent.yml")
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "failed reading customizations file")
|
||||
assert.Nil(t, cc)
|
||||
}
|
||||
|
||||
func TestApplyToResource(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := assert.New(t)
|
||||
|
||||
cc, err := NewCodeCustomizer("")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a dummy Resource for 'Device'
|
||||
res := &Resource{StructName: "Device"}
|
||||
cc.ApplyToResource(res)
|
||||
a.NotNil(res.FieldProcessor, "FieldProcessor should be set after applying customizations")
|
||||
|
||||
// Test field 'X': should update FieldType to "float64" and _all customization sets omitEmpty true
|
||||
fiX := &FieldInfo{
|
||||
FieldName: "X",
|
||||
FieldType: "string",
|
||||
OmitEmpty: false,
|
||||
}
|
||||
err = res.FieldProcessor("X", fiX)
|
||||
require.NoError(t, err)
|
||||
a.Equal("float64", fiX.FieldType, "X field type should be updated to float64")
|
||||
a.True(fiX.OmitEmpty, "OmitEmpty should be true due to _all customization")
|
||||
|
||||
// Test field 'Channel': applied only when FieldType equals "string"
|
||||
fiChannel := &FieldInfo{
|
||||
FieldName: "Channel",
|
||||
FieldType: "string",
|
||||
}
|
||||
err = res.FieldProcessor("Channel", fiChannel)
|
||||
require.NoError(t, err)
|
||||
a.Equal("numberOrString", fiChannel.CustomUnmarshalType, "Channel should get customUnmarshalType override")
|
||||
|
||||
// Test 'Channel' with non-matching FieldType: no override gets applied
|
||||
fiChannelMismatch := &FieldInfo{
|
||||
FieldName: "Channel",
|
||||
FieldType: "int",
|
||||
}
|
||||
err = res.FieldProcessor("Channel", fiChannelMismatch)
|
||||
require.NoError(t, err)
|
||||
a.Equal("", fiChannelMismatch.CustomUnmarshalType, "Override should not apply when FieldType does not match")
|
||||
}
|
||||
|
||||
func TestCompositeFieldProcessor(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := assert.New(t)
|
||||
|
||||
cc, err := NewCodeCustomizer("")
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a Resource for 'Account' with a pre-existing FieldProcessor that appends "_original" to FieldName
|
||||
res := &Resource{
|
||||
StructName: "Account",
|
||||
FieldProcessor: func(name string, f *FieldInfo) error {
|
||||
// Original processing: append '_original' to FieldName
|
||||
f.FieldName = f.FieldName + "_original"
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cc.ApplyToResource(res)
|
||||
a.NotNil(res.FieldProcessor, "Composite FieldProcessor should be set")
|
||||
|
||||
// For Account, customization for field 'IP' sets omitEmpty true
|
||||
fiIP := &FieldInfo{
|
||||
FieldName: "IP",
|
||||
FieldType: "string",
|
||||
OmitEmpty: false,
|
||||
}
|
||||
err = res.FieldProcessor("IP", fiIP)
|
||||
require.NoError(t, err)
|
||||
// Expected behavior: customization applies first (e.g. setting omitEmpty) and then the original processor appends suffix
|
||||
a.True(fiIP.OmitEmpty, "OmitEmpty should be set to true by customization")
|
||||
a.Equal("IP_original", fiIP.FieldName, "FieldName should have '_original' appended by the composite processor")
|
||||
}
|
||||
|
||||
func TestNoCustomizationForResource(t *testing.T) {
|
||||
t.Parallel()
|
||||
// Create a Resource that does not have any associated customizations
|
||||
res := &Resource{StructName: "NonExistent"}
|
||||
|
||||
cc, err := NewCodeCustomizer("")
|
||||
require.NoError(t, err)
|
||||
|
||||
cc.ApplyToResource(res)
|
||||
assert.Nil(t, res.FieldProcessor, "FieldProcessor should remain nil if no customization applies")
|
||||
}
|
||||
|
||||
func createTempCustomizationsYaml(t *testing.T, data string) string {
|
||||
t.Helper()
|
||||
tempFile := filepath.Join(t.TempDir(), "temp_customizations.yml")
|
||||
err := os.WriteFile(tempFile, []byte(data), 0o644)
|
||||
require.NoError(t, err, "should create temp file")
|
||||
return tempFile
|
||||
}
|
||||
|
||||
func TestReadCustomizationsYmlError(t *testing.T) {
|
||||
t.Parallel()
|
||||
tempFile := createTempCustomizationsYaml(t, "invalid: yaml: ::::\n")
|
||||
|
||||
// Expect an error due to invalid YAML
|
||||
_, err := unmarshalCustomizationYaml(tempFile)
|
||||
require.Error(t, err)
|
||||
require.ErrorContains(t, err, "failed unmarshalling YAML")
|
||||
}
|
||||
|
||||
func TestApplyToResource_CustomInline(t *testing.T) {
|
||||
t.Parallel()
|
||||
yamlContent := `
|
||||
customizations:
|
||||
resources:
|
||||
CustomResource:
|
||||
fields:
|
||||
CustomField:
|
||||
fieldType: int
|
||||
omitEmpty: true
|
||||
`
|
||||
tempFile := createTempCustomizationsYaml(t, yamlContent)
|
||||
cc, err := NewCodeCustomizer(tempFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
res := &Resource{StructName: "CustomResource"}
|
||||
cc.ApplyToResource(res)
|
||||
require.NotNil(t, res.FieldProcessor)
|
||||
|
||||
fi := &FieldInfo{
|
||||
FieldName: "CustomField",
|
||||
FieldType: "string",
|
||||
OmitEmpty: false,
|
||||
}
|
||||
err = res.FieldProcessor("CustomField", fi)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "int", fi.FieldType, "Custom field type should be updated to int")
|
||||
assert.True(t, fi.OmitEmpty, "Custom field omitEmpty should be true")
|
||||
}
|
||||
|
||||
func TestApplyToResource_CustomFieldMismatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
yamlContent := `
|
||||
customizations:
|
||||
resources:
|
||||
CustomResource:
|
||||
fields:
|
||||
CustomField:
|
||||
ifFieldType: string
|
||||
customUnmarshalType: customType
|
||||
`
|
||||
tempFile := createTempCustomizationsYaml(t, yamlContent)
|
||||
cc, err := NewCodeCustomizer(tempFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
res := &Resource{StructName: "CustomResource"}
|
||||
cc.ApplyToResource(res)
|
||||
require.NotNil(t, res.FieldProcessor)
|
||||
|
||||
fi := &FieldInfo{
|
||||
FieldName: "CustomField",
|
||||
FieldType: "int",
|
||||
}
|
||||
err = res.FieldProcessor("CustomField", fi)
|
||||
require.NoError(t, err)
|
||||
assert.Empty(t, fi.CustomUnmarshalType, "Customization should not apply if field type mismatches")
|
||||
}
|
||||
@@ -41,18 +41,19 @@ func generateCodeFromTemplate(templateName, templateContent string, toWrite any)
|
||||
}
|
||||
|
||||
// generateCode generates code for each generation source and writes it to file.
|
||||
func generateCode(fieldsDir string, outDir string) error {
|
||||
func generateCode(fieldsDir string, outDir string, customizer CodeCustomizer) error {
|
||||
if _, err := ensurePath(outDir); err != nil {
|
||||
return fmt.Errorf("unable to create output directory %s: %w", outDir, err)
|
||||
}
|
||||
|
||||
generators := make([]Generatable, 0)
|
||||
resources, err := buildResourcesFromDownloadedFields(fieldsDir)
|
||||
resources, err := buildResourcesFromDownloadedFields(fieldsDir, customizer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to build resources from downloaded fields: %w", err)
|
||||
}
|
||||
client := newClientInfo(resources)
|
||||
for _, resource := range resources {
|
||||
customizer.ApplyToResource(resource)
|
||||
generators = append(generators, resource)
|
||||
}
|
||||
generators = append(generators, client)
|
||||
|
||||
@@ -199,7 +199,7 @@ func TestGenerateCodeFromFields(t *testing.T) {
|
||||
tt.setupMockFiles(tt.fieldsDir)
|
||||
}
|
||||
|
||||
err := generateCode(tt.fieldsDir, tt.outDir)
|
||||
err := generateCode(tt.fieldsDir, tt.outDir, noopCustomizer{})
|
||||
|
||||
if tt.expectedError {
|
||||
require.Error(t, err)
|
||||
|
||||
@@ -37,11 +37,12 @@ func setupLogging(debugEnabled, traceEnabled bool) {
|
||||
}
|
||||
|
||||
type options struct {
|
||||
versionBaseDir string
|
||||
outputDir string
|
||||
downloadOnly bool
|
||||
version string
|
||||
firmwareUpdateApi string
|
||||
versionBaseDir string
|
||||
outputDir string
|
||||
downloadOnly bool
|
||||
version string
|
||||
firmwareUpdateApi string
|
||||
customizationsPath string
|
||||
}
|
||||
|
||||
func main() {
|
||||
@@ -61,11 +62,12 @@ func main() {
|
||||
specifiedVersion = LatestVersionMarker // default to latest version
|
||||
}
|
||||
err := generate(options{
|
||||
versionBaseDir: *versionBaseDirFlag,
|
||||
outputDir: *outputDirFlag,
|
||||
downloadOnly: *downloadOnly,
|
||||
version: specifiedVersion,
|
||||
firmwareUpdateApi: defaultFirmwareUpdateApi,
|
||||
versionBaseDir: *versionBaseDirFlag,
|
||||
outputDir: *outputDirFlag,
|
||||
downloadOnly: *downloadOnly,
|
||||
version: specifiedVersion,
|
||||
firmwareUpdateApi: defaultFirmwareUpdateApi,
|
||||
customizationsPath: "customizations.yml",
|
||||
})
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -114,7 +116,11 @@ func generate(opts options) error {
|
||||
} else {
|
||||
outDir = filepath.Join(wd, opts.outputDir)
|
||||
}
|
||||
if err = generateCode(structuresDir, outDir); err != nil {
|
||||
customizer, err := NewCodeCustomizer(opts.customizationsPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create code customizer: %w", err)
|
||||
}
|
||||
if err = generateCode(structuresDir, outDir, customizer); err != nil {
|
||||
return fmt.Errorf("unable to generate resources code: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -82,11 +82,13 @@ var fileReps = []replacement{
|
||||
{"ApGroups", "APGroup"},
|
||||
}
|
||||
|
||||
type FieldProcessor func(name string, f *FieldInfo) error
|
||||
|
||||
type Resource struct {
|
||||
StructName string
|
||||
ResourcePath string
|
||||
Types map[string]*FieldInfo
|
||||
FieldProcessor func(name string, f *FieldInfo) error
|
||||
FieldProcessor FieldProcessor
|
||||
}
|
||||
|
||||
func (r *Resource) BaseType() *FieldInfo {
|
||||
@@ -318,7 +320,7 @@ func normalizeValidation(re string) string {
|
||||
|
||||
var skippable = []string{"AuthenticationRequest.json", "Setting.json", "Wall.json"}
|
||||
|
||||
func buildResourcesFromDownloadedFields(fieldsDir string) ([]*Resource, error) {
|
||||
func buildResourcesFromDownloadedFields(fieldsDir string, customizer CodeCustomizer) ([]*Resource, error) {
|
||||
fieldsFiles, err := os.ReadDir(fieldsDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read fields directory %s: %w", fieldsDir, err)
|
||||
@@ -348,6 +350,7 @@ func buildResourcesFromDownloadedFields(fieldsDir string) ([]*Resource, error) {
|
||||
|
||||
resource := NewResource(structName, urlPath)
|
||||
customizeResource(resource)
|
||||
customizer.ApplyToResource(resource)
|
||||
|
||||
err = resource.processJSON(b)
|
||||
if err != nil {
|
||||
@@ -396,63 +399,6 @@ func customizeResource(resource *Resource) {
|
||||
customizeBaseType(resource)
|
||||
|
||||
switch resource.StructName {
|
||||
case "Account":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
switch name {
|
||||
case "IP", "NetworkID":
|
||||
f.OmitEmpty = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case "ChannelPlan":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
switch name {
|
||||
case "Channel", "BackupChannel", "TxPower":
|
||||
if f.FieldType == "string" {
|
||||
f.CustomUnmarshalType = "numberOrString"
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case "Device":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
switch name {
|
||||
case "X", "Y":
|
||||
f.FieldType = "float64"
|
||||
case "StpPriority":
|
||||
f.FieldType = "string"
|
||||
f.CustomUnmarshalType = "numberOrString"
|
||||
case "Ht":
|
||||
f.FieldType = "int"
|
||||
case "Channel", "BackupChannel", "TxPower":
|
||||
if f.FieldType == "string" {
|
||||
f.CustomUnmarshalType = "numberOrString"
|
||||
}
|
||||
case "LteExtAnt", "LtePoe":
|
||||
f.CustomUnmarshalType = "booleanishString"
|
||||
}
|
||||
|
||||
f.OmitEmpty = true
|
||||
switch name {
|
||||
case "PortOverrides":
|
||||
f.OmitEmpty = false
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
case "Network":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
switch name {
|
||||
case "InternetAccessEnabled", "IntraNetworkAccessEnabled":
|
||||
if f.FieldType == "bool" {
|
||||
f.CustomUnmarshalType = "*bool"
|
||||
f.CustomUnmarshalFunc = "emptyBoolToTrue"
|
||||
}
|
||||
case "WANUsername", "XWANPassword":
|
||||
f.OmitEmpty = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case "SettingGlobalAp":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
if strings.HasPrefix(name, "6E") {
|
||||
@@ -487,25 +433,5 @@ func customizeResource(resource *Resource) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case "User":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
switch name {
|
||||
case "Blocked":
|
||||
f.FieldType = "bool"
|
||||
case "LastSeen":
|
||||
f.FieldType = "int"
|
||||
f.CustomUnmarshalType = "emptyStringInt"
|
||||
}
|
||||
return nil
|
||||
}
|
||||
case "WLAN":
|
||||
resource.FieldProcessor = func(name string, f *FieldInfo) error {
|
||||
switch name {
|
||||
case "ScheduleWithDuration":
|
||||
// always send schedule, so we can empty it if we want to
|
||||
f.OmitEmpty = false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,7 +354,7 @@ func TestBuildResourcesFromDownloadedFields(t *testing.T) {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
a := assert.New(t)
|
||||
resources, err := buildResourcesFromDownloadedFields(tc.dir)
|
||||
resources, err := buildResourcesFromDownloadedFields(tc.dir, noopCustomizer{})
|
||||
if tc.errorContains != "" {
|
||||
require.ErrorContains(t, err, tc.errorContains)
|
||||
a.Nil(resources)
|
||||
|
||||
Reference in New Issue
Block a user