forked from tkrajina/typescriptify-golang-structs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding conversion handlers with original conversion as the default handler
- Loading branch information
1 parent
2728b08
commit d6f2401
Showing
5 changed files
with
397 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
package typescriptify | ||
|
||
import ( | ||
"reflect" | ||
) | ||
|
||
type TypeConversionHandler interface { | ||
HandleTypeConversion(depth int, result string, t *TypeScriptify, builder *TypeScriptClassBuilder, typeOf reflect.Type, customCode map[string]string, field reflect.StructField, fldOpts TypeOptions, jsonFieldName string) (string, error) | ||
} | ||
|
||
type DefaultTypeConversionHandler struct { | ||
} | ||
|
||
func (handler *DefaultTypeConversionHandler) HandleTypeConversion(depth int, result string, t *TypeScriptify, builder *TypeScriptClassBuilder, typeOf reflect.Type, customCode map[string]string, field reflect.StructField, fldOpts TypeOptions, jsonFieldName string) (string, error) { | ||
var err error | ||
|
||
if fldOpts.TSDoc != "" { | ||
builder.AddFieldDefinitionLine("/** " + fldOpts.TSDoc + " */") | ||
} | ||
if fldOpts.TSTransform != "" { | ||
t.Logf(depth, "- simple field %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleField(jsonFieldName, field, fldOpts) | ||
} else if t.IsEnum(field) { | ||
t.Logf(depth, "- enum field %s.%s", typeOf.Name(), field.Name) | ||
builder.AddEnumField(jsonFieldName, field) | ||
} else if fldOpts.TSType != "" { // Struct: | ||
t.Logf(depth, "- simple field 1 %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleField(jsonFieldName, field, fldOpts) | ||
} else if field.Type.Kind() == reflect.Struct { // Struct: | ||
t.Logf(depth, "- struct %s.%s (%s)", typeOf.Name(), field.Name, field.Type.String()) | ||
typeScriptChunk, err := t.ConvertType(depth+1, field.Type, customCode) | ||
if err != nil { | ||
return "", err | ||
} | ||
if typeScriptChunk != "" { | ||
result = typeScriptChunk + "\n" + result | ||
} | ||
builder.AddStructField(jsonFieldName, field) | ||
} else if field.Type.Kind() == reflect.Map { | ||
t.Logf(depth, "- map field %s.%s", typeOf.Name(), field.Name) | ||
// Also convert map key types if needed | ||
var keyTypeToConvert reflect.Type | ||
switch field.Type.Key().Kind() { | ||
case reflect.Struct: | ||
keyTypeToConvert = field.Type.Key() | ||
case reflect.Ptr: | ||
keyTypeToConvert = field.Type.Key().Elem() | ||
} | ||
if keyTypeToConvert != nil { | ||
typeScriptChunk, err := t.ConvertType(depth+1, keyTypeToConvert, customCode) | ||
if err != nil { | ||
return "", err | ||
} | ||
if typeScriptChunk != "" { | ||
result = typeScriptChunk + "\n" + result | ||
} | ||
} | ||
// Also convert map value types if needed | ||
var valueTypeToConvert reflect.Type | ||
switch field.Type.Elem().Kind() { | ||
case reflect.Struct: | ||
valueTypeToConvert = field.Type.Elem() | ||
case reflect.Ptr: | ||
valueTypeToConvert = field.Type.Elem().Elem() | ||
} | ||
if valueTypeToConvert != nil { | ||
typeScriptChunk, err := t.ConvertType(depth+1, valueTypeToConvert, customCode) | ||
if err != nil { | ||
return "", err | ||
} | ||
if typeScriptChunk != "" { | ||
result = typeScriptChunk + "\n" + result | ||
} | ||
} | ||
|
||
builder.AddMapField(jsonFieldName, field) | ||
} else if field.Type.Kind() == reflect.Slice || field.Type.Kind() == reflect.Array { // Slice: | ||
if field.Type.Elem().Kind() == reflect.Ptr { //extract ptr type | ||
field.Type = field.Type.Elem() | ||
} | ||
|
||
arrayDepth := 1 | ||
for field.Type.Elem().Kind() == reflect.Slice { // Slice of slices: | ||
field.Type = field.Type.Elem() | ||
arrayDepth++ | ||
} | ||
|
||
if field.Type.Elem().Kind() == reflect.Struct { // Slice of structs: | ||
t.Logf(depth, "- struct slice %s.%s (%s)", typeOf.Name(), field.Name, field.Type.String()) | ||
typeScriptChunk, err := t.ConvertType(depth+1, field.Type.Elem(), customCode) | ||
if err != nil { | ||
return "", err | ||
} | ||
if typeScriptChunk != "" { | ||
result = typeScriptChunk + "\n" + result | ||
} | ||
builder.AddArrayOfStructsField(jsonFieldName, field, arrayDepth) | ||
} else { // Slice of simple fields: | ||
t.Logf(depth, "- slice field %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleArrayField(jsonFieldName, field, arrayDepth, fldOpts) | ||
} | ||
} else { // Simple field: | ||
t.Logf(depth, "- simple field 2 %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleField(jsonFieldName, field, fldOpts) | ||
} | ||
return result, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package typescriptify | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
"time" | ||
) | ||
|
||
type customTypeConversionHandler struct { | ||
} | ||
|
||
func (handler *customTypeConversionHandler) HandleTypeConversion(depth int, result string, t *TypeScriptify, builder *TypeScriptClassBuilder, typeOf reflect.Type, customCode map[string]string, field reflect.StructField, fldOpts TypeOptions, jsonFieldName string) (string, error) { | ||
var err error | ||
t.Logf(depth, "CUSTOM HANDLER - %q - %q", typeOf.Name(), field.Name) | ||
timeFieldOptions := TypeOptions{TSType: "Date", TSTransform: "new Date(__VALUE__)"} | ||
if typeOf.Name() == "ConfigFile" { | ||
switch field.Name { | ||
case "OSVersion": | ||
t.Logf(depth, "- (custom) simple field %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleField("osVersion?", field, fldOpts) | ||
return result, err | ||
case "OSFeatures": | ||
t.Logf(depth, "- (custom) simple field %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleArrayField("osFeatures?", field, 1, fldOpts) | ||
return result, err | ||
case "Created": | ||
t.Logf(depth, "- (custom) simple field %s.%s", typeOf.Name(), field.Name) | ||
err = builder.AddSimpleField(jsonFieldName, field, timeFieldOptions) | ||
return result, err | ||
default: | ||
t.Logf(depth, "- calling default conversion for %s.%s", typeOf.Name(), field.Name) | ||
return t.DefaultTypeConversionHandler.HandleTypeConversion(depth, result, t, builder, typeOf, customCode, field, fldOpts, jsonFieldName) | ||
} | ||
} | ||
if typeOf.Name() == "History" && field.Type.Name() == "Time" { | ||
t.Logf(depth, "- (custom) simple field %s.%s (%s)", typeOf.Name(), field.Name, field.Type.Name()) | ||
err = builder.AddSimpleField(jsonFieldName, field, timeFieldOptions) | ||
return result, err | ||
} | ||
return t.DefaultTypeConversionHandler.HandleTypeConversion(depth, result, t, builder, typeOf, customCode, field, fldOpts, jsonFieldName) | ||
} | ||
|
||
func TestCustomTypeConversionHandler(t *testing.T) { | ||
t.Parallel() | ||
// Time is a wrapper around time.Time to help with deep copying | ||
type Time struct { | ||
time.Time | ||
} | ||
type History struct { | ||
Author string `json:"author,omitempty"` | ||
Created Time `json:"created,omitempty"` | ||
CreatedBy string `json:"created_by,omitempty"` | ||
Comment string `json:"comment,omitempty"` | ||
EmptyLayer bool `json:"empty_layer,omitempty"` | ||
} | ||
type ConfigFile struct { | ||
Architecture string `json:"architecture"` | ||
Author string `json:"author,omitempty"` | ||
Container string `json:"container,omitempty"` | ||
Created Time `json:"created,omitempty"` | ||
DockerVersion string `json:"docker_version,omitempty"` | ||
History []History `json:"history,omitempty"` | ||
OS string `json:"os"` | ||
OSVersion string `json:"os.version,omitempty"` | ||
Variant string `json:"variant,omitempty"` | ||
OSFeatures []string `json:"os.features,omitempty"` | ||
} | ||
type Metadata struct { | ||
Size int64 `json:",omitempty"` | ||
|
||
// Container image | ||
ImageID string `json:",omitempty"` | ||
DiffIDs []string `json:",omitempty"` | ||
RepoTags []string `json:",omitempty"` | ||
RepoDigests []string `json:",omitempty"` | ||
ImageConfig ConfigFile `json:",omitempty"` | ||
} | ||
|
||
converter := New().WithCamelCaseFields(true, nil) | ||
|
||
converter.ManageTypeConversion(&customTypeConversionHandler{}, reflect.TypeOf(ConfigFile{})) | ||
converter.Add( | ||
NewStruct(History{}).WithTypeHandler(reflect.TypeOf(Time{}), &customTypeConversionHandler{}), | ||
) | ||
converter.AddType(reflect.TypeOf(Metadata{})) | ||
converter.BackupDir = "" | ||
converter.ReadOnlyFields = true | ||
converter.CreateInterface = true | ||
|
||
desiredResult := `export interface History { | ||
readonly author?: string; | ||
readonly created?: Date; | ||
readonly created_by?: string; | ||
readonly comment?: string; | ||
readonly empty_layer?: boolean; | ||
} | ||
export interface ConfigFile { | ||
readonly architecture: string; | ||
readonly author?: string; | ||
readonly container?: string; | ||
readonly created?: Date; | ||
readonly docker_version?: string; | ||
readonly history?: History[]; | ||
readonly os: string; | ||
readonly osVersion?: string; | ||
readonly variant?: string; | ||
readonly osFeatures?: string[]; | ||
} | ||
export interface Metadata { | ||
readonly size?: number; | ||
readonly imageID?: string; | ||
readonly diffIDs?: string[]; | ||
readonly repoTags?: string[]; | ||
readonly repoDigests?: string[]; | ||
readonly imageConfig?: ConfigFile; | ||
}` | ||
testConverter(t, converter, false, desiredResult, nil) | ||
} |
Oops, something went wrong.