Skip to content

Commit

Permalink
Fix (core): makeTheme should perform deep merges of objects
Browse files Browse the repository at this point in the history
  • Loading branch information
SBoudrias committed May 11, 2024
1 parent 12b0617 commit 89f62be
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 6 deletions.
4 changes: 1 addition & 3 deletions packages/checkbox/src/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ export default createPrompt(
required,
validate = () => true,
} = config;
const theme = makeTheme<CheckboxTheme>(checkboxTheme, config.theme, {
icon: Object.assign({}, checkboxTheme.icon, config.theme?.icon),
});
const theme = makeTheme<CheckboxTheme>(checkboxTheme, config.theme);
const prefix = usePrefix({ theme });
const firstRender = useRef(true);
const [status, setStatus] = useState('pending');
Expand Down
36 changes: 33 additions & 3 deletions packages/core/src/lib/make-theme.mts
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
import type { Prettify, PartialDeep } from '@inquirer/type';
import { defaultTheme, type Theme } from './theme.mjs';

function isPlainObject(value: unknown): value is object {
if (typeof value !== 'object' || value === null) return false;

let proto = value;
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto);
}

return Object.getPrototypeOf(value) === proto;
}

function deepMerge<T extends object>(...objects: Partial<T>[]): T {
const output: { [key: string]: unknown } = {};

for (const obj of objects) {
for (const [key, value] of Object.entries(obj)) {
const prevValue = output[key];

output[key] =
isPlainObject(prevValue) && isPlainObject(value)
? deepMerge(prevValue, value)
: value;
}
}

return output as T;
}

export function makeTheme<SpecificTheme extends object>(
...themes: ReadonlyArray<undefined | PartialDeep<Theme<SpecificTheme>>>
): Prettify<Theme<SpecificTheme>> {
return Object.assign({}, defaultTheme, ...themes, {
style: Object.assign({}, defaultTheme.style, ...themes.map((theme) => theme?.style)),
});
const themesToMerge = [
defaultTheme,
...themes.filter((theme) => theme != null),
] as Theme<SpecificTheme>[];
return deepMerge(...themesToMerge);
}

0 comments on commit 89f62be

Please sign in to comment.