{ pkgs, ... }: let inherit (pkgs) lib; parseFile = filePath: let fileContent = builtins.readFile filePath; fileLines = lib.strings.splitString "\n" fileContent; in parseLines fileLines { } null false [ ]; parseKeyValue = line: let matchResult = builtins.match ''^[ ]*"?([^" ]+)"?[ ]+"?([^"]+)"?$'' line; in if matchResult == null then null else if builtins.length matchResult < 2 then null else { key = builtins.elemAt matchResult 0; value = builtins.elemAt matchResult 1; }; isDependencySection = line: builtins.match ''^[ ]*(dependencies|optionalDependencies):$'' line != null; parsePackageHeader = line: builtins.match ''^(.*):$'' line; deepMergeAttr = attrName: update: attrSet: let previous = attrSet.${attrName} or { }; in attrSet // { "${attrName}" = previous // update; }; cleanKey = rawKey: let # Remove surrounding quotes if present unquoted = if builtins.match ''^"(.*)"$'' rawKey != null then builtins.elemAt (builtins.match ''^"(.*)"$'' rawKey) 0 else rawKey; # Remove leading @ if present noAtPrefix = if builtins.match ''^@(.*)$'' unquoted != null then builtins.elemAt (builtins.match ''^@(.*)$'' unquoted) 0 else unquoted; # Remove everything after (and including) the last @ if present splitAt = builtins.match ''^([^@]+)@.*$'' noAtPrefix; cleaned = if splitAt != null then builtins.elemAt splitAt 0 else noAtPrefix; in cleaned; parseLines = lines: acc: currentPkg: inDeps: depList: if lines == [ ] then acc else let line = builtins.head lines; rest = builtins.tail lines; pkgHeader = parsePackageHeader line; in if inDeps then let kv = parseKeyValue line; in if kv != null then parseLines rest acc currentPkg true (depList ++ [ kv ]) else parseLines rest (deepMergeAttr currentPkg { deps = depList; } acc) currentPkg false [ ] else if isDependencySection line then parseLines rest acc currentPkg true [ ] else if pkgHeader != null then let pkgName = builtins.elemAt pkgHeader 0; in parseLines rest (acc // { "${pkgName}" = { }; }) pkgName false depList else if currentPkg != null then let kv = parseKeyValue line; in if kv == null then parseLines rest acc currentPkg false depList else parseLines rest (deepMergeAttr currentPkg { "${kv.key}" = kv.value; } acc) currentPkg false depList else parseLines rest acc currentPkg false depList; convertKey = key: let hasSlash = builtins.match ".*/.*" key != null; split = lib.strings.splitString "/" key; first = builtins.elemAt split 0; last = builtins.elemAt split (builtins.length split - 1); result = if hasSlash then "_${first}_${last}___${last}" else "${key}___${key}"; in result; parseMap = pkgMap: builtins.listToAttrs ( lib.mapAttrsToList ( originalKey: pkgAttrs: let cleanedKey = cleanKey originalKey; convertedKey = convertKey cleanedKey; filenameRaw = "${convertedKey}_${pkgAttrs.version}.tgz"; filename = builtins.replaceStrings [ "-" ] [ "_" ] filenameRaw; in { name = filename; value = pkgs.fetchurl { url = pkgAttrs.resolved; hash = pkgAttrs.integrity; }; } ) pkgMap ); combineAll = fileMap: yarnLockPath: let copyCmds = lib.mapAttrsToList (filename: filePath: "cp ${filePath} $out/${filename}") fileMap; script = builtins.concatStringsSep "\n" copyCmds; in pkgs.runCommand "combine-all" { } '' mkdir -p $out; ${script} cp ${yarnLockPath} $out/yarn.lock ''; in { yarnLock ? null, }: combineAll (parseMap (parseFile yarnLock)) yarnLock