From ac54433a8aae4cd6e6c660263503b96660a35fa8 Mon Sep 17 00:00:00 2001 Message-ID: In-Reply-To: References: From: Daniel Khodabakhsh Date: Sun, 29 Dec 2024 10:24:23 -0800 Subject: [PATCH 2/2] Introduce (modify-json), (delete-fields), and (replace-fields) to node-build-system This change introduces helper procedures (modify-json) which takes in lambdas which modify the target json #:file which defaults to package.json This change also includes (delete-fields) and (replace-fields) to help deleting and replacing the value of fields in a package.json file. Signed-off-by: Daniel Khodabakhsh Change-Id: I957f7ca814078d2136d5261985174820235f1369 --- gnu/packages/node-xyz.scm | 324 ++++++++++++++----------------- gnu/packages/node.scm | 86 ++++---- guix/build/node-build-system.scm | 198 +++++++++++++++---- 3 files changed, 355 insertions(+), 253 deletions(-) diff --git a/gnu/packages/node-xyz.scm b/gnu/packages/node-xyz.scm index ec3f9fbfb1..cdc69de0c1 100644 --- a/gnu/packages/node-xyz.scm +++ b/gnu/packages/node-xyz.scm @@ -69,18 +69,7 @@ (define-public node-acorn ;; We need to remove the prepare script from "package.json", as ;; it would try to use the build environment and would block the ;; automatic building by other packages making use of node-acorn. - ;; TODO: Add utility function - (with-atomic-json-file-replacement (lambda (pkg-meta-alist) - (map - (match-lambda - (("scripts" . scripts-alist) - (cons "scripts" (filter - (match-lambda - (("prepare" . _) #f) - (_ #t)) - scripts-alist))) - (other other)) - pkg-meta-alist))))) + (modify-json (delete-fields '(("scripts" "prepare")))))) (replace 'build (lambda* (#:key inputs native-inputs #:allow-other-keys) (let ((esbuild (search-input-file (or native-inputs inputs) @@ -136,38 +125,26 @@ (define-public node-addon-api (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies - `("benchmark" - "bindings" - "clang-format" - "eslint" - "eslint-config-semistandard" - "eslint-config-standard" - "eslint-plugin-import" - "eslint-plugin-node" - "eslint-plugin-promise" - "fs-extra" - "neostandard" - "path" - "pre-commit" - "semver")))) - (add-after 'unpack 'skip-js-tests - ;; We can't run the js-based tests, - ;; but we can still do the C++ parts - (lambda args - (define new-test-script - "echo stopping after pretest on Guix") - (with-atomic-json-file-replacement (lambda (pkg-meta-alist) - (map - (match-lambda - (("scripts" . scripts-alist) - (cons "scripts" (map - (match-lambda - (("test" . _) (cons "test" new-test-script)) - (other other)) - scripts-alist))) - (other other)) - pkg-meta-alist)))))))) + (modify-json + (delete-dependencies `( + "benchmark" + "bindings" + "clang-format" + "eslint" + "eslint-config-semistandard" + "eslint-config-standard" + "eslint-plugin-import" + "eslint-plugin-node" + "eslint-plugin-promise" + "fs-extra" + "neostandard" + "path" + "pre-commit" + "semver")) + ;; We can't run the js-based tests, + ;; but we can still do the C++ parts + (replace-fields (list (cons + "scripts.test" "echo stopping after pretest on Guix"))))))))) (home-page "https://github.com/nodejs/node-addon-api") (synopsis "Node.js API (Node-API) header-only C++ wrappers") (description "This module contains header-only C++ wrapper classes which @@ -232,7 +209,7 @@ (define-public node-buffer-crc32 #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("tap"))))))) + (modify-json (delete-dependencies '("tap")))))))) (home-page "https://github.com/brianloveswords/buffer-crc32") (synopsis "CRC32 implementation in Javascript") (description @@ -288,14 +265,15 @@ (define-public node-crx3 "minimist")))) (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("c8" - "docdash" - "eslint" - "eslint-plugin-jsdoc" - "jsdoc" - "tap-diff" - "tape" - "tape-catch"))))))) + (modify-json (delete-dependencies + '("c8" + "docdash" + "eslint" + "eslint-plugin-jsdoc" + "jsdoc" + "tap-diff" + "tape" + "tape-catch")))))))) (inputs (list node-minimist node-pbf node-yazl)) (home-page "https://github.com/ahwayakchih/crx3") (synopsis "Create CRXv3 browser extensions with Javascript") @@ -325,18 +303,19 @@ (define-public node-debug (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("brfs" - "browserify" - "coveralls" - "istanbul" - "karma" - "karma-browserify" - "karma-chrome-launcher" - "karma-mocha" - "mocha" - "mocha-lcov-reporter" - "xo" - "supports-color"))))) + (modify-json (delete-dependencies + `("brfs" + "browserify" + "coveralls" + "istanbul" + "karma" + "karma-browserify" + "karma-chrome-launcher" + "karma-mocha" + "mocha" + "mocha-lcov-reporter" + "xo" + "supports-color")))))) #:tests? #f)) (home-page "https://github.com/debug-js/debug") (synopsis "Debugging utility for Node.js") @@ -421,21 +400,22 @@ (define-public node-file-uri-to-path (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("@types/mocha" - "@types/node" - "@typescript-eslint/eslint-plugin" - "@typescript-eslint/parser" - "cpy-cli" - "eslint" - "eslint-config-airbnb" - "eslint-config-prettier" - "eslint-import-resolver-typescript" - "eslint-plugin-import" - "eslint-plugin-jsx-a11y" - "eslint-plugin-react" - "mocha" - "rimraf" - "typescript")))) + (modify-json (delete-dependencies + `("@types/mocha" + "@types/node" + "@typescript-eslint/eslint-plugin" + "@typescript-eslint/parser" + "cpy-cli" + "eslint" + "eslint-config-airbnb" + "eslint-config-prettier" + "eslint-import-resolver-typescript" + "eslint-plugin-import" + "eslint-plugin-jsx-a11y" + "eslint-plugin-react" + "mocha" + "rimraf" + "typescript"))))) (replace 'build (lambda* (#:key inputs native-inputs #:allow-other-keys) (copy-recursively "src" "dist") @@ -497,7 +477,8 @@ (define-public node-ieee754 #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("airtap" "standard" "tape"))))))) + (modify-json (delete-dependencies + '("airtap" "standard" "tape")))))))) (home-page "https://github.com/feross/ieee754") (synopsis "Read/write IEEE754 floating point numbers in Javascript") (description "This package can read and write IEEE754 floating point @@ -524,7 +505,7 @@ (define-public node-inherits (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("tap"))))) + (modify-json (delete-dependencies '("tap")))))) ;; FIXME: Tests depend on node-tap #:tests? #f)) (home-page "https://github.com/isaacs/inherits") @@ -553,8 +534,8 @@ (define-public node-irc (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies - `("ansi-color" "faucet" "jscs" "tape"))))) + (modify-json (delete-dependencies + `("ansi-color" "faucet" "jscs" "tape")))))) #:tests? #f)) (inputs (list node-irc-colors)) @@ -583,7 +564,7 @@ (define-public node-irc-colors (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("istanbul" "vows"))))) + (modify-json (delete-dependencies `("istanbul" "vows")))))) #:tests? #f)) (home-page "https://github.com/fent/irc-colors.js") (synopsis "Node.js module providing color and formatting for IRC") @@ -657,7 +638,8 @@ (define-public node-minimist #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("covert" "tap" "tape"))))))) + (modify-json (delete-dependencies + '("covert" "tap" "tape")))))))) (home-page "https://github.com/substack/minimist") (synopsis "Parse CLI arguments in Javascript") (description "This package can scan for CLI flags and arguments in @@ -683,12 +665,13 @@ (define-public node-ms (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("eslint" - "expect.js" - "husky" - "lint-staged" - "mocha" - "prettier"))))) + (modify-json (delete-dependencies + `("eslint" + "expect.js" + "husky" + "lint-staged" + "mocha" + "prettier")))))) #:tests? #f)) (home-page "https://github.com/vercel/ms") (synopsis "Convert time to milliseconds") @@ -716,14 +699,14 @@ (define-public node-nan (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies + (modify-json (delete-dependencies '("bindings" "commander" "glob" "request" "node-gyp" ;; would be needed for tests "tap" - "xtend"))))) + "xtend")))))) ;; tests need tap and other dependencies #:tests? #f)) (inputs @@ -755,7 +738,8 @@ (define-public node-normalize-path #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("gulp-format-md" "mocha"))))))) + (modify-json (delete-dependencies + '("gulp-format-md" "mocha")))))))) (native-inputs (list node-minimist)) (home-page "https://github.com/jonschlinkert/normalize-path") (synopsis "Normalize slashes in a file path") @@ -784,7 +768,7 @@ (define-public node-once (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("tap"))))) + (modify-json (delete-dependencies '("tap")))))) ;; FIXME: Tests depend on node-tap #:tests? #f)) (inputs @@ -841,7 +825,8 @@ (define-public node-path-key #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("@types/node" "ava" "tsd" "xo"))))))) + (modify-json (delete-dependencies + '("@types/node" "ava" "tsd" "xo")))))))) (home-page "https://github.com/sindresorhus/path-key") (synopsis "Cross-platform utility to compute the PATH environment variable key") (description "@code{path-key} provides an implementation to compute the @@ -867,7 +852,7 @@ (define-public node-pbf #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies + (modify-json (delete-dependencies '("benchmark" "browserify" "eslint" @@ -877,7 +862,7 @@ (define-public node-pbf "protocol-buffers" "tap" "tile-stats-runner" - "uglify-js"))))))) + "uglify-js")))))))) (inputs (list node-ieee754 node-resolve-protobuf-schema)) (home-page "https://github.com/mapbox/pbf") (synopsis "Decode and encode protocol buffers in Javascript") @@ -908,7 +893,8 @@ (define-public node-protocol-buffers-schema #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("standard" "tape"))))))) + (modify-json (delete-dependencies + '("standard" "tape")))))))) (home-page "https://github.com/mafintosh/protocol-buffers-schema") (synopsis "Protocol buffers schema parser written in Javascript") (description "This package provides a protocol buffers schema parser @@ -935,26 +921,27 @@ (define-public node-readable-stream (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("@babel/cli" - "@babel/core" - "@babel/polyfill" - "@babel/preset-env" - "airtap" - "assert" - "bl" - "deep-strict-equal" - "events.once" - "glob" - "gunzip-maybe" - "hyperquest" - "lolex" - "nyc" - "pump" - "rimraf" - "tap" - "tape" - "tar-fs" - "util-promisify"))))) + (modify-json (delete-dependencies + `("@babel/cli" + "@babel/core" + "@babel/polyfill" + "@babel/preset-env" + "airtap" + "assert" + "bl" + "deep-strict-equal" + "events.once" + "glob" + "gunzip-maybe" + "hyperquest" + "lolex" + "nyc" + "pump" + "rimraf" + "tap" + "tape" + "tar-fs" + "util-promisify")))))) #:tests? #f)) (inputs (list node-util-deprecate node-string-decoder node-inherits)) (home-page "https://github.com/nodejs/readable-stream") @@ -983,7 +970,8 @@ (define-public node-resolve-protobuf-schema #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("standard" "tape"))))))) + (modify-json (delete-dependencies + '("standard" "tape")))))))) (inputs (list node-protocol-buffers-schema)) (home-page "https://github.com/mafintosh/resolve-protobuf-schema") (synopsis "Resolve protobuf imports") @@ -1012,7 +1000,7 @@ (define-public node-safe-buffer (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("tape" "standard"))))) + (modify-json (delete-dependencies '("tape" "standard")))))) #:tests? #f)) (home-page "https://github.com/feross/safe-buffer") (synopsis "Buffer creation with explicit semantics") @@ -1040,20 +1028,21 @@ (define-public node-safe-stable-stringify #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("benchmark" "clone" - "fast-json-stable-stringify" - "fast-safe-stringify" - "fast-stable-stringify" - "faster-stable-stringify" - "fastest-stable-stringify" - "json-stable-stringify" - "json-stringify-deterministic" - "json-stringify-safe" - "standard" - "tap" - "typescript" - "@types/node" - "@types/json-stable-stringify"))))))) + (modify-json (delete-dependencies + '("benchmark" "clone" + "fast-json-stable-stringify" + "fast-safe-stringify" + "fast-stable-stringify" + "faster-stable-stringify" + "fastest-stable-stringify" + "json-stable-stringify" + "json-stringify-deterministic" + "json-stringify-safe" + "standard" + "tap" + "typescript" + "@types/node" + "@types/json-stable-stringify")))))))) (home-page "https://github.com/BridgeAR/safe-stable-stringify") (synopsis "Serialization of javascript objects") (description @@ -1111,7 +1100,7 @@ (define-public node-semver (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("tap"))))) + (modify-json (delete-dependencies '("tap")))))) ;; FIXME: Tests depend on node-tap #:tests? #f)) (home-page "https://github.com/npm/node-semver") @@ -1151,7 +1140,8 @@ (define-public node-serialport (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("@serialport/binding-mock")))) + (modify-json (delete-dependencies + `("@serialport/binding-mock"))))) (add-after 'unpack 'chdir (lambda args (chdir "packages/serialport")))) @@ -1210,25 +1200,10 @@ (define-public node-serialport-bindings (chdir "packages/bindings"))) (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("prebuild-install" - ;; devDependencies - "@serialport/binding-mock" - "node-abi")))) - (add-after 'chdir 'avoid-prebuild-install - (lambda args - (with-atomic-json-file-replacement (lambda (pkg-meta-alist) - (map - (match-lambda - (("scripts" . scripts-alist) - (cons "scripts" (filter - (match-lambda - (("install" . _) #f) - (_ #t)) - scripts-alist))) - (("gypfile" . _) - (cons "gypfile" #f)) - (other other)) - pkg-meta-alist)))))) + (modify-json + (delete-dependencies `( + ;; devDependencies + "node-abi")))))) #:tests? #f)) (synopsis "Abstract base class for Node SerialPort bindings") (description "Node SerialPort is a modular suite of Node.js packages for @@ -1409,8 +1384,9 @@ (define-public node-serialport-stream (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `(;; devDependencies - "@serialport/binding-mock")))) + (modify-json + (delete-dependencies ;; devDependencies + `("@serialport/binding-mock"))))) (add-after 'unpack 'chdir (lambda args (chdir "packages/stream")))) @@ -1461,7 +1437,7 @@ (define-public node-sqlite3 (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies + (modify-json (delete-dependencies `(;; Normally, this is "built" using @mapbox/node-pre-gyp, ;; which publishes or downloads pre-built binaries or ;; falls back to building from source. Here, we patch out @@ -1480,7 +1456,7 @@ (define-public node-sqlite3 "node-gyp" ;; These we'd like, we just don't have them yet: "eslint" - "mocha")))) + "mocha"))))) (add-before 'configure 'npm-config-sqlite ;; We need this step even if we do replace @mapbox/node-pre-gyp ;; because the package expects to build its bundled sqlite @@ -1514,8 +1490,9 @@ (define-public node-sqlite3 (substitute* ".npmignore" (("lib/binding") "#lib/binding # <- patched for Guix")) - (with-atomic-json-file-replacement (lambda (pkg-meta-alist) - (let ((binary-alist (assoc-ref pkg-meta-alist "binary"))) + (modify-json + (lambda (pkg-meta-alist) + (let ((binary-alist (assoc-ref pkg-meta-alist "binary"))) ;; When it builds from source, node-pre-gyp supplies ;; module_name and module_path based on the entries under ;; "binary" from "package.json", so this package's @@ -1528,19 +1505,11 @@ (define-public node-sqlite3 (assoc-ref binary-alist "module_name") " module_path=" (assoc-ref binary-alist "module_path")))) + pkg-meta-alist) ;; We need to remove the install script from "package.json", ;; as it would try to use node-pre-gyp and would block the ;; automatic building performed by `npm install`. - (map - (match-lambda - (("scripts" . scripts-alist) - (cons "scripts" (filter - (match-lambda - (("install" . _) #f) - (_ #t)) - scripts-alist))) - (other other)) - pkg-meta-alist)))))))) + (delete-fields `(("scripts" "install"))))))))) (home-page "https://github.com/mapbox/node-sqlite3") (synopsis "Node.js bindings for SQLite3") (description @@ -1623,8 +1592,8 @@ (define-public node-string-decoder (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies - '("tap" "core-util-is" "babel-polyfill"))))) + (modify-json (delete-dependencies + '("tap" "core-util-is" "babel-polyfill")))))) ;; FIXME: Tests depend on node-tap #:tests? #f)) (inputs (list node-safe-buffer node-inherits)) @@ -1678,7 +1647,7 @@ (define-public node-wrappy (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("tap"))))))) + (modify-json (delete-dependencies '("tap")))))))) (home-page "https://github.com/npm/wrappy") (synopsis "Callback wrapping utility") (description "@code{wrappy} is a utility for Node.js to wrap callbacks.") @@ -1703,7 +1672,8 @@ (define-public node-yazl #:phases (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies '("airtap" "bl" "istanbul" "yauzl"))))))) + (modify-json (delete-dependencies + '("airtap" "bl" "istanbul" "yauzl")))))))) (inputs (list node-buffer-crc32)) (home-page "https://github.com/thejoshwolfe/yazl") (synopsis "Yet another zip library for node") diff --git a/gnu/packages/node.scm b/gnu/packages/node.scm index 20acffb3df..a13ec5d077 100644 --- a/gnu/packages/node.scm +++ b/gnu/packages/node.scm @@ -13,6 +13,7 @@ ;;; Copyright © 2021, 2022 Philip McGrath ;;; Copyright © 2022 Hilton Chain ;;; Copyright © 2024 Efraim Flashner +;;; Copyright © 2024 Daniel Khodabakhsh ;;; ;;; This file is part of GNU Guix. ;;; @@ -366,7 +367,7 @@ (define-public node-semver-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("tap"))))))) + (modify-json (delete-dependencies '("tap")))))))) (home-page "https://github.com/npm/node-semver") (properties '((hidden? . #t))) (synopsis "Parses semantic versions strings") @@ -397,11 +398,12 @@ (define-public node-ms-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies '("eslint" - "expect.js" - "husky" - "lint-staged" - "mocha"))))))) + (modify-json (delete-dependencies + '("eslint" + "expect.js" + "husky" + "lint-staged" + "mocha")))))))) (home-page "https://github.com/zeit/ms#readme") (properties '((hidden? . #t))) (synopsis "Tiny millisecond conversion utility") @@ -431,7 +433,7 @@ (define-public node-binary-search-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("chai" "mocha"))))))) + (modify-json (delete-dependencies `("chai" "mocha")))))))) (home-page "https://github.com/darkskyapp/binary-search#readme") (properties '((hidden? . #t))) (synopsis "Tiny binary search function with comparators") @@ -460,17 +462,18 @@ (define-public node-debug-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("brfs" - "browserify" - "coveralls" - "istanbul" - "karma" - "karma-browserify" - "karma-chrome-launcher" - "karma-mocha" - "mocha" - "mocha-lcov-reporter" - "xo"))))))) + (modify-json (delete-dependencies + `("brfs" + "browserify" + "coveralls" + "istanbul" + "karma" + "karma-browserify" + "karma-chrome-launcher" + "karma-mocha" + "mocha" + "mocha-lcov-reporter" + "xo")))))))) (inputs (list node-ms-bootstrap)) (home-page "https://github.com/visionmedia/debug#readme") (properties '((hidden? . #t))) @@ -526,12 +529,13 @@ (define-public node-llparse-builder-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda _ - (delete-dependencies `("@types/mocha" - "@types/node" - "mocha" - "ts-node" - "tslint" - "typescript")))) + (modify-json (delete-dependencies + `("@types/mocha" + "@types/node" + "mocha" + "ts-node" + "tslint" + "typescript"))))) (replace 'build (lambda* (#:key inputs #:allow-other-keys) (let ((esbuild (search-input-file inputs "/bin/esbuild"))) @@ -587,13 +591,14 @@ (define-public node-llparse-frontend-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("@types/debug" - "@types/mocha" - "@types/node" - "mocha" - "ts-node" - "tslint" - "typescript")))) + (modify-json (delete-dependencies + `("@types/debug" + "@types/mocha" + "@types/node" + "mocha" + "ts-node" + "tslint" + "typescript"))))) (replace 'build (lambda* (#:key inputs #:allow-other-keys) (let ((esbuild (search-input-file inputs "/bin/esbuild"))) @@ -648,15 +653,16 @@ (define-public node-llparse-bootstrap (modify-phases %standard-phases (add-after 'patch-dependencies 'delete-dependencies (lambda args - (delete-dependencies `("@types/debug" - "@types/mocha" - "@types/node" - "esm" - "llparse-test-fixture" - "mocha" - "ts-node" - "tslint" - "typescript")))) + (modify-json (delete-dependencies + `("@types/debug" + "@types/mocha" + "@types/node" + "esm" + "llparse-test-fixture" + "mocha" + "ts-node" + "tslint" + "typescript"))))) (replace 'build (lambda* (#:key inputs #:allow-other-keys) (let ((esbuild (search-input-file inputs "/bin/esbuild"))) diff --git a/guix/build/node-build-system.scm b/guix/build/node-build-system.scm index df7ea7774c..ea23d92a05 100644 --- a/guix/build/node-build-system.scm +++ b/guix/build/node-build-system.scm @@ -31,18 +31,14 @@ (define-module (guix build node-build-system) #:use-module (srfi srfi-1) #:use-module (srfi srfi-71) #:export (%standard-phases - with-atomic-json-file-replacement delete-dependencies - node-build)) - -(define* (with-atomic-json-file-replacement proc - #:optional (file "package.json")) - "Like 'with-atomic-file-replacement', but PROC is called with a single -argument---the result of parsing FILE's contents as json---and should a value -to be written as json to the replacement FILE." - (with-atomic-file-replacement file - (lambda (in out) - (scm->json (proc (json->scm in)) out)))) + delete-dev-dependencies + delete-fields + modify-json + modify-json-fields + node-build + replace-fields + with-atomic-json-file-replacement)) (define* (assoc-ref* alist key #:optional default) "Like assoc-ref, but return DEFAULT instead of #f if no value exists." @@ -72,6 +68,161 @@ (define* (alist-update alist key proc #:optional (= equal?)) (acons key (proc (cdr pair)) rest) alist))) +;;; +;;; package.json modification procedures +;;; + +(define* (with-atomic-json-file-replacement proc + #:optional (file "package.json")) + "Like 'with-atomic-file-replacement', but PROC is called with a single +argument---the result of parsing FILE's contents as json---and should a value +to be written as json to the replacement FILE." + (with-atomic-file-replacement file + (lambda (in out) + (scm->json (proc (json->scm in)) out)))) + +(define* (modify-json #:key (file "package.json") #:rest all-arguments) + "Provide package.json modifying callbacks such as (delete-dependencies ...)" + (let + ( + (modifications + (let loop ((arguments all-arguments)) + (cond + ((null? arguments) '()) + ((keyword? (car arguments)) (loop (cddr arguments))) + (else (cons (car arguments) (loop (cdr arguments)))))))) + (with-atomic-json-file-replacement + (lambda (package) + (fold + (lambda (modification package) + (modification package)) + package + modifications)) + file))) + +(define (delete-dependencies dependencies-to-remove) + "Rewrite 'package.json' to allow the build to proceed without packages +listed in 'dependencies-to-remove', a list of strings naming npm packages. + +To prevent the deleted dependencies from being reintroduced, use this function +only after the 'patch-dependencies' phase." + (lambda (pkg-meta) + (fold + (lambda (dependency-key pkg-meta) + (alist-update + pkg-meta + dependency-key + (lambda (dependencies) + (remove + (lambda (dependency) + (member (car dependency) dependencies-to-remove)) + dependencies)))) + pkg-meta + (list + "devDependencies" + "dependencies" + "peerDependencies" + "optionalDependencies")))) + +(define* (modify-json-fields + fields + field-modifier + #:key + (field-path-mapper (lambda (field) field)) + (insert? #f) + (strict? #t)) + "Provides a lambda to supply to modify-json which modifies the specified + json file. +- `fields` is a list procedure-specific data structures which should include + the definition of a `field-path` in one of two syntaxes: dot-syntax string + such as `\"devDependencies.esbuild\"`, or a list of strings such as + `(list \"devDependencies\" \"esbuild\")`. +- `field-modifier` is a lambda which is invoked at the position of the field. + It is supplied with the current field definition, the association list (alist) + at the field location in the json file, and the field name, also called `key`. +- `field-path-mapper` is a lambda which instructs where the field-path is + located within the field structure. +- `insert?` allows the creation of the field and any missing intermediate + fields. +- `strict?` causes an error to be thrown if the exact field-path is not found + in the data" + (lambda (package) + (fold + (lambda (field package) + (let* + ( + (field-path (field-path-mapper field)) + ( + field-path + (cond + ((string? field-path) + (string-split field-path #\.)) + ((and (list? field-path) (every string? field-path)) + field-path) + (else + (error + (string-append + "Invalid field value provided, expecting a string or a " + "list of string but instead got: " + (with-output-to-string (lambda _ (display field-path)))))) + ))) + (let loop + ( + (data package) + (field-path field-path)) + (let* + ( + (key (car field-path)) + (data + (if (and (not (assoc key data)) insert?) + (acons key '() data) + data))) + (if (not (assoc key data)) + (if strict? + (error (string-append + "Key '" key "' was not found in data: " + (with-output-to-string (lambda _ (display data))))) + data) + (if (= (length field-path) 1) + (field-modifier field data key) + (assoc-set! + data + key + (loop (assoc-ref data key) (cdr field-path))))))))) + package + fields))) + +(define* (delete-fields fields #:key (strict? #t)) + "Provides a lambda to supply to modify-json which deletes the specified + `fields` which is a list of field-paths as mentioned in `modify-json-fields`. + Examples: + (delete-fields '( + (\"path\" \"to\" \"field\") + \"path.to.other.field\"))" + (modify-json-fields + fields + (lambda (_ data key) + (assoc-remove! data key)) + #:strict? strict?)) + +(define* (replace-fields fields #:key (strict? #t)) + "Provides a lambda to supply to modify-json which replaces the value of the + supplied field. `fields` is a list of pairs, where the first element is the + field-path and the second element is the value to replace the target with. + Examples: + (replace-fields '( + ((\"path\" \"to\" \"field\") \"new field value\") + (\"path.to.other.field\" \"new field value\")))" + (modify-json-fields + fields + (lambda (field data key) + (assoc-set! data key (cdr field))) + #:field-path-mapper (lambda (field) (car field)) + #:strict? strict?)) + +(define (delete-dev-dependencies) + (delete-fields (list "devDependencies") #:strict #f)) + ;;; ;;; Phases. ;;; @@ -144,31 +295,6 @@ (define* (patch-dependencies #:key inputs #:allow-other-keys) (assoc-ref* pkg-meta "dependencies" '()))))))))) #t) -(define (delete-dependencies dependencies-to-remove) - "Rewrite 'package.json' to allow the build to proceed without packages -listed in 'dependencies-to-remove', a list of strings naming npm packages. - -To prevent the deleted dependencies from being reintroduced, use this function -only after the 'patch-dependencies' phase." - (with-atomic-json-file-replacement - (lambda (pkg-meta) - (fold - (lambda (dependency-key pkg-meta) - (alist-update - pkg-meta - dependency-key - (lambda (dependencies) - (remove - (lambda (dependency) - (member (car dependency) dependencies-to-remove)) - dependencies)))) - pkg-meta - (list - "devDependencies" - "dependencies" - "peerDependencies" - "optionalDependencies"))))) - (define* (delete-lockfiles #:key inputs #:allow-other-keys) "Delete 'package-lock.json', 'yarn.lock', and 'npm-shrinkwrap.json', if they exist." -- 2.46.0