{ lib, fetchurl }: with lib; with builtins; let # Convert a base64-encoded string into a list of quads and padding. fromBase64 = str: let len = stringLength str; quads = 3 * len - 4 * padding; padding = if hasSuffix "==" str then 2 else if hasSuffix "=" str then 1 else 0; chars = stringToCharacters (substring 0 (len - padding) str); table = { A = [0 0 0]; B = [0 0 1]; C = [0 0 2]; D = [0 0 3]; E = [0 1 0]; F = [0 1 1]; G = [0 1 2]; H = [0 1 3]; I = [0 2 0]; J = [0 2 1]; K = [0 2 2]; L = [0 2 3]; M = [0 3 0]; N = [0 3 1]; O = [0 3 2]; P = [0 3 3]; Q = [1 0 0]; R = [1 0 1]; S = [1 0 2]; T = [1 0 3]; U = [1 1 0]; V = [1 1 1]; W = [1 1 2]; X = [1 1 3]; Y = [1 2 0]; Z = [1 2 1]; a = [1 2 2]; b = [1 2 3]; c = [1 3 0]; d = [1 3 1]; e = [1 3 2]; f = [1 3 3]; g = [2 0 0]; h = [2 0 1]; i = [2 0 2]; j = [2 0 3]; k = [2 1 0]; l = [2 1 1]; m = [2 1 2]; n = [2 1 3]; o = [2 2 0]; p = [2 2 1]; q = [2 2 2]; r = [2 2 3]; s = [2 3 0]; t = [2 3 1]; u = [2 3 2]; v = [2 3 3]; w = [3 0 0]; x = [3 0 1]; y = [3 0 2]; z = [3 0 3]; "0" = [3 1 0]; "1" = [3 1 1]; "2" = [3 1 2]; "3" = [3 1 3]; "4" = [3 2 0]; "5" = [3 2 1]; "6" = [3 2 2]; "7" = [3 2 3]; "8" = [3 3 0]; "9" = [3 3 1]; "+" = [3 3 2]; "/" = [3 3 3]; }; in take quads (concatMap (c: table.${c}) chars); # Convert a list of quads with padding into a base16-encoded string. toBase16 = quads: if length quads == 0 then "" else if length quads == 1 then throw "toBase16: odd quads" else let hexad = 4 * elemAt quads 0 + elemAt quads 1; hexits = "0123456789abcdef"; in substring hexad 1 hexits + toBase16 (drop 2 quads); in let fetchResolved = { resolved, integrity, ... }: let args = { url = resolved; } // integrityHash integrity; in fetchurl args; integrityHash = integrity: if hasPrefix "sha1-" integrity then integritySHA1 integrity else if hasPrefix "sha512-" integrity then integritySHA512 integrity else throw "don't understand integrity: ${integrity}"; integritySHA1 = integrity: { sha1 = toBase16 (fromBase64 (removePrefix "sha1-" integrity)); }; integritySHA512 = integrity: { sha512 = toBase16 (fromBase64 (removePrefix "sha512-" integrity)); }; in let depend = name: attrs@{ version, dependencies ? {}, ... }: { inherit name version; src = fetchResolved attrs; depends = mapAttrsToList depend dependencies; }; prepareDepend = { name, src, depends, ... }: '' unpackFile '${src}' mv package '${name}' mkdir -p '${name}/node_modules' ( cd '${name}/node_modules' ${concatMapStrings prepareDepend depends} ) ''; in packageLockFile: let packageLock = fromJSON (readFile packageLockFile); depends = mapAttrsToList depend packageLock.dependencies; in '' mkdir -p node_modules ( cd node_modules ${concatMapStrings prepareDepend depends} ) ''