Skip to content

Commit

Permalink
made Config.redacted more general (#3873)
Browse files Browse the repository at this point in the history
Co-authored-by: maksim.khramtsov <maksim.khramtsov@btsdigital.kz>
  • Loading branch information
2 people authored and tim-smart committed Oct 31, 2024
1 parent cf11383 commit e0ba56d
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 9 deletions.
22 changes: 22 additions & 0 deletions .changeset/tidy-trainers-serve.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
"effect": minor
---

`Config.redacted` has been made more flexible and can now wrap any other config. This allows to transform or validate config values before it’s hidden.

```ts
import { Config } from "effect"

Effect.gen(function* () {
// can be any string including empty
const pass1 = yield* Config.redacted("PASSWORD")
// ^? Redacted<string>

// can't be empty string
const pass2 = yield* Config.redacted(Config.nonEmptyString("PASSWORD"))
// ^? Redacted<string>

const pass2 = yield* Config.redacted(Config.number("SECRET_NUMBER"))
// ^? Redacted<number>
})
```
5 changes: 4 additions & 1 deletion packages/effect/src/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ export const secret: (name?: string) => Config<Secret.Secret> = internal.secret
* @since 2.0.0
* @category constructors
*/
export const redacted: (name?: string) => Config<Redacted.Redacted> = internal.redacted
export const redacted: {
(name?: string): Config<Redacted.Redacted>
<A>(config: Config<A>): Config<Redacted.Redacted<A>>
} = internal.redacted

/**
* Constructs a config for a sequence of values.
Expand Down
11 changes: 5 additions & 6 deletions packages/effect/src/internal/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,12 +437,11 @@ export const secret = (name?: string): Config.Config<Secret.Secret> => {
}

/** @internal */
export const redacted = (name?: string): Config.Config<Redacted.Redacted> => {
const config = primitive(
"a redacted property",
(text) => Either.right(redacted_.make(text))
)
return name === undefined ? config : nested(config, name)
export const redacted = <A>(
nameOrConfig?: string | Config.Config<A>
): Config.Config<Redacted.Redacted<A | string>> => {
const config: Config.Config<A | string> = isConfig(nameOrConfig) ? nameOrConfig : string(nameOrConfig)
return map(config, redacted_.make)
}

/** @internal */
Expand Down
19 changes: 17 additions & 2 deletions packages/effect/test/Config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ const assertSuccess = <A>(
expect(result).toStrictEqual(Exit.succeed(a))
}

const assertEqualSuccess = <A>(
config: Config.Config<A>,
map: ReadonlyArray<readonly [string, string]>,
a: A
) => {
const configProvider = ConfigProvider.fromMap(new Map(map))
const result = Effect.runSync(Effect.exit(configProvider.load(config)))
expect(Equal.equals(Exit.succeed(a), result)).toBe(true)
}

describe("Config", () => {
describe("boolean", () => {
it("name = undefined", () => {
Expand Down Expand Up @@ -534,7 +544,12 @@ describe("Config", () => {

it("name != undefined", () => {
const config = Config.redacted("SECRET")
assertSuccess(config, [["SECRET", "a"]], Redacted.make("a"))
assertEqualSuccess(config, [["SECRET", "a"]], Redacted.make("a"))
})

it("can wrap generic Config", () => {
const config = Config.redacted(Config.integer("NUM"))
assertEqualSuccess(config, [["NUM", "2"]], Redacted.make(2))
})
})

Expand All @@ -547,7 +562,7 @@ describe("Config", () => {

it("name != undefined", () => {
const config = Config.secret("SECRET")
assertSuccess(config, [["SECRET", "a"]], Secret.fromString("a"))
assertEqualSuccess(config, [["SECRET", "a"]], Secret.fromString("a"))
})
})

Expand Down

0 comments on commit e0ba56d

Please sign in to comment.