Skip to content

Instantly share code, notes, and snippets.

@moatorres
Created May 2, 2025 14:35
Show Gist options
  • Save moatorres/b2f6d6a85a40fc90b651810137daa6b9 to your computer and use it in GitHub Desktop.
Save moatorres/b2f6d6a85a40fc90b651810137daa6b9 to your computer and use it in GitHub Desktop.
Effect Config
import { resolve } from 'path'
import { NodeContext, NodeRuntime } from '@effect/platform-node'
import dotenv from 'dotenv'
import { Config, Effect, identity, Logger, LogLevel } from 'effect'
import { argv } from 'process'
const ENV_FILE = resolve(
process.cwd(),
`${argv[2]?.includes('.env') ? argv[2] : `${argv[2]}/.env`}`
)
dotenv.config({ path: ENV_FILE })
function orange(str: string): string {
return `\x1b[1;33m${str}\x1b[0m`
}
function warn(e: unknown): void {
console.error(orange('\nWARNING:'), e)
}
const program = Effect.gen(function* () {
yield* Effect.log('Config')
if (argv.length < 3) {
yield* Effect.logWarning(
'Path to the .env file was not provided. Running with defaults. Usage: `tsx src/utils/cli.ts <path-to-env>`.'
)
} else {
yield* Effect.log(`.env: \x1b[0m${ENV_FILE}`).pipe(
Effect.annotateLogs({ ['.env']: ENV_FILE })
)
}
const config = {
author: yield* Config.nonEmptyString('NEXT_PUBLIC_AUTHOR_NAME').pipe(
Config.withDefault('John Doe')
),
baseUrl: yield* Config.nonEmptyString('NEXT_PUBLIC_BASE_URL').pipe(
Config.withDefault('http://localhost:3000')
),
contentDirectory: yield* Config.string('APP_CONTENT_DIRECTORY').pipe(
Config.withDefault('src/content')
),
contentRoute: yield* Config.string('APP_CONTENT_ROUTE').pipe(
Config.withDefault('blog')
),
description: yield* Config.string('APP_DESCRIPTION').pipe(
Config.withDefault("John Doe's Personal Blog")
),
discordUrl: yield* Config.string('NEXT_PUBLIC_DISCORD_URL').pipe(
Config.withDefault('https://discord.com/')
),
facebookUrl: yield* Config.string('NEXT_PUBLIC_FACEBOOK_URL').pipe(
Config.withDefault('https://facebook.com/')
),
githubUrl: yield* Config.string('NEXT_PUBLIC_GITHUB_URL').pipe(
Config.withDefault('https://github.com/')
),
instagramUrl: yield* Config.string('NEXT_PUBLIC_INSTAGRAM_URL').pipe(
Config.withDefault('https://instagram.com/')
),
linkedinUrl: yield* Config.string('NEXT_PUBLIC_LINKEDIN_URL').pipe(
Config.withDefault('https://linkedin.com/in/')
),
metadataDirectory: yield* Config.string('APP_METADATA_DIRECTORY').pipe(
Config.withDefault('src/data')
),
orcidUrl: yield* Config.string('NEXT_PUBLIC_ORCID_URL').pipe(
Config.withDefault('https://orcid.org/')
),
sections: yield* Config.string('APP_SECTIONS').pipe(
Config.withDefault('blog'),
Config.map((s) => {
const sections = s.split(',').map((section) => ({
name: section.trim(),
}))
return sections
})
),
title: yield* Config.nonEmptyString('APP_TITLE').pipe(
Config.withDefault('John Doe')
),
twitterUrl: yield* Config.string('NEXT_PUBLIC_TWITTER_URL').pipe(
Config.withDefault('https://twitter.com/')
),
}
yield* Effect.logDebug(config)
yield* Effect.log(orange(`Author: ${config.author}`))
yield* Effect.log(orange(`Title: ${config.title}`))
yield* Effect.log(orange(`Description: ${config.description}`))
yield* Effect.log(orange(`Base URL: ${config.baseUrl}`))
yield* Effect.log(orange(`Content Directory: ${config.contentDirectory}`))
yield* Effect.log(orange(`Content Route: ${config.contentRoute}`))
yield* Effect.log(orange(`Metadata Directory: ${config.metadataDirectory}`))
yield* Effect.log('Done')
return config
}).pipe(
Effect.match({
onFailure: (error) => 'message' in error && warn(error.message),
onSuccess: identity,
})
)
export const config = NodeRuntime.runMain(
program.pipe(
Effect.provide(NodeContext.layer),
Logger.withMinimumLogLevel(LogLevel.Info),
Effect.catchAllCause(Effect.logError)
)
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment