From 51e601b63bb81fa3eef125a60e694da13dedc67f Mon Sep 17 00:00:00 2001 From: Tymoteusz Czech <2625371+Tymek@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:57:31 +0100 Subject: [PATCH] feat: variant feature status - client specification update --- package.json | 2 +- src/client.ts | 61 ++++++++--------- src/index.ts | 6 +- src/test/client.test.ts | 8 +-- src/test/snapshots/client.test.ts.md | 18 ++--- src/test/snapshots/client.test.ts.snap | Bin 372 -> 373 bytes src/test/snapshots/index.test.ts.md | 1 + src/test/snapshots/index.test.ts.snap | Bin 222 -> 234 bytes src/unleash.ts | 91 +++++++++++++------------ src/variant.ts | 22 +++--- yarn.lock | 8 +-- 11 files changed, 108 insertions(+), 109 deletions(-) diff --git a/package.json b/package.json index 6d8c78e8..9a0f2d9b 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@types/sinon": "^10.0.15", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", - "@unleash/client-specification": "^5.0.2", + "@unleash/client-specification": "^5.1.0", "ava": "^5.3.0", "coveralls": "^3.1.1", "cross-env": "^7.0.3", diff --git a/src/client.ts b/src/client.ts index 59c7705b..cbc28a38 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2,10 +2,7 @@ import { EventEmitter } from 'events'; import { Strategy, StrategyTransportInterface } from './strategy'; import { FeatureInterface } from './feature'; import { RepositoryInterface } from './repository'; -import { - Variant, VariantDefinition, - getDefaultVariant, selectVariant, VariantWithFeatureStatus, -} from './variant'; +import { Variant, VariantDefinition, defaultVariant, selectVariant } from './variant'; import { Context } from './context'; import { Constraint, Segment, StrategyResult } from './strategy/strategy'; import { createImpressionEvent, UnleashEvents } from './events'; @@ -46,9 +43,11 @@ export default class UnleashClient extends EventEmitter { return this.strategies.find((strategy: Strategy): boolean => strategy.name === name); } - warnStrategyOnce(missingStrategy: string, - name: string, - strategies: StrategyTransportInterface[]) { + warnStrategyOnce( + missingStrategy: string, + name: string, + strategies: StrategyTransportInterface[], + ) { if (!this.warnedStrategies[missingStrategy + name]) { this.warnedStrategies[missingStrategy + name] = true; this.emit( @@ -75,7 +74,7 @@ export default class UnleashClient extends EventEmitter { return true; } - return feature.dependencies.every(parent => { + return feature.dependencies.every((parent) => { const parentToggle = this.repository.getToggle(parent.feature); if (!parentToggle) { @@ -88,7 +87,10 @@ export default class UnleashClient extends EventEmitter { if (parent.enabled !== false) { if (parent.variants?.length) { - const {name, featureEnabled} = this.getVariant(parent.feature, context); + const { name, feature_enabled: featureEnabled } = this.getVariant( + parent.feature, + context, + ); return featureEnabled && parent.variants.includes(name); } return this.isEnabled(parent.feature, context, () => false); @@ -149,11 +151,12 @@ export default class UnleashClient extends EventEmitter { return false; } const constraints = this.yieldConstraintsFor(strategySelector); - const result = - strategy.getResult(strategySelector.parameters, - context, - constraints, - strategySelector.variants); + const result = strategy.getResult( + strategySelector.parameters, + context, + constraints, + strategySelector.variants, + ); if (result.enabled) { strategyResult = result; @@ -165,7 +168,7 @@ export default class UnleashClient extends EventEmitter { return strategyResult; } - * yieldConstraintsFor( + *yieldConstraintsFor( strategy: StrategyTransportInterface, ): IterableIterator { if (strategy.constraints) { @@ -178,7 +181,7 @@ export default class UnleashClient extends EventEmitter { yield* this.yieldSegmentConstraints(segments); } - * yieldSegmentConstraints( + *yieldSegmentConstraints( segments: (Segment | undefined)[], ): IterableIterator { // eslint-disable-next-line no-restricted-syntax @@ -194,7 +197,7 @@ export default class UnleashClient extends EventEmitter { } } - getVariant(name: string, context: Context, fallbackVariant?: Variant): VariantWithFeatureStatus { + getVariant(name: string, context: Context, fallbackVariant?: Variant): Variant { const feature = this.repository.getToggle(name); const variant = this.resolveVariant(feature, context, true, fallbackVariant); if (feature?.impressionData) { @@ -215,9 +218,7 @@ export default class UnleashClient extends EventEmitter { // This function is intended to close an issue in the proxy where feature enabled // state gets checked twice when resolving a variant with random stickiness and // gradual rollout. This is not intended for general use, prefer getVariant instead - forceGetVariant(name: string, - context: Context, - fallbackVariant?: Variant): VariantWithFeatureStatus { + forceGetVariant(name: string, context: Context, fallbackVariant?: Variant): Variant { const feature = this.repository.getToggle(name); return this.resolveVariant(feature, context, true, fallbackVariant); } @@ -227,11 +228,11 @@ export default class UnleashClient extends EventEmitter { context: Context, checkToggle: boolean, fallbackVariant?: Variant, - ): VariantWithFeatureStatus { - const fallback = fallbackVariant || getDefaultVariant(); + ): Variant { + const fallback = fallbackVariant || defaultVariant; if (typeof feature === 'undefined') { - return { ...fallback, featureEnabled: false }; + return { ...fallback, feature_enabled: false }; } let featureEnabled = !checkToggle; @@ -240,30 +241,28 @@ export default class UnleashClient extends EventEmitter { featureEnabled = result.enabled; if (result.enabled && result.variant) { - return { ...result.variant, featureEnabled }; + return { ...result.variant, feature_enabled: featureEnabled }; } if (!result.enabled) { - return { ...fallback, featureEnabled }; + return { ...fallback, feature_enabled: featureEnabled }; } } - if (!feature.variants || - !Array.isArray(feature.variants) || - feature.variants.length === 0) { - return { ...fallback, featureEnabled }; + if (!feature.variants || !Array.isArray(feature.variants) || feature.variants.length === 0) { + return { ...fallback, feature_enabled: featureEnabled }; } const variant: VariantDefinition | null = selectVariant(feature, context); if (variant === null) { - return { ...fallback, featureEnabled }; + return { ...fallback, feature_enabled: featureEnabled }; } return { name: variant.name, payload: variant.payload, enabled: true, - featureEnabled, + feature_enabled: featureEnabled, }; } } diff --git a/src/index.ts b/src/index.ts index 0467824d..e21602b7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { once } from 'events'; import { Unleash } from './unleash'; -import { Variant, getDefaultVariant, PayloadType } from './variant'; +import { Variant, defaultVariant, PayloadType } from './variant'; import { Context } from './context'; import { TagFilter } from './tags'; import { UnleashEvents } from './events'; @@ -53,7 +53,7 @@ export function getVariant( context: Context = {}, fallbackVariant?: Variant, ): Variant { - const variant = fallbackVariant || getDefaultVariant(); + const variant = fallbackVariant || defaultVariant; return instance ? instance.getVariant(name, context, variant) : variant; } @@ -62,7 +62,7 @@ export function forceGetVariant( context: Context = {}, fallbackVariant?: Variant, ): Variant { - const variant = fallbackVariant || getDefaultVariant(); + const variant = fallbackVariant || defaultVariant; return instance ? instance.forceGetVariant(name, context, variant) : variant; } diff --git a/src/test/client.test.ts b/src/test/client.test.ts index 426c44aa..0117d018 100644 --- a/src/test/client.test.ts +++ b/src/test/client.test.ts @@ -248,7 +248,7 @@ test('should always return defaultVariant if missing variant', (t) => { const defaultVariant = { enabled: false, name: 'disabled', - featureEnabled: true + feature_enabled: true }; t.deepEqual(result, defaultVariant); @@ -259,7 +259,7 @@ test('should always return defaultVariant if missing variant', (t) => { type: 'string', value: '', }, - featureEnabled: true + feature_enabled: true }; const result2 = client.getVariant('feature-but-no-variant', {}, fallback); @@ -381,7 +381,7 @@ test('should favor strategy variant over feature variant', (t) => { name: 'strategyVariantName', payload: { type: 'string', value: 'strategyVariantValue' }, enabled: true, - featureEnabled: true + feature_enabled: true }, ); }); @@ -411,7 +411,7 @@ test('should return disabled variant for non-matching strategy variant', (t) => t.deepEqual(variant, { name: 'disabled', enabled: false, - featureEnabled: false, + feature_enabled: false, }, ); }); diff --git a/src/test/snapshots/client.test.ts.md b/src/test/snapshots/client.test.ts.md index 15fa9ec8..67e13901 100644 --- a/src/test/snapshots/client.test.ts.md +++ b/src/test/snapshots/client.test.ts.md @@ -10,7 +10,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -22,7 +22,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -34,7 +34,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -48,7 +48,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -60,7 +60,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant1', payload: { type: 'string', @@ -72,7 +72,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -86,7 +86,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -98,7 +98,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant3', payload: { type: 'string', @@ -110,7 +110,7 @@ Generated by [AVA](https://avajs.dev). { enabled: true, - featureEnabled: true, + feature_enabled: true, name: 'variant2', payload: { type: 'string', diff --git a/src/test/snapshots/client.test.ts.snap b/src/test/snapshots/client.test.ts.snap index 8bf258394171363658de29db3b8dd16d3b9e122c..3c3968d8e54be3a8216f5344637b5f10a5eadddb 100644 GIT binary patch literal 373 zcmV-*0gC=XRzV;t zBm4o>S|5uD00000000B+RxwV)FckGq)3ggD6^Pjf$dEJ=LQLF%nFaLIxJ|$~A#qwd zmy48*Yj7VXF2HZqWC#*c#XwMF`^o!$t>19Ror)}Cxya{4(VdGjv~}}0~b9uV4DU*=wH%&MYtur z5Z(wUV2!}K4)4W81Jp~$aTpviFd5jCW1K>dL4O1Tp)iyp+Qx?6*tMquiL1E#G0Rl= zD5_w%yH>#97~q{4)ul3A$`qpw_1*_N4IgLZpV4Pp-aS3O zRfJOrnjeb@00000000B+Rv+nuHdh%u#%5?gem#?T3E%C+6O|sMzfq=FY0o3uCqkV8!6UO$fC~a zQ51Cgb^86Kew7CV2Y5gbxVzEWz|lTqzg_zI|4qNPy}!x^E)Mw$c%HjQ=LARV1f71r S({Iu){U%?2Y8ycw3;+O)&aM9d diff --git a/src/test/snapshots/index.test.ts.md b/src/test/snapshots/index.test.ts.md index 11a74b24..680844d6 100644 --- a/src/test/snapshots/index.test.ts.md +++ b/src/test/snapshots/index.test.ts.md @@ -18,6 +18,7 @@ Generated by [AVA](https://avajs.dev). { enabled: false, + feature_enabled: false, name: 'disabled', } diff --git a/src/test/snapshots/index.test.ts.snap b/src/test/snapshots/index.test.ts.snap index e7521419ff49f6c8ecf303bb37c8f7412ced3ecd..50b8566647f91e6a849e0285659fb112e6cf2024 100644 GIT binary patch literal 234 zcmVO)lFKJ34;eq)L{d-U1X9SZ}XZ5eSjuT z<*MNeLLZ9=00000000AhjzJEBKnz8vfWn3_L=V6zTzLc&x5kYrObO@!#wmMUco0my zrvpY3NwmpN|9}09c6q9s>||~a;*vEPQ#7qsNrqY{6>-rhQ<@sjmb1BcN+ILM6~5>P z93iL37vUT2o+AsuTiLy~+FM<%7BG)tzD boolean { o.values.some((value) => value === resolveContextValue(context, o.contextName)); } -function findOverride(variants: VariantDefinition[], - context: Context): VariantDefinition | undefined { +function findOverride( + variants: VariantDefinition[], + context: Context, +): VariantDefinition | undefined { return variants .filter((variant) => variant.overrides) .find((variant) => variant.overrides?.some(overrideMatchesContext(context))); diff --git a/yarn.lock b/yarn.lock index e0420986..3b89d859 100644 --- a/yarn.lock +++ b/yarn.lock @@ -785,10 +785,10 @@ "@typescript-eslint/types" "6.4.1" eslint-visitor-keys "^3.4.1" -"@unleash/client-specification@^5.0.2": - version "5.0.2" - resolved "https://registry.yarnpkg.com/@unleash/client-specification/-/client-specification-5.0.2.tgz#810303f04baf6f547148c90cecbbe87dd5fb221e" - integrity sha512-KW/NEQFcjuuxoDDTyL9GcotJxntr4qQ1Kk+iHA/FrFMXpLHvulGNwPE9ojcwVRk02jNE+7hLW4q1B5JSblnTFA== +"@unleash/client-specification@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@unleash/client-specification/-/client-specification-5.1.0.tgz#f95d76b085d857ab89830e5f3ba7ea5482254bd0" + integrity sha512-703U1Sw2hXg5MrVXXfEwAIWMinUxTfOHpbcjdjbTyxejaK0mjx4S8zBc5pffs/jlmwSct9eJuRNWnRvWGPQaxg== acorn-jsx@^5.3.2: version "5.3.2"