Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dist
.openfeature.yaml

.idea/
.vscode/

node_modules/
npm-debug.log*
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ test-integration-nodejs:
@echo "Running NodeJS integration test with Dagger..."
@go run ./test/integration/cmd/nodejs/run.go

.PHONY: test-integration-angular
test-integration-angular:
@echo "Running Angular integration test with Dagger..."
@go run ./test/integration/cmd/angular/run.go

.PHONY: test-integration
test-integration:
@echo "Running all integration tests with Dagger..."
Expand Down
1 change: 1 addition & 0 deletions docs/commands/openfeature_generate.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ openfeature generate [flags]
### SEE ALSO

* [openfeature](openfeature.md) - CLI for OpenFeature.
* [openfeature generate angular](openfeature_generate_angular.md) - Generate typesafe Angular services and directives.
* [openfeature generate csharp](openfeature_generate_csharp.md) - Generate typesafe C# client.
* [openfeature generate go](openfeature_generate_go.md) - Generate typesafe accessors for OpenFeature.
* [openfeature generate java](openfeature_generate_java.md) - Generate typesafe Java client.
Expand Down
37 changes: 37 additions & 0 deletions docs/commands/openfeature_generate_angular.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!-- markdownlint-disable-file -->
<!-- WARNING: THIS DOC IS AUTO-GENERATED. DO NOT EDIT! -->
## openfeature generate angular

Generate typesafe Angular services and directives.


> **Stability**: alpha

### Synopsis

Generate typesafe Angular services and directives compatible with the OpenFeature Angular SDK.

```
openfeature generate angular [flags]
```

### Options

```
-h, --help help for angular
```

### Options inherited from parent commands

```
--debug Enable debug logging
-m, --manifest string Path to the flag manifest (default "flags.json")
--no-input Disable interactive prompts
-o, --output string Path to where the generated files should be saved
-t, --template string Path to a custom template file. If not specified, the default template is used
```

### SEE ALSO

* [openfeature generate](openfeature_generate.md) - Generate typesafe OpenFeature accessors.

48 changes: 48 additions & 0 deletions internal/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/open-feature/cli/internal/config"
"github.com/open-feature/cli/internal/generators"
"github.com/open-feature/cli/internal/generators/angular"
"github.com/open-feature/cli/internal/generators/csharp"
"github.com/open-feature/cli/internal/generators/golang"
"github.com/open-feature/cli/internal/generators/java"
Expand Down Expand Up @@ -416,8 +417,55 @@ func getGeneratePythonCmd() *cobra.Command {
return pythonCmd
}

func getGenerateAngularCmd() *cobra.Command {
angularCmd := &cobra.Command{
Use: "angular",
Short: "Generate typesafe Angular services and directives.",
Long: `Generate typesafe Angular services and directives compatible with the OpenFeature Angular SDK.`,
Annotations: map[string]string{
"stability": string(generators.Alpha),
},
PreRunE: func(cmd *cobra.Command, args []string) error {
return initializeConfig(cmd, "generate.angular")
},
RunE: func(cmd *cobra.Command, args []string) error {
manifestPath := config.GetManifestPath(cmd)
outputPath := config.GetOutputPath(cmd)
templatePath := config.GetTemplatePath(cmd)

logger.Default.GenerationStarted("Angular")

params := generators.Params[angular.Params]{
OutputPath: outputPath,
TemplatePath: templatePath,
Custom: angular.Params{},
}
flagset, err := manifest.LoadFlagSet(manifestPath)
if err != nil {
return err
}

generator := angular.NewGenerator(flagset)
logger.Default.Debug("Executing Angular generator")
err = generator.Generate(&params)
if err != nil {
return err
}

logger.Default.GenerationComplete("Angular")

return nil
},
}

addStabilityInfo(angularCmd)

return angularCmd
}

func init() {
// Register generators with the manager
generators.DefaultManager.Register(getGenerateAngularCmd)
generators.DefaultManager.Register(getGenerateReactCmd)
generators.DefaultManager.Register(getGenerateGoCmd)
generators.DefaultManager.Register(getGenerateNodeJSCmd)
Expand Down
15 changes: 15 additions & 0 deletions internal/cmd/generate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ type generateTestCase struct {

func TestGenerate(t *testing.T) {
testCases := []generateTestCase{
{
name: "Angular generation success",
command: "angular",
manifestGolden: "testdata/success_manifest.golden",
outputGolden: "testdata/success_angular.golden",
outputFile: "openfeature.generated.ts",
},
{
name: "Go generation success",
command: "go",
Expand Down Expand Up @@ -78,6 +85,14 @@ func TestGenerate(t *testing.T) {
outputFile: "OpenFeature.java",
packageName: "com.example.openfeature",
},
{
name: "Angular generation with custom template",
command: "angular",
manifestGolden: "testdata/success_manifest.golden",
outputGolden: "testdata/custom_template/custom_angular.golden",
outputFile: "openfeature.generated.ts",
templateFile: "testdata/custom_template/custom_angular.tmpl",
},
{
name: "Go generation with custom template",
command: "go",
Expand Down
22 changes: 22 additions & 0 deletions internal/cmd/testdata/custom_template/custom_angular.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Custom Angular template - generated by OpenFeature CLI
import { Injectable, inject } from '@angular/core';
import { FeatureFlagService } from '@openfeature/angular-sdk';

export const FlagKeys = {
DISCOUNT_PERCENTAGE: "discountPercentage",
ENABLE_FEATURE_A: "enableFeatureA",
GREETING_MESSAGE: "greetingMessage",
THEME_CUSTOMIZATION: "themeCustomization",
USERNAME_MAX_LENGTH: "usernameMaxLength",
} as const;

@Injectable({ providedIn: 'root' })
export class GeneratedFlags {
private flags = inject(FeatureFlagService);

discountPercentage$ = this.flags.getNumberDetails("discountPercentage", 0.15);
enableFeatureA$ = this.flags.getBooleanDetails("enableFeatureA", false);
greetingMessage$ = this.flags.getStringDetails("greetingMessage", "Hello there!");
themeCustomization$ = this.flags.getObjectDetails("themeCustomization", {"primaryColor":"#007bff","secondaryColor":"#6c757d"});
usernameMaxLength$ = this.flags.getNumberDetails("usernameMaxLength", 50);
}
17 changes: 17 additions & 0 deletions internal/cmd/testdata/custom_template/custom_angular.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Custom Angular template - generated by OpenFeature CLI
import { Injectable, inject } from '@angular/core';
import { FeatureFlagService } from '@openfeature/angular-sdk';

export const FlagKeys = {
{{- range .Flagset.Flags }}
{{ .Key | ToScreamingSnake }}: {{ .Key | Quote }},
{{- end }}
} as const;

@Injectable({ providedIn: 'root' })
export class GeneratedFlags {
private flags = inject(FeatureFlagService);
{{ range .Flagset.Flags }}
{{ .Key | ToCamel }}$ = this.flags.{{ .Type | SdkServiceMethod }}({{ .Key | Quote }}, {{ if eq (.Type | OpenFeatureType) "object" }}{{ .DefaultValue | ToJSONString }}{{ else }}{{ .DefaultValue | QuoteString }}{{ end }});
{{- end }}
}
Loading
Loading