Skip to content

Commit

Permalink
feat(core-shared-env): Added the Environment Variable Management package
Browse files Browse the repository at this point in the history
  • Loading branch information
sullivanpj committed Aug 23, 2023
1 parent 53e9a49 commit 9e071d3
Show file tree
Hide file tree
Showing 15 changed files with 314 additions and 4 deletions.
1 change: 1 addition & 0 deletions .vscode/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"supertokens",
"svgr",
"Swashbuckle",
"swcrc",
"systemvars",
"tailwindcss",
"tbenning",
Expand Down
21 changes: 21 additions & 0 deletions libs/core/typescript/shared/env/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"extends": ["../../../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
"parserOptions": {
"project": ["libs/core/typescript/shared/env/tsconfig.*?.json"]
},
"rules": {}
},
{
"files": ["*.ts", "*.tsx"],
"rules": {}
},
{
"files": ["*.js", "*.jsx"],
"rules": {}
}
]
}
31 changes: 31 additions & 0 deletions libs/core/typescript/shared/env/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"jsc": {
"target": "es2017",
"parser": {
"syntax": "typescript",
"decorators": true,
"dynamicImport": true
},
"transform": {
"decoratorMetadata": true,
"legacyDecorator": true
},
"keepClassNames": true,
"externalHelpers": true,
"loose": true
},
"module": {
"type": "commonjs",
"strict": true,
"noInterop": true
},
"sourceMaps": true,
"exclude": [
"jest.config.ts",
".*\\.spec.tsx?$",
".*\\.test.tsx?$",
"./src/jest-setup.ts$",
"./**/jest-setup.ts$",
".*.js$"
]
}
23 changes: 23 additions & 0 deletions libs/core/typescript/shared/env/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!-- START header -->

<!-- END header -->

# Core Environment Variable Management Library (Shared)

This library was generated with [Nx](https://nx.dev).

<!-- START doctoc -->

<!-- END doctoc -->

## Building

Run `nx build core-shared-env` to build the library.

## Running unit tests

Run `nx test core-shared-env` to execute the unit tests via [Jest](https://jestjs.io).

<!-- START footer -->

<!-- END footer -->
30 changes: 30 additions & 0 deletions libs/core/typescript/shared/env/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* eslint-disable */
import { readFileSync } from "fs";

// Reading the SWC compilation config and remove the "exclude"
// for the test files to be compiled by SWC
const { exclude: _, ...swcJestConfig } = JSON.parse(
readFileSync(`${__dirname}/.swcrc`, "utf-8")
);

// disable .swcrc look-up by SWC core because we're passing in swcJestConfig ourselves.
// If we do not disable this, SWC Core will read .swcrc and won't transform our test files due to "exclude"
if (swcJestConfig.swcrc === undefined) {
swcJestConfig.swcrc = false;
}

// Uncomment if using global setup/teardown files being transformed via swc
// https://nx.dev/packages/jest/documents/overview#global-setup/teardown-with-nx-libraries
// jest needs EsModule Interop to find the default exported setup/teardown functions
// swcJestConfig.module.noInterop = false;

export default {
displayName: "core-shared-env",
preset: "../../../../../testing/jest.preset.js",
transform: {
"^.+\\.[tj]s$": ["@swc/jest", swcJestConfig]
},
moduleFileExtensions: ["ts", "js", "html"],
testEnvironment: "node",
coverageDirectory: "../../../../../coverage/libs/core/typescript/shared/env"
};
8 changes: 8 additions & 0 deletions libs/core/typescript/shared/env/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"name": "@open-system/core-shared-env",
"version": "0.0.1",
"type": "commonjs",
"dependencies": {
"inversify": "^6.0.1"
}
}
50 changes: 50 additions & 0 deletions libs/core/typescript/shared/env/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "core-shared-env",
"$schema": "../../../../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "libs/core/typescript/shared/env/src",
"projectType": "library",
"targets": {
"build": {
"executor": "@nx/js:swc",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/libs/core/typescript/shared/env",
"main": "libs/core/typescript/shared/env/src/index.ts",
"tsConfig": "libs/core/typescript/shared/env/tsconfig.lib.json",
"assets": ["libs/core/typescript/shared/env/*.md"]
}
},
"lint": {
"executor": "@nx/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["libs/core/typescript/shared/env/**/*.ts"]
}
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "libs/core/typescript/shared/env/jest.config.ts",
"passWithNoTests": true
},
"configurations": {
"ci": {
"ci": true,
"codeCoverage": true
}
}
},
"semantic-release": {
"executor": "@theunderscorer/nx-semantic-release:semantic-release",
"options": {
"github": true,
"npm": false,
"changelog": true,
"tagFormat": "core-shared-env-v${VERSION}"
}
}
},
"tags": [],
"implicitDependencies": ["core-shared-utilities"]
}
52 changes: 52 additions & 0 deletions libs/core/typescript/shared/env/src/create-env-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import { isFunction, isPromise } from "@open-system/core-shared-utilities";
import { BaseOptions } from "./types";

const cache = new Map<string | symbol, any>();
let obj!: any;

const defaultOptions: BaseOptions = {
isServer: typeof window === "undefined",
skipValidation: false,
onValidationError: (error: any) => {
throw error;
},
onInvalidAccess: (variable: string) => {
throw new Error(
`Tried to access environment variable "${variable}" on the client.`
);
},
env: process.env
};

export const createEnvManager = <
T = Record<string, string | boolean | number | undefined>
>(
options: BaseOptions = defaultOptions
): T => {
if (!obj) {
obj = new Proxy(options?.env ?? defaultOptions.env ?? {}, {
get: async (target, prop) => {
let value: any;
if (cache.has(prop as string)) {
value = cache.get(prop as string);
}

if (!value && isFunction(options.handler)) {
value = options.handler(prop as string);
if (isPromise(value)) {
value = await value;
}

target[prop as string] = value;
cache.set(prop as string, value);
}

return value;
}
});
}

return obj;
};
2 changes: 2 additions & 0 deletions libs/core/typescript/shared/env/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./create-env-manager";
export * from "./types";
42 changes: 42 additions & 0 deletions libs/core/typescript/shared/env/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { ZodError } from "zod";

export const CONFIG_TOKEN = Symbol.for("CONFIG_TOKEN");

export interface BaseOptions {
/**
* How to determine whether the app is running on the server or the client.
* @default typeof window === "undefined"
*/
isServer?: boolean;

/**
* Called when validation fails. By default the error is logged,
* and an error is thrown telling what environment variables are invalid.
*/
onValidationError?: (error: ZodError) => never;

/**
* Called when a server-side environment variable is accessed on the client.
* By default an error is thrown.
*/
onInvalidAccess?: (variable: string) => never;

/**
* Whether to skip validation of environment variables.
* @default false
*/
skipValidation?: boolean;

/**
* Handler for when an environment variable is accessed and does not exist
* in the environment.
* @param prop The name of the environment variable that was accessed.
* @returns The value of the environment variable.
*/
handler?: (prop: string | symbol) => Awaited<Promise<any> | any>;

/**
* The environment variables to use. Defaults to `process.env`.
*/
env?: Record<string, string | undefined>;
}
22 changes: 22 additions & 0 deletions libs/core/typescript/shared/env/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"extends": "../../../../../tsconfig.base.json",
"compilerOptions": {
"module": "commonjs",
"forceConsistentCasingInFileNames": true,
"strict": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.lib.json"
},
{
"path": "./tsconfig.spec.json"
}
]
}
10 changes: 10 additions & 0 deletions libs/core/typescript/shared/env/tsconfig.lib.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../../dist/out-tsc",
"declaration": true,
"types": ["node"]
},
"include": ["src/**/*.ts"],
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}
14 changes: 14 additions & 0 deletions libs/core/typescript/shared/env/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../../../../dist/out-tsc",
"module": "commonjs",
"types": ["jest", "node"]
},
"include": [
"jest.config.ts",
"src/**/*.test.ts",
"src/**/*.spec.ts",
"src/**/*.d.ts"
]
}
4 changes: 2 additions & 2 deletions prettier.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
plugins: [require("prettier-plugin-tailwindcss")],
trailingComma: "es5",
trailingComma: "none",
tabWidth: 2,
semi: true,
singleQuote: false,
Expand All @@ -11,5 +11,5 @@ module.exports = {
bracketSpacing: true,
arrowParens: "avoid",
endOfLine: "lf",
insertFinalNewline: false,
insertFinalNewline: false
};
8 changes: 6 additions & 2 deletions tsconfig.base.json
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,12 @@
"@open-system/core-shared-data-access/*": [
"libs/core/typescript/shared/data-access/src/*"
],
"@open-system/core-shared-env": [
"libs/core/typescript/shared/env/src/index.ts"
],
"@open-system/core-shared-env/*": [
"libs/core/typescript/shared/env/src/*"
],
"@open-system/core-shared-injection": [
"libs/core/typescript/shared/injection/src/index.ts"
],
Expand Down Expand Up @@ -212,8 +218,6 @@
"libs/engagement/typescript/shared/data-access/src/*"
],
"@open-system/engagement/config": ["libs/engagement/config/src/index.ts"],
"@open-system/executors-dotnet": ["tools/executors/dotnet/index.ts"],
"@open-system/generators-dotnet": ["tools/generators/dotnet/index.ts"],
"@open-system/portfolio-client-resume": [
"libs/portfolio/typescript/client/resume/src/index.ts"
],
Expand Down

0 comments on commit 9e071d3

Please sign in to comment.