effect icon indicating copy to clipboard operation
effect copied to clipboard

Config provider Deno support

Open peterreisz opened this issue 2 years ago • 6 comments

What is the problem this feature would solve?

Deno has a different api for accessing the environment variables. There is no process.env. https://github.com/Effect-TS/effect/blob/ee7abb75d91d7c1c673935db254af0d4a6eb591d/src/internal/configProvider.ts#L106

What is the feature you are proposing to solve the problem?

Support Deno out of box for config provider. I'm willing to contribute.

What alternatives have you considered?

Using the ConfigProvider.fromMap and manually passing the Deno env is an option, but

  • you have to set env variables one by one
  • or grant access the whole env reading in Deno.

peterreisz avatar Oct 06 '23 09:10 peterreisz

How would supporting Deno look like?

mikearnaldi avatar Oct 07 '23 14:10 mikearnaldi

Haven't tried, but something like this should work:

diff --git a/src/internal/configProvider.ts b/src/internal/configProvider.ts
index 44af3ae58..6de804e54 100644
--- a/src/internal/configProvider.ts
+++ b/src/internal/configProvider.ts
@@ -95,6 +95,37 @@ export const fromFlat = (flat: ConfigProvider.ConfigProvider.Flat): ConfigProvid
     flattened: flat
   })
 
+interface Environment {
+  getVariable(name: string): string | undefined;
+  getAllVariables(): { [key: string]: string | undefined; }
+}
+
+interface DenoRuntime {
+  Deno: {
+    env: {
+      get(key: string): string | undefined;
+      toObject(): { [index: string]: string; };
+    }
+  }
+}
+
+const isDenoRuntime = (runtime: {}): runtime is DenoRuntime => 'Deno' in runtime
+
+const getEnvironment = (): Environment => {
+  const runtime = globalThis;
+  if (isDenoRuntime(runtime)) {
+    return {
+      getVariable: (name) => runtime.Deno.env.get(name),
+      getAllVariables: () => runtime.Deno.env.toObject(),
+    }
+  }
+
+  return {
+    getVariable: (name) => process.env[name],
+    getAllVariables: () => process.env,
+  }
+}
+
 /** @internal */
 export const fromEnv = (
   config: Partial<ConfigProvider.ConfigProvider.FromEnvConfig> = {}
@@ -103,17 +134,14 @@ export const fromEnv = (
   const makePathString = (path: ReadonlyArray<string>): string => pipe(path, RA.join(pathDelim))
   const unmakePathString = (pathString: string): ReadonlyArray<string> => pathString.split(pathDelim)
 
-  const getEnv = () =>
-    typeof process !== "undefined" && "env" in process && typeof process.env === "object" ? process.env : {}
-
   const load = <A>(
     path: ReadonlyArray<string>,
     primitive: Config.Config.Primitive<A>,
     split = true
   ): Effect.Effect<never, ConfigError.ConfigError, ReadonlyArray<A>> => {
     const pathString = makePathString(path)
-    const current = getEnv()
-    const valueOpt = pathString in current ? Option.some(current[pathString]!) : Option.none()
+    const current = getEnvironment()
+    const valueOpt = Option.fromNullable(current.getVariable(pathString)) // this is doing a different thing, but otherwise you have to grant access to all env in Deno
     return pipe(
       valueOpt,
       core.mapError(() => configError.MissingData(path, `Expected ${pathString} to exist in the process context`)),
@@ -125,8 +153,8 @@ export const fromEnv = (
     path: ReadonlyArray<string>
   ): Effect.Effect<never, ConfigError.ConfigError, HashSet.HashSet<string>> =>
     core.sync(() => {
-      const current = getEnv()
-      const keys = Object.keys(current)
+      const current = getEnvironment()
+      const keys = Object.keys(current.getAllVariables())
       const keyPaths = Array.from(keys).map((value) => unmakePathString(value.toUpperCase()))
       const filteredKeyPaths = keyPaths.filter((keyPath) => {
         for (let i = 0; i < path.length; i++) {

peterreisz avatar Oct 07 '23 16:10 peterreisz

If you want to open a PR I'd be happy to review & merge

mikearnaldi avatar Oct 26 '23 01:10 mikearnaldi

I'm glad you are open to support Deno. I'll submit a PR then, just have to figure out some things. For example how to test the project with Deno.

peterreisz avatar Oct 26 '23 08:10 peterreisz

cc @fubhy who's proposing a multi-runtime test matrix

mikearnaldi avatar Oct 28 '23 00:10 mikearnaldi

I can add a PR for the test matrix later today.

fubhy avatar Oct 28 '23 07:10 fubhy