projects/guix·blob javascript-team · refs

848 lines · 38.1 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2014 Cyrill Schenkel <[email protected]>
3;;; Copyright © 2015 Andreas Enge <[email protected]>
4;;; Copyright © 2015, 2016 David Thompson <[email protected]>
5;;; Copyright © 2016, 2021 Ludovic Courtès <[email protected]>
6;;; Copyright © 2017 Mike Gerwitz <[email protected]>
7;;; Copyright © 2018 Tobias Geerinckx-Rice <[email protected]>
8;;; Copyright © 2018-2022 Marius Bakke <[email protected]>
9;;; Copyright © 2020, 2021 Pierre Langlois <[email protected]>
10;;; Copyright © 2020, 2023 Ricardo Wurmus <[email protected]>
11;;; Copyright © 2021 Simon Tournier <[email protected]>
12;;; Copyright © 2021 Guillaume Le Vaillant <[email protected]>
13;;; Copyright © 2021, 2022 Philip McGrath <[email protected]>
14;;; Copyright © 2022 Hilton Chain <[email protected]>
15;;; Copyright © 2024 Efraim Flashner <[email protected]>
16;;; Copyright © 2024, 2025 Daniel Khodabakhsh <[email protected]>
17;;; Copyright © 2026 Maxim Cournoyer <[email protected]>
18;;;
19;;; This file is part of GNU Guix.
20;;;
21;;; GNU Guix is free software; you can redistribute it and/or modify it
22;;; under the terms of the GNU General Public License as published by
23;;; the Free Software Foundation; either version 3 of the License, or (at
24;;; your option) any later version.
25;;;
26;;; GNU Guix is distributed in the hope that it will be useful, but
27;;; WITHOUT ANY WARRANTY; without even the implied warranty of
28;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29;;; GNU General Public License for more details.
30;;;
31;;; You should have received a copy of the GNU General Public License
32;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
33
34(define-module (gnu packages node)
35 #:use-module (gnu packages base)
36 #:use-module (gnu packages bash)
37 #:use-module (gnu packages c)
38 #:use-module (gnu packages check)
39 #:use-module (gnu packages compression)
40 #:use-module (gnu packages cpp)
41 #:use-module (gnu packages dns)
42 #:use-module (gnu packages elf)
43 #:use-module (gnu packages gcc)
44 #:use-module (gnu packages guile)
45 #:use-module (gnu packages icu4c)
46 #:use-module (gnu packages javascript)
47 #:use-module (gnu packages libevent)
48 #:use-module (gnu packages libffi)
49 #:use-module (gnu packages linux)
50 #:use-module (gnu packages networking)
51 #:use-module (gnu packages perl)
52 #:use-module (gnu packages pkg-config)
53 #:use-module (gnu packages python)
54 #:use-module (gnu packages sqlite)
55 #:use-module (gnu packages time)
56 #:use-module (gnu packages tls)
57 #:use-module (gnu packages web)
58 #:use-module (gnu packages)
59 #:use-module ((guix build utils) #:select (alist-replace))
60 #:use-module (guix build-system gnu)
61 #:use-module (guix derivations)
62 #:use-module (guix download)
63 #:use-module (guix gexp)
64 #:use-module (guix git-download)
65 #:use-module (guix gexp)
66 #:autoload (guix http-client) (http-fetch/cached)
67 #:use-module ((guix licenses) #:prefix license:)
68 #:use-module (guix packages)
69 #:use-module (guix utils)
70 #:use-module (ice-9 match)
71 #:autoload (json parser) (json->scm)
72 #:use-module (srfi srfi-1)
73 #:use-module (srfi srfi-26)
74
75 #:export (latest-node-lts-version))
76
77;; Stripped-down build phases for JS packages. Uses esbuild + NODE_PATH instead
78;; of npm, so editing node-build-system does not rebuild node-lts. Set the
79;; ENTRYPOINT environment variable before the build phase to override the entry
80;; point auto-detected from package.json's "main" field, used when "main" points
81;; to compiled output but the TypeScript source is what esbuild should bundle.
82(define set-node-path-phase
83 #~(lambda* (#:key inputs native-inputs #:allow-other-keys)
84 (setenv "NODE_PATH"
85 (string-join
86 (delq #f
87 (map (lambda (input)
88 (let ((dir (string-append (cdr input) "/lib/node_modules")))
89 (and (file-exists? dir) dir)))
90 (append (or native-inputs '()) inputs)))
91 ":"))))
92
93(define (bootstrap-node-phases)
94 (with-extensions (list guile-json-4)
95 #~(begin
96 (use-modules (json))
97 (modify-phases %standard-phases
98 (replace 'configure #$set-node-path-phase)
99 (replace 'build
100 (lambda* (#:key inputs native-inputs #:allow-other-keys)
101 (let* ((all-inputs (append (or native-inputs '()) inputs))
102 (esbuild (search-input-file all-inputs "/bin/esbuild"))
103 (pkg (call-with-input-file "package.json" json->scm))
104 (entry (or (getenv "ENTRYPOINT")
105 (assoc-ref pkg "main")
106 "index.js")))
107 (invoke esbuild "--bundle" "--platform=node" "--format=cjs"
108 "--outfile=bundle.js" entry))))
109 (replace 'install
110 (lambda* (#:key outputs #:allow-other-keys)
111 (let* ((out (assoc-ref outputs "out"))
112 (pkg (call-with-input-file "package.json" json->scm))
113 (name (assoc-ref pkg "name"))
114 (dest (string-append out "/lib/node_modules/" name)))
115 (mkdir-p dest)
116 (call-with-output-file (string-append dest "/package.json")
117 (lambda (port)
118 (scm->json (assoc-set! pkg "main" "./index.js") port)))
119 (copy-file "bundle.js" (string-append dest "/index.js")))))))))
120
121(define-public node-semver-bootstrap
122 (package
123 (name "node-semver-bootstrap")
124 (version "7.2.1")
125 (source (origin
126 (method git-fetch)
127 (uri (git-reference
128 (url "https://github.com/npm/node-semver")
129 (commit (string-append "v" version))))
130 (file-name (git-file-name name version))
131 (sha256
132 (base32
133 "06biknqb05r9xsmcflm3ygh50pjvdk84x6r79w43kmck4fn3qn5p"))))
134 (build-system gnu-build-system)
135 (arguments
136 (list
137 #:tests? #f
138 #:phases (bootstrap-node-phases)))
139 (native-inputs (list esbuild))
140 (home-page "https://github.com/npm/node-semver")
141 (properties '((hidden? . #t)))
142 (synopsis "Parses semantic versions strings")
143 (description
144 "@code{node-semver} is a JavaScript implementation of the
145@uref{https://semver.org/, SemVer.org} specification.")
146 (license license:isc)))
147
148(define-public node-llparse-builder-bootstrap
149 ;; The binary-search package is vendored in 1351b75. It's not unvendored
150 ;; here because it's small, and as a bootstrap package doesn't bring
151 ;; deduplication to a profile.
152 (let ((commit "b04a70c8a3344adcfb8f5132528f7ae9852af79b")
153 (revision "1"))
154 (package
155 (name "node-llparse-builder-bootstrap")
156 (version (git-version "1.5.2" revision commit))
157 (source
158 (origin
159 (method git-fetch)
160 (uri (git-reference
161 (url "https://github.com/nodejs/llparse-builder.git")
162 (commit commit)))
163 (file-name (git-file-name name version))
164 (sha256
165 (base32 "08wsxyz7hhaf1n3jgvlnhhaaafq576wmpf4k4whihz012i4sxncg"))))
166 (build-system gnu-build-system)
167 (arguments
168 (list
169 #:tests? #f
170 #:phases
171 #~(modify-phases #$(bootstrap-node-phases)
172 (add-after 'unpack 'fix-imports-for-esbuild
173 ;; https://github.com/evanw/esbuild/issues/477
174 (lambda _
175 (substitute* '("src/node/invoke.ts"
176 "src/node/base.ts"
177 "src/node/consume.ts"
178 "src/node/match.ts"
179 "src/node/error.ts"
180 "src/node/pause.ts"
181 "src/edge.ts"
182 "src/utils.ts"
183 "src/loop-checker/index.ts"
184 "src/loop-checker/lattice.ts"
185 "src/code/field.ts"
186 "src/span-allocator.ts")
187 (("\\* as assert") "assert"))))
188 (add-before 'build 'set-entrypoint
189 (lambda _
190 (setenv "ENTRYPOINT" "src/builder.ts"))))))
191 (native-inputs
192 (list esbuild))
193 (home-page "https://github.com/nodejs/llparse-builder#readme")
194 (properties '((hidden? . #t)))
195 (synopsis "Graph builder for consumption by llparse")
196 (description "This package builds graphs for consumption by llparse.")
197 (license license:expat))))
198
199(define-public node-llparse-frontend-bootstrap
200 (package
201 (name "node-llparse-frontend-bootstrap")
202 (version "3.0.0")
203 (source
204 (origin
205 (method git-fetch)
206 (uri (git-reference
207 (url "https://github.com/nodejs/llparse-frontend.git")
208 (commit (string-append "v" version))))
209 (file-name (git-file-name name version))
210 (sha256
211 (base32 "1rm9g4ifyip30svm5cgnf0gx7d45jgh4mpf2hkd092xhngmfvicc"))))
212 (build-system gnu-build-system)
213 (arguments
214 (list
215 #:tests? #f
216 #:phases
217 #~(modify-phases #$(bootstrap-node-phases)
218 (add-after 'unpack 'fix-imports-for-esbuild
219 ;; https://github.com/evanw/esbuild/issues/477
220 (lambda _
221 (substitute* '("src/frontend.ts"
222 "src/code/field-value.ts"
223 "src/container/index.ts"
224 "src/container/wrap.ts"
225 "src/node/sequence.ts"
226 "src/node/single.ts"
227 "src/node/table-lookup.ts"
228 "src/trie/index.ts")
229 (("\\* as assert") "assert"))
230 ;; Drop debug dependency, see
231 ;; https://github.com/nodejs/llparse-frontend/pull/8
232 (substitute* "src/frontend.ts"
233 (("import \\* as debugAPI from 'debug';")
234 "import { debuglog } from 'node:util';")
235 (("debugAPI")
236 "debuglog"))))
237 (add-before 'build 'set-entrypoint
238 (lambda _
239 (setenv "ENTRYPOINT" "src/frontend.ts"))))))
240 (inputs
241 (list node-llparse-builder-bootstrap))
242 (native-inputs
243 (list esbuild))
244 (home-page "https://github.com/nodejs/llparse-frontend#readme")
245 (properties '((hidden? . #t)))
246 (synopsis "Frontend for the llparse compiler")
247 (description "This package is a frontend for the llparse compiler.")
248 (license license:expat)))
249
250(define-public node-llparse-bootstrap
251 (package
252 (name "node-llparse-bootstrap")
253 (version "7.3.1")
254 (source
255 (origin
256 (method git-fetch)
257 (uri (git-reference
258 (url "https://github.com/nodejs/llparse.git")
259 (commit (string-append "v" version))))
260 (file-name (git-file-name name version))
261 (sha256
262 (base32 "0srahcyqgnx2f2w0hwsayx7ihvqgll6a6bcwrsiyvccis4hccww2"))))
263 (build-system gnu-build-system)
264 (arguments
265 (list
266 #:tests? #f
267 #:phases
268 #~(modify-phases #$(bootstrap-node-phases)
269 (add-after 'unpack 'fix-imports-for-esbuild
270 ;; https://github.com/evanw/esbuild/issues/477
271 (lambda _
272 (substitute* '("src/compiler/index.ts"
273 "src/implementation/c/node/base.ts"
274 "src/implementation/c/node/table-lookup.ts"
275 "src/implementation/c/compilation.ts"
276 "src/implementation/c/helpers/match-sequence.ts"
277 "src/implementation/c/code/mul-add.ts")
278 (("\\* as assert") "assert"))
279 ;; Drop debug dependency, see
280 ;; https://github.com/nodejs/llparse/pull/87
281 (substitute* "src/compiler/index.ts"
282 (("import \\* as debugAPI from 'debug';")
283 "import { debuglog } from 'node:util';")
284 (("debugAPI")
285 "debuglog"))))
286 (add-before 'build 'set-entrypoint
287 (lambda _
288 (setenv "ENTRYPOINT" "src/api.ts"))))))
289 (inputs
290 (list node-llparse-frontend-bootstrap))
291 (native-inputs
292 (list esbuild))
293 (home-page "https://github.com/nodejs/llparse#readme")
294 (properties '((hidden? . #t)))
295 (synopsis "Compile incremental parsers to C code")
296 (description "This package offers an API for compiling an incremental
297parser definition into a C output.")
298 (license license:expat)))
299
300(define (latest-node-lts-version)
301 "Return the last Node.js LTS release version string, or #f."
302 (define release-index-url "https://nodejs.org/dist/index.json")
303 (define releases (vector->list
304 (call-with-port (http-fetch/cached release-index-url)
305 json->scm)))
306 (let ((version (and=> (find (lambda (release)
307 (assoc-ref release "lts"))
308 releases)
309 (cut assoc-ref <> "version"))))
310 (if (string-prefix? "v" version)
311 (string-drop version 1)
312 version)))
313
314;;; To find out if %current-node-lts-major-version needs to be updated, you
315;;; can use: (version-major (latest-node-lts-version))
316(define %current-node-lts-major-version "24")
317
318(define-public node-lts
319 (package
320 (name "node")
321 (version "24.21.0")
322 (source (origin
323 (method url-fetch)
324 (uri (string-append "https://nodejs.org/dist/v" version
325 "/node-v" version ".tar.xz"))
326 (sha256
327 (base32
328 "1z4lxmf5zh0mjzr63kqj2ybf1d79g0gdc4xs3ps88z7xnvplvxd6"))
329 (modules '((guix build utils)
330 (ice-9 ftw)
331 (srfi srfi-26)))
332 (snippet
333 #~(begin
334 ;; XXX: 'delete-all-but' is copied from the turbovnc package.
335 (define (delete-all-but directory . preserve)
336 (with-directory-excursion directory
337 (let* ((pred (negate (cut member <>
338 (cons* "." ".." preserve))))
339 (items (scandir "." pred)))
340 (for-each (cut delete-file-recursively <>) items))))
341
342 ;; the nodejs-openssl.cnf file is required by the build
343 ;; system.
344 (delete-all-but "deps/openssl" "nodejs-openssl.cnf")
345 (delete-all-but "deps"
346 "acorn"
347 "amaro"
348 "corepack" ;used by test suite
349 "inspector_protocol"
350 "minimatch"
351 "ncrypto"
352 "npm" ;used by test suite
353 "openssl"
354 "postject"
355 "undici"
356 "v8")
357 ;; TODO: Remove when the node-lts version becomes >= 25.
358 ;; <https://chromium-review.googlesource.com/c/v8/v8/+/6830052>
359 (substitute*
360 "deps/v8/src/compiler/turboshaft/int64-lowering-reducer.h"
361 (("__ Tuple<Word32, Word32>")
362 "__ template Tuple<Word32, Word32>"))))))
363 (build-system gnu-build-system)
364 (arguments
365 (list
366 #:configure-flags
367 ;; Search for 'shared_optgroup.add_argument' in
368 ;; configure.py to find the relevant options.
369 #~(list "--shared"
370 "--shared-ada"
371 "--shared-brotli"
372 "--shared-cares"
373 "--shared-gtest"
374 "--shared-hdr-histogram"
375 "--shared-http-parser"
376 "--shared-http-parser-libname=llhttp"
377 "--shared-libuv"
378 "--shared-merve"
379 "--shared-nbytes"
380 "--shared-nghttp2"
381 "--shared-nghttp3"
382 "--shared-ngtcp2"
383 "--shared-openssl"
384 "--shared-simdjson"
385 "--shared-simdutf"
386 "--shared-sqlite"
387 "--shared-uvwasi"
388 "--shared-zlib"
389 "--shared-zstd"
390 ;; Needed for correct snapshot checksums.
391 "--v8-enable-snapshot-compression"
392 "--with-intl=system-icu")
393 #:make-flags #~(list "V=1") ;to see build commands
394 #:test-target "test-ci-js"
395 #:modules `(,@%default-gnu-modules
396 (srfi srfi-1)
397 (ice-9 format)
398 (ice-9 match))
399 #:phases
400 #~(modify-phases %standard-phases
401 (add-before 'configure 'patch-hardcoded-program-references
402 (lambda* (#:key inputs #:allow-other-keys)
403 ;; Fix hardcoded /bin/sh references.
404 (substitute* '("lib/child_process.js"
405 "lib/internal/v8_prof_polyfill.js"
406 "test/parallel/test-child-process-spawnsync-shell.js"
407 "test/parallel/test-stdio-closed.js"
408 "test/sequential/test-child-process-emfile.js"
409 "test/parallel/test-fs-write-sigxfsz.js"
410 "test/parallel/test-stdin-from-file-spawn.js")
411 (("'/bin/sh'")
412 (string-append "'" (search-input-file inputs "/bin/sh") "'")))
413 ;; Fix hardcoded /usr/bin/env references.
414 (substitute* '("test/parallel/test-child-process-default-options.js"
415 "test/parallel/test-child-process-env.js"
416 "test/parallel/test-child-process-exec-env.js")
417 (("'/usr/bin/env'")
418 (string-append "'" (search-input-file inputs "/bin/env") "'")))))
419 (add-after 'patch-hardcoded-program-references 'delete-problematic-tests
420 (lambda* (#:key inputs #:allow-other-keys)
421 ;; FIXME: These tests fail in the build container, but they don't
422 ;; seem to be indicative of real problems in practice.
423 (for-each delete-file
424 '("test/parallel/test-cluster-primary-error.js"
425 "test/parallel/test-cluster-primary-kill.js"
426 "test/parallel/test-node-run.js"))
427 ;; These require a DNS resolver.
428 (for-each delete-file
429 '("test/parallel/test-dns.js"
430 "test/parallel/test-dns-lookupService-promises.js"
431 "test/parallel/test-net-socket-connect-without-cb.js"
432 "test/parallel/test-tcp-wrap-listen.js"
433 "test/report/test-report-exclude-network.js"))
434 ;; These tests require networking.
435 (for-each delete-file
436 '("test/parallel/test-https-agent-unref-socket.js"))
437 ;; These tests are timing-sensitive, and fail sporadically on
438 ;; slow, busy, or even very fast machines.
439 (for-each delete-file
440 '("test/parallel/test-fs-utimes.js"))
441 ;; FIXME: This test fails randomly:
442 ;; https://github.com/nodejs/node/issues/31213
443 (delete-file "test/parallel/test-net-listen-after-destroying-stdin.js")
444 ;; FIXME: These tests fail on armhf-linux:
445 ;; https://github.com/nodejs/node/issues/31970
446 #$@(if (target-arm32?)
447 '((for-each delete-file
448 '("test/parallel/test-zlib.js"
449 "test/parallel/test-zlib-brotli.js"
450 "test/parallel/test-zlib-brotli-flush.js"
451 "test/parallel/test-zlib-brotli-from-brotli.js"
452 "test/parallel/test-zlib-brotli-from-string.js"
453 "test/parallel/test-zlib-convenience-methods.js"
454 "test/parallel/test-zlib-random-byte-pipes.js"
455 "test/parallel/test-zlib-write-after-flush.js")))
456 '())
457 ;; https://github.com/nodejs/node/issues/45906
458 ;; This test depends on 64-bit time_t so skipping on 32-bit systems.
459 #$@(if (target-32bit?)
460 '((delete-file "test/parallel/test-fs-utimes-y2K38.js")
461 (delete-file "test/parallel/test-debugger-heap-profiler.js"))
462 '())
463 ;; These tests have an expiry date: they depend on the validity of
464 ;; TLS certificates that are bundled with the source. We want this
465 ;; package to be reproducible forever, so remove those.
466 ;; TODO: Regenerate certs instead.
467 (for-each delete-file
468 '("test/parallel/test-tls-passphrase.js"
469 "test/parallel/test-tls-server-verify.js"))
470 ;; These tests fail when linking to upstream libuv.
471 ;; https://github.com/nodejs/node/commit/3f6addd590
472 (for-each delete-file
473 '("test/parallel/test-process-euid-egid.js"
474 "test/parallel/test-process-initgroups.js"
475 "test/parallel/test-process-setgroups.js"
476 "test/parallel/test-process-uid-gid.js"))))
477 (add-after 'delete-problematic-tests 'patch-problematic-tests
478 (lambda _
479 ;; TODO: These tests seem to not work by default, but seem fixed now online
480 (substitute*
481 '("test/parallel/test-http2-premature-close.js"
482 "test/parallel/test-http2-invalid-last-stream-id.js")
483 (("client\\.connect\\(address\\)")
484 "client.connect(address.port)"))))
485 (add-before 'configure 'set-bootstrap-host-rpath
486 (lambda* (#:key native-inputs #:allow-other-keys)
487 (when native-inputs
488 (let* ((safe-lookup (lambda (label)
489 (or (assoc-ref native-inputs label)
490 (error "could not find native input"
491 label))))
492 (host-inputs (map safe-lookup
493 '("brotli"
494 "c-ares"
495 "cpp-ada-url-parser"
496 "googletest"
497 "hdrhistogram-c"
498 "icu4c"
499 "libuv"
500 "llhttpish"
501 "merve"
502 "nbytes"
503 "nghttp2"
504 "nghttp3"
505 "ngtcp2"
506 "openssl"
507 "simdjson"
508 "simdutf"
509 "sqlite"
510 "uvwasi"
511 "zlib"
512 "zstd")))
513 (host-binaries '("torque"
514 "bytecode_builtins_list_generator"
515 "gen-regexp-special-case"
516 "node_mksnapshot"
517 "mksnapshot"
518 "node_js2c")))
519 (substitute* '("node.gyp" "tools/v8_gypfiles/v8.gyp")
520 (((string-append "'target_name': '("
521 (string-join host-binaries "|")
522 ")',")
523 target)
524 (format #f "~a 'ldflags': ['-Wl,-rpath=~{~a/lib~^:~}'],"
525 target host-inputs)))))))
526 (replace 'configure
527 ;; Node's configure script is actually a python script, so we can't
528 ;; run it with bash.
529 (lambda* (#:key configure-flags #:allow-other-keys)
530 (let* ((xflags #$(if (%current-target-system)
531 `'("--cross-compiling"
532 ,(string-append
533 "--dest-cpu="
534 (match (%current-target-system)
535 ((? (cut string-prefix? "arm" <>))
536 "arm")
537 ((? (cut string-prefix? "aarch64" <>))
538 "arm64")
539 ((? (cut string-prefix? "i686" <>))
540 "ia32")
541 ((? (cut string-prefix? "x86_64" <>))
542 "x64")
543 ((? (cut string-prefix? "powerpc64" <>))
544 "ppc64")
545 ((? (cut string-prefix? "riscv64" <>))
546 "riscv64")
547 (_ "unsupported"))))
548 ''()))
549 (flags (cons (string-append "--prefix=" #$output)
550 (append xflags configure-flags))))
551 (format #t "build directory: ~s~%" (getcwd))
552 (format #t "configure flags: ~s~%" flags)
553 ;; Node's configure script expects the CC environment variable to
554 ;; be set.
555 (setenv "CC_host" "gcc")
556 (setenv "CXX_host" "g++")
557 (setenv "CC" #$(cc-for-target))
558 (setenv "CXX" #$(cxx-for-target))
559 (setenv "PKG_CONFIG" #$(pkg-config-for-target))
560 (apply invoke "python3" "configure" flags))))
561 (add-after 'patch-shebangs 'patch-nested-shebangs
562 (lambda* (#:key inputs outputs #:allow-other-keys)
563 ;; Based on the implementation of patch-shebangs
564 ;; from (guix build gnu-build-system).
565 (let ((path (append-map (match-lambda
566 ((_ . dir)
567 (list (string-append dir "/bin")
568 (string-append dir "/sbin")
569 (string-append dir "/libexec"))))
570 (append outputs inputs))))
571 (for-each
572 (lambda (file)
573 (patch-shebang file path))
574 (find-files (search-input-directory outputs "lib/node_modules")
575 (lambda (file stat)
576 (executable-file? file))
577 #:stat lstat)))))
578 (add-after 'patch-nested-shebangs 'do-not-capture-python
579 (lambda _
580 ;; patch-shebangs embeds the Python store path into node-gyp's
581 ;; Python scripts, pulling Python into node's closure. Revert
582 ;; to /usr/bin/env python3 so downstream gyp builds supply
583 ;; their own Python.
584 (let ((node-gyp (string-append #$output
585 "/lib/node_modules/npm"
586 "/node_modules/node-gyp")))
587 (for-each
588 (lambda (f)
589 (substitute* f
590 (("^#!.*/bin/python3") "#!/usr/bin/env python3")))
591 (find-files node-gyp "\\.py$")))))
592 ;; npm installs dependencies by copying their files over a tar
593 ;; stream. A file with more than one hardlink is marked as a
594 ;; "Link". pacote/lib/fetcher.js calls node-tar's extractor with a
595 ;; filter that ignores any "Link" entries. This means that
596 ;; dependending on the number of hardlinks on files in a node-*
597 ;; package *some* of its files may not be installed when generating
598 ;; another package's "node_modules" directory. The build output
599 ;; would differ depending on irrelevant file system state.
600 ;;
601 ;; To avoid this, we patch node-tar to treat files with hardlinks
602 ;; the same as any other file, so that node-tar has no choice but
603 ;; to extract all of them --- independent of pacote's filter.
604 ;;
605 ;; Why not patch pacote's filter instead? This has led to subtle
606 ;; differences in where the files are installed, so it's easier to
607 ;; just ensure that files with hardlinks are always treated as
608 ;; regular files.
609 ;;
610 ;; Discussion:
611 ;; https://lists.gnu.org/archive/html/guix-devel/2023-07/msg00040.html
612 ;; Upstream bug report:
613 ;; https://github.com/npm/pacote/issues/285
614 (add-after 'install 'ignore-number-of-hardlinks
615 (lambda _
616 (let ((dir (string-append #$output
617 "/lib/node_modules/npm/node_modules"
618 "/tar/dist")))
619 (substitute*
620 (list (string-append dir "/esm/write-entry.js")
621 (string-append dir "/commonjs/write-entry.js"))
622 (("this.stat.nlink > 1") "false")))))
623 (add-after 'install 'fix-node-gyp-reference
624 ;; Note: programs like node-gyp only receive these values if
625 ;; they are started via `npm` or `npx`.
626 ;; See: https://github.com/nodejs/node-gyp#npm-configuration
627 (lambda* (#:key inputs outputs #:allow-other-keys)
628 (for-each
629 (lambda (command)
630 (wrap-program (search-input-file outputs command)
631 `("npm_package_config_node_gyp_nodedir" = (,#$output))))
632 '("bin/npm"
633 "bin/npx")))))))
634 (native-inputs
635 (list
636 ;; Runtime dependencies for binaries used as a bootstrap.
637 brotli
638 c-ares-for-node-lts
639 cpp-ada-url-parser
640 googletest
641 hdrhistogram-c
642 icu4c-78
643 libuv-for-node-lts
644 llhttpish
645 merve
646 nbytes
647 `(,nghttp2-for-node-lts "lib")
648 nghttp3
649 ngtcp2
650 openssl
651 simdjson
652 simdutf
653 sqlite-next
654 uvwasi-for-node-lts
655 zlib
656 `(,zstd "lib")
657 ;; Regular build-time dependencies.
658 perl
659 pkg-config
660 procps
661 python
662 util-linux))
663 (inputs
664 (list bash-minimal
665 brotli
666 c-ares-for-node-lts
667 coreutils-minimal
668 cpp-ada-url-parser
669 googletest
670 hdrhistogram-c
671 icu4c-78
672 libuv-for-node-lts
673 llhttpish
674 merve
675 nbytes
676 `(,nghttp2-for-node-lts "lib")
677 nghttp3
678 ngtcp2
679 openssl
680 simdjson
681 simdutf
682 sqlite-next
683 uvwasi-for-node-lts
684 zlib
685 `(,zstd "lib")))
686 (native-search-paths
687 (list (search-path-specification
688 (variable "NODE_PATH")
689 (files '("lib/node_modules")))))
690 (synopsis "Evented I/O for V8 JavaScript")
691 (description
692 "Node.js is a platform built on Chrome's JavaScript runtime
693for easily building fast, scalable network applications. Node.js uses an
694event-driven, non-blocking I/O model that makes it lightweight and efficient,
695perfect for data-intensive real-time applications that run across distributed
696devices.")
697 (supported-systems (fold delete %supported-systems '("powerpc-linux")))
698 (home-page "https://nodejs.org/")
699 (license license:expat)
700 (properties `((max-silent-time . 7200) ;2h, needed on ARM
701 (timeout . 21600) ;6h
702 (cpe-name . "node.js")
703 (release-monitoring-url
704 . ,(format #f "https://nodejs.org/dist/latest-v~a.x/"
705 %current-node-lts-major-version))))))
706
707(define-public node-latest
708 (package
709 (inherit node-lts)
710 (version "26.10.0")
711 (source (origin
712 (inherit (package-source node-lts))
713 (uri (string-append "https://nodejs.org/dist/v" version
714 "/node-v" version ".tar.xz"))
715 (sha256
716 (base32
717 "1i90pbq6cgh3430y9rjkqpzxapsxpvh5fynx7fj1aznb6dnm8fkv"))
718 (patches (search-patches "node-latest-i686.patch"
719 "node-latest-lief-1.0.0.patch"))))
720 (arguments
721 (substitute-keyword-arguments arguments
722 ((#:configure-flags flags ''())
723 #~(cons* "--shared-ffi"
724 "--shared-lief"
725 #$@(if (this-package-input "temporal-capi")
726 #~("--shared-temporal_capi")
727 #~("--v8-disable-temporal-support"))
728 #$flags))
729 ((#:phases phases '%standard-phases)
730 #~(modify-phases #$phases
731 (add-before 'configure 'set-bootstrap-host-rpath
732 (lambda* (#:key native-inputs #:allow-other-keys)
733 (when native-inputs
734 (let* ((safe-lookup (lambda (label)
735 (or (assoc-ref native-inputs label)
736 (error "could not find native input"
737 label))))
738 (host-inputs (map safe-lookup
739 '("brotli"
740 "c-ares"
741 "cpp-ada-url-parser"
742 "googletest"
743 "hdrhistogram-c"
744 "icu4c"
745 "libffi"
746 "libuv"
747 "lief"
748 "llhttpish"
749 "merve"
750 "nbytes"
751 "nghttp2"
752 "nghttp3"
753 "ngtcp2"
754 "openssl"
755 "simdjson"
756 "simdutf"
757 "sqlite"
758 "temporal-capi"
759 "uvwasi"
760 "zlib"
761 "zstd")))
762 (host-binaries '("torque"
763 "bytecode_builtins_list_generator"
764 "gen-regexp-special-case"
765 "node_mksnapshot"
766 "mksnapshot"
767 "node_js2c")))
768 (substitute* '("node.gyp" "tools/v8_gypfiles/v8.gyp")
769 (((string-append "'target_name': '("
770 (string-join host-binaries "|")
771 ")',")
772 target)
773 (format #f "~a 'ldflags': ['-Wl,-rpath=~{~a/lib~^:~}'],"
774 target host-inputs)))))))))))
775 (native-inputs
776 (append (if (supported-package? temporal-capi)
777 (list `("temporal-capi" ,temporal-capi))
778 '())
779 (modify-inputs native-inputs
780 (append libffi-next lief))))
781 (inputs
782 (append (if (supported-package? temporal-capi)
783 (list `("temporal-capi" ,temporal-capi))
784 '())
785 (modify-inputs inputs
786 (append libffi-next lief))))
787 (properties (alist-delete 'release-monitoring-url
788 (package-properties node-lts)))))
789
790(define-public node node-lts)
791
792(define-deprecated-package libnode node-lts)
793
794(define-public llhttpish
795 (package
796 (name "llhttpish")
797 (version "9.4.3")
798 (source (origin
799 (method url-fetch)
800 (uri (string-append "https://codeberg.org/jlicht/llhttpish/releases/download/v" version
801 "/llhttpish-" version ".tgz"))
802 (sha256
803 (base32
804 "19zw4issqjhyfvwi7q39zvjhfmx1cq1kf887zp3sv7g7agyvczr8"))))
805 (build-system gnu-build-system)
806 (arguments
807 (list
808 #:tests? #f ; no tests
809 #:make-flags
810 #~(list (string-append "CLANG=" #$(cc-for-target))
811 (string-append "DESTDIR=" #$output)
812 "PREFIX=")
813 #:phases
814 #~(modify-phases %standard-phases
815 (replace 'configure #$set-node-path-phase)
816 (add-after 'install 'install-pkg-config-file
817 (lambda _
818 ;; This is an issue upstream (in llhttp) when using the
819 ;; Make-based build system (see:
820 ;; <https://github.com/nodejs/llhttp/issues/883>).
821 (let ((dest (string-append #$output "/lib/pkgconfig")))
822 (mkdir-p dest)
823 (with-directory-excursion dest
824 (call-with-output-file "libllhttp.pc"
825 (lambda (port)
826 (format port "\
827prefix=~a
828exec_prefix=${prefix}
829libdir=${exec_prefix}/lib
830includedir=${prefix}/include
831
832Name: libllhttp
833Description: Node.js llhttp Library
834Version: ~a
835Libs: -L${libdir} -lllhttp
836Cflags: -I${includedir}~%" #$output #$version))))))))))
837 (native-inputs
838 (list esbuild
839 quickjs
840 node-llparse-bootstrap
841 node-semver-bootstrap))
842 (home-page "https://codeberg.org/jlicht/llhttpish")
843 (synopsis "Parser for HTTP messages")
844 (description "This is a soft fork of a rewrite of
845@url{https://github.com/nodejs/http-parser, http-parser} using
846@url{https://github.com/nodejs/llparse, llparse} to generate the C source
847files.")
848 (license license:expat)))