about summary refs log tree commit diff
path: root/nixpkgs/pkgs/build-support/node/import-npm-lock/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixpkgs/pkgs/build-support/node/import-npm-lock/default.nix')
-rw-r--r--nixpkgs/pkgs/build-support/node/import-npm-lock/default.nix134
1 files changed, 134 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/build-support/node/import-npm-lock/default.nix b/nixpkgs/pkgs/build-support/node/import-npm-lock/default.nix
new file mode 100644
index 000000000000..d530b8ee30ff
--- /dev/null
+++ b/nixpkgs/pkgs/build-support/node/import-npm-lock/default.nix
@@ -0,0 +1,134 @@
+{ lib
+, fetchurl
+, stdenv
+, callPackages
+, runCommand
+}:
+
+let
+  inherit (builtins) match elemAt toJSON removeAttrs;
+  inherit (lib) importJSON mapAttrs;
+
+  matchGitHubReference = match "github(.com)?:.+";
+  getName = package: package.name or "unknown";
+  getVersion = package: package.version or "0.0.0";
+
+  # Fetch a module from package-lock.json -> packages
+  fetchModule =
+    { module
+    , npmRoot ? null
+    }: (
+      if module ? "resolved" then
+        (
+          let
+            # Parse scheme from URL
+            mUrl = match "(.+)://(.+)" module.resolved;
+            scheme = elemAt mUrl 0;
+          in
+          (
+            if mUrl == null then
+              (
+                assert npmRoot != null; {
+                  outPath = npmRoot + "/${module.resolved}";
+                }
+              )
+            else if (scheme == "http" || scheme == "https") then
+              (
+                fetchurl {
+                  url = module.resolved;
+                  hash = module.integrity;
+                }
+              )
+            else if lib.hasPrefix "git" module.resolved then
+              (
+                builtins.fetchGit {
+                  url = module.resolved;
+                }
+              )
+            else throw "Unsupported URL scheme: ${scheme}"
+          )
+        )
+      else null
+    );
+
+  # Manage node_modules outside of the store with hooks
+  hooks = callPackages ./hooks { };
+
+in
+{
+  importNpmLock =
+    { npmRoot ? null
+    , package ? importJSON (npmRoot + "/package.json")
+    , packageLock ? importJSON (npmRoot + "/package-lock.json")
+    , pname ? getName package
+    , version ? getVersion package
+    }:
+    let
+      mapLockDependencies =
+        mapAttrs
+          (name: version: (
+            # Substitute the constraint with the version of the dependency from the top-level of package-lock.
+            if (
+              # if the version is `latest`
+              version == "latest"
+              ||
+              # Or if it's a github reference
+              matchGitHubReference version != null
+            ) then packageLock'.packages.${"node_modules/${name}"}.version
+            # But not a regular version constraint
+            else version
+          ));
+
+      packageLock' = packageLock // {
+        packages =
+          mapAttrs
+            (_: module:
+              let
+                src = fetchModule {
+                  inherit module npmRoot;
+                };
+              in
+              (removeAttrs module [
+                "link"
+                "funding"
+              ]) // lib.optionalAttrs (src != null) {
+                resolved = "file:${src}";
+              } // lib.optionalAttrs (module ? dependencies) {
+                dependencies = mapLockDependencies module.dependencies;
+              } // lib.optionalAttrs (module ? optionalDependencies) {
+                optionalDependencies = mapLockDependencies module.optionalDependencies;
+              })
+            packageLock.packages;
+      };
+
+      mapPackageDependencies = mapAttrs (name: _: packageLock'.packages.${"node_modules/${name}"}.resolved);
+
+      # Substitute dependency references in package.json with Nix store paths
+      packageJSON' = package // lib.optionalAttrs (package ? dependencies) {
+        dependencies = mapPackageDependencies package.dependencies;
+      } // lib.optionalAttrs (package ? devDependencies) {
+        devDependencies = mapPackageDependencies package.devDependencies;
+      };
+
+      pname = package.name or "unknown";
+
+    in
+    runCommand "${pname}-${version}-sources"
+      {
+        inherit pname version;
+
+        passAsFile = [ "package" "packageLock" ];
+
+        package = toJSON packageJSON';
+        packageLock = toJSON packageLock';
+      } ''
+      mkdir $out
+      cp "$packagePath" $out/package.json
+      cp "$packageLockPath" $out/package-lock.json
+    '';
+
+  inherit hooks;
+  inherit (hooks) npmConfigHook;
+
+  __functor = self: self.importNpmLock;
+}