-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## This PR - proof-of-concept React code gen implementation ### How to test #### Run: `go run main.go generate react --flag_manifest_path ./sample/sample_manifest.json --output_path ./output.ts` #### Output ```ts 'use client'; import { useBooleanFlagDetails, useNumberFlagDetails, useStringFlagDetails, } from "@openfeature/react-sdk"; /** * Discount percentage applied to purchases. * * **Details:** * - flag key: `discountPercentage` * - default value: `0.15` * - type: `number` */ export const useDiscountPercentage = (options: Parameters<typeof useNumberFlagDetails>[2]) => { return useNumberFlagDetails("discountPercentage", 0.15, options); }; /** * Controls whether Feature A is enabled. * * **Details:** * - flag key: `enableFeatureA` * - default value: `false` * - type: `boolean` */ export const useEnableFeatureA = (options: Parameters<typeof useBooleanFlagDetails>[2]) => { return useBooleanFlagDetails("enableFeatureA", false, options); }; /** * Maximum allowed length for usernames. * * **Details:** * - flag key: `usernameMaxLength` * - default value: `50` * - type: `number` */ export const useUsernameMaxLength = (options: Parameters<typeof useNumberFlagDetails>[2]) => { return useNumberFlagDetails("usernameMaxLength", 50, options); }; /** * The message to use for greeting users. * * **Details:** * - flag key: `greetingMessage` * - default value: `Hello there!` * - type: `string` */ export const useGreetingMessage = (options: Parameters<typeof useStringFlagDetails>[2]) => { return useStringFlagDetails("greetingMessage", "Hello there!", options); }; ``` Signed-off-by: Michael Beemer <[email protected]>
- Loading branch information
Showing
5 changed files
with
169 additions
and
2 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
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,24 @@ | ||
package react | ||
|
||
import ( | ||
"codegen/internal/generate" | ||
"codegen/internal/generate/plugins/react" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
// Cmd for "generate" command, handling code generation for flag accessors | ||
var Cmd = &cobra.Command{ | ||
Use: "react", | ||
Short: "Generate typesafe React Hooks.", | ||
Long: `Generate typesafe React Hooks compatible with the OpenFeature React SDK.`, | ||
RunE: func(cmd *cobra.Command, args []string) error { | ||
params := react.Params{} | ||
gen := react.NewGenerator(params) | ||
err := generate.CreateFlagAccessors(gen) | ||
return err | ||
}, | ||
} | ||
|
||
func init() { | ||
} |
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
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,121 @@ | ||
package react | ||
|
||
import ( | ||
_ "embed" | ||
"sort" | ||
"strconv" | ||
"text/template" | ||
|
||
"codegen/internal/generate" | ||
"codegen/internal/generate/types" | ||
|
||
"github.com/iancoleman/strcase" | ||
) | ||
|
||
type TmplData struct { | ||
*types.BaseTmplData | ||
} | ||
|
||
type genImpl struct { | ||
} | ||
|
||
// BaseTmplDataInfo provides the base template data for the codegen. | ||
func (td *TmplData) BaseTmplDataInfo() *types.BaseTmplData { | ||
return td.BaseTmplData | ||
} | ||
|
||
// supportedFlagTypes is the flag types supported by the Go template. | ||
var supportedFlagTypes = map[types.FlagType]bool{ | ||
types.FloatType: true, | ||
types.StringType: true, | ||
types.IntType: true, | ||
types.BoolType: true, | ||
types.ObjectType: false, | ||
} | ||
|
||
func (*genImpl) SupportedFlagTypes() map[types.FlagType]bool { | ||
return supportedFlagTypes | ||
} | ||
|
||
//go:embed react.tmpl | ||
var reactTmpl string | ||
|
||
func flagVarName(flagName string) string { | ||
return strcase.ToCamel(flagName) | ||
} | ||
|
||
func flagInitParam(flagName string) string { | ||
return strconv.Quote(flagName) | ||
} | ||
|
||
func flagAccessFunc(t types.FlagType) string { | ||
switch t { | ||
case types.IntType, types.FloatType: | ||
return "useNumberFlagDetails" | ||
case types.BoolType: | ||
return "useBooleanFlagDetails" | ||
case types.StringType: | ||
return "useStringFlagDetails" | ||
default: | ||
return "" | ||
} | ||
} | ||
|
||
func supportImports(flags []*types.FlagTmplData) []string { | ||
imports := make(map[string]struct{}) | ||
for _, flag := range flags { | ||
imports[flagAccessFunc(flag.Type)] = struct{}{} | ||
} | ||
var result []string | ||
for k := range imports { | ||
result = append(result, k) | ||
} | ||
sort.Strings(result) | ||
return result | ||
} | ||
|
||
func defaultValueLiteral(flag *types.FlagTmplData) string { | ||
switch flag.Type { | ||
case types.StringType: | ||
return strconv.Quote(flag.DefaultValue) | ||
default: | ||
return flag.DefaultValue | ||
} | ||
} | ||
|
||
func typeString(flagType types.FlagType) string { | ||
switch flagType { | ||
case types.StringType: | ||
return "string" | ||
case types.IntType, types.FloatType: | ||
return "number" | ||
case types.BoolType: | ||
return "boolean" | ||
default: | ||
return "" | ||
} | ||
} | ||
|
||
func (g *genImpl) Generate(input types.Input) error { | ||
funcs := template.FuncMap{ | ||
"FlagVarName": flagVarName, | ||
"FlagInitParam": flagInitParam, | ||
"FlagAccessFunc": flagAccessFunc, | ||
"SupportImports": supportImports, | ||
"DefaultValueLiteral": defaultValueLiteral, | ||
"TypeString": typeString, | ||
} | ||
td := TmplData{ | ||
BaseTmplData: input.BaseData, | ||
} | ||
return generate.GenerateFile(funcs, reactTmpl, &td) | ||
} | ||
|
||
// Params are parameters for creating a Generator | ||
type Params struct { | ||
} | ||
|
||
// NewGenerator creates a generator for React. | ||
func NewGenerator(params Params) types.Generator { | ||
return &genImpl{} | ||
} |
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,20 @@ | ||
'use client'; | ||
|
||
import { | ||
{{- range $_, $p := SupportImports .Flags}} | ||
{{$p}}, | ||
{{- end}} | ||
} from "@openfeature/react-sdk"; | ||
{{ range .Flags}} | ||
/** | ||
* {{.Docs}} | ||
* | ||
* **Details:** | ||
* - flag key: `{{ .Name}}` | ||
* - default value: `{{ .DefaultValue}}` | ||
* - type: `{{TypeString .Type}}` | ||
*/ | ||
export const use{{FlagVarName .Name}} = (options: Parameters<typeof {{FlagAccessFunc .Type}}>[2]) => { | ||
return {{FlagAccessFunc .Type}}({{FlagInitParam .Name}}, {{DefaultValueLiteral .}}, options); | ||
}; | ||
{{ end}} |