diff --git a/API.md b/API.md index ea50b97..7623013 100644 --- a/API.md +++ b/API.md @@ -16,6 +16,7 @@ The `node_modules` function takes an attribute set with the following attributes - **nodejs** *(default `nixpkgs.nodejs`, which is the Active LTS version)*: Node.js derivation to use - **preInstallLinks** *(default `{}`)*: Map of symlinks to create inside npm dependencies in the `node_modules` output (See [Concepts](#concepts) for details). - **githubSourceHashMap** *(default `{}`)*: Dependency hashes for evaluation in restricted mode (See [Concepts](#concepts) for details). +- **sourceOverrides** *(default `{}`)*: Derivation attributes to apply to sources, allowing patching (See the [source derivation overrides](#source-derivation-overrides) concept for details) #### Notes - You may provide additional arguments accepted by `mkDerivation` all of which are going to be passed on. @@ -114,3 +115,32 @@ npmlock2nix.build { }; } ``` + +### Source derivation overrides + +`node_modules` takes a `sourceOverrides` argument, which allows you to modify the source derivations of individual npm packages you depend on, mainly useful for adding Nix-specific fixes to packages. This could be used for patching interpreter or paths, or to replace vendored binaries with ones provided by Nix. + +The `sourceOverrides` argument expects an attribute set mapping npm package names to a function describing the modifications of that package. Each function receives an attribute set as a first argument, containing either a `version` attribute if the version is known, or a `github = { org, repo, rev, ref }` attribute if the package is fetched from GitHub. These values can be used to have different overrides depending on the version. The function receives another argument which is the derivation of the fetched source, which can be modified using `.overrideAttrs`. The fetched source mainly runs the [patch phase](https://nixos.org/manual/nixpkgs/stable/#ssec-patch-phase), so of particular interest are the `patches` and `postPatch` attributes, in which `patchShebangs` can be called. Note that `patchShebangs` can only patch shebangs to binaries accessible in the derivation, which you can extend with `buildInputs`. For convenience, the correct version of `nodejs` is always included in `buildInputs`. + +```nix +npmlock2nix.node_modules { + sourceOverrides = { + # sourceInfo either contains: + # - A version attribute + # - A github = { org, repo, rev, ref } attribute for GitHub sources + package-name = sourceInfo: drv: drv.overrideAttrs (old: { + buildInputs = [ somePackage ]; + patches = [ somePatch ]; + postPatch = '' + some script + ''; + # ... + }) + + # Example + node-pre-gyp = sourceInfo: drv: drv.overrideAttrs (old: { + postPatch = "patchShebangs bin"; + }); + }; +} +``` diff --git a/internal.nix b/internal.nix index f097351..0104205 100644 --- a/internal.nix +++ b/internal.nix @@ -1,4 +1,4 @@ -{ nodejs-14_x, stdenv, mkShell, lib, fetchurl, writeText, writeTextFile, runCommand, fetchFromGitHub }: +{ nodejs-14_x, jq, openssl, stdenv, mkShell, lib, fetchurl, writeText, writeTextFile, runCommand, fetchFromGitHub }: rec { # Versions >= 15 use npm >= 7, which uses npm lockfile version 2, which we don't support yet # See the assertion in the node_modules function @@ -62,7 +62,7 @@ rec { # hash attribute it will provide the value to `fetchFromGitHub` which will # also work in restricted evaluation. # Type: Set -> Path - buildTgzFromGitHub = { name, org, repo, rev, ref, hash ? null }: + buildTgzFromGitHub = { name, org, repo, rev, ref, hash ? null, sourceOptions ? { } }: let src = if hash != null then @@ -78,20 +78,41 @@ rec { inherit rev ref; allRefs = true; }; + + sourceInfo = { + github = { inherit org repo rev ref; }; + }; + drv = packTgz sourceOptions.nodejs name ref src; in - runCommand - name - { } '' - set +x - tar -C ${src} -czf $out ./ + if sourceOptions ? sourceOverrides.${name} + then sourceOptions.sourceOverrides.${name} sourceInfo drv + else drv; + + # Description: Packs a source directory into a .tgz tar archive. If the + # source is an archive, it gets unpacked first. + # Type: Path -> String -> String -> Path -> Path + packTgz = nodejs: pname: version: src: stdenv.mkDerivation { + name = "${pname}-${version}.tgz"; + phases = "unpackPhase patchPhase installPhase"; + inherit src; + buildInputs = [ + # Allows patchShebangs in postPatch to patch shebangs to nodejs + nodejs + ]; + installPhase = '' + runHook preInstall + tar -C . -czf $out ./ + runHook postInstall ''; + }; # Description: Turns a dependency with a from field of the format # `github:org/repo#revision` into a git fetcher. The fetcher can # receive a hash value by calling 'sourceHashFunc' if a source hash - # map has been provided. Otherwise the function yields `null`. - # Type: Fn -> String -> Set -> Path - makeGithubSource = sourceHashFunc: name: dependency: + # map has been provided. Otherwise the function yields `null`. Patches + # specified with sourceOverrides will be applied + # Type: { sourceHashFunc :: Fn } -> String -> Set -> Path + makeGithubSource = sourceOptions@{ sourceHashFunc, ... }: name: dependency: assert !(dependency ? version) -> builtins.throw "version` attribute missing from `${name}`"; assert (lib.hasPrefix "github: " dependency.version) -> builtins.throw "invalid prefix for `version` field of `${name}` expected `github:`, got: `${dependency.version}`."; @@ -108,6 +129,7 @@ rec { ref = f.rev; inherit (v) org repo rev; hash = sourceHashFunc { type = "github"; value = v; }; + inherit sourceOptions; }; in (builtins.removeAttrs dependency [ "from" ]) // { @@ -127,19 +149,45 @@ rec { shouldUseVersionAsUrl = dependency: dependency ? version && dependency ? integrity && ! (dependency ? resolved) && looksLikeUrl dependency.version; + # Description: Replaces the `resolved` field of a dependency with a + # prefetched version from the Nix store. Patches specified with sourceOverrides + # will be applied, in which case the `integrity` attribute is set to `null`, + # in order to be recomputer later + # Type: { sourceOverrides :: Fn, nodejs :: Package } -> String -> Set -> Set + makeUrlSource = { sourceOverrides ? { }, nodejs, ... }: name: dependency: + let + src = fetchurl (makeSourceAttrs name dependency); + sourceInfo = { + inherit (dependency) version; + }; + drv = packTgz nodejs name dependency.version src; + tgz = + if sourceOverrides ? ${name} + # If we have modification to this source, unpack the tgz, apply the + # patches and repack the tgz + then sourceOverrides.${name} sourceInfo drv + else src; + resolved = "file://" + toString tgz; + in + dependency // { inherit resolved; } // lib.optionalAttrs (sourceOverrides ? ${name}) { + # Integrity was tampered with due to the source attributes, so it needs + # to be recalculated, which is done in the node_modules builder + integrity = null; + }; + # Description: Turns an npm lockfile dependency into a fetchurl derivation - # Type: Fn -> String -> Set -> Derivation - makeSource = sourceHashFunc: name: dependency: + # Type: { sourceHashFunc :: Fn } -> String -> Set -> Derivation + makeSource = sourceOptions: name: dependency: assert (builtins.typeOf name != "string") -> throw "Name of dependency ${toString name} must be a string"; assert (builtins.typeOf dependency != "set") -> throw "Specification of dependency ${toString name} must be a set"; if dependency ? resolved && dependency ? integrity then - dependency // { resolved = "file://" + (toString (fetchurl (makeSourceAttrs name dependency))); } + makeUrlSource sourceOptions name dependency else if dependency ? from && dependency ? version then - makeGithubSource sourceHashFunc name dependency + makeGithubSource sourceOptions name dependency else if shouldUseVersionAsUrl dependency then - makeSource sourceHashFunc name (dependency // { resolved = dependency.version; }) + makeSource sourceOptions name (dependency // { resolved = dependency.version; }) else throw "A valid dependency consists of at least the resolved and integrity field. Missing one or both of them for `${name}`. The object I got looks like this: ${builtins.toJSON dependency}"; # Description: Parses the lock file as json and returns an attribute set @@ -158,7 +206,7 @@ rec { # Description: Turns a github string reference into a store path with a tgz of the reference # Type: Fn -> String -> String -> Path - stringToTgzPath = sourceHashFunc: name: str: + stringToTgzPath = sourceOptions@{ sourceHashFunc, ... }: name: str: let gitAttrs = parseGitHubRef str; in @@ -167,20 +215,21 @@ rec { ref = gitAttrs.rev; inherit (gitAttrs) org repo rev; hash = sourceHashFunc { type = "github"; value = gitAttrs; }; + inherit sourceOptions; }; # Description: Patch the `requires` attributes of a dependency spec to refer to paths in the store - # Type: Fn -> String -> Set -> Set - patchRequires = sourceHashFunc: name: requires: + # Type: { sourceHashFunc :: Fn } -> String -> Set -> Set + patchRequires = sourceOptions: name: requires: let - patchReq = name: version: if lib.hasPrefix "github:" version then stringToTgzPath sourceHashFunc name version else version; + patchReq = name: version: if lib.hasPrefix "github:" version then stringToTgzPath sourceOptions name version else version; in lib.mapAttrs patchReq requires; # Description: Patches a single lockfile dependency (recursively) by replacing the resolved URL with a store path - # Type: Fn -> String -> Set -> Set - patchDependency = sourceHashFunc: name: spec: + # Type: List String -> { sourceHashFunc :: Fn } -> String -> Set -> { result :: Set, integrityUpdates :: List { path, file } } + patchDependency = path: sourceOptions: name: spec: assert (builtins.typeOf name != "string") -> throw "Name of dependency ${toString name} must be a string"; assert (builtins.typeOf spec != "set") -> @@ -188,29 +237,45 @@ rec { let isBundled = spec ? bundled && spec.bundled == true; hasGitHubRequires = spec: (spec ? requires) && (lib.any (x: lib.hasPrefix "github:" x) (lib.attrValues spec.requires)); - patchSource = lib.optionalAttrs (!isBundled) (makeSource sourceHashFunc name spec); - patchRequiresSources = lib.optionalAttrs (hasGitHubRequires spec) { requires = (patchRequires sourceHashFunc name spec.requires); }; - patchDependenciesSources = lib.optionalAttrs (spec ? dependencies) { dependencies = lib.mapAttrs (patchDependency sourceHashFunc) spec.dependencies; }; - in - # For our purposes we need a dependency with + patchSource = lib.optionalAttrs (!isBundled) (makeSource sourceOptions name spec); + patchRequiresSources = lib.optionalAttrs (hasGitHubRequires spec) { requires = (patchRequires sourceOptions name spec.requires); }; + nestedDependencies = lib.mapAttrs (name: patchDependency (path ++ [ name ]) sourceOptions name) spec.dependencies; + patchDependenciesSources = lib.optionalAttrs (spec ? dependencies) { dependencies = lib.mapAttrs (_: value: value.result) nestedDependencies; }; + nestedIntegrityUpdates = lib.concatMap (value: value.integrityUpdates) (lib.attrValues nestedDependencies); + + # For our purposes we need a dependency with # - `resolved` set to a path in the nix store (`patchSource`) # - All `requires` entries of this dependency that are set to github URLs set to a path in the nix store (`patchRequiresSources`) # - This needs to be done recursively for all `dependencies` in the lockfile (`patchDependenciesSources`) - (spec // patchSource // patchRequiresSources // patchDependenciesSources); + result = spec // patchSource // patchRequiresSources // patchDependenciesSources; + in + { + result = result; + integrityUpdates = lib.optional (result ? resolved && result ? integrity && result.integrity == null) { + inherit path; + file = lib.removePrefix "file://" result.resolved; + }; + }; # Description: Takes a Path to a lockfile and returns the patched version as attribute set - # Type: Fn -> Path -> Set - patchLockfile = sourceHashFunc: file: + # Type: { sourceHashFunc :: Fn } -> Path -> { result :: Set, integrityUpdates :: List { path, file } } + patchLockfile = sourceOptions: file: assert (builtins.typeOf file != "path" && builtins.typeOf file != "string") -> throw "file ${toString file} must be a path or string"; - let content = readLockfile file; in - content // { - dependencies = lib.mapAttrs (patchDependency sourceHashFunc) content.dependencies; + let + content = readLockfile file; + dependencies = lib.mapAttrs (name: patchDependency [ name ] sourceOptions name) content.dependencies; + in + { + result = content // { + dependencies = lib.mapAttrs (_: value: value.result) dependencies; + }; + integrityUpdates = lib.concatMap (value: value.integrityUpdates) (lib.attrValues dependencies); }; # Description: Rewrite all the `github:` references to wildcards. - # Type: Fn -> Path -> Set - patchPackagefile = sourceHashFunc: file: + # Type: Path -> Set + patchPackagefile = file: assert (builtins.typeOf file != "path" && builtins.typeOf file != "string") -> throw "file ${toString file} must be a path or string"; let @@ -233,16 +298,22 @@ rec { content // { inherit devDependencies dependencies; }; # Description: Takes a Path to a package file and returns the patched version as file in the Nix store - # Type: Fn -> Path -> Derivation - patchedPackagefile = sourceHashFunc: file: writeText "package.json" + # Type: Path -> Derivation + patchedPackagefile = file: writeText "package.json" ( - builtins.toJSON (patchPackagefile sourceHashFunc file) + builtins.toJSON (patchPackagefile file) ); # Description: Takes a Path to a lockfile and returns the patched version as file in the Nix store - # Type: Fn -> Path -> Derivation - patchedLockfile = sourceHashFunc: file: writeText "package-lock.json" - (builtins.toJSON (patchLockfile sourceHashFunc file)); + # Type: { sourceHashFunc :: Fn } -> Path -> { result :: Derivation, integrityUpdates :: List { path, file } } + patchedLockfile = sourceOptions: file: + let + patched = patchLockfile sourceOptions file; + in + { + result = writeText "package-lock.json" (builtins.toJSON patched.result); + integrityUpdates = patched.integrityUpdates; + }; # Description: Turn a derivation (with name & src attribute) into a directory containing the unpacked sources # Type: Derivation -> Derivation @@ -316,6 +387,7 @@ rec { , preBuild ? "" , postBuild ? "" , preInstallLinks ? { } # set that describes which files should be linked in a specific packages folder + , sourceOverrides ? { } , githubSourceHashMap ? { } , passthru ? { } , ... @@ -325,9 +397,17 @@ rec { assert (builtins.typeOf preInstallLinks != "set") -> throw "`preInstallLinks` must be an attributeset of attributesets"; let - cleanArgs = builtins.removeAttrs args [ "src" "packageJson" "packageLockJson" "buildInputs" "nativeBuildInputs" "nodejs" "preBuild" "postBuild" "preInstallLinks" "githubSourceHashMap" ]; + cleanArgs = builtins.removeAttrs args [ "src" "packageJson" "packageLockJson" "buildInputs" "nativeBuildInputs" "nodejs" "preBuild" "postBuild" "preInstallLinks" "sourceOverrides" "githubSourceHashMap" ]; lockfile = readLockfile packageLockJson; + sourceOptions = { + sourceHashFunc = sourceHashFunc githubSourceHashMap; + inherit nodejs sourceOverrides; + }; + + patchedLockfile' = patchedLockfile sourceOptions packageLockJson; + patchedPackagefilePath = patchedPackagefile packageJson; + preinstall_node_modules = writeTextFile { name = "prepare"; destination = "/node_modules/.hooks/prepare"; @@ -372,6 +452,9 @@ rec { dontUnpack = true; nativeBuildInputs = nativeBuildInputs ++ [ + jq + ] ++ lib.optionals (patchedLockfile'.integrityUpdates != [ ]) [ + openssl nodejs ]; @@ -387,9 +470,39 @@ rec { export HOME=$(mktemp -d) ''; + # A script for updating specific JSON paths (.path) with specific + # values (.value), as given in a list of objects, of an $original[0] + # JSON value + jqSetIntegrity = '' + reduce .[] as $update + ( $original[0] + ; . * setpath($update | .path; $update | .value) + ) + ''; + + passAsFile = [ "jqSetIntegrity" ]; + postPatch = '' - ln -sf ${patchedLockfile (sourceHashFunc githubSourceHashMap) packageLockJson} package-lock.json - ln -sf ${patchedPackagefile (sourceHashFunc githubSourceHashMap) packageJson} package.json + # Patches the lockfile at build time to replace the `"integrity": + # null` entries as set by `makeUrlSource` at eval time. + # integrityUpdates is a list of { file, path } + ${if patchedLockfile'.integrityUpdates == [] then '' + cp ${patchedLockfile'.result} package-lock.json + '' else '' + { + ${lib.concatMapStrings ({ file, path }: '' + # https://docs.npmjs.com/cli/v8/configuring-npm/package-lock-json#packages + # https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#tools_for_generating_sri_hashes + hash="sha512-$(openssl dgst -sha512 -binary ${lib.escapeShellArg file} | openssl base64 -A)" + + # Constructs a simple { path, value } JSON of the given arguments + jq -c --argjson path ${lib.escapeShellArg (builtins.toJSON path)} --arg value "$hash" -n '$ARGS.named' + '') patchedLockfile'.integrityUpdates} + } | jq -s --slurpfile original ${patchedLockfile'.result} -f "$jqSetIntegrityPath" > package-lock.json + set +x + ''} + + ln -sf ${patchedPackagefilePath} package.json ''; buildPhase = '' @@ -418,8 +531,8 @@ rec { passthru = passthru // { inherit nodejs; - lockfile = patchedLockfile packageLockJson; - packagesfile = patchedPackagefile packageJson; + lockfile = patchedLockfile'.result; + packagesfile = patchedPackagefilePath; }; } // cleanArgs); diff --git a/tests/examples-projects/source-patching/package-lock.json b/tests/examples-projects/source-patching/package-lock.json new file mode 100644 index 0000000..889f3e3 --- /dev/null +++ b/tests/examples-projects/source-patching/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "source-patching", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "custom-hello-world": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/custom-hello-world/-/custom-hello-world-1.0.3.tgz", + "integrity": "sha512-Rinkq1q+uLmgbDLZRNZrlyeK3G9e+o0gbVy6r948kySbau0ymwOPNybu4iIkb4R1gE5aZsQUHgtfCg2oZ4zfbw==" + } + } +} diff --git a/tests/examples-projects/source-patching/package.json b/tests/examples-projects/source-patching/package.json new file mode 100644 index 0000000..d0ea4e4 --- /dev/null +++ b/tests/examples-projects/source-patching/package.json @@ -0,0 +1,11 @@ +{ + "name": "source-patching", + "version": "1.0.0", + "description": "", + "main": "index.js", + "author": "", + "license": "ISC", + "dependencies": { + "custom-hello-world": "^1.0.0" + } +} diff --git a/tests/examples-projects/source-patching/shell.nix b/tests/examples-projects/source-patching/shell.nix new file mode 100644 index 0000000..928d6f0 --- /dev/null +++ b/tests/examples-projects/source-patching/shell.nix @@ -0,0 +1,25 @@ +{ npmlock2nix }: +npmlock2nix.shell { + src = ./.; + node_modules_attrs = { + sourceOverrides = { + custom-hello-world = sourceInfo: drv: drv.overrideAttrs (old: { + patches = builtins.toFile "custom-hello-world.patch" '' + diff --git a/lib/index.js b/lib/index.js + index 1f66513..64391a7 100644 + --- a/lib/index.js + +++ b/lib/index.js + @@ -21,7 +21,7 @@ function generateHelloWorld({ comma, exclamation, lowercase }) { + if (comma) + helloWorldStr += ','; + + - helloWorldStr += ' World'; + + helloWorldStr += ' Nix'; + + if (exclamation) + helloWorldStr += '!'; + ''; + }); + }; + }; +} diff --git a/tests/integration-tests/default.nix b/tests/integration-tests/default.nix index 1813fa1..7aa485b 100644 --- a/tests/integration-tests/default.nix +++ b/tests/integration-tests/default.nix @@ -284,4 +284,13 @@ testLib.makeIntegrationTests { ''; }; }; + + source-patching = { + description = "Source patching works"; + shell = callPackage ../examples-projects/source-patching/shell.nix { }; + command = '' + node -e 'console.log(require("custom-hello-world")({}));' + ''; + expected = "Hello Nix\n"; + }; } diff --git a/tests/lib.nix b/tests/lib.nix index 3c70678..8764b3c 100644 --- a/tests/lib.nix +++ b/tests/lib.nix @@ -10,7 +10,10 @@ # Reads a given file (either drv, path or string) and returns it's sha256 hash hashFile = filename: builtins.hashString "sha256" (builtins.readFile filename); - noGithubHashes = (_: null); + noSourceOptions = { + sourceHashFunc = _: null; + nodejs = null; + }; runTests = tests: let diff --git a/tests/make-github-source.nix b/tests/make-github-source.nix index b282e05..f78e9b9 100644 --- a/tests/make-github-source.nix +++ b/tests/make-github-source.nix @@ -1,6 +1,6 @@ { lib, npmlock2nix, testLib }: let - inherit (testLib) noGithubHashes; + inherit (testLib) noSourceOptions; i = npmlock2nix.internal; testDependency = { @@ -12,7 +12,7 @@ in testSimpleCase = { expr = let - version = (i.makeGithubSource noGithubHashes "leftpad" testDependency).version; + version = (i.makeGithubSource noSourceOptions "leftpad" testDependency).version; in lib.hasPrefix "file:///nix/store" version; expected = true; @@ -21,7 +21,7 @@ in testDropsFrom = { expr = let - dep = i.makeGithubSource noGithubHashes "leftpad" testDependency; + dep = i.makeGithubSource noSourceOptions "leftpad" testDependency; in dep ? from; expected = false; diff --git a/tests/make-source.nix b/tests/make-source.nix index 05eb783..dd44426 100644 --- a/tests/make-source.nix +++ b/tests/make-source.nix @@ -1,7 +1,10 @@ { testLib, npmlock2nix }: let i = npmlock2nix.internal; - f = builtins.throw "Shouldn't be called"; + f = { + sourceHashFunc = builtins.throw "Shouldn't be called"; + nodejs = null; + }; in testLib.runTests { testMakeSourceRegular = { diff --git a/tests/patch-lockfile.nix b/tests/patch-lockfile.nix index 0993673..2db2051 100644 --- a/tests/patch-lockfile.nix +++ b/tests/patch-lockfile.nix @@ -1,13 +1,13 @@ { npmlock2nix, testLib, lib }: let - inherit (testLib) noGithubHashes; + inherit (testLib) noSourceOptions; in testLib.runTests { testPatchDependencyHandlesGitHubRefsInRequires = { expr = let - libxmljsUrl = (npmlock2nix.internal.patchDependency noGithubHashes "test" { + libxmljsUrl = (npmlock2nix.internal.patchDependency [ ] noSourceOptions "test" { version = "github:tmcw/leftpad#db1442a0556c2b133627ffebf455a78a1ced64b9"; from = "github:tmcw/leftpad#db1442a0556c2b133627ffebf455a78a1ced64b9"; integrity = "sha512-8/UvHFG90J4O4QNRzb0jB5Ni1QuvuB7XFTLfDMQnCzAsFemF29VKnNGUESFFcSP/r5WWh/PMe0YRz90+3IqsUA=="; @@ -15,19 +15,19 @@ testLib.runTests { libxmljs = "github:znerol/libxmljs#0517e063347ea2532c9fdf38dc47878c628bf0ae"; }; } - ).requires.libxmljs; + ).result.requires.libxmljs; in lib.hasPrefix builtins.storeDir libxmljsUrl; expected = true; }; testBundledDependenciesAreRetained = { - expr = npmlock2nix.internal.patchDependency noGithubHashes "test" { + expr = (npmlock2nix.internal.patchDependency [ ] noSourceOptions "test" { bundled = true; integrity = "sha1-hrGk3k+s4YCsVFqD8VA1I9j+0RU="; something = "bar"; dependencies = { }; - }; + }).result; expected = { bundled = true; integrity = "sha1-hrGk3k+s4YCsVFqD8VA1I9j+0RU="; @@ -37,18 +37,18 @@ testLib.runTests { }; testPatchLockfileWithoutDependencies = { - expr = (npmlock2nix.internal.patchLockfile noGithubHashes ./examples-projects/no-dependencies/package-lock.json).dependencies; + expr = (npmlock2nix.internal.patchLockfile noSourceOptions ./examples-projects/no-dependencies/package-lock.json).result.dependencies; expected = { }; }; testPatchDependencyDoesntDropAttributes = { - expr = npmlock2nix.internal.patchDependency noGithubHashes "test" { + expr = (npmlock2nix.internal.patchDependency [ ] noSourceOptions "test" { a = 1; foo = "something"; resolved = "https://examples.com/something.tgz"; integrity = "sha1-00000000000000000000000+0RU="; dependencies = { }; - }; + }).result; expected = { a = 1; foo = "something"; @@ -59,7 +59,7 @@ testLib.runTests { }; testPatchDependencyPatchesDependenciesRecursively = { - expr = npmlock2nix.internal.patchDependency noGithubHashes "test" { + expr = (npmlock2nix.internal.patchDependency [ ] noSourceOptions "test" { a = 1; foo = "something"; resolved = "https://examples.com/something.tgz"; @@ -68,7 +68,7 @@ testLib.runTests { resolved = "https://examples.com/somethingelse.tgz"; integrity = "sha1-00000000000000000000000+00U="; }; - }; + }).result; expected = { a = 1; @@ -85,7 +85,7 @@ testLib.runTests { testPatchLockfileTurnsUrlsIntoStorePaths = { expr = let - deps = (npmlock2nix.internal.patchLockfile noGithubHashes ./examples-projects/single-dependency/package-lock.json).dependencies; + deps = (npmlock2nix.internal.patchLockfile noSourceOptions ./examples-projects/single-dependency/package-lock.json).result.dependencies; in lib.count (dep: lib.hasPrefix "file:///nix/store/" dep.resolved) (lib.attrValues deps); expected = 1; @@ -94,19 +94,19 @@ testLib.runTests { testPatchLockfileTurnsGitHubUrlsIntoStorePaths = { expr = let - leftpad = (npmlock2nix.internal.patchLockfile noGithubHashes ./examples-projects/github-dependency/package-lock.json).dependencies.leftpad; + leftpad = (npmlock2nix.internal.patchLockfile noSourceOptions ./examples-projects/github-dependency/package-lock.json).result.dependencies.leftpad; in lib.hasPrefix ("file://" + builtins.storeDir) leftpad.version; expected = true; }; testConvertPatchedLockfileToJSON = { - expr = builtins.typeOf (builtins.toJSON (npmlock2nix.internal.patchLockfile noGithubHashes ./examples-projects/nested-dependencies/package-lock.json)) == "string"; + expr = builtins.typeOf (builtins.toJSON (npmlock2nix.internal.patchLockfile noSourceOptions ./examples-projects/nested-dependencies/package-lock.json).result) == "string"; expected = true; }; testPatchedLockFile = { - expr = testLib.hashFile (npmlock2nix.internal.patchedLockfile noGithubHashes ./examples-projects/nested-dependencies/package-lock.json); + expr = testLib.hashFile (npmlock2nix.internal.patchedLockfile noSourceOptions ./examples-projects/nested-dependencies/package-lock.json).result; expected = "980323c3a53d86ab6886f21882936cfe7c06ac633993f16431d79e3185084414"; }; diff --git a/tests/patch-packagefile.nix b/tests/patch-packagefile.nix index dc122ea..7cc1d32 100644 --- a/tests/patch-packagefile.nix +++ b/tests/patch-packagefile.nix @@ -1,19 +1,18 @@ { lib, npmlock2nix, testLib }: let - inherit (testLib) noGithubHashes; i = npmlock2nix.internal; in (testLib.runTests { testTurnsGitHubRefsToWildcards = { - expr = (npmlock2nix.internal.patchPackagefile noGithubHashes ./examples-projects/github-dependency/package.json).dependencies.leftpad; + expr = (npmlock2nix.internal.patchPackagefile ./examples-projects/github-dependency/package.json).dependencies.leftpad; expected = "*"; }; testHandlesBranches = { - expr = (npmlock2nix.internal.patchPackagefile noGithubHashes ./examples-projects/github-dependency-branch/package.json).dependencies.leftpad; + expr = (npmlock2nix.internal.patchPackagefile ./examples-projects/github-dependency-branch/package.json).dependencies.leftpad; expected = "*"; }; testHandlesDevDependencies = { - expr = (npmlock2nix.internal.patchPackagefile noGithubHashes ./examples-projects/github-dev-dependency/package.json).devDependencies.leftpad; + expr = (npmlock2nix.internal.patchPackagefile ./examples-projects/github-dev-dependency/package.json).devDependencies.leftpad; expected = "*"; }; })