Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nic-21 configure husky #30

Merged
merged 2 commits into from
Apr 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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