Skip to content

Commit

Permalink
Merge pull request #30 from vordgi/nic-21
Browse files Browse the repository at this point in the history
nic-21 configure husky
  • Loading branch information
vordgi committed Apr 11, 2024
2 parents c4ee8e0 + 61c1a52 commit 993cce1
Show file tree
Hide file tree
Showing 19 changed files with 109 additions and 88 deletions.
1 change: 1 addition & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pnpm run lint
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "",
"scripts": {
"nimpl:config": "pnpm --filter @nimpl/config",
"eslint": "eslint \"package/\""
"lint": "eslint \"package/\"",
"eslint": "eslint",
"prepare": "husky"
},
"keywords": [],
"author": "",
Expand All @@ -13,6 +15,7 @@
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"husky": "^9.0.11",
"prettier": "^3.2.5",
"typescript-eslint": "^7.6.0"
}
Expand Down
2 changes: 1 addition & 1 deletion package/src/build-config.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const buildConfig = process.env.NIMPL_CONFIG_BUILD && JSON.parse(process.env.NIMPL_CONFIG_BUILD);
export const buildConfig = process.env.NIMPL_CONFIG_BUILD && JSON.parse(process.env.NIMPL_CONFIG_BUILD);
19 changes: 11 additions & 8 deletions package/src/lib/configure-package-types.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
import path from 'path';
import { existsSync, writeFileSync } from 'fs';
import path from "path";
import { existsSync, writeFileSync } from "fs";

const configurePackageTypes = (folder: string) => {
const configDeclarationsPath = path.join(process.cwd(), 'nimpl-config.d.ts');
const configDeclarationsPath = path.join(process.cwd(), "nimpl-config.d.ts");
const configFolderPath = path.join(process.cwd(), folder);

if (!existsSync(configFolderPath)) {
throw new Error('@nimpl/config: config folder doesn\'t exist');
throw new Error("@nimpl/config: config folder doesn't exist");
}

const configFolderRelativePath = path.relative(process.cwd(), configFolderPath);
const normalizedRelativePath = './' + configFolderRelativePath.replace(/\/{2,}|\\+/g, '/').replace(/\/$/, '');
const normalizedRelativePath = "./" + configFolderRelativePath.replace(/\/{2,}|\\+/g, "/").replace(/\/$/, "");

if (!existsSync(configDeclarationsPath)) {
console.log(`nimpl-config: nimpl-config.d.ts file with configs types was generated`);
writeFileSync(configDeclarationsPath, `// NOTE: This file should not be edited
writeFileSync(
configDeclarationsPath,
`// NOTE: This file should not be edited
// see https://nimpl.tech/config/configuration#typescript for more information.
declare module "@nimpl/config/use-runtime-config" {
Expand All @@ -33,8 +35,9 @@ declare module "@nimpl/config/postbuild-config" {
declare module "@nimpl/config/server-config" {
export declare const serverConfig: Promise<typeof import('${normalizedRelativePath}/server/default')>;
}
`);
`,
);
}
}
};

export default configurePackageTypes;
38 changes: 22 additions & 16 deletions package/src/lib/format-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { Config, ConfigItem } from "./types";

const isMergeablePart = (part: ConfigItem): part is Record<string, ConfigItem> => {
return Boolean(part) && typeof part === 'object' && !Array.isArray(part);
}
return Boolean(part) && typeof part === "object" && !Array.isArray(part);
};

const mergeParts = async (basePart: ConfigItem, parts: ConfigItem[], subKey?: string): Promise<ConfigItem> => {
if (isMergeablePart(basePart)) {
Expand All @@ -15,45 +15,51 @@ const mergeParts = async (basePart: ConfigItem, parts: ConfigItem[], subKey?: st
acc.push(cur[key]);
}
} else {
throw new Error(`Different type for "${subKey}". Should be: object; got: ${Array.isArray(cur) ? 'Array' : typeof cur}`);
throw new Error(
`Different type for "${subKey}". Should be: object; got: ${Array.isArray(cur) ? "Array" : typeof cur}`,
);
}
return acc;
}, []);
newPart[key] = await mergeParts(value, existedParts, `${subKey ? `${subKey}.` : ''}${key}`);
newPart[key] = await mergeParts(value, existedParts, `${subKey ? `${subKey}.` : ""}${key}`);
}

return newPart;
}

if (typeof basePart === 'function') {
if (typeof basePart === "function") {
const basePartResult = await basePart();
const partsResult = await Promise.all(parts.map(part => {
if (typeof part === 'function') {
return part();
} else {
throw new Error(`Different type for "${subKey}". Should be: function; got: ${typeof part}`);
}
}))
const partsResult = await Promise.all(
parts.map((part) => {
if (typeof part === "function") {
return part();
} else {
throw new Error(`Different type for "${subKey}". Should be: function; got: ${typeof part}`);
}
}),
);
const newPart = await mergeParts(basePartResult, partsResult, subKey);
return newPart;
}

const lastExistedPart = parts.findLast(part => part !== undefined);
const lastExistedPart = parts.findLast((part) => part !== undefined);

if (lastExistedPart) {
if (Array.isArray(basePart) && !Array.isArray(lastExistedPart)) {
throw new Error(`Different type for "${subKey}". Should be: Array; got: ${typeof lastExistedPart}`);
}
if (lastExistedPart !== null && typeof basePart !== typeof lastExistedPart) {
throw new Error(`Different type for "${subKey}". Should be: ${typeof basePart}; got: ${typeof lastExistedPart}`);
throw new Error(
`Different type for "${subKey}". Should be: ${typeof basePart}; got: ${typeof lastExistedPart}`,
);
}
return lastExistedPart;
}

return lastExistedPart || basePart;
}
};

export const mergeConfigs = async (baseConfig: Config, configs: Config[]) => {
const result = await mergeParts(baseConfig, configs);
return result;
}
};
4 changes: 2 additions & 2 deletions package/src/lib/get-build-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import getConfig from "./get-config";

const getBuildConfig = async (configFolder?: string) => {
const config = await getConfig({ variant: 'build', configFolder });
const config = await getConfig({ variant: "build", configFolder });
return config;
}
};

export default getBuildConfig;
6 changes: 3 additions & 3 deletions package/src/lib/get-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import { injectEnvsToConfig } from "./inject-envs";
import { findConfigs, getConfigVariantFolder, loadConfig } from "./utils";

type GetConfigParam = {
variant: 'build' | 'postbuild' | 'server' | 'runtime';
variant: "build" | "postbuild" | "server" | "runtime";
env?: string;
configFolder?: string;
}
};

const getConfig = async ({ variant, env, configFolder }: GetConfigParam) => {
const variantFolder = getConfigVariantFolder(variant, configFolder);
Expand All @@ -25,6 +25,6 @@ const getConfig = async ({ variant, env, configFolder }: GetConfigParam) => {

const config = await mergeConfigs(defaultConfig, otherConfigs.filter(Boolean));
return config;
}
};

export default getConfig;
6 changes: 3 additions & 3 deletions package/src/lib/get-postbuild-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import getConfig from "./get-config";

const getPostbuildConfig = async (envs: string[], configFolder?: string) => {
const configsEntries = await Promise.all(
envs.map((env) => getConfig({ variant: 'postbuild', env, configFolder }).then(config => [env, config]))
)
envs.map((env) => getConfig({ variant: "postbuild", env, configFolder }).then((config) => [env, config])),
);
return Object.fromEntries(configsEntries);
}
};

export default getPostbuildConfig;
4 changes: 2 additions & 2 deletions package/src/lib/get-runtime-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import getConfig from "./get-config";

const getRuntimeConfig = async (configFolder?: string) => {
const config = await getConfig({ variant: 'runtime', configFolder });
const config = await getConfig({ variant: "runtime", configFolder });
return config;
}
};

export default getRuntimeConfig;
4 changes: 2 additions & 2 deletions package/src/lib/get-server-config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import getConfig from "./get-config";

const getServerConfig = async (configFolder?: string) => {
const config = await getConfig({ variant: 'server', configFolder });
const config = await getConfig({ variant: "server", configFolder });
return config;
}
};

export default getServerConfig;
16 changes: 7 additions & 9 deletions package/src/lib/inject-envs.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
import type { EnvConfig, EnvConfigItem } from "./types";

const injectEnvs = (part: EnvConfigItem): EnvConfigItem => {
if (typeof part === 'string') {
if (typeof part === "string") {
return process.env[part];
}

if (Array.isArray(part)) {
return part.map(injectEnvs);
}

if (part && typeof part === 'object') {
if (part && typeof part === "object") {
const newPart: EnvConfigItem = {};
Object.entries(part).map(([key, value]) => (
newPart[key] = injectEnvs(value)
));
Object.entries(part).map(([key, value]) => (newPart[key] = injectEnvs(value)));
return newPart;
}

throw new Error(`Invalid value in envs config: ${part}`)
}
throw new Error(`Invalid value in envs config: ${part}`);
};

export const injectEnvsToConfig = (config: EnvConfig) => {
const newConfig: EnvConfig = {};

Object.entries(config).map(([key, value]) => {
newConfig[key] = injectEnvs(value);
})
});

return newConfig;
}
};
10 changes: 5 additions & 5 deletions package/src/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
type ConfigItemEl = string | boolean | number | null;

type ConfigItemFunc = () => (ConfigItem | Promise<ConfigItem>);
type ConfigItemFunc = () => ConfigItem | Promise<ConfigItem>;

export type ConfigItem = {[key: string]: ConfigItem} | ConfigItem[] | ConfigItemEl | ConfigItemFunc;
export type ConfigItem = { [key: string]: ConfigItem } | ConfigItem[] | ConfigItemEl | ConfigItemFunc;

export type Config = {
[key: string]: ConfigItem;
}
};

type EnvConfigItemEl = string | boolean | number | null | undefined;

export type EnvConfigItem = {[key: string]: EnvConfigItem} | EnvConfigItem[] | EnvConfigItemEl;
export type EnvConfigItem = { [key: string]: EnvConfigItem } | EnvConfigItem[] | EnvConfigItemEl;

export type EnvConfig = {
[key: string]: EnvConfigItem;
}
};
28 changes: 14 additions & 14 deletions package/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import path from "path"
import path from "path";
import { pathToFileURL } from "url";
import { readdir } from 'fs/promises';
import { readdir } from "fs/promises";

export const getConfigVariantFolder = (variant: string, configFolder: string = 'config') => {
export const getConfigVariantFolder = (variant: string, configFolder: string = "config") => {
return path.join(process.cwd(), configFolder, variant);
}
};

export const findConfigs = async (variantFolder: string, env?: string) => {
let configs: string[] = [];
Expand All @@ -21,29 +21,29 @@ export const findConfigs = async (variantFolder: string, env?: string) => {
if (configs.includes(`${base}.json`)) {
return path.join(variantFolder, `${base}.json`);
}
}
};

const defaultConfig = getFilePath('default');
const defaultConfig = getFilePath("default");

if (!defaultConfig) {
throw new Error('Should exist default config');
throw new Error("Should exist default config");
}

const validConfigs = {
defaultBase: defaultConfig,
defaultLocal: getFilePath('default.local'),
defaultLocal: getFilePath("default.local"),
processBase: env && getFilePath(env),
processLocal: env && getFilePath(`${env}.local`),
envsBase: getFilePath('envs'),
envsLocal: getFilePath('envs.local'),
}
envsBase: getFilePath("envs"),
envsLocal: getFilePath("envs.local"),
};

return validConfigs;
}
};

const dynamicImport = new Function('p', 'return import(p)');
const dynamicImport = new Function("p", "return import(p)");

export const loadConfig = async (path: string) => {
const config = await dynamicImport(pathToFileURL(path).toString());
return config.default || config;
}
};
6 changes: 4 additions & 2 deletions package/src/postbuild-config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const configs: {[key: string]: any} | undefined = process.env.NIMPL_CONFIG_POSTBUILD && JSON.parse(process.env.NIMPL_CONFIG_POSTBUILD);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const configs: { [key: string]: any } | undefined =
process.env.NIMPL_CONFIG_POSTBUILD && JSON.parse(process.env.NIMPL_CONFIG_POSTBUILD);

export const postbuildConfig = process.env.NODE_ENV && configs?.[process.env.NODE_ENV] || null;
export const postbuildConfig = (process.env.NODE_ENV && configs?.[process.env.NODE_ENV]) || null;
4 changes: 2 additions & 2 deletions package/src/runtime-config-api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import getRuntimeConfig from './lib/get-runtime-config';
import getRuntimeConfig from "./lib/get-runtime-config";

const runtimeConfig = getRuntimeConfig(process.env.NIMPL_CONFIG_FOLDER);

export const runtimeConfigApi = async () => {
const config = await runtimeConfig;
return Response.json(config);
}
};
20 changes: 8 additions & 12 deletions package/src/runtime-config-provider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';
"use client";

import React, { useRef } from "react"
import type { Config } from "./lib/types"
import React, { useRef } from "react";
import type { Config } from "./lib/types";
import { RuntimeConfigContext } from "./lib/runtime-config-context";

const RuntimeConfigProvider: React.FC<{ children: React.ReactNode; apiPath: string }> = ({ children, apiPath }) => {
Expand All @@ -12,16 +12,12 @@ const RuntimeConfigProvider: React.FC<{ children: React.ReactNode; apiPath: stri
if (!isLoadingRef.current) {
isLoadingRef.current = true;
fetch(apiPath)
.then(resp => resp.json())
.then(data => setConfig(data))
.then((resp) => resp.json())
.then((data) => setConfig(data));
}
}, [])
}, []);

return (
<RuntimeConfigContext.Provider value={config}>
{children}
</RuntimeConfigContext.Provider>
)
}
return <RuntimeConfigContext.Provider value={config}>{children}</RuntimeConfigContext.Provider>;
};

export default RuntimeConfigProvider;
2 changes: 1 addition & 1 deletion package/src/use-runtime-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ const useRuntimeConfig = (): Config | null => {
const configData = useContext(RuntimeConfigContext);

return configData;
}
};

export default useRuntimeConfig;
Loading

0 comments on commit 993cce1

Please sign in to comment.