113 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			113 lines
		
	
	
	
		
			3.1 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
| {lib, ...}: let
 | |
|   inherit (lib) toInt all min max;
 | |
|   inherit (builtins) mapAttrs elemAt isInt isFloat match getAttr hasAttr;
 | |
| 
 | |
|   # basic checks
 | |
|   range = a: b: v: (v <= max a b) && (v >= min a b);
 | |
|   number = v: isInt v || isFloat v;
 | |
|   unary = range 0.0 1.0;
 | |
|   hue = range 0.0 360.0;
 | |
| 
 | |
|   # type checking
 | |
|   hex = {
 | |
|     string = color: let
 | |
|       hexPatternWithHash = match "#[[:xdigit:]]{6}" color;
 | |
|       hexPatternNoHash = match "[[:xdigit:]]{6}" color;
 | |
|       isValid = hexPatternWithHash != null || hexPatternNoHash != null;
 | |
|     in
 | |
|       if !isValid
 | |
|       then abort "Invalid hex color format: ${color}"
 | |
|       else color;
 | |
| 
 | |
|     set = color: let
 | |
|       hasAttributes = all (k: hasAttr k color) ["r" "g" "b"];
 | |
|       validPattern = all (k: let
 | |
|         v = getAttr k color;
 | |
|       in
 | |
|         match "[[:xdigit:]]{2}" v != null) ["r" "g" "b"];
 | |
|     in
 | |
|       if !(hasAttributes && validPattern)
 | |
|       then abort "Invalid Hex values: r=${toString color.r}, g=${toString color.g}, b=${toString color.b}"
 | |
|       else color;
 | |
|   };
 | |
| 
 | |
|   rgb = {
 | |
|     string = color: let
 | |
|       rgbPattern = match "([0-9]{1,3}),([0-9]{1,3}),([0-9]{1,3})" color;
 | |
|       toNum = str: let
 | |
|         num = toInt str;
 | |
|       in
 | |
|         num != null && range 0 255 num;
 | |
|       isValid = rgbPattern != null && all toNum rgbPattern;
 | |
|     in
 | |
|       if !isValid
 | |
|       then abort "Invalid RGB string: ${color}"
 | |
|       else color;
 | |
| 
 | |
|     set = color: let
 | |
|       hasAttributes = all (k: hasAttr k color) ["r" "g" "b"];
 | |
|       validRanges = all (
 | |
|         k: let
 | |
|           v = getAttr k color;
 | |
|         in
 | |
|           number v && range 0 255 v
 | |
|       ) ["r" "g" "b"];
 | |
|     in
 | |
|       if !(hasAttributes && validRanges)
 | |
|       then abort "Invalid RGB set: r=${toString color.r}, g=${toString color.g}, b=${toString color.b}"
 | |
|       else color;
 | |
|   };
 | |
|   hsl = {
 | |
|     string = color: let
 | |
|       hslPattern = match "([0-9]{1,3}),[ ]*([0-9]{1,3})%,[ ]*([0-9]{1,3})%" color;
 | |
|       # Convert matched values to numbers and check ranges
 | |
|       validateHSL = groups: let
 | |
|         h = toInt (elemAt groups 0);
 | |
|         s = toInt (elemAt groups 1);
 | |
|         l = toInt (elemAt groups 2);
 | |
|       in
 | |
|         h
 | |
|         != null
 | |
|         && h >= 0
 | |
|         && h <= 360
 | |
|         && s != null
 | |
|         && s >= 0
 | |
|         && s <= 100
 | |
|         && l != null
 | |
|         && l >= 0
 | |
|         && l <= 100;
 | |
|       isValid = hslPattern != null && validateHSL hslPattern;
 | |
|     in
 | |
|       if !isValid
 | |
|       then abort "Invalid HSL string: ${color} (expected format: h(0-360),s(0-100%),l(0-100%))"
 | |
|       else color;
 | |
| 
 | |
|     set = color: let
 | |
|       hasAttributes = all (k: hasAttr k color) ["h" "s" "l"];
 | |
|       validRanges =
 | |
|         color.h
 | |
|         >= 0
 | |
|         && color.h <= 360
 | |
|         && color.s >= 0
 | |
|         && color.s <= 1.0
 | |
|         && color.l >= 0
 | |
|         && color.l <= 1.0;
 | |
|     in
 | |
|       if !(hasAttributes && validRanges)
 | |
|       then
 | |
|         abort ''
 | |
|           Invalid HSL set: h=${toString color.h}, s=${toString color.s}, l=${toString color.l}
 | |
|           Expected:
 | |
|             h: 0-360
 | |
|             s: 0.0-1.0
 | |
|             l: 0.0-1.0
 | |
|         ''
 | |
|       else color;
 | |
|   };
 | |
| 
 | |
|   # validate neutral hex values
 | |
|   neutrals = {neutrals, ...}:
 | |
|     mapAttrs (_: value:
 | |
|       hex.string value)
 | |
|     neutrals;
 | |
| in {inherit neutrals range number unary hue hex rgb hsl;}
 |