diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..9e31981 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @splitio/sdk diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..81a9a8e --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,32 @@ +name: test +on: + pull_request: + branches: + - '*' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build: + name: Run tests + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'npm' + + - name: npm ci + run: npm ci + + - name: npm check + run: npm run check + + - name: npm test + run: npm run test diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..49239fa --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,9 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: check-added-large-files + - id: check-json + - id: check-yaml + - id: end-of-file-fixer + - id: trailing-whitespace diff --git a/package.json b/package.json index 527e3dc..54ffd02 100644 --- a/package.json +++ b/package.json @@ -60,9 +60,6 @@ "build": "rimraf lib es && npm run build-cjs && npm run build-esm", "check": "npm run check:version", "check:version": "cross-env NODE_ENV=test tape -r ./ts-node.register src/settings/__tests__/defaults.spec.js", - "pretest-ts-decls": "npm run build-esm && npm run build-cjs && npm link", - "test-ts-decls": "./scripts/ts-tests.sh", - "posttest-ts-decls": "npm unlink && npm install", "test": "cross-env NODE_ENV=test tape -r ./ts-node.register src/__tests__/node.spec.js | tap-min", "publish:rc": "npm run check && npm run build && npm publish --tag canary", "publish:stable": "npm run check && npm run build && npm publish" diff --git a/scripts/build_esm_replace_imports.sh b/scripts/build_esm_replace_imports.sh index 81cfb81..efa9e81 100755 --- a/scripts/build_esm_replace_imports.sh +++ b/scripts/build_esm_replace_imports.sh @@ -3,6 +3,9 @@ # replace splitio-commons imports to use ES modules replace '@splitsoftware/splitio-commons/src' '@splitsoftware/splitio-commons/esm' ./es -r +# Fix import extension in es/index.js +replace './lib/js-split-provider' './lib/js-split-provider.js' ./es/index.js -r + if [ $? -eq 0 ] then exit 0 diff --git a/scripts/ts-tests.sh b/scripts/ts-tests.sh deleted file mode 100755 index 2263e92..0000000 --- a/scripts/ts-tests.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -cd ts-tests ## Go to typescript tests folder -echo "Installing dependencies for TypeScript declarations testing..." -npm install ## Install dependencies -npm install @types/node@6.0.31 ## Install type definitions for Node.js v6.x (the oldest supported version) -echo "Dependencies installed, linking the package." -npm link @splitsoftware/splitio ## Link to the cloned code -echo "Running tsc compiler." -./node_modules/.bin/tsc ## Run typescript compiler. No need for flags as we have a tsconfig.json file - -echo "Testing again with the latest @types/node version..." -npm install @types/node@14 ## Install latest type definitions for Node.js -echo "Dependencies installed, linking the package." -npm link @splitsoftware/splitio ## Link to the cloned code -echo "Running tsc compiler." -./node_modules/.bin/tsc ## Run typescript compiler. No need for flags as we have a tsconfig.json file - -if [ $? -eq 0 ] -then - echo "✅ Successfully compiled TS tests." - npm unlink @splitsoftware/splitio - exit 0 -else - echo "☠️ Error compiling TS tests." - npm unlink @splitsoftware/splitio - exit 1 -fi diff --git a/src/__tests__/nodeSuites/client.spec.js b/src/__tests__/nodeSuites/client.spec.js index e134e64..2cdc813 100644 --- a/src/__tests__/nodeSuites/client.spec.js +++ b/src/__tests__/nodeSuites/client.spec.js @@ -47,11 +47,13 @@ export default async function(assert) { }; const getBooleanSplitWithKeyTest = async (client) => { - let result = await client.getBooleanValue('my_feature', false); - assert.equals(result, true); + let result = await client.getBooleanDetails('my_feature', false); + assert.equals(result.value, true); + assert.looseEquals(result.flagMetadata, { desc: 'this applies only to ON treatment' }); - result = await client.getBooleanValue('my_feature', true, { targetingKey: 'randomKey' }); - assert.equals(result, false); + result = await client.getBooleanDetails('my_feature', true, { targetingKey: 'randomKey' }); + assert.equals(result.value, false); + assert.looseEquals(result.flagMetadata, {}); }; const getStringSplitTest = async (client) => { diff --git a/src/index.ts b/src/index.ts index 039d5a4..6750e9f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1 @@ -export * from './lib/js-split-provider.js'; +export * from './lib/js-split-provider'; diff --git a/src/lib/js-split-provider.ts b/src/lib/js-split-provider.ts index 6fdaf55..6bcfc1b 100644 --- a/src/lib/js-split-provider.ts +++ b/src/lib/js-split-provider.ts @@ -20,6 +20,7 @@ type Consumer = { }; const CONTROL_VALUE_ERROR_MESSAGE = "Received the 'control' value from Split."; +const CONTROL_TREATMENT = "control"; export class OpenFeatureSplitProvider implements Provider { metadata = { @@ -53,32 +54,15 @@ export class OpenFeatureSplitProvider implements Provider { this.transformContext(context) ); - let value: boolean; - switch (details.value as unknown) { - case "on": - value = true; - break; - case "off": - value = false; - break; - case "true": - value = true; - break; - case "false": - value = false; - break; - case true: - value = true; - break; - case false: - value = false; - break; - case "control": - throw new FlagNotFoundError(CONTROL_VALUE_ERROR_MESSAGE); - default: - throw new ParseError(`Invalid boolean value for ${details.value}`); + if ( details.value === "on" || details.value === "true" ) { + return { ...details, value: true }; + } + + if ( details.value === "off" || details.value === "false" ) { + return { ...details, value: false }; } - return { ...details, value }; + + throw new ParseError(`Invalid boolean value for ${details.value}`); } async resolveStringEvaluation( @@ -90,9 +74,6 @@ export class OpenFeatureSplitProvider implements Provider { flagKey, this.transformContext(context) ); - if (details.value === "control") { - throw new FlagNotFoundError(CONTROL_VALUE_ERROR_MESSAGE); - } return details; } @@ -130,14 +111,19 @@ export class OpenFeatureSplitProvider implements Provider { ); } else { await this.initialized; - const value = this.client.getTreatment( + const {treatment: value, config}: SplitIO.TreatmentWithConfig = this.client.getTreatmentWithConfig( consumer.key, flagKey, consumer.attributes ); + if (value === CONTROL_TREATMENT) { + throw new FlagNotFoundError(CONTROL_VALUE_ERROR_MESSAGE); + } + const flagMetadata = config ? JSON.parse(config) : undefined; const details: ResolutionDetails = { value: value, variant: value, + flagMetadata: flagMetadata, reason: StandardResolutionReasons.TARGETING_MATCH, }; return details;