guix_mirror_bot pushed a commit to branch javascript-team in repository guix.
commit 91edb3f34ef51e4628f06edf6281f651cd0e36f4 Author: Maxim Cournoyer <[email protected]> AuthorDate: Wed Jun 10 09:00:16 2026 +0900 build/node: Add `delete-dependencies/except' procedure. This adds a more convenient means to filter out most, but not all, development dependencies. * guix/build/node-build-system.scm (%dependency-keys) (%dev-dependency-keys): New variables. (delete-dependencies) [#:negate?, #:dependency-keys]: New arguments. Log removed dependencies. (delete-dependencies/except, delete-dev-dependencies/except): New procedures. * tests/node.scm: New test. * Makefile.am (SCM_TESTS): Register it. --- Makefile.am | 1 + guix/build/node-build-system.scm | 51 +++++++++++++++++---- tests/node.scm | 99 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 10 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0f7a93278c..b693cdd77d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -599,6 +599,7 @@ SCM_TESTS = \ tests/monads.scm \ tests/nar.scm \ tests/networking.scm \ + tests/node.scm \ tests/openpgp.scm \ tests/packages.scm \ tests/pack.scm \ diff --git a/guix/build/node-build-system.scm b/guix/build/node-build-system.scm index 501fb630bd..5ee4f9a37d 100644 --- a/guix/build/node-build-system.scm +++ b/guix/build/node-build-system.scm @@ -36,7 +36,9 @@ #:use-module (srfi srfi-71) #:export (%standard-phases delete-dependencies + delete-dependencies/except delete-dev-dependencies + delete-dev-dependencies/except delete-fields add-fields modify-json @@ -74,26 +76,55 @@ a value to be written as JSON to the replacement FILE." modifications)) file))) -(define (delete-dependencies dependencies-to-remove) +(define %dependency-keys + '("devDependencies" + "dependencies" + "peerDependencies" + "optionalDependencies")) + +(define %dev-dependency-keys + '("devDependencies" + "peerDependencies")) + +(define* (delete-dependencies dependencies-to-remove + #:key negate? + (dependency-keys %dependency-keys)) "Rewrite 'package.json' to allow the build to proceed without packages -listed in 'dependencies-to-remove', a list of strings naming npm packages. +listed in 'dependencies-to-remove', a list of strings naming npm packages. To +negate its effect, and keep DEPENDENCIES-TO-REMOVE instead of removing them, +set NEGATE? to #t. DEPENDENCY-KEYS can be used to adjust which dependency +fields are targeted. To prevent the deleted dependencies from being reintroduced, use this function only after the 'patch-dependencies' phase." (let ((predicate (lambda (dependency) (member (car dependency) dependencies-to-remove))) - (dependency? (cut member <> (list "devDependencies" - "dependencies" - "peerDependencies" - "optionalDependencies")))) + (dependency? (cut member <> %dependency-keys))) (lambda (pkg-meta) (map (match-lambda (((? dependency? key) . dependencies) - (cons key (remove predicate dependencies))) - (otherwise - otherwise)) + (let* (((values removed kept) + (partition ((if negate? negate identity) + predicate) + dependencies))) + (format #t "deleting ~s dependencies: ~y~%" key removed) + (cons key kept))) + (otherwise otherwise)) pkg-meta)))) +(define* (delete-dependencies/except dependencies-to-preserve + #:key (dependency-keys %dependency-keys)) + "Like `delete-dependencies', but deleting all dependencies except those +listed in DEPENDENCIES-TO-PRESERVE." + (delete-dependencies dependencies-to-preserve #:negate? #t + #:dependency-keys dependency-keys)) + +(define* (delete-dev-dependencies/except dependencies-to-preserve) + "Like `delete-dependencies/except' but only acting on development +dependencies." + (delete-dependencies/except dependencies-to-preserve + #:dependency-keys %dev-dependency-keys)) + (define* (modify-json-fields fields field-modifier #:key (field-path-mapper identity) @@ -175,7 +206,7 @@ invalid field value provided, expected string or list of strings, got ~s~%" fields (lambda (field data key) (let ((value (cdr field))) - (format #t "setting field ~s to value ~s%" key value) + (format #t "setting field ~s to value: ~y~%" key value) (assoc-set! data key value))) #:field-path-mapper (lambda (field) (car field)) #:insert? insert? diff --git a/tests/node.scm b/tests/node.scm new file mode 100644 index 0000000000..5159d530a1 --- /dev/null +++ b/tests/node.scm @@ -0,0 +1,99 @@ +;;; GNU Guix --- Tests for the node-build-system procedures. +;;; Copyright © 2026 Maxim Cournoyer <[email protected]> +;;; +;;; This file is part of GNU Guix. +;;; +;;; GNU Guix is free software; you can redistribute it and/or modify it +;;; under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3 of the License, or (at +;;; your option) any later version. +;;; +;;; GNU Guix is distributed in the hope that it will be useful, but +;;; WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License +;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. + +(use-modules (json) + (guix build node-build-system) + (guix tests) + (srfi srfi-64)) + +(define (package.json) + "Sample package.json file." + (call-with-output-string + (lambda (out) + (scm->json + '(("devDependencies" + ("typescript-eslint" . "^8.61.0") + ("typescript" . "^5.9.3") + ("typedoc" . "^0.28.19") + ("htmlparser2" . "^10.1.0") + ("eslint" . "^10.4.1") + ("@types/node" . "^25.9.2")) + ("dependencies" + ("domelementtype" . "^3.0.0") + ("boolbase" . ">=2.0.0")) + ("peerDependencies" + ("mkdirp" . ">=1.0.0") + ("react" . "^16.8.0")) + ("engines" ("node" . ">=20.19.0")) + ("repository" + ("url" . "https://example.com/dummy/dummy.git") + ("type" . "git")) + ("scripts" + ("test" . "npm run test") + ("lint" . "eslint .") + ("build" . "tsc")) + ("files" . #("dist" "src" "!**/*.spec.ts")) + ("sideEffects" . #f) + ("exports" + ("." ("default" . "./dist/index.js") ("types" . "./dist/index.d.ts"))) + ("types" . "dist/index.d.ts") + ("main" . "dist/index.js") + ("license" . "GPL-3.0") + ("description" . "Dummy package.json") + ("version" . "6.0.1") + ("name" . "dummy") + ("type" . "module")) + out #:pretty #t)))) + +(define* (modify-json* #:rest all-arguments) + "Wrap modify-json to use our package.json test sample and avoid file I/O. +It also returns the data as an alist directly." + (mock ((guix build utils) with-atomic-file-replacement + (lambda (_ proc) + (call-with-input-string (package.json) + (lambda (in) + (call-with-output-string + (lambda (out) + (proc in out))))))) + (json-string->scm (apply modify-json all-arguments) + #:ordered #t))) + + +(test-begin "node related tests") + +(test-equal "delete-dependencies" + '(("domelementtype" . "^3.0.0")) + (assoc-ref (modify-json* + (delete-dependencies '("boolbase"))) + "dependencies")) + +(test-equal "delete-dependencies/except" + '(("boolbase" . ">=2.0.0")) + (assoc-ref (modify-json* + (delete-dependencies/except '("boolbase"))) + "dependencies")) + +(test-equal "delete-dev-dependencies/except" + '(("@types/node" . "^25.9.2") + ("typescript" . "^5.9.3")) + (assoc-ref (modify-json* + (delete-dev-dependencies/except + '("typescript" "@types/node"))) + "devDependencies")) + +(test-end)
