{ lib }: let inherit (lib) genList length lowerChars replaceStrings stringToCharacters upperChars ; in rec { # Figures out a valid Nix store name for the given path. storeFileName = path: let # All characters that are considered safe. Note "-" is not # included to avoid "-" followed by digit being interpreted as a # version. safeChars = [ "+" "." "_" "?" "=" ] ++ lowerChars ++ upperChars ++ stringToCharacters "0123456789"; empties = l: genList (x: "") (length l); unsafeInName = stringToCharacters (replaceStrings safeChars (empties safeChars) path); safeName = replaceStrings unsafeInName (empties unsafeInName) path; in "hm_" + safeName; /* Convert a string from camelCase or PascalCase to another case format using a separator Type: string -> string -> string */ toCaseWithSeparator = separator: string: let splitByWords = builtins.split "([A-Z])"; processWord = s: if lib.isString s then s else separator + lib.toLower (lib.elemAt s 0); words = splitByWords string; converted = lib.concatStrings (map processWord words); in lib.removePrefix separator converted; /* Convert a string from camelCase or PascalCase to snake_case Type: string -> string */ toSnakeCase = toCaseWithSeparator "_"; /* Convert a string from camelCase or PascalCase to kebab-case Type: string -> string */ toKebabCase = toCaseWithSeparator "-"; # A predicate that returns true only for camelCase. isCamelCase = str: # This regex enforces the entire structure: # - Must start with one or more lowercase letters. # - Must be followed by one or more "humps" of an uppercase letter # and then subsequent lowercase letters/numbers. builtins.match "^[a-z]+([A-Z][a-z0-9]*)+$" str != null; # Returns true for strings like `PascalCase`, `Application`, `URLShortener`. # Must start with an uppercase letter. isPascalCase = str: builtins.match "^[A-Z][a-z0-9]*([A-Z][a-z0-9]*)*$" str != null; # Returns true for strings like `snake_case`, `a_longer_variable`, `var1`. # Must be all lowercase letters/numbers, with words separated by single underscores. isSnakeCase = str: builtins.match "^[a-z0-9]+(_[a-z0-9]+)*$" str != null; # Returns true for strings like `kebab-case`, `a-css-class-name`. # Must be all lowercase letters/numbers, with words separated by single hyphens. isKebabCase = str: builtins.match "^[a-z0-9]+(-[a-z0-9]+)*$" str != null; # Returns true for strings like `SCREAMING_SNAKE_CASE`, `SOME_CONSTANT`. # Must be all uppercase letters/numbers, with words separated by single underscores. isScreamingSnakeCase = str: builtins.match "^[A-Z0-9]+(_[A-Z0-9]+)*$" str != null; }