diff --git a/internal/cmd/testdata/success_angular.golden b/internal/cmd/testdata/success_angular.golden index b0deeed..14acf3d 100644 --- a/internal/cmd/testdata/success_angular.golden +++ b/internal/cmd/testdata/success_angular.golden @@ -27,7 +27,7 @@ import { FeatureFlagService, JsonValue, } from '@openfeature/angular-sdk'; -import { Observable } from 'rxjs'; +import { Observable, map } from 'rxjs'; // ============================================================================ // FLAG KEYS @@ -131,6 +131,24 @@ export class GeneratedFeatureFlagService { ); } + /** + * Get the value of the `discountPercentage` flag. + * + * Discount percentage applied to purchases. + * + * @param domain - Optional domain for flag evaluation (scopes the flag to a specific provider). + * @param options - Optional configuration for the flag evaluation. + * @returns An Observable that emits the flag value whenever it changes. + */ + getDiscountPercentage( + domain?: string, + options?: AngularFlagEvaluationOptions + ): Observable { + return this.getDiscountPercentageDetails(domain, options).pipe( + map((details) => details.value) + ); + } + /** * Get evaluation details for the `enableFeatureA` flag. * @@ -160,6 +178,24 @@ export class GeneratedFeatureFlagService { ); } + /** + * Get the value of the `enableFeatureA` flag. + * + * Controls whether Feature A is enabled. + * + * @param domain - Optional domain for flag evaluation (scopes the flag to a specific provider). + * @param options - Optional configuration for the flag evaluation. + * @returns An Observable that emits the flag value whenever it changes. + */ + getEnableFeatureA( + domain?: string, + options?: AngularFlagEvaluationOptions + ): Observable { + return this.getEnableFeatureADetails(domain, options).pipe( + map((details) => details.value) + ); + } + /** * Get evaluation details for the `greetingMessage` flag. * @@ -189,6 +225,24 @@ export class GeneratedFeatureFlagService { ); } + /** + * Get the value of the `greetingMessage` flag. + * + * The message to use for greeting users. + * + * @param domain - Optional domain for flag evaluation (scopes the flag to a specific provider). + * @param options - Optional configuration for the flag evaluation. + * @returns An Observable that emits the flag value whenever it changes. + */ + getGreetingMessage( + domain?: string, + options?: AngularFlagEvaluationOptions + ): Observable { + return this.getGreetingMessageDetails(domain, options).pipe( + map((details) => details.value) + ); + } + /** * Get evaluation details for the `themeCustomization` flag. * @@ -218,6 +272,24 @@ export class GeneratedFeatureFlagService { ); } + /** + * Get the value of the `themeCustomization` flag. + * + * Allows customization of theme colors. + * + * @param domain - Optional domain for flag evaluation (scopes the flag to a specific provider). + * @param options - Optional configuration for the flag evaluation. + * @returns An Observable that emits the flag value whenever it changes. + */ + getThemeCustomization( + domain?: string, + options?: AngularFlagEvaluationOptions + ): Observable { + return this.getThemeCustomizationDetails(domain, options).pipe( + map((details) => details.value) + ); + } + /** * Get evaluation details for the `usernameMaxLength` flag. * @@ -247,6 +319,24 @@ export class GeneratedFeatureFlagService { ); } + /** + * Get the value of the `usernameMaxLength` flag. + * + * Maximum allowed length for usernames. + * + * @param domain - Optional domain for flag evaluation (scopes the flag to a specific provider). + * @param options - Optional configuration for the flag evaluation. + * @returns An Observable that emits the flag value whenever it changes. + */ + getUsernameMaxLength( + domain?: string, + options?: AngularFlagEvaluationOptions + ): Observable { + return this.getUsernameMaxLengthDetails(domain, options).pipe( + map((details) => details.value) + ); + } + } // ============================================================================ diff --git a/internal/generators/angular/angular.tmpl b/internal/generators/angular/angular.tmpl index f0766ff..9ebdbf1 100644 --- a/internal/generators/angular/angular.tmpl +++ b/internal/generators/angular/angular.tmpl @@ -27,7 +27,7 @@ import { FeatureFlagService, JsonValue, } from '@openfeature/angular-sdk'; -import { Observable } from 'rxjs'; +import { Observable, map } from 'rxjs'; // ============================================================================ // FLAG KEYS @@ -108,6 +108,24 @@ export class GeneratedFeatureFlagService { } ); } + + /** + * Get the value of the `{{ .Key }}` flag. + * + * {{ if .Description }}{{ .Description }}{{ else }}Feature flag.{{ end }} + * + * @param domain - Optional domain for flag evaluation (scopes the flag to a specific provider). + * @param options - Optional configuration for the flag evaluation. + * @returns An Observable that emits the flag value whenever it changes. + */ + get{{ .Key | ToPascal }}( + domain?: string, + options?: AngularFlagEvaluationOptions + ): Observable<{{ if eq (.Type | OpenFeatureType) "object" }}JsonValue{{ else }}{{ .Type | OpenFeatureType }}{{ end }}> { + return this.get{{ .Key | ToPascal }}Details(domain, options).pipe( + map((details) => details.value) + ); + } {{ end }} } diff --git a/test/angular-integration/specs/service.spec.ts b/test/angular-integration/specs/service.spec.ts index 6dc4a8a..11c9a58 100644 --- a/test/angular-integration/specs/service.spec.ts +++ b/test/angular-integration/specs/service.spec.ts @@ -211,4 +211,103 @@ describe("GeneratedFeatureFlagService", () => { }); }); }); + + describe("getEnableFeatureA (convenience)", () => { + it("should return boolean value directly", async () => { + const value = await firstValueFrom(service.getEnableFeatureA(domain)); + + expect(typeof value).toBe("boolean"); + expect(value).toBe(true); + }); + + it("should return default value when flag is not configured", async () => { + const emptyDomain = uuid(); + const emptyProvider = new InMemoryProvider({}); + await OpenFeature.setProviderAndWait(emptyDomain, emptyProvider); + + const value = await firstValueFrom( + service.getEnableFeatureA(emptyDomain), + ); + + expect(value).toBe(false); + }); + }); + + describe("getGreetingMessage (convenience)", () => { + it("should return string value directly", async () => { + const value = await firstValueFrom(service.getGreetingMessage(domain)); + + expect(typeof value).toBe("string"); + expect(value).toBe("Hello from provider!"); + }); + + it("should return default value when flag is not configured", async () => { + const emptyDomain = uuid(); + const emptyProvider = new InMemoryProvider({}); + await OpenFeature.setProviderAndWait(emptyDomain, emptyProvider); + + const value = await firstValueFrom( + service.getGreetingMessage(emptyDomain), + ); + + expect(value).toBe("Hello there!"); + }); + }); + + describe("getDiscountPercentage (convenience)", () => { + it("should return number value directly", async () => { + const value = await firstValueFrom(service.getDiscountPercentage(domain)); + + expect(typeof value).toBe("number"); + expect(value).toBe(0.25); + }); + + it("should return default value when flag is not configured", async () => { + const emptyDomain = uuid(); + const emptyProvider = new InMemoryProvider({}); + await OpenFeature.setProviderAndWait(emptyDomain, emptyProvider); + + const value = await firstValueFrom( + service.getDiscountPercentage(emptyDomain), + ); + + expect(value).toBe(0.15); + }); + }); + + describe("getUsernameMaxLength (convenience)", () => { + it("should return number value directly", async () => { + const value = await firstValueFrom(service.getUsernameMaxLength(domain)); + + expect(typeof value).toBe("number"); + expect(value).toBe(100); + }); + }); + + describe("getThemeCustomization (convenience)", () => { + it("should return object value directly", async () => { + const value = await firstValueFrom(service.getThemeCustomization(domain)); + + expect(typeof value).toBe("object"); + expect(value).toEqual({ + primaryColor: "#ff0000", + secondaryColor: "#00ff00", + }); + }); + + it("should return default value when flag is not configured", async () => { + const emptyDomain = uuid(); + const emptyProvider = new InMemoryProvider({}); + await OpenFeature.setProviderAndWait(emptyDomain, emptyProvider); + + const value = await firstValueFrom( + service.getThemeCustomization(emptyDomain), + ); + + expect(value).toEqual({ + primaryColor: "#007bff", + secondaryColor: "#6c757d", + }); + }); + }); });