-
-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(compiler): add verbose errors for wrong user config (#288)
- Loading branch information
1 parent
712e80b
commit 8162693
Showing
4 changed files
with
79 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,79 @@ | ||
import { CatppuccinPalette, ThemeContext } from "@/types"; | ||
import type { ThemeContext, ColorName } from "@/types"; | ||
import { opacity } from "@/theme/utils"; | ||
import { flavors } from "@catppuccin/palette"; | ||
|
||
type CustomNamedColors = Record<string, string>; | ||
|
||
const ctpColors = new Set(Object.keys(flavors.mocha.colors)); | ||
|
||
class CustomUIColorError extends Error { | ||
constructor(key: string, value: string, message = "") { | ||
super( | ||
`Invalid value: "${value}" for key "${key}" in "catppuccin.customUIColors".\n${message}`, | ||
); | ||
this.name = "CustomUIColorError"; | ||
} | ||
} | ||
|
||
/** | ||
* @throws if the value is not a valid 'colorName' or 'colorName opacityValue' | ||
* @returns a tuple of [colorName, opacityValue] | ||
*/ | ||
const parseCustomUiColor = (k: string, v: string): [string, number] => { | ||
const entry = v.split(" "); | ||
if (entry.length > 2) { | ||
throw new CustomUIColorError( | ||
k, | ||
v, | ||
'Too many arguments, expected "colorName" or "colorName opacityValue".', | ||
); | ||
} | ||
let opacityValue = 1; | ||
if (entry.length == 2) { | ||
opacityValue = Number(entry[1]); | ||
if (Number.isNaN(opacityValue)) { | ||
throw new CustomUIColorError(k, v, "Opacity value is not a number."); | ||
} | ||
if (opacityValue < 0 || opacityValue > 1) { | ||
throw new CustomUIColorError( | ||
k, | ||
v, | ||
"Opacity value is not between 0 and 1.", | ||
); | ||
} | ||
} | ||
return [entry[0], opacityValue]; | ||
}; | ||
const hexColorRegex = /^#([\dA-Fa-f]{3,4}){1,2}$/; | ||
|
||
const customNamedColors = (context: ThemeContext): CustomNamedColors => { | ||
const { flavor, palette, options } = context; | ||
const accent = palette[options.accent]; | ||
|
||
return { | ||
...Object.entries({ | ||
// collect the options, overwrite the "all" config with the current palette config | ||
...options.customUIColors.all, | ||
...options.customUIColors[flavor], | ||
}) | ||
.map(([k, v]) => { | ||
// deal with accents | ||
if (v.startsWith("accent")) { | ||
const entry = v.split(" "); | ||
return entry.length === 1 | ||
? { | ||
[k]: accent, | ||
} | ||
: { | ||
[k]: opacity(accent, Number(entry[1])), | ||
}; | ||
} | ||
|
||
// allow custom hex colors | ||
if (v.startsWith("#")) { | ||
return { | ||
[k]: v, | ||
}; | ||
} | ||
|
||
//check if the entry is a "color opacity" mapping | ||
const entry = v.split(" "); | ||
v = | ||
entry.length === 1 | ||
? // resolve to the palette color | ||
palette[v as keyof CatppuccinPalette] | ||
: // call the opacity function | ||
opacity( | ||
palette[entry[0] as keyof CatppuccinPalette], | ||
Number(entry[1]), | ||
); | ||
|
||
return { | ||
[k]: v, | ||
}; | ||
}) | ||
// TODO: rework this to get rid of the reduce | ||
// eslint-disable-next-line unicorn/no-array-reduce | ||
.reduce((previous, current) => ({ ...previous, ...current }), {}), | ||
const customUIColors = { | ||
...options.customUIColors.all, | ||
...options.customUIColors[flavor], | ||
}; | ||
|
||
for (const [k, v] of Object.entries(customUIColors)) { | ||
// don't change custom hex colors | ||
if (hexColorRegex.test(v)) continue; | ||
|
||
const [parsedColor, opacityValue] = parseCustomUiColor(k, v); | ||
|
||
let color: string; | ||
if (parsedColor === "accent") { | ||
color = accent; | ||
} else if (ctpColors.has(parsedColor)) { | ||
color = palette[parsedColor as ColorName]; | ||
} else { | ||
throw new CustomUIColorError(k, v, "Invalid color name."); | ||
} | ||
|
||
customUIColors[k] = opacity(color, opacityValue); | ||
} | ||
|
||
return customUIColors; | ||
}; | ||
|
||
export default customNamedColors; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters