From 0c9a3916186398a732aca2aeb1dcc5ffaa05bd5a Mon Sep 17 00:00:00 2001 From: imxyy_soope_ Date: Thu, 12 Mar 2026 17:47:46 +0800 Subject: [PATCH] clean up --- .lazy.lua | 3 - Cargo.lock | 1078 +-------- Cargo.toml | 3 +- {nix-js => fix}/Cargo.toml | 31 +- {nix-js => fix}/benches/basic_ops.rs | 0 {nix-js => fix}/benches/builtins.rs | 0 {nix-js => fix}/benches/thunk_scope.rs | 0 {nix-js => fix}/benches/utils.rs | 13 +- {nix-js => fix}/src/bytecode.rs | 146 +- {nix-js => fix}/src/context.rs | 271 +-- {nix-js => fix}/src/derivation.rs | 0 {nix-js => fix}/src/disassembler.rs | 0 {nix-js => fix}/src/downgrade.rs | 0 {nix-js => fix}/src/error.rs | 129 -- {nix-js => fix}/src/fetcher.rs | 11 - {nix-js => fix}/src/fetcher/archive.rs | 0 {nix-js => fix}/src/fetcher/cache.rs | 2 +- {nix-js => fix}/src/fetcher/download.rs | 0 {nix-js => fix}/src/fetcher/git.rs | 0 {nix-js => fix}/src/fetcher/metadata_cache.rs | 0 {nix-js => fix}/src/ir.rs | 0 {nix-js => fix}/src/lib.rs | 3 +- {nix-js => fix}/src/logging.rs | 0 {nix-js => fix}/src/main.rs | 44 +- {nix-js => fix}/src/nar.rs | 0 {nix-js => fix}/src/nix_utils.rs | 0 .../eval-okay-hash.exp => fix/src/runtime.rs | 0 .../src/runtime/corepkgs/derivation.nix | 0 .../src/runtime/corepkgs/fetchurl.nix | 0 {nix-js => fix}/src/store.rs | 0 {nix-js => fix}/src/store/config.rs | 0 {nix-js => fix}/src/store/daemon.rs | 0 {nix-js => fix}/src/store/error.rs | 0 {nix-js => fix}/src/store/validation.rs | 0 {nix-js => fix}/src/string_context.rs | 0 {nix-js => fix}/src/value.rs | 0 {nix-js => fix}/tests/tests/basic_eval.rs | 2 +- {nix-js => fix}/tests/tests/builtins.rs | 2 +- {nix-js => fix}/tests/tests/builtins_store.rs | 2 +- {nix-js => fix}/tests/tests/derivation.rs | 2 +- {nix-js => fix}/tests/tests/findfile.rs | 0 {nix-js => fix}/tests/tests/free_globals.rs | 2 +- {nix-js => fix}/tests/tests/functions.rs | 2 +- {nix-js => fix}/tests/tests/io_operations.rs | 6 +- {nix-js => fix}/tests/tests/lang.rs | 8 +- {nix-js => fix}/tests/tests/lang/binary-data | Bin {nix-js => fix}/tests/tests/lang/data | 0 {nix-js => fix}/tests/tests/lang/dir1/a.nix | 0 {nix-js => fix}/tests/tests/lang/dir2/a.nix | 0 {nix-js => fix}/tests/tests/lang/dir2/b.nix | 0 {nix-js => fix}/tests/tests/lang/dir3/a.nix | 0 {nix-js => fix}/tests/tests/lang/dir3/b.nix | 0 {nix-js => fix}/tests/tests/lang/dir3/c.nix | 0 {nix-js => fix}/tests/tests/lang/dir4/a.nix | 0 {nix-js => fix}/tests/tests/lang/dir4/c.nix | 0 .../tests/tests/lang/eval-fail-abort.err.exp | 0 .../tests/tests/lang/eval-fail-abort.nix | 0 ...rvOutputDependencies-empty-context.err.exp | 0 ...addDrvOutputDependencies-empty-context.nix | 0 ...putDependencies-multi-elem-context.err.exp | 0 ...vOutputDependencies-multi-elem-context.nix | 0 ...putDependencies-wrong-element-kind.err.exp | 0 ...vOutputDependencies-wrong-element-kind.nix | 0 .../eval-fail-addErrorContext-example.err.exp | 0 .../eval-fail-addErrorContext-example.nix | 0 ...al-fail-assert-equal-attrs-names-2.err.exp | 0 .../eval-fail-assert-equal-attrs-names-2.nix | 0 ...eval-fail-assert-equal-attrs-names.err.exp | 0 .../eval-fail-assert-equal-attrs-names.nix | 0 ...ail-assert-equal-derivations-extra.err.exp | 0 ...al-fail-assert-equal-derivations-extra.nix | 0 ...eval-fail-assert-equal-derivations.err.exp | 0 .../eval-fail-assert-equal-derivations.nix | 0 .../eval-fail-assert-equal-floats.err.exp | 0 .../lang/eval-fail-assert-equal-floats.nix | 0 ...-fail-assert-equal-function-direct.err.exp | 0 ...eval-fail-assert-equal-function-direct.nix | 0 .../eval-fail-assert-equal-int-float.err.exp | 0 .../lang/eval-fail-assert-equal-int-float.nix | 0 .../lang/eval-fail-assert-equal-ints.err.exp | 0 .../lang/eval-fail-assert-equal-ints.nix | 0 ...eval-fail-assert-equal-list-length.err.exp | 0 .../eval-fail-assert-equal-list-length.nix | 0 .../lang/eval-fail-assert-equal-paths.err.exp | 0 .../lang/eval-fail-assert-equal-paths.nix | 0 ...eval-fail-assert-equal-type-nested.err.exp | 0 .../eval-fail-assert-equal-type-nested.nix | 0 .../lang/eval-fail-assert-equal-type.err.exp | 0 .../lang/eval-fail-assert-equal-type.nix | 0 .../lang/eval-fail-assert-nested-bool.err.exp | 0 .../lang/eval-fail-assert-nested-bool.nix | 0 .../tests/tests/lang/eval-fail-assert.err.exp | 0 .../tests/tests/lang/eval-fail-assert.nix | 0 .../lang/eval-fail-attr-name-type.err.exp | 0 .../tests/lang/eval-fail-attr-name-type.nix | 0 ...fail-attrset-merge-drops-later-rec.err.exp | 0 ...val-fail-attrset-merge-drops-later-rec.nix | 0 ...al-fail-bad-string-interpolation-1.err.exp | 0 .../eval-fail-bad-string-interpolation-1.nix | 0 ...al-fail-bad-string-interpolation-2.err.exp | 0 .../eval-fail-bad-string-interpolation-2.nix | 0 ...al-fail-bad-string-interpolation-3.err.exp | 0 .../eval-fail-bad-string-interpolation-3.nix | 0 ...al-fail-bad-string-interpolation-4.err.exp | 0 .../eval-fail-bad-string-interpolation-4.nix | 0 .../tests/lang/eval-fail-blackhole.err.exp | 0 .../tests/tests/lang/eval-fail-blackhole.nix | 0 .../tests/lang/eval-fail-call-primop.err.exp | 0 .../tests/lang/eval-fail-call-primop.nix | 0 .../tests/lang/eval-fail-deepseq.err.exp | 0 .../tests/tests/lang/eval-fail-deepseq.nix | 0 .../lang/eval-fail-derivation-name.err.exp | 0 .../tests/lang/eval-fail-derivation-name.nix | 0 .../lang/eval-fail-dup-dynamic-attrs.err.exp | 0 .../lang/eval-fail-dup-dynamic-attrs.nix | 0 .../lang/eval-fail-duplicate-traces.err.exp | 0 .../tests/lang/eval-fail-duplicate-traces.nix | 0 .../tests/tests/lang/eval-fail-eol-1.err.exp | 0 .../tests/tests/lang/eval-fail-eol-1.nix | 0 .../tests/tests/lang/eval-fail-eol-2.err.exp | 0 .../tests/tests/lang/eval-fail-eol-2.nix | 0 .../tests/tests/lang/eval-fail-eol-3.err.exp | 0 .../tests/tests/lang/eval-fail-eol-3.nix | 0 .../lang/eval-fail-fetchTree-negative.err.exp | 0 .../lang/eval-fail-fetchTree-negative.nix | 0 ...-fail-fetchurl-baseName-attrs-name.err.exp | 0 ...eval-fail-fetchurl-baseName-attrs-name.nix | 0 .../eval-fail-fetchurl-baseName-attrs.err.exp | 0 .../eval-fail-fetchurl-baseName-attrs.nix | 0 .../lang/eval-fail-fetchurl-baseName.err.exp | 0 .../lang/eval-fail-fetchurl-baseName.nix | 0 ...ake-ref-to-string-negative-integer.err.exp | 0 ...l-flake-ref-to-string-negative-integer.nix | 0 ...-foldlStrict-strict-op-application.err.exp | 0 ...fail-foldlStrict-strict-op-application.nix | 0 ...eval-fail-fromJSON-keyWithNullByte.err.exp | 0 .../eval-fail-fromJSON-keyWithNullByte.nix | 0 .../eval-fail-fromJSON-overflowing.err.exp | 0 .../lang/eval-fail-fromJSON-overflowing.nix | 0 ...al-fail-fromJSON-valueWithNullByte.err.exp | 0 .../eval-fail-fromJSON-valueWithNullByte.nix | 0 ...eval-fail-fromTOML-keyWithNullByte.err.exp | 0 .../eval-fail-fromTOML-keyWithNullByte.nix | 0 .../eval-fail-fromTOML-timestamps.err.exp | 0 .../lang/eval-fail-fromTOML-timestamps.nix | 0 ...al-fail-fromTOML-valueWithNullByte.err.exp | 0 .../eval-fail-fromTOML-valueWithNullByte.nix | 0 .../lang/eval-fail-hashfile-missing.err.exp | 0 .../tests/lang/eval-fail-hashfile-missing.nix | 0 ...val-fail-infinite-recursion-lambda.err.exp | 0 .../eval-fail-infinite-recursion-lambda.nix | 0 .../tests/tests/lang/eval-fail-list.err.exp | 0 .../tests/tests/lang/eval-fail-list.nix | 0 .../tests/lang/eval-fail-missing-arg.err.exp | 0 .../tests/lang/eval-fail-missing-arg.nix | 0 .../lang/eval-fail-mutual-recursion.err.exp | 0 .../tests/lang/eval-fail-mutual-recursion.nix | 0 .../lang/eval-fail-nested-list-items.err.exp | 0 .../lang/eval-fail-nested-list-items.nix | 0 .../lang/eval-fail-nonexist-path.err.exp | 0 .../tests/lang/eval-fail-nonexist-path.nix | 0 .../tests/lang/eval-fail-not-throws.err.exp | 0 .../tests/tests/lang/eval-fail-not-throws.nix | 0 .../lang/eval-fail-overflowing-add.err.exp | 0 .../tests/lang/eval-fail-overflowing-add.nix | 0 .../lang/eval-fail-overflowing-div.err.exp | 0 .../tests/lang/eval-fail-overflowing-div.nix | 0 .../lang/eval-fail-overflowing-mul.err.exp | 0 .../tests/lang/eval-fail-overflowing-mul.nix | 0 .../lang/eval-fail-overflowing-sub.err.exp | 0 .../tests/lang/eval-fail-overflowing-sub.nix | 0 .../tests/lang/eval-fail-path-slash.err.exp | 0 .../tests/tests/lang/eval-fail-path-slash.nix | 0 .../lang/eval-fail-pipe-operators.err.exp | 0 .../tests/lang/eval-fail-pipe-operators.nix | 0 .../tests/lang/eval-fail-recursion.err.exp | 0 .../tests/tests/lang/eval-fail-recursion.nix | 0 .../tests/tests/lang/eval-fail-remove.err.exp | 0 .../tests/tests/lang/eval-fail-remove.nix | 0 .../tests/lang/eval-fail-scope-5.err.exp | 0 .../tests/tests/lang/eval-fail-scope-5.nix | 0 .../tests/tests/lang/eval-fail-seq.err.exp | 0 .../tests/tests/lang/eval-fail-seq.nix | 0 .../tests/lang/eval-fail-set-override.err.exp | 0 .../tests/lang/eval-fail-set-override.nix | 0 .../tests/tests/lang/eval-fail-set.err.exp | 0 .../tests/tests/lang/eval-fail-set.nix | 0 .../tests/lang/eval-fail-string-nul-1.err.exp | Bin .../tests/lang/eval-fail-string-nul-1.nix | Bin .../tests/lang/eval-fail-string-nul-2.err.exp | Bin .../tests/lang/eval-fail-string-nul-2.nix | Bin .../tests/lang/eval-fail-substring.err.exp | 0 .../tests/tests/lang/eval-fail-substring.nix | 0 .../tests/lang/eval-fail-to-path.err.exp | 0 .../tests/tests/lang/eval-fail-to-path.nix | 0 .../lang/eval-fail-toJSON-non-utf-8.err.exp | 0 .../tests/lang/eval-fail-toJSON-non-utf-8.nix | 0 .../tests/tests/lang/eval-fail-toJSON.err.exp | 0 .../tests/tests/lang/eval-fail-toJSON.nix | 0 .../lang/eval-fail-undeclared-arg.err.exp | 0 .../tests/lang/eval-fail-undeclared-arg.nix | 0 .../eval-fail-using-set-as-attr-name.err.exp | 0 .../lang/eval-fail-using-set-as-attr-name.nix | 0 .../tests/tests/lang/eval-okay-any-all.exp | 0 .../tests/tests/lang/eval-okay-any-all.nix | 0 .../tests/tests/lang/eval-okay-arithmetic.exp | 0 .../tests/tests/lang/eval-okay-arithmetic.nix | 0 .../tests/tests/lang/eval-okay-attrnames.exp | 0 .../tests/tests/lang/eval-okay-attrnames.nix | 0 .../tests/tests/lang/eval-okay-attrs.exp | 0 .../tests/tests/lang/eval-okay-attrs.nix | 0 .../tests/tests/lang/eval-okay-attrs2.exp | 0 .../tests/tests/lang/eval-okay-attrs2.nix | 0 .../tests/tests/lang/eval-okay-attrs3.exp | 0 .../tests/tests/lang/eval-okay-attrs3.nix | 0 .../tests/tests/lang/eval-okay-attrs4.exp | 0 .../tests/tests/lang/eval-okay-attrs4.nix | 0 .../tests/tests/lang/eval-okay-attrs5.exp | 0 .../tests/tests/lang/eval-okay-attrs5.nix | 0 .../tests/tests/lang/eval-okay-attrs6.exp | 0 .../tests/tests/lang/eval-okay-attrs6.nix | 0 .../tests/tests/lang/eval-okay-autoargs.exp | 0 .../tests/tests/lang/eval-okay-autoargs.nix | 0 .../lang/eval-okay-backslash-newline-1.exp | 0 .../lang/eval-okay-backslash-newline-1.nix | 0 .../lang/eval-okay-backslash-newline-2.exp | 0 .../lang/eval-okay-backslash-newline-2.nix | 0 .../tests/tests/lang/eval-okay-baseNameOf.exp | 0 .../tests/tests/lang/eval-okay-baseNameOf.nix | 0 .../tests/lang/eval-okay-builtins-add.exp | 0 .../tests/lang/eval-okay-builtins-add.nix | 0 .../tests/tests/lang/eval-okay-builtins.exp | 0 .../tests/tests/lang/eval-okay-builtins.nix | 0 .../tests/lang/eval-okay-callable-attrs.exp | 0 .../tests/lang/eval-okay-callable-attrs.nix | 0 .../tests/tests/lang/eval-okay-catattrs.exp | 0 .../tests/tests/lang/eval-okay-catattrs.nix | 0 .../tests/tests/lang/eval-okay-closure.exp | 0 .../tests/tests/lang/eval-okay-closure.nix | 0 .../tests/tests/lang/eval-okay-comments.exp | 0 .../tests/tests/lang/eval-okay-comments.nix | 0 .../tests/tests/lang/eval-okay-concat.exp | 0 .../tests/tests/lang/eval-okay-concat.nix | 0 .../tests/tests/lang/eval-okay-concatmap.exp | 0 .../tests/tests/lang/eval-okay-concatmap.nix | 0 .../tests/lang/eval-okay-concatstringssep.exp | 0 .../tests/lang/eval-okay-concatstringssep.nix | 0 .../lang/eval-okay-context-introspection.exp | 0 .../lang/eval-okay-context-introspection.nix | 0 .../tests/tests/lang/eval-okay-context.exp | 0 .../tests/tests/lang/eval-okay-context.nix | 0 .../tests/lang/eval-okay-convertHash.err.exp | 0 .../tests/lang/eval-okay-convertHash.exp | 0 .../tests/lang/eval-okay-convertHash.nix | 0 .../tests/tests/lang/eval-okay-curpos.exp | 0 .../tests/tests/lang/eval-okay-curpos.nix | 0 .../tests/tests/lang/eval-okay-deepseq.exp | 0 .../tests/tests/lang/eval-okay-deepseq.nix | 0 .../lang/eval-okay-delayed-with-inherit.exp | 0 .../lang/eval-okay-delayed-with-inherit.nix | 0 .../tests/lang/eval-okay-delayed-with.exp | 0 .../tests/lang/eval-okay-delayed-with.nix | 0 .../eval-okay-deprecate-cursed-or.err.exp | 0 .../lang/eval-okay-deprecate-cursed-or.exp | 0 .../lang/eval-okay-deprecate-cursed-or.nix | 0 .../lang/eval-okay-derivation-legacy.err.exp | 0 .../lang/eval-okay-derivation-legacy.exp | 0 .../lang/eval-okay-derivation-legacy.nix | 0 .../tests/lang/eval-okay-dynamic-attrs-2.exp | 0 .../tests/lang/eval-okay-dynamic-attrs-2.nix | 0 .../lang/eval-okay-dynamic-attrs-bare.exp | 0 .../lang/eval-okay-dynamic-attrs-bare.nix | 0 .../tests/lang/eval-okay-dynamic-attrs.exp | 0 .../tests/lang/eval-okay-dynamic-attrs.nix | 0 .../tests/tests/lang/eval-okay-elem.exp | 0 .../tests/tests/lang/eval-okay-elem.nix | 0 .../tests/tests/lang/eval-okay-empty-args.exp | 0 .../tests/tests/lang/eval-okay-empty-args.nix | 0 .../tests/lang/eval-okay-eq-derivations.exp | 0 .../tests/lang/eval-okay-eq-derivations.nix | 0 .../tests/tests/lang/eval-okay-eq.exp | 0 .../tests/tests/lang/eval-okay-eq.nix | 0 .../tests/tests/lang/eval-okay-filter.exp | 0 .../tests/tests/lang/eval-okay-filter.nix | 0 .../lang/eval-okay-flake-ref-to-string.exp | 0 .../lang/eval-okay-flake-ref-to-string.nix | 0 .../tests/tests/lang/eval-okay-flatten.exp | 0 .../tests/tests/lang/eval-okay-flatten.nix | 0 .../tests/tests/lang/eval-okay-float.exp | 0 .../tests/tests/lang/eval-okay-float.nix | 0 .../tests/tests/lang/eval-okay-floor-ceil.exp | 0 .../tests/tests/lang/eval-okay-floor-ceil.nix | 0 .../eval-okay-foldlStrict-lazy-elements.exp | 0 .../eval-okay-foldlStrict-lazy-elements.nix | 0 ...y-foldlStrict-lazy-initial-accumulator.exp | 0 ...y-foldlStrict-lazy-initial-accumulator.nix | 0 .../tests/lang/eval-okay-foldlStrict.exp | 0 .../tests/lang/eval-okay-foldlStrict.nix | 0 .../lang/eval-okay-fromTOML-timestamps.exp | 0 .../lang/eval-okay-fromTOML-timestamps.nix | 0 .../tests/tests/lang/eval-okay-fromTOML.exp | 0 .../tests/tests/lang/eval-okay-fromTOML.nix | 0 .../tests/lang/eval-okay-fromjson-escapes.exp | 0 .../tests/lang/eval-okay-fromjson-escapes.nix | 0 .../tests/tests/lang/eval-okay-fromjson.exp | 0 .../tests/tests/lang/eval-okay-fromjson.nix | 0 .../tests/lang/eval-okay-functionargs.exp | 0 .../tests/lang/eval-okay-functionargs.nix | 0 .../eval-okay-getattrpos-functionargs.exp | 0 .../eval-okay-getattrpos-functionargs.nix | 0 .../lang/eval-okay-getattrpos-undefined.exp | 0 .../lang/eval-okay-getattrpos-undefined.nix | 0 .../tests/tests/lang/eval-okay-getattrpos.exp | 0 .../tests/tests/lang/eval-okay-getattrpos.nix | 0 .../tests/tests/lang/eval-okay-getenv.exp | 0 .../tests/tests/lang/eval-okay-getenv.nix | 0 .../tests/tests/lang/eval-okay-groupBy.exp | 0 .../tests/tests/lang/eval-okay-groupBy.nix | 0 .../tests/tests/lang/eval-okay-hash.exp | 0 .../tests/tests/lang/eval-okay-hashfile.exp | 0 .../tests/tests/lang/eval-okay-hashfile.nix | 0 .../tests/tests/lang/eval-okay-hashstring.exp | 0 .../tests/tests/lang/eval-okay-hashstring.nix | 0 .../tests/tests/lang/eval-okay-if.exp | 0 .../tests/tests/lang/eval-okay-if.nix | 0 .../tests/tests/lang/eval-okay-import.exp | 0 .../tests/tests/lang/eval-okay-import.nix | 0 .../tests/tests/lang/eval-okay-ind-string.exp | 0 .../tests/tests/lang/eval-okay-ind-string.nix | 0 .../tests/lang/eval-okay-inherit-attr-pos.exp | 0 .../tests/lang/eval-okay-inherit-attr-pos.nix | 0 .../tests/lang/eval-okay-inherit-from.err.exp | 0 .../tests/lang/eval-okay-inherit-from.exp | 0 .../tests/lang/eval-okay-inherit-from.nix | 0 .../tests/lang/eval-okay-intersectAttrs.exp | 0 .../tests/lang/eval-okay-intersectAttrs.nix | 0 .../tests/tests/lang/eval-okay-let.exp | 0 .../tests/tests/lang/eval-okay-let.nix | 0 .../tests/tests/lang/eval-okay-list.exp | 0 .../tests/tests/lang/eval-okay-list.nix | 0 .../tests/lang/eval-okay-listtoattrs.exp | 0 .../tests/lang/eval-okay-listtoattrs.nix | 0 .../tests/tests/lang/eval-okay-logic.exp | 0 .../tests/tests/lang/eval-okay-logic.nix | 0 .../tests/tests/lang/eval-okay-map.exp | 0 .../tests/tests/lang/eval-okay-map.nix | 0 .../tests/tests/lang/eval-okay-mapattrs.exp | 0 .../tests/tests/lang/eval-okay-mapattrs.nix | 0 .../lang/eval-okay-merge-dynamic-attrs.exp | 0 .../lang/eval-okay-merge-dynamic-attrs.nix | 0 .../tests/lang/eval-okay-nested-with.exp | 0 .../tests/lang/eval-okay-nested-with.nix | 0 .../tests/tests/lang/eval-okay-new-let.exp | 0 .../tests/tests/lang/eval-okay-new-let.nix | 0 .../lang/eval-okay-null-dynamic-attrs.exp | 0 .../lang/eval-okay-null-dynamic-attrs.nix | 0 .../tests/tests/lang/eval-okay-overrides.exp | 0 .../tests/tests/lang/eval-okay-overrides.nix | 0 .../tests/lang/eval-okay-parse-flake-ref.exp | 0 .../tests/lang/eval-okay-parse-flake-ref.nix | 0 .../tests/tests/lang/eval-okay-partition.exp | 0 .../tests/tests/lang/eval-okay-partition.nix | 0 .../eval-okay-path-string-interpolation.exp | 0 .../eval-okay-path-string-interpolation.nix | 0 .../tests/tests/lang/eval-okay-path.exp | 0 .../tests/tests/lang/eval-okay-path.nix | 0 .../tests/tests/lang/eval-okay-pathexists.exp | 0 .../tests/tests/lang/eval-okay-pathexists.nix | 0 .../tests/tests/lang/eval-okay-patterns.exp | 0 .../tests/tests/lang/eval-okay-patterns.nix | 0 .../tests/tests/lang/eval-okay-print.err.exp | 0 .../tests/tests/lang/eval-okay-print.exp | 0 .../tests/tests/lang/eval-okay-print.nix | 0 .../tests/tests/lang/eval-okay-readDir.exp | 0 .../tests/tests/lang/eval-okay-readDir.nix | 0 .../tests/lang/eval-okay-readFileType.exp | 0 .../tests/lang/eval-okay-readFileType.nix | 0 .../tests/tests/lang/eval-okay-readfile.exp | 0 .../tests/tests/lang/eval-okay-readfile.nix | 0 .../tests/lang/eval-okay-redefine-builtin.exp | 0 .../tests/lang/eval-okay-redefine-builtin.nix | 0 .../tests/lang/eval-okay-regex-match.exp | 0 .../tests/lang/eval-okay-regex-match.nix | 0 .../tests/lang/eval-okay-regex-split.exp | 0 .../tests/lang/eval-okay-regex-split.nix | 0 .../lang/eval-okay-regression-20220122.exp | 0 .../lang/eval-okay-regression-20220122.nix | 0 .../lang/eval-okay-regression-20220125.exp | 0 .../lang/eval-okay-regression-20220125.nix | 0 ...val-okay-regrettable-rec-attrset-merge.exp | 0 ...val-okay-regrettable-rec-attrset-merge.nix | 0 .../tests/tests/lang/eval-okay-remove.exp | 0 .../tests/tests/lang/eval-okay-remove.nix | 0 .../lang/eval-okay-repeated-empty-attrs.exp | 0 .../lang/eval-okay-repeated-empty-attrs.nix | 0 .../lang/eval-okay-repeated-empty-list.exp | 0 .../lang/eval-okay-repeated-empty-list.nix | 0 .../tests/lang/eval-okay-replacestrings.exp | 0 .../tests/lang/eval-okay-replacestrings.nix | 0 .../tests/tests/lang/eval-okay-scope-1.exp | 0 .../tests/tests/lang/eval-okay-scope-1.nix | 0 .../tests/tests/lang/eval-okay-scope-2.exp | 0 .../tests/tests/lang/eval-okay-scope-2.nix | 0 .../tests/tests/lang/eval-okay-scope-3.exp | 0 .../tests/tests/lang/eval-okay-scope-3.nix | 0 .../tests/tests/lang/eval-okay-scope-4.exp | 0 .../tests/tests/lang/eval-okay-scope-4.nix | 0 .../tests/tests/lang/eval-okay-scope-6.exp | 0 .../tests/tests/lang/eval-okay-scope-6.nix | 0 .../tests/tests/lang/eval-okay-scope-7.exp | 0 .../tests/tests/lang/eval-okay-scope-7.nix | 0 .../tests/lang/eval-okay-search-path.exp | 0 .../tests/lang/eval-okay-search-path.nix | 0 .../tests/tests/lang/eval-okay-seq.exp | 0 .../tests/tests/lang/eval-okay-seq.nix | 0 .../tests/tests/lang/eval-okay-sort.exp | 0 .../tests/tests/lang/eval-okay-sort.nix | 0 .../tests/lang/eval-okay-splitversion.exp | 0 .../tests/lang/eval-okay-splitversion.nix | 0 .../tests/tests/lang/eval-okay-string.exp | 0 .../tests/tests/lang/eval-okay-string.nix | 0 .../lang/eval-okay-strings-as-attrs-names.exp | 0 .../lang/eval-okay-strings-as-attrs-names.nix | 0 .../lang/eval-okay-substring-context.exp | 0 .../lang/eval-okay-substring-context.nix | 0 .../tests/tests/lang/eval-okay-substring.exp | 0 .../tests/tests/lang/eval-okay-substring.nix | 0 .../lang/eval-okay-symlink-resolution.exp | 0 .../lang/eval-okay-symlink-resolution.nix | 0 .../tests/lang/eval-okay-tail-call-1.nix | 0 .../tests/tests/lang/eval-okay-tojson.exp | 0 .../tests/tests/lang/eval-okay-tojson.nix | 0 .../tests/tests/lang/eval-okay-toxml.exp | 0 .../tests/tests/lang/eval-okay-toxml.nix | 0 .../tests/tests/lang/eval-okay-toxml2.exp | 0 .../tests/tests/lang/eval-okay-toxml2.nix | 0 .../tests/tests/lang/eval-okay-tryeval.exp | 0 .../tests/tests/lang/eval-okay-tryeval.nix | 0 .../tests/tests/lang/eval-okay-types.exp | 0 .../tests/tests/lang/eval-okay-types.nix | 0 .../tests/tests/lang/eval-okay-versions.exp | 0 .../tests/tests/lang/eval-okay-versions.nix | 0 .../tests/tests/lang/eval-okay-with.exp | 0 .../tests/tests/lang/eval-okay-with.nix | 0 .../tests/tests/lang/eval-okay-xml.exp | 0 .../tests/tests/lang/eval-okay-xml.nix | 0 .../tests/lang/eval-okay-zipAttrsWith.exp | 0 .../tests/lang/eval-okay-zipAttrsWith.nix | 0 {nix-js => fix}/tests/tests/lang/imported.nix | 0 .../tests/tests/lang/imported2.nix | 0 {nix-js => fix}/tests/tests/lang/lib.nix | 0 .../tests/tests/lang/readDir/bar | 0 .../lang/readDir/foo/git-hates-directories | 0 {nix-js => fix}/tests/tests/lang/readDir/ldir | 0 .../tests/tests/lang/readDir/linked | 0 .../tests/lang/symlink-resolution/broken | 0 .../symlink-resolution/foo/lib/default.nix | 0 .../lang/symlink-resolution/foo/overlays | 0 .../symlink-resolution/overlays/overlay.nix | 0 {nix-js => fix}/tests/tests/lang/utils | 0 {nix-js => fix}/tests/tests/main.rs | 0 {nix-js => fix}/tests/tests/numeric_types.rs | 2 +- {nix-js => fix}/tests/tests/operators.rs | 2 +- .../tests/tests/path_operations.rs | 2 +- {nix-js => fix}/tests/tests/regex.rs | 2 +- {nix-js => fix}/tests/tests/string_context.rs | 4 +- {nix-js => fix}/tests/tests/thunk_scope.rs | 2 +- {nix-js => fix}/tests/tests/to_string.rs | 2 +- {nix-js => fix}/tests/tests/utils.rs | 6 +- nix-js-macros/Cargo.toml | 13 - nix-js-macros/src/ir.rs | 241 -- nix-js-macros/src/lib.rs | 13 - nix-js/benches/compile_time.rs | 141 -- nix-js/build.rs | 70 - nix-js/runtime-ts/.gitignore | 2 - nix-js/runtime-ts/build.mjs | 8 - nix-js/runtime-ts/eslint.config.mts | 20 - nix-js/runtime-ts/package-lock.json | 1966 ----------------- nix-js/runtime-ts/package.json | 22 - nix-js/runtime-ts/src/builtins/arithmetic.ts | 65 - nix-js/runtime-ts/src/builtins/attrs.ts | 159 -- nix-js/runtime-ts/src/builtins/context.ts | 202 -- nix-js/runtime-ts/src/builtins/conversion.ts | 371 ---- nix-js/runtime-ts/src/builtins/derivation.ts | 408 ---- nix-js/runtime-ts/src/builtins/flake.ts | 17 - nix-js/runtime-ts/src/builtins/functional.ts | 61 - nix-js/runtime-ts/src/builtins/hash.ts | 34 - nix-js/runtime-ts/src/builtins/index.ts | 224 -- nix-js/runtime-ts/src/builtins/io.ts | 486 ---- nix-js/runtime-ts/src/builtins/list.ts | 145 -- nix-js/runtime-ts/src/builtins/math.ts | 14 - nix-js/runtime-ts/src/builtins/misc.ts | 344 --- nix-js/runtime-ts/src/builtins/path.ts | 133 -- nix-js/runtime-ts/src/builtins/string.ts | 94 - nix-js/runtime-ts/src/builtins/type-check.ts | 63 - nix-js/runtime-ts/src/helpers.ts | 326 --- nix-js/runtime-ts/src/index.ts | 98 - nix-js/runtime-ts/src/operators.ts | 285 --- nix-js/runtime-ts/src/path.ts | 38 - nix-js/runtime-ts/src/print.ts | 111 - nix-js/runtime-ts/src/string-context.ts | 153 -- nix-js/runtime-ts/src/thunk.ts | 188 -- nix-js/runtime-ts/src/type-assert.ts | 127 -- nix-js/runtime-ts/src/types.ts | 115 - nix-js/runtime-ts/src/types/global.d.ts | 134 -- nix-js/runtime-ts/src/vm.ts | 617 ------ nix-js/runtime-ts/tsconfig.json | 22 - nix-js/src/codegen.rs | 618 ------ nix-js/src/runtime.rs | 687 ------ nix-js/src/runtime/inspector.rs | 493 ----- nix-js/src/runtime/ops.rs | 1896 ---------------- 511 files changed, 234 insertions(+), 12772 deletions(-) rename {nix-js => fix}/Cargo.toml (66%) rename {nix-js => fix}/benches/basic_ops.rs (100%) rename {nix-js => fix}/benches/builtins.rs (100%) rename {nix-js => fix}/benches/thunk_scope.rs (100%) rename {nix-js => fix}/benches/utils.rs (55%) rename {nix-js => fix}/src/bytecode.rs (91%) rename {nix-js => fix}/src/context.rs (67%) rename {nix-js => fix}/src/derivation.rs (100%) rename {nix-js => fix}/src/disassembler.rs (100%) rename {nix-js => fix}/src/downgrade.rs (100%) rename {nix-js => fix}/src/error.rs (63%) rename {nix-js => fix}/src/fetcher.rs (96%) rename {nix-js => fix}/src/fetcher/archive.rs (100%) rename {nix-js => fix}/src/fetcher/cache.rs (95%) rename {nix-js => fix}/src/fetcher/download.rs (100%) rename {nix-js => fix}/src/fetcher/git.rs (100%) rename {nix-js => fix}/src/fetcher/metadata_cache.rs (100%) rename {nix-js => fix}/src/ir.rs (100%) rename {nix-js => fix}/src/lib.rs (92%) rename {nix-js => fix}/src/logging.rs (100%) rename {nix-js => fix}/src/main.rs (75%) rename {nix-js => fix}/src/nar.rs (100%) rename {nix-js => fix}/src/nix_utils.rs (100%) rename nix-js/tests/tests/lang/eval-okay-hash.exp => fix/src/runtime.rs (100%) rename {nix-js => fix}/src/runtime/corepkgs/derivation.nix (100%) rename {nix-js => fix}/src/runtime/corepkgs/fetchurl.nix (100%) rename {nix-js => fix}/src/store.rs (100%) rename {nix-js => fix}/src/store/config.rs (100%) rename {nix-js => fix}/src/store/daemon.rs (100%) rename {nix-js => fix}/src/store/error.rs (100%) rename {nix-js => fix}/src/store/validation.rs (100%) rename {nix-js => fix}/src/string_context.rs (100%) rename {nix-js => fix}/src/value.rs (100%) rename {nix-js => fix}/tests/tests/basic_eval.rs (98%) rename {nix-js => fix}/tests/tests/builtins.rs (99%) rename {nix-js => fix}/tests/tests/builtins_store.rs (99%) rename {nix-js => fix}/tests/tests/derivation.rs (99%) rename {nix-js => fix}/tests/tests/findfile.rs (100%) rename {nix-js => fix}/tests/tests/free_globals.rs (97%) rename {nix-js => fix}/tests/tests/functions.rs (99%) rename {nix-js => fix}/tests/tests/io_operations.rs (99%) rename {nix-js => fix}/tests/tests/lang.rs (98%) rename {nix-js => fix}/tests/tests/lang/binary-data (100%) rename {nix-js => fix}/tests/tests/lang/data (100%) rename {nix-js => fix}/tests/tests/lang/dir1/a.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir2/a.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir2/b.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir3/a.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir3/b.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir3/c.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir4/a.nix (100%) rename {nix-js => fix}/tests/tests/lang/dir4/c.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-abort.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-abort.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addErrorContext-example.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-addErrorContext-example.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-attrs-names.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-attrs-names.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-derivations-extra.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-derivations-extra.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-derivations.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-derivations.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-floats.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-floats.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-function-direct.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-function-direct.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-int-float.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-int-float.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-ints.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-ints.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-list-length.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-list-length.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-paths.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-paths.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-type-nested.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-type-nested.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-type.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-equal-type.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-nested-bool.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert-nested-bool.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-assert.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-attr-name-type.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-attr-name-type.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-1.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-1.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-2.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-3.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-3.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-4.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-bad-string-interpolation-4.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-blackhole.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-blackhole.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-call-primop.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-call-primop.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-deepseq.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-deepseq.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-derivation-name.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-derivation-name.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-duplicate-traces.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-duplicate-traces.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-eol-1.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-eol-1.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-eol-2.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-eol-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-eol-3.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-eol-3.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchTree-negative.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchTree-negative.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fetchurl-baseName.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromJSON-overflowing.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromJSON-overflowing.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromTOML-timestamps.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromTOML-timestamps.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-hashfile-missing.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-hashfile-missing.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-infinite-recursion-lambda.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-infinite-recursion-lambda.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-list.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-list.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-missing-arg.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-missing-arg.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-mutual-recursion.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-mutual-recursion.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-nested-list-items.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-nested-list-items.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-nonexist-path.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-nonexist-path.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-not-throws.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-not-throws.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-add.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-add.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-div.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-div.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-mul.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-mul.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-sub.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-overflowing-sub.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-path-slash.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-path-slash.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-pipe-operators.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-pipe-operators.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-recursion.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-recursion.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-remove.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-remove.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-scope-5.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-scope-5.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-seq.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-seq.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-set-override.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-set-override.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-set.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-set.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-string-nul-1.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-string-nul-1.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-string-nul-2.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-string-nul-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-substring.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-substring.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-to-path.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-to-path.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-toJSON-non-utf-8.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-toJSON-non-utf-8.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-toJSON.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-toJSON.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-undeclared-arg.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-undeclared-arg.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-using-set-as-attr-name.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-fail-using-set-as-attr-name.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-any-all.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-any-all.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-arithmetic.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-arithmetic.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrnames.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrnames.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs2.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs3.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs3.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs4.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs4.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs5.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs5.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs6.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-attrs6.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-autoargs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-autoargs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-backslash-newline-1.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-backslash-newline-1.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-backslash-newline-2.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-backslash-newline-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-baseNameOf.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-baseNameOf.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-builtins-add.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-builtins-add.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-builtins.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-builtins.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-callable-attrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-callable-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-catattrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-catattrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-closure.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-closure.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-comments.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-comments.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-concat.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-concat.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-concatmap.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-concatmap.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-concatstringssep.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-concatstringssep.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-context-introspection.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-context-introspection.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-context.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-context.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-convertHash.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-convertHash.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-convertHash.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-curpos.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-curpos.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-deepseq.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-deepseq.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-delayed-with-inherit.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-delayed-with-inherit.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-delayed-with.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-delayed-with.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-deprecate-cursed-or.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-deprecate-cursed-or.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-deprecate-cursed-or.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-derivation-legacy.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-derivation-legacy.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-derivation-legacy.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-dynamic-attrs-2.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-dynamic-attrs-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-dynamic-attrs-bare.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-dynamic-attrs-bare.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-dynamic-attrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-dynamic-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-elem.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-elem.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-empty-args.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-empty-args.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-eq-derivations.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-eq-derivations.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-eq.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-eq.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-filter.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-filter.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-flake-ref-to-string.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-flake-ref-to-string.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-flatten.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-flatten.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-float.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-float.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-floor-ceil.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-floor-ceil.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-foldlStrict.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-foldlStrict.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromTOML-timestamps.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromTOML-timestamps.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromTOML.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromTOML.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromjson-escapes.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromjson-escapes.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromjson.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-fromjson.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-functionargs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-functionargs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getattrpos-functionargs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getattrpos-functionargs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getattrpos-undefined.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getattrpos-undefined.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getattrpos.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getattrpos.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getenv.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-getenv.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-groupBy.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-groupBy.nix (100%) rename nix-js/tests/tests/lang/readDir/bar => fix/tests/tests/lang/eval-okay-hash.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-hashfile.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-hashfile.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-hashstring.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-hashstring.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-if.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-if.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-import.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-import.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-ind-string.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-ind-string.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-inherit-attr-pos.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-inherit-attr-pos.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-inherit-from.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-inherit-from.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-inherit-from.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-intersectAttrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-intersectAttrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-let.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-let.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-list.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-list.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-listtoattrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-listtoattrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-logic.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-logic.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-map.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-map.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-mapattrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-mapattrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-merge-dynamic-attrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-merge-dynamic-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-nested-with.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-nested-with.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-new-let.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-new-let.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-null-dynamic-attrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-null-dynamic-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-overrides.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-overrides.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-parse-flake-ref.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-parse-flake-ref.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-partition.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-partition.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-path-string-interpolation.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-path-string-interpolation.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-path.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-path.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-pathexists.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-pathexists.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-patterns.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-patterns.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-print.err.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-print.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-print.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-readDir.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-readDir.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-readFileType.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-readFileType.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-readfile.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-readfile.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-redefine-builtin.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-redefine-builtin.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regex-match.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regex-match.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regex-split.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regex-split.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regression-20220122.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regression-20220122.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regression-20220125.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regression-20220125.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-remove.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-remove.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-repeated-empty-attrs.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-repeated-empty-attrs.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-repeated-empty-list.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-repeated-empty-list.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-replacestrings.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-replacestrings.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-1.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-1.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-2.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-3.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-3.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-4.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-4.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-6.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-6.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-7.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-scope-7.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-search-path.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-search-path.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-seq.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-seq.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-sort.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-sort.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-splitversion.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-splitversion.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-string.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-string.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-strings-as-attrs-names.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-strings-as-attrs-names.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-substring-context.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-substring-context.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-substring.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-substring.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-symlink-resolution.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-symlink-resolution.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-tail-call-1.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-tojson.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-tojson.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-toxml.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-toxml.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-toxml2.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-toxml2.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-tryeval.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-tryeval.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-types.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-types.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-versions.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-versions.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-with.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-with.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-xml.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-xml.nix (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-zipAttrsWith.exp (100%) rename {nix-js => fix}/tests/tests/lang/eval-okay-zipAttrsWith.nix (100%) rename {nix-js => fix}/tests/tests/lang/imported.nix (100%) rename {nix-js => fix}/tests/tests/lang/imported2.nix (100%) rename {nix-js => fix}/tests/tests/lang/lib.nix (100%) rename nix-js/tests/tests/lang/readDir/foo/git-hates-directories => fix/tests/tests/lang/readDir/bar (100%) create mode 100644 fix/tests/tests/lang/readDir/foo/git-hates-directories rename {nix-js => fix}/tests/tests/lang/readDir/ldir (100%) rename {nix-js => fix}/tests/tests/lang/readDir/linked (100%) rename {nix-js => fix}/tests/tests/lang/symlink-resolution/broken (100%) rename {nix-js => fix}/tests/tests/lang/symlink-resolution/foo/lib/default.nix (100%) rename {nix-js => fix}/tests/tests/lang/symlink-resolution/foo/overlays (100%) rename {nix-js => fix}/tests/tests/lang/symlink-resolution/overlays/overlay.nix (100%) rename {nix-js => fix}/tests/tests/lang/utils (100%) rename {nix-js => fix}/tests/tests/main.rs (100%) rename {nix-js => fix}/tests/tests/numeric_types.rs (99%) rename {nix-js => fix}/tests/tests/operators.rs (98%) rename {nix-js => fix}/tests/tests/path_operations.rs (99%) rename {nix-js => fix}/tests/tests/regex.rs (99%) rename {nix-js => fix}/tests/tests/string_context.rs (99%) rename {nix-js => fix}/tests/tests/thunk_scope.rs (99%) rename {nix-js => fix}/tests/tests/to_string.rs (99%) rename {nix-js => fix}/tests/tests/utils.rs (87%) delete mode 100644 nix-js-macros/Cargo.toml delete mode 100644 nix-js-macros/src/ir.rs delete mode 100644 nix-js-macros/src/lib.rs delete mode 100644 nix-js/benches/compile_time.rs delete mode 100644 nix-js/build.rs delete mode 100644 nix-js/runtime-ts/.gitignore delete mode 100644 nix-js/runtime-ts/build.mjs delete mode 100644 nix-js/runtime-ts/eslint.config.mts delete mode 100644 nix-js/runtime-ts/package-lock.json delete mode 100644 nix-js/runtime-ts/package.json delete mode 100644 nix-js/runtime-ts/src/builtins/arithmetic.ts delete mode 100644 nix-js/runtime-ts/src/builtins/attrs.ts delete mode 100644 nix-js/runtime-ts/src/builtins/context.ts delete mode 100644 nix-js/runtime-ts/src/builtins/conversion.ts delete mode 100644 nix-js/runtime-ts/src/builtins/derivation.ts delete mode 100644 nix-js/runtime-ts/src/builtins/flake.ts delete mode 100644 nix-js/runtime-ts/src/builtins/functional.ts delete mode 100644 nix-js/runtime-ts/src/builtins/hash.ts delete mode 100644 nix-js/runtime-ts/src/builtins/index.ts delete mode 100644 nix-js/runtime-ts/src/builtins/io.ts delete mode 100644 nix-js/runtime-ts/src/builtins/list.ts delete mode 100644 nix-js/runtime-ts/src/builtins/math.ts delete mode 100644 nix-js/runtime-ts/src/builtins/misc.ts delete mode 100644 nix-js/runtime-ts/src/builtins/path.ts delete mode 100644 nix-js/runtime-ts/src/builtins/string.ts delete mode 100644 nix-js/runtime-ts/src/builtins/type-check.ts delete mode 100644 nix-js/runtime-ts/src/helpers.ts delete mode 100644 nix-js/runtime-ts/src/index.ts delete mode 100644 nix-js/runtime-ts/src/operators.ts delete mode 100644 nix-js/runtime-ts/src/path.ts delete mode 100644 nix-js/runtime-ts/src/print.ts delete mode 100644 nix-js/runtime-ts/src/string-context.ts delete mode 100644 nix-js/runtime-ts/src/thunk.ts delete mode 100644 nix-js/runtime-ts/src/type-assert.ts delete mode 100644 nix-js/runtime-ts/src/types.ts delete mode 100644 nix-js/runtime-ts/src/types/global.d.ts delete mode 100644 nix-js/runtime-ts/src/vm.ts delete mode 100644 nix-js/runtime-ts/tsconfig.json delete mode 100644 nix-js/src/codegen.rs delete mode 100644 nix-js/src/runtime.rs delete mode 100644 nix-js/src/runtime/inspector.rs delete mode 100644 nix-js/src/runtime/ops.rs diff --git a/.lazy.lua b/.lazy.lua index f034c64..aa6b3ab 100644 --- a/.lazy.lua +++ b/.lazy.lua @@ -16,9 +16,6 @@ vim.lsp.config("rust_analyzer", { settings = { ["rust-analyzer"] = { cargo = { - features = { - "inspector" - } } } } diff --git a/Cargo.lock b/Cargo.lock index e6a8ad8..6d6c807 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,6 +41,12 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" +[[package]] +name = "allocator-api2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c880a97d28a3681c0267bd29cff89621202715b065127cd445fa0f0fe0aa2880" + [[package]] name = "anes" version = "0.1.6" @@ -137,12 +143,6 @@ dependencies = [ "fs_extra", ] -[[package]] -name = "az" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" - [[package]] name = "backtrace" version = "0.3.76" @@ -167,96 +167,24 @@ dependencies = [ "backtrace", ] -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "base64-simd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" -dependencies = [ - "outref", - "vsimd", -] - [[package]] name = "base64ct" version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bindgen" -version = "0.72.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.13.0", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 2.1.1", - "shlex", - "syn", -] - -[[package]] -name = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" - [[package]] name = "bitflags" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -267,13 +195,12 @@ dependencies = [ ] [[package]] -name = "boxed_error" -version = "0.2.3" +name = "boxing" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17d4f95e880cfd28c4ca5a006cf7f6af52b4bcb7b5866f573b2faa126fb7affb" +checksum = "7a817f12ef805b34fe1565bea00630d84f8f08bf26200b05c41456c77cdada88" dependencies = [ - "quote", - "syn", + "sptr", ] [[package]] @@ -293,7 +220,7 @@ version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" dependencies = [ - "allocator-api2", + "allocator-api2 0.2.21", ] [[package]] @@ -311,42 +238,12 @@ dependencies = [ "libbz2-rs-sys", ] -[[package]] -name = "calendrical_calculations" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a0b39595c6ee54a8d0900204ba4c401d0ab4eb45adaf07178e8d017541529e7" -dependencies = [ - "core_maths", - "displaydoc", -] - [[package]] name = "camino" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" -[[package]] -name = "capacity_builder" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f2d24a6dcf0cd402a21b65d35340f3a49ff3475dc5fdac91d22d2733e6641c6" -dependencies = [ - "capacity_builder_macros", - "itoa", -] - -[[package]] -name = "capacity_builder_macros" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b4a6cae9efc04cc6cbb8faf338d2c497c165c83e74509cf4dbedea948bbf6e5" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "cast" version = "0.3.0" @@ -371,15 +268,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom 7.1.3", -] - [[package]] name = "cfg-if" version = "1.0.4" @@ -419,17 +307,6 @@ dependencies = [ "half", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.5.59" @@ -528,21 +405,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "convert_case" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "cooked-waker" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147be55d677052dabc6b22252d5dd0fd4c29c8c27aa4f2fbef0f94aa003b406f" - [[package]] name = "core-foundation" version = "0.10.1" @@ -559,15 +421,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core_maths" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" -dependencies = [ - "libm", -] - [[package]] name = "countme" version = "3.0.1" @@ -701,127 +554,6 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "serde", - "uuid", -] - -[[package]] -name = "deno_core" -version = "0.385.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e348ea58ad12f6bee5407768b571a8af09756246a45c83dfd27a5aeeb338c5eb" -dependencies = [ - "anyhow", - "az", - "bincode", - "bit-set", - "bit-vec", - "boxed_error", - "bytes", - "capacity_builder", - "cooked-waker", - "deno_core_icudata", - "deno_error", - "deno_ops", - "deno_path_util", - "deno_unsync", - "futures", - "indexmap", - "libc", - "parking_lot", - "percent-encoding", - "pin-project", - "serde", - "serde_json", - "serde_v8", - "smallvec", - "sourcemap", - "static_assertions", - "thiserror 2.0.18", - "tokio", - "url", - "v8", - "wasm_dep_analyzer", -] - -[[package]] -name = "deno_core_icudata" -version = "0.77.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9efff8990a82c1ae664292507e1a5c6749ddd2312898cdf9cd7cb1fd4bc64c6" - -[[package]] -name = "deno_error" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3007d3f1ea92ea503324ae15883aac0c2de2b8cf6fead62203ff6a67161007ab" -dependencies = [ - "deno_error_macro", - "libc", - "serde", - "serde_json", - "tokio", - "url", -] - -[[package]] -name = "deno_error_macro" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b565e60a9685cdf312c888665b5f8647ac692a7da7e058a5e2268a466da8eaf" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "deno_ops" -version = "0.261.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86077bea01b43941082edef61e150fa661bab25a839f17592bb763faaae0c14b" -dependencies = [ - "indexmap", - "proc-macro2", - "quote", - "stringcase", - "strum", - "strum_macros", - "syn", - "syn-match", - "thiserror 2.0.18", -] - -[[package]] -name = "deno_path_util" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c7e98943f0d068928906db0c7bde89de684fa32c6a8018caacc4cee2cdd72b" -dependencies = [ - "deno_error", - "percent-encoding", - "sys_traits", - "thiserror 2.0.18", - "url", -] - -[[package]] -name = "deno_unsync" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6742a724e8becb372a74c650a1aefb8924a5b8107f7d75b3848763ea24b27a87" -dependencies = [ - "futures-util", - "parking_lot", - "tokio", -] - [[package]] name = "der" version = "0.7.10" @@ -847,7 +579,7 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ - "convert_case 0.10.0", + "convert_case", "proc-macro2", "quote", "rustc_version", @@ -865,38 +597,6 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "diplomat" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9adb46b05e2f53dcf6a7dfc242e4ce9eb60c369b6b6eb10826a01e93167f59c6" -dependencies = [ - "diplomat_core", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "diplomat-runtime" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0569bd3caaf13829da7ee4e83dbf9197a0e1ecd72772da6d08f0b4c9285c8d29" - -[[package]] -name = "diplomat_core" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51731530ed7f2d4495019abc7df3744f53338e69e2863a6a64ae91821c763df1" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "smallvec", - "strck", - "syn", -] - [[package]] name = "dirs" version = "6.0.0" @@ -1066,26 +766,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "fastwebsockets" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305d3ba574508e27190906d11707dad683e0494e6b85eae9b044cb2734a5e422" -dependencies = [ - "base64 0.21.7", - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "pin-project", - "rand 0.8.5", - "sha1", - "simdutf8", - "thiserror 1.0.69", - "tokio", - "utf-8", -] - [[package]] name = "fd-lock" version = "4.0.4" @@ -1093,7 +773,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78" dependencies = [ "cfg-if", - "rustix 1.1.3", + "rustix", "windows-sys 0.59.0", ] @@ -1120,6 +800,58 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +[[package]] +name = "fix" +version = "0.1.0" +dependencies = [ + "allocator-api2 0.4.0", + "anyhow", + "base64", + "boxing", + "bumpalo", + "bzip2", + "clap", + "colored", + "criterion", + "derive_more", + "dirs", + "ere", + "flate2", + "gc-arena", + "ghost-cell", + "hashbrown 0.16.1", + "hex", + "itertools 0.14.0", + "md5", + "miette", + "mimalloc", + "nix-compat", + "nix-nar", + "num_enum", + "regex", + "reqwest", + "rnix", + "rowan", + "rusqlite", + "rust-embed", + "rustyline", + "serde", + "serde_json", + "sha1", + "sha2", + "string-interner", + "tap", + "tar", + "tempfile", + "test-log", + "thiserror 2.0.18", + "tokio", + "toml", + "tracing", + "tracing-subscriber", + "xz2", +] + [[package]] name = "flate2" version = "1.1.9" @@ -1157,22 +889,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" -[[package]] -name = "fslock" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04412b8935272e3a9bae6f48c7bfff74c2911f60525404edfdd28e49884c3bfb" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" version = "0.3.32" @@ -1261,6 +977,30 @@ dependencies = [ "slab", ] +[[package]] +name = "gc-arena" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cd70cf88a32937834aae9614ff2569b5d9467fa0c42c5d7762fd94a8de88266" +dependencies = [ + "allocator-api2 0.2.21", + "gc-arena-derive", + "hashbrown 0.14.5", + "sptr", +] + +[[package]] +name = "gc-arena-derive" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c612a69f5557a11046b77a7408d2836fe77077f842171cd211c5ef504bd3cddd" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -1323,21 +1063,6 @@ version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "gzip-header" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95cc527b92e6029a62960ad99aa8a6660faa4555fe5f731aab13aa6a921795a2" -dependencies = [ - "crc32fast", -] - [[package]] name = "half" version = "2.7.1" @@ -1354,6 +1079,9 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "allocator-api2 0.2.21", +] [[package]] name = "hashbrown" @@ -1370,7 +1098,7 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "allocator-api2", + "allocator-api2 0.2.21", "equivalent", "foldhash 0.2.0", ] @@ -1444,12 +1172,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - [[package]] name = "hyper" version = "1.8.1" @@ -1463,7 +1185,6 @@ dependencies = [ "http", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", "pin-utils", @@ -1494,7 +1215,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-util", @@ -1511,28 +1232,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "icu_calendar" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6f0e52e009b6b16ba9c0693578796f2dd4aaa59a7f8f920423706714a89ac4e" -dependencies = [ - "calendrical_calculations", - "displaydoc", - "icu_calendar_data", - "icu_locale", - "icu_locale_core", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_calendar_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527f04223b17edfe0bd43baf14a0cb1b017830db65f3950dc00224860a9a446d" - [[package]] name = "icu_collections" version = "2.1.1" @@ -1546,21 +1245,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locale" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532b11722e350ab6bf916ba6eb0efe3ee54b932666afec989465f9243fe6dd60" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_locale_data", - "icu_provider", - "potential_utf", - "tinystr", - "zerovec", -] - [[package]] name = "icu_locale_core" version = "2.1.1" @@ -1569,18 +1253,11 @@ checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", - "serde", "tinystr", "writeable", "zerovec", ] -[[package]] -name = "icu_locale_data" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c5f1d16b4c3a2642d3a719f18f6b06070ab0aef246a6418130c955ae08aa831" - [[package]] name = "icu_normalizer" version = "2.1.1" @@ -1629,8 +1306,6 @@ checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "serde", - "stable_deref_trait", "writeable", "yoke", "zerofrom", @@ -1665,12 +1340,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "if_chain" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb" - [[package]] name = "indexmap" version = "2.13.0" @@ -1744,12 +1413,6 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" -[[package]] -name = "ixdtf" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84de9d95a6d2547d9b77ee3f25fa0ee32e3c3a6484d47a55adebc0439c077992" - [[package]] name = "jni" version = "0.21.1" @@ -1816,22 +1479,6 @@ version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link", -] - -[[package]] -name = "libm" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" - [[package]] name = "libmimalloc-sys" version = "0.1.44" @@ -1850,7 +1497,7 @@ checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ "bitflags", "libc", - "redox_syscall 0.7.1", + "redox_syscall", ] [[package]] @@ -1864,12 +1511,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1882,15 +1523,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" @@ -1974,12 +1606,6 @@ dependencies = [ "libmimalloc-sys", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -2036,7 +1662,7 @@ dependencies = [ "futures", "mimalloc", "nix-compat-derive", - "nom 8.0.0", + "nom", "num_enum", "pin-project-lite", "sha2", @@ -2055,74 +1681,6 @@ dependencies = [ "syn", ] -[[package]] -name = "nix-js" -version = "0.1.0" -dependencies = [ - "anyhow", - "base64 0.22.1", - "bumpalo", - "bzip2", - "clap", - "colored", - "criterion", - "deno_core", - "deno_error", - "derive_more", - "dirs", - "ere", - "fastwebsockets", - "flate2", - "ghost-cell", - "hashbrown 0.16.1", - "hex", - "http", - "http-body-util", - "hyper", - "hyper-util", - "itertools 0.14.0", - "md5", - "miette", - "mimalloc", - "nix-compat", - "nix-js-macros", - "nix-nar", - "num_enum", - "regex", - "reqwest", - "rnix", - "rowan", - "rusqlite", - "rust-embed", - "rustyline", - "serde", - "serde_json", - "sha1", - "sha2", - "string-interner", - "tap", - "tar", - "tempfile", - "test-log", - "thiserror 2.0.18", - "tokio", - "toml", - "tracing", - "tracing-subscriber", - "uuid", - "xz2", -] - -[[package]] -name = "nix-js-macros" -version = "0.1.0" -dependencies = [ - "convert_case 0.11.0", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "nix-nar" version = "0.3.1" @@ -2135,16 +1693,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - [[package]] name = "nom" version = "8.0.0" @@ -2163,26 +1711,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num-bigint" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", - "rand 0.8.5", -] - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.19" @@ -2253,12 +1781,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "outref" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" - [[package]] name = "owo-colors" version = "4.2.3" @@ -2275,61 +1797,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.5.18", - "smallvec", - "windows-link", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -2392,8 +1865,6 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ - "serde_core", - "writeable", "zerovec", ] @@ -2464,7 +1935,7 @@ dependencies = [ "bytes", "getrandom 0.3.4", "lru-slab", - "rand 0.9.2", + "rand", "ring", "rustc-hash 2.1.1", "rustls", @@ -2505,12 +1976,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "radix_trie" version = "0.2.1" @@ -2521,37 +1986,16 @@ dependencies = [ "nibble_vec", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -2600,15 +2044,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_syscall" version = "0.7.1" @@ -2664,7 +2099,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", "futures-core", @@ -2695,16 +2130,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "resb" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a067ab3b5ca3b4dc307d0de9cf75f9f5e6ca9717b192b2f28a36c83e5de9e76" -dependencies = [ - "potential_utf", - "serde_core", -] - [[package]] name = "ring" version = "0.17.14" @@ -2826,19 +2251,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.3" @@ -2848,7 +2260,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys", "windows-sys 0.61.2", ] @@ -2973,12 +2385,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "security-framework" version = "3.6.0" @@ -3044,7 +2450,6 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap", "itoa", "memchr", "serde", @@ -3061,20 +2466,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_v8" -version = "0.294.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8386a10eddc03e63b28ad6963dbd0552470b430419d81fd6409e19e28146a3c8" -dependencies = [ - "deno_error", - "num-bigint", - "serde", - "smallvec", - "thiserror 2.0.18", - "v8", -] - [[package]] name = "sha1" version = "0.10.6" @@ -3112,16 +2503,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" -dependencies = [ - "errno", - "libc", -] - [[package]] name = "signature" version = "2.2.0" @@ -3137,12 +2518,6 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - [[package]] name = "slab" version = "0.4.12" @@ -3165,24 +2540,6 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "sourcemap" -version = "9.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "314d62a489431668f719ada776ca1d49b924db951b7450f8974c9ae51ab05ad7" -dependencies = [ - "base64-simd", - "bitvec", - "data-encoding", - "debugid", - "if_chain", - "rustc-hash 2.1.1", - "serde", - "serde_json", - "unicode-id-start", - "url", -] - [[package]] name = "spki" version = "0.7.3" @@ -3193,6 +2550,12 @@ dependencies = [ "der", ] +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + [[package]] name = "sqlite-wasm-rs" version = "0.5.2" @@ -3211,21 +2574,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strck" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42316e70da376f3d113a68d138a60d8a9883c604fe97942721ec2068dab13a9f" -dependencies = [ - "unicode-ident", -] - [[package]] name = "string-interner" version = "0.19.0" @@ -3236,39 +2584,12 @@ dependencies = [ "serde", ] -[[package]] -name = "stringcase" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72abeda133c49d7bddece6c154728f83eec8172380c80ab7096da9487e20d27c" - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af23d6f6c1a224baef9d3f61e287d2761385a5b88fdab4eb4c6f11aeb54c4bcf" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "subtle" version = "2.6.1" @@ -3313,17 +2634,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn-match" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b8f0a9004d6aafa6a588602a1119e6cdaacec9921aa1605383e6e7d6258fd6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -3344,26 +2654,6 @@ dependencies = [ "syn", ] -[[package]] -name = "sys_traits" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5410f31d223892c1ce7a098da845c99d023b4c7f18632bc8f09e60dfae3cbb75" -dependencies = [ - "sys_traits_macros", -] - -[[package]] -name = "sys_traits_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "181f22127402abcf8ee5c83ccd5b408933fec36a6095cf82cda545634692657e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tap" version = "1.0.1" @@ -3390,50 +2680,17 @@ dependencies = [ "fastrand", "getrandom 0.4.1", "once_cell", - "rustix 1.1.3", + "rustix", "windows-sys 0.61.2", ] -[[package]] -name = "temporal_capi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a151e402c2bdb6a3a2a2f3f225eddaead2e7ce7dd5d3fa2090deb11b17aa4ed8" -dependencies = [ - "diplomat", - "diplomat-runtime", - "icu_calendar", - "icu_locale", - "num-traits", - "temporal_rs", - "timezone_provider", - "writeable", - "zoneinfo64", -] - -[[package]] -name = "temporal_rs" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88afde3bd75d2fc68d77a914bece426aa08aa7649ffd0cdd4a11c3d4d33474d1" -dependencies = [ - "core_maths", - "icu_calendar", - "icu_locale", - "ixdtf", - "num-traits", - "timezone_provider", - "tinystr", - "writeable", -] - [[package]] name = "terminal_size" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ - "rustix 1.1.3", + "rustix", "windows-sys 0.60.2", ] @@ -3524,18 +2781,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "timezone_provider" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9ba0000e9e73862f3e7ca1ff159e2ddf915c9d8bb11e38a7874760f445d993" -dependencies = [ - "tinystr", - "zerotrie", - "zerovec", - "zoneinfo64", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -3543,7 +2788,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", - "serde_core", "zerovec", ] @@ -3581,9 +2825,7 @@ dependencies = [ "bytes", "libc", "mio", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2", "tokio-macros", "windows-sys 0.61.2", @@ -3612,9 +2854,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.12+spec-1.1.0" +version = "0.9.9+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863" +checksum = "eb5238e643fc34a1d5d7e753e1532a91912d74b63b92b3ea51fde8d1b7bc79dd" dependencies = [ "indexmap", "serde_core", @@ -3779,12 +3021,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "unicode-id-start" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81b79ad29b5e19de4260020f8919b443b2ef0277d242ce532ec7b7a2cc8b6007" - [[package]] name = "unicode-ident" version = "1.0.24" @@ -3837,15 +3073,8 @@ dependencies = [ "idna", "percent-encoding", "serde", - "serde_derive", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8-ranges" version = "1.0.5" @@ -3864,34 +3093,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" -dependencies = [ - "getrandom 0.4.1", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "v8" -version = "145.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61d9a107e16bae35a0be2bb0096ac1d2318aac352c82edd796ab2b9cac66d8f0" -dependencies = [ - "bindgen", - "bitflags", - "fslock", - "gzip-header", - "home", - "miniz_oxide", - "paste", - "temporal_capi", - "which", -] - [[package]] name = "valuable" version = "0.1.1" @@ -3910,12 +3111,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - [[package]] name = "walkdir" version = "2.5.0" @@ -4040,16 +3235,6 @@ dependencies = [ "wasmparser", ] -[[package]] -name = "wasm_dep_analyzer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a10e6b67c951a84de7029487e0e0a496860dae49f6699edd279d5ff35b8fbf54" -dependencies = [ - "deno_error", - "thiserror 2.0.18", -] - [[package]] name = "wasmparser" version = "0.244.0" @@ -4091,18 +3276,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "6.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" -dependencies = [ - "either", - "home", - "rustix 0.38.44", - "winsafe", -] - [[package]] name = "winapi" version = "0.3.9" @@ -4380,12 +3553,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "winsafe" -version = "0.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" - [[package]] name = "wit-bindgen" version = "0.51.0" @@ -4480,15 +3647,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "xattr" version = "1.6.1" @@ -4496,7 +3654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "rustix 1.1.3", + "rustix", ] [[package]] @@ -4595,7 +3753,6 @@ version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ - "serde", "yoke", "zerofrom", "zerovec-derive", @@ -4617,16 +3774,3 @@ name = "zmij" version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - -[[package]] -name = "zoneinfo64" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2e5597efbe7c421da8a7fd396b20b571704e787c21a272eecf35dfe9d386f0" -dependencies = [ - "calendrical_calculations", - "icu_locale_core", - "potential_utf", - "resb", - "serde", -] diff --git a/Cargo.toml b/Cargo.toml index 6e7ea10..eb64a44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] resolver = "3" members = [ - "nix-js", - "nix-js-macros" + "fix" ] [profile.profiling] diff --git a/nix-js/Cargo.toml b/fix/Cargo.toml similarity index 66% rename from nix-js/Cargo.toml rename to fix/Cargo.toml index c04788b..4d91c5a 100644 --- a/nix-js/Cargo.toml +++ b/fix/Cargo.toml @@ -1,8 +1,7 @@ [package] -name = "nix-js" +name = "fix" version = "0.1.0" edition = "2024" -build = "build.rs" [dependencies] mimalloc = "0.1" @@ -35,9 +34,6 @@ itertools = "0.14" regex = "1.11" -deno_core = "0.385" -deno_error = "0.7" - nix-nar = "0.3" sha2 = "0.10" sha1 = "0.10" @@ -54,7 +50,7 @@ bzip2 = "0.6" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" # spec 1.0.0 -toml = "0.9.9" +toml = "=0.9.9" dirs = "6.0" tempfile = "3.24" rusqlite = { version = "0.38", features = ["bundled"] } @@ -62,24 +58,15 @@ rusqlite = { version = "0.38", features = ["bundled"] } rnix = "0.14" rowan = "0.16" -nix-js-macros = { path = "../nix-js-macros" } ere = "0.2.4" num_enum = "0.7.5" tap = "1.0.1" -# Inspector (optional) -fastwebsockets = { version = "0.10", features = ["upgrade"], optional = true } -hyper = { version = "1", features = ["http1", "server"], optional = true } -hyper-util = { version = "0.1", features = ["tokio"], optional = true } -http-body-util = { version = "0.1", optional = true } -http = { version = "1", optional = true } -uuid = { version = "1", features = ["v4"], optional = true } -ghost-cell = "0.2.6" -colored = "3.1.1" - -[features] -inspector = ["dep:fastwebsockets", "dep:hyper", "dep:hyper-util", "dep:http-body-util", "dep:http", "dep:uuid"] -prof = [] +ghost-cell = "0.2" +colored = "3.1" +boxing = "0.1" +gc-arena = { version = "0.5.3", features = ["allocator-api2"] } +allocator-api2 = "0.4.0" [dev-dependencies] criterion = { version = "0.8", features = ["html_reports"] } @@ -96,7 +83,3 @@ harness = false [[bench]] name = "thunk_scope" harness = false - -[[bench]] -name = "compile_time" -harness = false diff --git a/nix-js/benches/basic_ops.rs b/fix/benches/basic_ops.rs similarity index 100% rename from nix-js/benches/basic_ops.rs rename to fix/benches/basic_ops.rs diff --git a/nix-js/benches/builtins.rs b/fix/benches/builtins.rs similarity index 100% rename from nix-js/benches/builtins.rs rename to fix/benches/builtins.rs diff --git a/nix-js/benches/thunk_scope.rs b/fix/benches/thunk_scope.rs similarity index 100% rename from nix-js/benches/thunk_scope.rs rename to fix/benches/thunk_scope.rs diff --git a/nix-js/benches/utils.rs b/fix/benches/utils.rs similarity index 55% rename from nix-js/benches/utils.rs rename to fix/benches/utils.rs index 5fe4173..21e9d01 100644 --- a/nix-js/benches/utils.rs +++ b/fix/benches/utils.rs @@ -1,8 +1,8 @@ #![allow(dead_code)] -use nix_js::context::Context; -use nix_js::error::{Result, Source}; -use nix_js::value::Value; +use fix::context::Context; +use fix::error::{Result, Source}; +use fix::value::Value; pub fn eval(expr: &str) -> Value { Context::new() @@ -16,10 +16,3 @@ pub fn eval_result(expr: &str) -> Result { .unwrap() .eval(Source::new_eval(expr.into()).unwrap()) } - -pub fn compile(expr: &str) -> String { - Context::new() - .unwrap() - .compile(Source::new_eval(expr.into()).unwrap()) - .unwrap() -} diff --git a/nix-js/src/bytecode.rs b/fix/src/bytecode.rs similarity index 91% rename from nix-js/src/bytecode.rs rename to fix/src/bytecode.rs index fc5aaea..2cc4927 100644 --- a/nix-js/src/bytecode.rs +++ b/fix/src/bytecode.rs @@ -30,72 +30,72 @@ pub(crate) trait BytecodeContext { #[derive(Clone, Copy, TryFromPrimitive)] #[allow(clippy::enum_variant_names)] pub enum Op { - PushConst = 0x01, - PushString = 0x02, - PushNull = 0x03, - PushTrue = 0x04, - PushFalse = 0x05, + PushConst, + PushString, + PushNull, + PushTrue, + PushFalse, - LoadLocal = 0x06, - LoadOuter = 0x07, - StoreLocal = 0x08, - AllocLocals = 0x09, + LoadLocal, + LoadOuter, + StoreLocal, + AllocLocals, - MakeThunk = 0x0A, - MakeClosure = 0x0B, - MakePatternClosure = 0x0C, + MakeThunk, + MakeClosure, + MakePatternClosure, - Call = 0x0D, - CallNoSpan = 0x0E, + Call, + CallNoSpan, - MakeAttrs = 0x0F, - MakeAttrsDyn = 0x10, - MakeEmptyAttrs = 0x11, - Select = 0x12, - SelectDefault = 0x13, - HasAttr = 0x14, + MakeAttrs, + MakeAttrsDyn, + MakeEmptyAttrs, + Select, + SelectDefault, + HasAttr, - MakeList = 0x15, + MakeList, - OpAdd = 0x16, - OpSub = 0x17, - OpMul = 0x18, - OpDiv = 0x19, - OpEq = 0x20, - OpNeq = 0x21, - OpLt = 0x22, - OpGt = 0x23, - OpLeq = 0x24, - OpGeq = 0x25, - OpConcat = 0x26, - OpUpdate = 0x27, + OpAdd, + OpSub, + OpMul, + OpDiv, + OpEq, + OpNeq, + OpLt, + OpGt, + OpLeq, + OpGeq, + OpConcat, + OpUpdate, - OpNeg = 0x28, - OpNot = 0x29, + OpNeg, + OpNot, - ForceBool = 0x30, - JumpIfFalse = 0x31, - JumpIfTrue = 0x32, - Jump = 0x33, + ForceBool, + JumpIfFalse, + JumpIfTrue, + Jump, - ConcatStrings = 0x34, - ResolvePath = 0x35, + ConcatStrings, + ResolvePath, - Assert = 0x36, + Assert, - PushWith = 0x37, - PopWith = 0x38, - WithLookup = 0x39, + PushWith, + PopWith, + WithLookup, - LoadBuiltins = 0x40, - LoadBuiltin = 0x41, + LoadBuiltins, + LoadBuiltin, - MkPos = 0x43, + MkPos, - LoadReplBinding = 0x44, - LoadScopedBinding = 0x45, + LoadReplBinding, + LoadScopedBinding, - Return = 0x46, + Return, } struct ScopeInfo { @@ -120,19 +120,6 @@ pub(crate) fn compile_bytecode(ir: RawIrRef<'_>, ctx: &mut impl BytecodeContext) } } -pub(crate) fn compile_bytecode_scoped( - ir: RawIrRef<'_>, - ctx: &mut impl BytecodeContext, -) -> Bytecode { - let current_dir = ctx.get_current_dir().to_string_lossy().to_string(); - let mut emitter = BytecodeEmitter::new(ctx); - emitter.emit_toplevel_scoped(ir); - Bytecode { - code: emitter.code.into_boxed_slice(), - current_dir, - } -} - impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { fn new(ctx: &'a mut Ctx) -> Self { Self { @@ -397,37 +384,6 @@ impl<'a, Ctx: BytecodeContext> BytecodeEmitter<'a, Ctx> { } } - fn emit_toplevel_scoped(&mut self, ir: RawIrRef<'_>) { - match ir.deref() { - Ir::TopLevel { body, thunks } => { - let with_thunk_count = self.count_with_thunks(*body); - let total_slots = thunks.len() + with_thunk_count; - - let all_thunks = self.collect_all_thunks(thunks, *body); - let thunk_ids: Vec = all_thunks.iter().map(|&(id, _)| id).collect(); - - self.push_scope(false, None, &thunk_ids); - - if total_slots > 0 { - self.emit_op(Op::AllocLocals); - self.emit_u32(total_slots as u32); - } - - self.emit_scope_thunks(thunks); - self.emit_expr(*body); - self.emit_op(Op::Return); - - self.pop_scope(); - } - _ => { - self.push_scope(false, None, &[]); - self.emit_expr(ir); - self.emit_op(Op::Return); - self.pop_scope(); - } - } - } - fn emit_scope_thunks(&mut self, thunks: &[(ThunkId, RawIrRef<'_>)]) { for &(id, inner) in thunks { let label = format!("e{}", id.0); diff --git a/nix-js/src/context.rs b/fix/src/context.rs similarity index 67% rename from nix-js/src/context.rs rename to fix/src/context.rs index 5d97c45..fd7bc1e 100644 --- a/nix-js/src/context.rs +++ b/fix/src/context.rs @@ -9,14 +9,10 @@ use rnix::TextRange; use string_interner::DefaultStringInterner; use crate::bytecode::{self, Bytecode, BytecodeContext, Constant}; -use crate::codegen::{CodegenContext, compile}; use crate::disassembler::{Disassembler, DisassemblerContext}; use crate::downgrade::*; use crate::error::{Error, Result, Source}; use crate::ir::{ArgId, Ir, IrKey, IrRef, RawIrRef, SymId, ThunkId, ir_content_eq}; -#[cfg(feature = "inspector")] -use crate::runtime::inspector::InspectorServer; -use crate::runtime::{ForceMode, Runtime, RuntimeContext}; use crate::store::{DaemonStore, Store, StoreConfig}; use crate::value::{Symbol, Value}; @@ -48,129 +44,27 @@ fn handle_parse_error<'a>( None } -pub struct Context { - ctx: Ctx, - runtime: Runtime, - #[cfg(feature = "inspector")] - _inspector_server: Option, -} - -macro_rules! eval_bc { - ($name:ident, $mode:expr) => { - pub fn $name(&mut self, source: Source) -> Result { - tracing::info!("Starting evaluation"); - - tracing::debug!("Compiling bytecode"); - let bytecode = self.ctx.compile_bytecode(source)?; - - tracing::debug!("Executing bytecode"); - self.runtime.eval_bytecode(bytecode, &mut self.ctx, $mode) - } - }; -} - impl Context { - pub fn new() -> Result { - let ctx = Ctx::new()?; - #[cfg(feature = "inspector")] - let runtime = Runtime::new(Default::default())?; - #[cfg(not(feature = "inspector"))] - let runtime = Runtime::new()?; - - let mut context = Self { - ctx, - runtime, - #[cfg(feature = "inspector")] - _inspector_server: None, - }; - context.init()?; - - Ok(context) + pub fn eval(&mut self, _source: Source) -> Result { + todo!() + } + pub fn eval_shallow(&mut self, _source: Source) -> Result { + todo!() + } + pub fn eval_deep(&mut self, _source: Source) -> Result { + todo!() } - #[cfg(feature = "inspector")] - pub fn new_with_inspector(addr: std::net::SocketAddr, wait_for_session: bool) -> Result { - use crate::runtime::InspectorOptions; - - let ctx = Ctx::new()?; - let runtime = Runtime::new(InspectorOptions { - enable: true, - wait: wait_for_session, - })?; - - let server = crate::runtime::inspector::InspectorServer::new(addr, "nix-js") - .map_err(|e| Error::internal(e.to_string()))?; - server.register_inspector("nix-js".to_string(), runtime.inspector(), wait_for_session); - - let mut context = Self { - ctx, - runtime, - _inspector_server: Some(server), - }; - context.init()?; - Ok(context) - } - - #[cfg(feature = "inspector")] - pub fn wait_for_inspector_disconnect(&mut self) { - self.runtime.wait_for_inspector_disconnect(); - } - - fn init(&mut self) -> Result<()> { - const DERIVATION_NIX: &str = include_str!("runtime/corepkgs/derivation.nix"); - let source = Source::new_virtual( - "".into(), - DERIVATION_NIX.to_string(), - ); - let code = self.ctx.compile(source, None)?; - self.runtime.eval( - format!( - "Nix.builtins.set('derivation',({}));Nix.builtins.set('storeDir','{}');{}0n", - code, - self.get_store_dir(), - if std::env::var("NIX_JS_DEBUG_THUNKS").is_ok() { - "Nix.DEBUG_THUNKS.enabled=true;" - } else { - "" - } - ), - &mut self.ctx, - )?; - Ok(()) - } - - eval_bc!(eval, ForceMode::Force); - eval_bc!(eval_shallow, ForceMode::ForceShallow); - eval_bc!(eval_deep, ForceMode::ForceDeep); - pub fn eval_repl<'a>(&'a mut self, source: Source, scope: &'a HashSet) -> Result { - tracing::info!("Starting evaluation"); - - tracing::debug!("Compiling code"); - let code = self.ctx.compile(source, Some(Scope::Repl(scope)))?; - - tracing::debug!("Executing JavaScript"); - self.runtime - .eval(format!("Nix.forceShallow({})", code), &mut self.ctx) - } - - pub fn compile(&mut self, source: Source) -> Result { - self.ctx.compile(source, None) - } - - pub fn compile_bytecode(&mut self, source: Source) -> Result { - self.ctx.compile_bytecode(source) + pub fn eval_repl<'a>(&'a mut self, _source: Source, _scope: &'a HashSet) -> Result { + todo!() } pub fn disassemble(&self, bytecode: &Bytecode) -> String { - Disassembler::new(bytecode, &self.ctx).disassemble() + Disassembler::new(bytecode, self).disassemble() } pub fn disassemble_colored(&self, bytecode: &Bytecode) -> String { - Disassembler::new(bytecode, &self.ctx).disassemble_colored() - } - - pub fn get_store_dir(&self) -> &str { - self.ctx.get_store_dir() + Disassembler::new(bytecode, self).disassemble_colored() } pub fn add_binding<'a>( @@ -179,22 +73,11 @@ impl Context { expr: &str, scope: &'a mut HashSet, ) -> Result { - let source = Source::new_repl(expr.to_string())?; - let code = self.ctx.compile(source, Some(Scope::Repl(scope)))?; - - let sym = self.ctx.symbols.get_or_intern(name); - - let eval_and_store = format!( - "(()=>{{const __v=Nix.forceShallow({});Nix.setReplBinding(\"{}\",__v);return __v}})()", - code, name - ); - - scope.insert(sym); - self.runtime.eval(eval_and_store, &mut self.ctx) + todo!() } } -struct Ctx { +pub struct Context { symbols: DefaultStringInterner, global: HashMap>>, sources: Vec, @@ -226,8 +109,8 @@ impl OwnedIr { } } -impl Ctx { - fn new() -> Result { +impl Context { + pub fn new() -> Result { let mut symbols = DefaultStringInterner::new(); let mut global = HashMap::new(); let builtins_sym = symbols.get_or_intern("builtins"); @@ -349,33 +232,7 @@ impl Ctx { }) } - fn compile<'ctx>( - &'ctx mut self, - source: Source, - extra_scope: Option>, - ) -> Result { - let root = self.downgrade(source, extra_scope)?; - tracing::debug!("Generating JavaScript code"); - let code = compile::(root.as_ref(), self); - tracing::debug!("Generated code: {}", &code); - Ok(code) - } - - fn compile_scoped(&mut self, source: Source, scope: Vec) -> Result { - let scope = Scope::ScopedImport( - scope - .into_iter() - .map(|k| self.symbols.get_or_intern(k)) - .collect(), - ); - let root = self.downgrade(source, Some(scope))?; - tracing::debug!("Generating JavaScript code for scoped import"); - let code = compile::(root.as_ref(), self); - tracing::debug!("Generated scoped code: {}", &code); - Ok(code) - } - - fn compile_bytecode(&mut self, source: Source) -> Result { + pub fn compile_bytecode(&mut self, source: Source) -> Result { let root = self.downgrade(source, None)?; tracing::debug!("Generating bytecode"); let bytecode = bytecode::compile_bytecode(root.as_ref(), self); @@ -383,47 +240,12 @@ impl Ctx { Ok(bytecode) } - fn compile_bytecode_scoped(&mut self, source: Source, scope: Vec) -> Result { - let scope = Scope::ScopedImport( - scope - .into_iter() - .map(|k| self.symbols.get_or_intern(k)) - .collect(), - ); - let root = self.downgrade(source, Some(scope))?; - tracing::debug!("Generating bytecode for scoped import"); - Ok(bytecode::compile_bytecode_scoped(root.as_ref(), self)) - } -} - -impl CodegenContext for Ctx { - fn get_sym(&self, id: SymId) -> Symbol<'_> { - self.symbols - .resolve(id) - .expect("SymId out of bounds") - .into() - } - fn get_current_dir(&self) -> &std::path::Path { - self.get_current_dir() - } - fn get_current_source_id(&self) -> usize { - self.sources - .len() - .checked_sub(1) - .expect("current_source not set") - } - fn get_store_dir(&self) -> &str { + pub fn get_store_dir(&self) -> &str { self.store.get_store_dir() } - fn register_span(&self, range: rnix::TextRange) -> usize { - let spans = unsafe { &mut *self.spans.get() }; - let id = spans.len(); - spans.push((self.get_current_source_id(), range)); - id - } } -impl BytecodeContext for Ctx { +impl BytecodeContext for Context { fn intern_string(&mut self, s: &str) -> u32 { if let Some(&idx) = self.global_string_map.get(s) { return idx; @@ -445,7 +267,16 @@ impl BytecodeContext for Ctx { } fn register_span(&self, range: TextRange) -> u32 { - CodegenContext::register_span(self, range) as u32 + // FIXME: SAFETY + let spans = unsafe { &mut *self.spans.get() }; + let id = spans.len(); + let source_id = self + .sources + .len() + .checked_sub(1) + .expect("current_source not set"); + spans.push((source_id, range)); + id as u32 } fn get_sym(&self, id: SymId) -> &str { @@ -453,51 +284,11 @@ impl BytecodeContext for Ctx { } fn get_current_dir(&self) -> &Path { - Ctx::get_current_dir(self) + Context::get_current_dir(self) } } -impl RuntimeContext for Ctx { - fn get_current_dir(&self) -> &Path { - self.get_current_dir() - } - fn add_source(&mut self, source: Source) { - self.sources.push(source); - } - fn compile(&mut self, source: Source) -> Result { - self.compile(source, None) - } - fn compile_scoped(&mut self, source: Source, scope: Vec) -> Result { - self.compile_scoped(source, scope) - } - fn compile_bytecode(&mut self, source: Source) -> Result { - self.compile_bytecode(source) - } - fn compile_bytecode_scoped(&mut self, source: Source, scope: Vec) -> Result { - self.compile_bytecode_scoped(source, scope) - } - fn get_source(&self, id: usize) -> Source { - self.sources.get(id).expect("source not found").clone() - } - fn get_store(&self) -> &DaemonStore { - &self.store - } - fn get_span(&self, id: usize) -> (usize, TextRange) { - let spans = unsafe { &*self.spans.get() }; - spans[id] - } - fn get_unsynced(&mut self) -> (&[String], &[Constant], usize, usize) { - let strings_base = self.synced_strings; - let constants_base = self.synced_constants; - let new_strings = &self.global_strings[strings_base..]; - let new_constants = &self.global_constants[constants_base..]; - self.synced_strings = self.global_strings.len(); - self.synced_constants = self.global_constants.len(); - (new_strings, new_constants, strings_base, constants_base) - } -} - -impl DisassemblerContext for Ctx { +impl DisassemblerContext for Context { fn lookup_string(&self, id: u32) -> &str { self.global_strings .get(id as usize) diff --git a/nix-js/src/derivation.rs b/fix/src/derivation.rs similarity index 100% rename from nix-js/src/derivation.rs rename to fix/src/derivation.rs diff --git a/nix-js/src/disassembler.rs b/fix/src/disassembler.rs similarity index 100% rename from nix-js/src/disassembler.rs rename to fix/src/disassembler.rs diff --git a/nix-js/src/downgrade.rs b/fix/src/downgrade.rs similarity index 100% rename from nix-js/src/downgrade.rs rename to fix/src/downgrade.rs diff --git a/nix-js/src/error.rs b/fix/src/error.rs similarity index 63% rename from nix-js/src/error.rs rename to fix/src/error.rs index 9598e01..40fdb65 100644 --- a/nix-js/src/error.rs +++ b/fix/src/error.rs @@ -1,14 +1,9 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; -use deno_core::error::JsError; -use deno_error::JsErrorClass as _; -use itertools::Itertools as _; use miette::{Diagnostic, NamedSource, SourceSpan}; use thiserror::Error; -use crate::runtime::RuntimeContext; - pub type Result = core::result::Result>; #[derive(Clone, Debug)] @@ -229,127 +224,3 @@ pub struct StackFrame { #[source_code] pub src: NamedSource>, } - -const MAX_STACK_FRAMES: usize = 20; -const FRAMES_AT_START: usize = 15; -const FRAMES_AT_END: usize = 5; - -pub(crate) fn parse_js_error(error: Box, ctx: &impl RuntimeContext) -> Error { - let (span, src, frames) = if let Some(stack) = &error.stack { - let mut frames = parse_frames(stack, ctx); - - if let Some(last_frame) = frames.pop() { - ( - Some(text_range_to_source_span(last_frame.span)), - Some(last_frame.src.into()), - frames, - ) - } else { - (None, None, frames) - } - } else { - (None, None, Vec::new()) - }; - let stack_trace = if std::env::var("NIX_JS_STACK_TRACE").is_ok() { - truncate_stack_trace(frames) - } else { - Vec::new() - }; - let message = error.get_message().to_string(); - let js_backtrace = error.stack.map(|stack| { - stack - .lines() - .filter(|line| !line.starts_with("NIX_STACK_FRAME:")) - .join("\n") - }); - - Error::EvalError { - src, - span, - message, - js_backtrace, - stack_trace, - } -} - -struct NixStackFrame { - span: rnix::TextRange, - message: String, - src: Source, -} - -impl From for StackFrame { - fn from(NixStackFrame { span, message, src }: NixStackFrame) -> Self { - StackFrame { - span: text_range_to_source_span(span), - message, - src: src.into(), - } - } -} - -fn parse_frames(stack: &str, ctx: &impl RuntimeContext) -> Vec { - let mut frames = Vec::new(); - - for line in stack.lines() { - // Format: NIX_STACK_FRAME:span_id:message - let Some(rest) = line.strip_prefix("NIX_STACK_FRAME:") else { - continue; - }; - let parts: Vec<&str> = rest.splitn(2, ':').collect(); - - if parts.is_empty() { - continue; - } - - let span_id: usize = match parts[0].parse() { - Ok(id) => id, - Err(_) => continue, - }; - let (source_id, span) = ctx.get_span(span_id); - let src = ctx.get_source(source_id); - - let message = if parts.len() == 2 { - parts[1].to_string() - } else { - String::new() - }; - - frames.push(NixStackFrame { span, message, src }); - } - - frames.dedup_by(|a, b| a.span == b.span && a.message == b.message); - - frames -} - -fn truncate_stack_trace(frames: Vec) -> Vec { - let reversed: Vec<_> = frames.into_iter().rev().collect(); - let total = reversed.len(); - - if total <= MAX_STACK_FRAMES { - return reversed.into_iter().map(Into::into).collect(); - } - - let omitted_count = total - FRAMES_AT_START - FRAMES_AT_END; - - reversed - .into_iter() - .enumerate() - .filter_map(|(i, frame)| { - if i < FRAMES_AT_START { - Some(frame.into()) - } else if i == FRAMES_AT_START { - Some(StackFrame { - span: text_range_to_source_span(frame.span), - message: format!("... ({} more frames omitted)", omitted_count), - src: frame.src.into(), - }) - } else if i >= total - FRAMES_AT_END { - Some(frame.into()) - } else { - None - } - }) - .collect() -} diff --git a/nix-js/src/fetcher.rs b/fix/src/fetcher.rs similarity index 96% rename from nix-js/src/fetcher.rs rename to fix/src/fetcher.rs index 8fc7759..9717e7b 100644 --- a/nix-js/src/fetcher.rs +++ b/fix/src/fetcher.rs @@ -5,8 +5,6 @@ use nix_compat::nixhash::HashAlgo; use nix_compat::nixhash::NixHash; use tracing::{debug, info, warn}; -use crate::runtime::OpStateExt; -use crate::runtime::RuntimeContext; use crate::store::Store as _; mod archive; @@ -20,7 +18,6 @@ pub use download::Downloader; pub use metadata_cache::MetadataCache; use crate::nar; -use crate::runtime::NixRuntimeError; #[derive(ToV8)] pub struct FetchUrlResult { @@ -306,11 +303,3 @@ fn normalize_hash(hash: &str) -> String { } hash.to_string() } - -pub fn register_ops() -> Vec { - vec![ - op_fetch_url::(), - op_fetch_tarball::(), - op_fetch_git::(), - ] -} diff --git a/nix-js/src/fetcher/archive.rs b/fix/src/fetcher/archive.rs similarity index 100% rename from nix-js/src/fetcher/archive.rs rename to fix/src/fetcher/archive.rs diff --git a/nix-js/src/fetcher/cache.rs b/fix/src/fetcher/cache.rs similarity index 95% rename from nix-js/src/fetcher/cache.rs rename to fix/src/fetcher/cache.rs index 4a41d97..da53779 100644 --- a/nix-js/src/fetcher/cache.rs +++ b/fix/src/fetcher/cache.rs @@ -10,7 +10,7 @@ impl FetcherCache { pub fn new() -> Result { let base_dir = dirs::cache_dir() .unwrap_or_else(|| PathBuf::from("/tmp")) - .join("nix-js") + .join("fix") .join("fetchers"); fs::create_dir_all(&base_dir)?; diff --git a/nix-js/src/fetcher/download.rs b/fix/src/fetcher/download.rs similarity index 100% rename from nix-js/src/fetcher/download.rs rename to fix/src/fetcher/download.rs diff --git a/nix-js/src/fetcher/git.rs b/fix/src/fetcher/git.rs similarity index 100% rename from nix-js/src/fetcher/git.rs rename to fix/src/fetcher/git.rs diff --git a/nix-js/src/fetcher/metadata_cache.rs b/fix/src/fetcher/metadata_cache.rs similarity index 100% rename from nix-js/src/fetcher/metadata_cache.rs rename to fix/src/fetcher/metadata_cache.rs diff --git a/nix-js/src/ir.rs b/fix/src/ir.rs similarity index 100% rename from nix-js/src/ir.rs rename to fix/src/ir.rs diff --git a/nix-js/src/lib.rs b/fix/src/lib.rs similarity index 92% rename from nix-js/src/lib.rs rename to fix/src/lib.rs index 6e2ac4c..2db92f4 100644 --- a/nix-js/src/lib.rs +++ b/fix/src/lib.rs @@ -6,11 +6,10 @@ pub mod logging; pub mod value; mod bytecode; -mod codegen; mod derivation; mod disassembler; mod downgrade; -mod fetcher; +// mod fetcher; mod ir; mod nar; mod nix_utils; diff --git a/nix-js/src/logging.rs b/fix/src/logging.rs similarity index 100% rename from nix-js/src/logging.rs rename to fix/src/logging.rs diff --git a/nix-js/src/main.rs b/fix/src/main.rs similarity index 75% rename from nix-js/src/main.rs rename to fix/src/main.rs index b31a2ab..fe21d4c 100644 --- a/nix-js/src/main.rs +++ b/fix/src/main.rs @@ -4,22 +4,14 @@ use std::process::exit; use anyhow::Result; use clap::{Args, Parser, Subcommand}; use hashbrown::HashSet; -use nix_js::context::Context; -use nix_js::error::Source; +use fix::context::Context; +use fix::error::Source; use rustyline::DefaultEditor; use rustyline::error::ReadlineError; #[derive(Parser)] #[command(name = "nix-js", about = "Nix expression evaluator")] struct Cli { - #[cfg(feature = "inspector")] - #[arg(long, value_name = "HOST:PORT", num_args = 0..=1, default_missing_value = "127.0.0.1:9229")] - inspect: Option, - - #[cfg(feature = "inspector")] - #[arg(long, value_name = "HOST:PORT", num_args = 0..=1, default_missing_value = "127.0.0.1:9229")] - inspect_brk: Option, - #[command(subcommand)] command: Command, } @@ -48,27 +40,6 @@ struct ExprSource { file: Option, } -fn create_context(#[cfg(feature = "inspector")] cli: &Cli) -> Result { - #[cfg(feature = "inspector")] - { - let (addr_str, wait) = if let Some(ref addr) = cli.inspect_brk { - (Some(addr.as_str()), true) - } else if let Some(ref addr) = cli.inspect { - (Some(addr.as_str()), false) - } else { - (None, false) - }; - - if let Some(addr_str) = addr_str { - let addr: std::net::SocketAddr = addr_str - .parse() - .map_err(|e| anyhow::anyhow!("invalid inspector address '{}': {}", addr_str, e))?; - return Ok(Context::new_with_inspector(addr, wait)?); - } - } - Ok(Context::new()?) -} - fn run_compile(context: &mut Context, src: ExprSource, silent: bool) -> Result<()> { let src = if let Some(expr) = src.expr { Source::new_eval(expr)? @@ -88,8 +59,6 @@ fn run_compile(context: &mut Context, src: ExprSource, silent: bool) -> Result<( exit(1); } }; - #[cfg(feature = "inspector")] - context.wait_for_inspector_disconnect(); Ok(()) } @@ -110,8 +79,6 @@ fn run_eval(context: &mut Context, src: ExprSource) -> Result<()> { exit(1); } }; - #[cfg(feature = "inspector")] - context.wait_for_inspector_disconnect(); Ok(()) } @@ -170,14 +137,11 @@ fn run_repl(context: &mut Context) -> Result<()> { } fn main() -> Result<()> { - nix_js::logging::init_logging(); + fix::logging::init_logging(); let cli = Cli::parse(); - let mut context = create_context( - #[cfg(feature = "inspector")] - &cli, - )?; + let mut context = Context::new()?; match cli.command { Command::Compile { source, silent } => run_compile(&mut context, source, silent), diff --git a/nix-js/src/nar.rs b/fix/src/nar.rs similarity index 100% rename from nix-js/src/nar.rs rename to fix/src/nar.rs diff --git a/nix-js/src/nix_utils.rs b/fix/src/nix_utils.rs similarity index 100% rename from nix-js/src/nix_utils.rs rename to fix/src/nix_utils.rs diff --git a/nix-js/tests/tests/lang/eval-okay-hash.exp b/fix/src/runtime.rs similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-hash.exp rename to fix/src/runtime.rs diff --git a/nix-js/src/runtime/corepkgs/derivation.nix b/fix/src/runtime/corepkgs/derivation.nix similarity index 100% rename from nix-js/src/runtime/corepkgs/derivation.nix rename to fix/src/runtime/corepkgs/derivation.nix diff --git a/nix-js/src/runtime/corepkgs/fetchurl.nix b/fix/src/runtime/corepkgs/fetchurl.nix similarity index 100% rename from nix-js/src/runtime/corepkgs/fetchurl.nix rename to fix/src/runtime/corepkgs/fetchurl.nix diff --git a/nix-js/src/store.rs b/fix/src/store.rs similarity index 100% rename from nix-js/src/store.rs rename to fix/src/store.rs diff --git a/nix-js/src/store/config.rs b/fix/src/store/config.rs similarity index 100% rename from nix-js/src/store/config.rs rename to fix/src/store/config.rs diff --git a/nix-js/src/store/daemon.rs b/fix/src/store/daemon.rs similarity index 100% rename from nix-js/src/store/daemon.rs rename to fix/src/store/daemon.rs diff --git a/nix-js/src/store/error.rs b/fix/src/store/error.rs similarity index 100% rename from nix-js/src/store/error.rs rename to fix/src/store/error.rs diff --git a/nix-js/src/store/validation.rs b/fix/src/store/validation.rs similarity index 100% rename from nix-js/src/store/validation.rs rename to fix/src/store/validation.rs diff --git a/nix-js/src/string_context.rs b/fix/src/string_context.rs similarity index 100% rename from nix-js/src/string_context.rs rename to fix/src/string_context.rs diff --git a/nix-js/src/value.rs b/fix/src/value.rs similarity index 100% rename from nix-js/src/value.rs rename to fix/src/value.rs diff --git a/nix-js/tests/tests/basic_eval.rs b/fix/tests/tests/basic_eval.rs similarity index 98% rename from nix-js/tests/tests/basic_eval.rs rename to fix/tests/tests/basic_eval.rs index 6a00e44..5fd7f60 100644 --- a/nix-js/tests/tests/basic_eval.rs +++ b/fix/tests/tests/basic_eval.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::{eval, eval_result}; diff --git a/nix-js/tests/tests/builtins.rs b/fix/tests/tests/builtins.rs similarity index 99% rename from nix-js/tests/tests/builtins.rs rename to fix/tests/tests/builtins.rs index 6cd944b..c4af9c3 100644 --- a/nix-js/tests/tests/builtins.rs +++ b/fix/tests/tests/builtins.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use nix_js::value::{AttrSet, List, Value}; +use fix::value::{AttrSet, List, Value}; use crate::utils::eval; diff --git a/nix-js/tests/tests/builtins_store.rs b/fix/tests/tests/builtins_store.rs similarity index 99% rename from nix-js/tests/tests/builtins_store.rs rename to fix/tests/tests/builtins_store.rs index 1c21414..224cb49 100644 --- a/nix-js/tests/tests/builtins_store.rs +++ b/fix/tests/tests/builtins_store.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::eval_result; diff --git a/nix-js/tests/tests/derivation.rs b/fix/tests/tests/derivation.rs similarity index 99% rename from nix-js/tests/tests/derivation.rs rename to fix/tests/tests/derivation.rs index 5eb2937..d1f8f70 100644 --- a/nix-js/tests/tests/derivation.rs +++ b/fix/tests/tests/derivation.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::{eval_deep, eval_deep_result}; diff --git a/nix-js/tests/tests/findfile.rs b/fix/tests/tests/findfile.rs similarity index 100% rename from nix-js/tests/tests/findfile.rs rename to fix/tests/tests/findfile.rs diff --git a/nix-js/tests/tests/free_globals.rs b/fix/tests/tests/free_globals.rs similarity index 97% rename from nix-js/tests/tests/free_globals.rs rename to fix/tests/tests/free_globals.rs index 6f7b13e..1eebca5 100644 --- a/nix-js/tests/tests/free_globals.rs +++ b/fix/tests/tests/free_globals.rs @@ -1,4 +1,4 @@ -use nix_js::value::{List, Value}; +use fix::value::{List, Value}; use crate::utils::{eval, eval_result}; diff --git a/nix-js/tests/tests/functions.rs b/fix/tests/tests/functions.rs similarity index 99% rename from nix-js/tests/tests/functions.rs rename to fix/tests/tests/functions.rs index 5bf9199..b354c57 100644 --- a/nix-js/tests/tests/functions.rs +++ b/fix/tests/tests/functions.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::{eval, eval_result}; diff --git a/nix-js/tests/tests/io_operations.rs b/fix/tests/tests/io_operations.rs similarity index 99% rename from nix-js/tests/tests/io_operations.rs rename to fix/tests/tests/io_operations.rs index a22e4c5..f83b04f 100644 --- a/nix-js/tests/tests/io_operations.rs +++ b/fix/tests/tests/io_operations.rs @@ -1,6 +1,6 @@ -use nix_js::context::Context; -use nix_js::error::Source; -use nix_js::value::Value; +use fix::context::Context; +use fix::error::Source; +use fix::value::Value; use crate::utils::{eval, eval_result}; diff --git a/nix-js/tests/tests/lang.rs b/fix/tests/tests/lang.rs similarity index 98% rename from nix-js/tests/tests/lang.rs rename to fix/tests/tests/lang.rs index b1597f3..2362f95 100644 --- a/nix-js/tests/tests/lang.rs +++ b/fix/tests/tests/lang.rs @@ -2,9 +2,9 @@ use std::path::PathBuf; -use nix_js::context::Context; -use nix_js::error::Source; -use nix_js::value::Value; +use fix::context::Context; +use fix::error::Source; +use fix::value::Value; fn get_lang_dir() -> PathBuf { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/tests/lang") @@ -18,7 +18,7 @@ fn eval_file(name: &str) -> Result<(Value, Source), String> { let mut ctx = Context::new().map_err(|e| e.to_string())?; let source = Source { - ty: nix_js::error::SourceType::File(nix_path.into()), + ty: fix::error::SourceType::File(nix_path.into()), src: expr.into(), }; ctx.eval_deep(source.clone()) diff --git a/nix-js/tests/tests/lang/binary-data b/fix/tests/tests/lang/binary-data similarity index 100% rename from nix-js/tests/tests/lang/binary-data rename to fix/tests/tests/lang/binary-data diff --git a/nix-js/tests/tests/lang/data b/fix/tests/tests/lang/data similarity index 100% rename from nix-js/tests/tests/lang/data rename to fix/tests/tests/lang/data diff --git a/nix-js/tests/tests/lang/dir1/a.nix b/fix/tests/tests/lang/dir1/a.nix similarity index 100% rename from nix-js/tests/tests/lang/dir1/a.nix rename to fix/tests/tests/lang/dir1/a.nix diff --git a/nix-js/tests/tests/lang/dir2/a.nix b/fix/tests/tests/lang/dir2/a.nix similarity index 100% rename from nix-js/tests/tests/lang/dir2/a.nix rename to fix/tests/tests/lang/dir2/a.nix diff --git a/nix-js/tests/tests/lang/dir2/b.nix b/fix/tests/tests/lang/dir2/b.nix similarity index 100% rename from nix-js/tests/tests/lang/dir2/b.nix rename to fix/tests/tests/lang/dir2/b.nix diff --git a/nix-js/tests/tests/lang/dir3/a.nix b/fix/tests/tests/lang/dir3/a.nix similarity index 100% rename from nix-js/tests/tests/lang/dir3/a.nix rename to fix/tests/tests/lang/dir3/a.nix diff --git a/nix-js/tests/tests/lang/dir3/b.nix b/fix/tests/tests/lang/dir3/b.nix similarity index 100% rename from nix-js/tests/tests/lang/dir3/b.nix rename to fix/tests/tests/lang/dir3/b.nix diff --git a/nix-js/tests/tests/lang/dir3/c.nix b/fix/tests/tests/lang/dir3/c.nix similarity index 100% rename from nix-js/tests/tests/lang/dir3/c.nix rename to fix/tests/tests/lang/dir3/c.nix diff --git a/nix-js/tests/tests/lang/dir4/a.nix b/fix/tests/tests/lang/dir4/a.nix similarity index 100% rename from nix-js/tests/tests/lang/dir4/a.nix rename to fix/tests/tests/lang/dir4/a.nix diff --git a/nix-js/tests/tests/lang/dir4/c.nix b/fix/tests/tests/lang/dir4/c.nix similarity index 100% rename from nix-js/tests/tests/lang/dir4/c.nix rename to fix/tests/tests/lang/dir4/c.nix diff --git a/nix-js/tests/tests/lang/eval-fail-abort.err.exp b/fix/tests/tests/lang/eval-fail-abort.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-abort.err.exp rename to fix/tests/tests/lang/eval-fail-abort.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-abort.nix b/fix/tests/tests/lang/eval-fail-abort.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-abort.nix rename to fix/tests/tests/lang/eval-fail-abort.nix diff --git a/nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.err.exp b/fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.err.exp rename to fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.nix b/fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.nix rename to fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-empty-context.nix diff --git a/nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.err.exp b/fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.err.exp rename to fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.nix b/fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.nix rename to fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-multi-elem-context.nix diff --git a/nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.err.exp b/fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.err.exp rename to fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.nix b/fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.nix rename to fix/tests/tests/lang/eval-fail-addDrvOutputDependencies-wrong-element-kind.nix diff --git a/nix-js/tests/tests/lang/eval-fail-addErrorContext-example.err.exp b/fix/tests/tests/lang/eval-fail-addErrorContext-example.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addErrorContext-example.err.exp rename to fix/tests/tests/lang/eval-fail-addErrorContext-example.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-addErrorContext-example.nix b/fix/tests/tests/lang/eval-fail-addErrorContext-example.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-addErrorContext-example.nix rename to fix/tests/tests/lang/eval-fail-addErrorContext-example.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.nix b/fix/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-attrs-names-2.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-attrs-names.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-attrs-names.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names.nix b/fix/tests/tests/lang/eval-fail-assert-equal-attrs-names.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-attrs-names.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-attrs-names.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-derivations-extra.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-derivations-extra.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-derivations-extra.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-derivations-extra.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-derivations-extra.nix b/fix/tests/tests/lang/eval-fail-assert-equal-derivations-extra.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-derivations-extra.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-derivations-extra.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-derivations.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-derivations.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-derivations.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-derivations.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-derivations.nix b/fix/tests/tests/lang/eval-fail-assert-equal-derivations.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-derivations.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-derivations.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-floats.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-floats.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-floats.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-floats.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-floats.nix b/fix/tests/tests/lang/eval-fail-assert-equal-floats.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-floats.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-floats.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-function-direct.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-function-direct.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-function-direct.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-function-direct.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-function-direct.nix b/fix/tests/tests/lang/eval-fail-assert-equal-function-direct.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-function-direct.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-function-direct.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-int-float.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-int-float.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-int-float.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-int-float.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-int-float.nix b/fix/tests/tests/lang/eval-fail-assert-equal-int-float.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-int-float.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-int-float.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-ints.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-ints.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-ints.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-ints.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-ints.nix b/fix/tests/tests/lang/eval-fail-assert-equal-ints.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-ints.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-ints.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-list-length.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-list-length.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-list-length.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-list-length.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-list-length.nix b/fix/tests/tests/lang/eval-fail-assert-equal-list-length.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-list-length.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-list-length.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-paths.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-paths.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-paths.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-paths.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-paths.nix b/fix/tests/tests/lang/eval-fail-assert-equal-paths.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-paths.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-paths.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-type-nested.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-type-nested.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-type-nested.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-type-nested.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-type-nested.nix b/fix/tests/tests/lang/eval-fail-assert-equal-type-nested.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-type-nested.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-type-nested.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-type.err.exp b/fix/tests/tests/lang/eval-fail-assert-equal-type.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-type.err.exp rename to fix/tests/tests/lang/eval-fail-assert-equal-type.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-equal-type.nix b/fix/tests/tests/lang/eval-fail-assert-equal-type.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-equal-type.nix rename to fix/tests/tests/lang/eval-fail-assert-equal-type.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert-nested-bool.err.exp b/fix/tests/tests/lang/eval-fail-assert-nested-bool.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-nested-bool.err.exp rename to fix/tests/tests/lang/eval-fail-assert-nested-bool.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert-nested-bool.nix b/fix/tests/tests/lang/eval-fail-assert-nested-bool.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert-nested-bool.nix rename to fix/tests/tests/lang/eval-fail-assert-nested-bool.nix diff --git a/nix-js/tests/tests/lang/eval-fail-assert.err.exp b/fix/tests/tests/lang/eval-fail-assert.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert.err.exp rename to fix/tests/tests/lang/eval-fail-assert.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-assert.nix b/fix/tests/tests/lang/eval-fail-assert.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-assert.nix rename to fix/tests/tests/lang/eval-fail-assert.nix diff --git a/nix-js/tests/tests/lang/eval-fail-attr-name-type.err.exp b/fix/tests/tests/lang/eval-fail-attr-name-type.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-attr-name-type.err.exp rename to fix/tests/tests/lang/eval-fail-attr-name-type.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-attr-name-type.nix b/fix/tests/tests/lang/eval-fail-attr-name-type.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-attr-name-type.nix rename to fix/tests/tests/lang/eval-fail-attr-name-type.nix diff --git a/nix-js/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.err.exp b/fix/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.err.exp rename to fix/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.nix b/fix/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.nix rename to fix/tests/tests/lang/eval-fail-attrset-merge-drops-later-rec.nix diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-1.err.exp b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-1.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-1.err.exp rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-1.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-1.nix b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-1.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-1.nix rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-1.nix diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-2.err.exp b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-2.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-2.err.exp rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-2.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-2.nix b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-2.nix rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-2.nix diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-3.err.exp b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-3.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-3.err.exp rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-3.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-3.nix b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-3.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-3.nix rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-3.nix diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-4.err.exp b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-4.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-4.err.exp rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-4.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-4.nix b/fix/tests/tests/lang/eval-fail-bad-string-interpolation-4.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-bad-string-interpolation-4.nix rename to fix/tests/tests/lang/eval-fail-bad-string-interpolation-4.nix diff --git a/nix-js/tests/tests/lang/eval-fail-blackhole.err.exp b/fix/tests/tests/lang/eval-fail-blackhole.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-blackhole.err.exp rename to fix/tests/tests/lang/eval-fail-blackhole.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-blackhole.nix b/fix/tests/tests/lang/eval-fail-blackhole.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-blackhole.nix rename to fix/tests/tests/lang/eval-fail-blackhole.nix diff --git a/nix-js/tests/tests/lang/eval-fail-call-primop.err.exp b/fix/tests/tests/lang/eval-fail-call-primop.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-call-primop.err.exp rename to fix/tests/tests/lang/eval-fail-call-primop.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-call-primop.nix b/fix/tests/tests/lang/eval-fail-call-primop.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-call-primop.nix rename to fix/tests/tests/lang/eval-fail-call-primop.nix diff --git a/nix-js/tests/tests/lang/eval-fail-deepseq.err.exp b/fix/tests/tests/lang/eval-fail-deepseq.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-deepseq.err.exp rename to fix/tests/tests/lang/eval-fail-deepseq.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-deepseq.nix b/fix/tests/tests/lang/eval-fail-deepseq.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-deepseq.nix rename to fix/tests/tests/lang/eval-fail-deepseq.nix diff --git a/nix-js/tests/tests/lang/eval-fail-derivation-name.err.exp b/fix/tests/tests/lang/eval-fail-derivation-name.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-derivation-name.err.exp rename to fix/tests/tests/lang/eval-fail-derivation-name.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-derivation-name.nix b/fix/tests/tests/lang/eval-fail-derivation-name.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-derivation-name.nix rename to fix/tests/tests/lang/eval-fail-derivation-name.nix diff --git a/nix-js/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp b/fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp rename to fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix b/fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix rename to fix/tests/tests/lang/eval-fail-dup-dynamic-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-fail-duplicate-traces.err.exp b/fix/tests/tests/lang/eval-fail-duplicate-traces.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-duplicate-traces.err.exp rename to fix/tests/tests/lang/eval-fail-duplicate-traces.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-duplicate-traces.nix b/fix/tests/tests/lang/eval-fail-duplicate-traces.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-duplicate-traces.nix rename to fix/tests/tests/lang/eval-fail-duplicate-traces.nix diff --git a/nix-js/tests/tests/lang/eval-fail-eol-1.err.exp b/fix/tests/tests/lang/eval-fail-eol-1.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-eol-1.err.exp rename to fix/tests/tests/lang/eval-fail-eol-1.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-eol-1.nix b/fix/tests/tests/lang/eval-fail-eol-1.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-eol-1.nix rename to fix/tests/tests/lang/eval-fail-eol-1.nix diff --git a/nix-js/tests/tests/lang/eval-fail-eol-2.err.exp b/fix/tests/tests/lang/eval-fail-eol-2.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-eol-2.err.exp rename to fix/tests/tests/lang/eval-fail-eol-2.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-eol-2.nix b/fix/tests/tests/lang/eval-fail-eol-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-eol-2.nix rename to fix/tests/tests/lang/eval-fail-eol-2.nix diff --git a/nix-js/tests/tests/lang/eval-fail-eol-3.err.exp b/fix/tests/tests/lang/eval-fail-eol-3.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-eol-3.err.exp rename to fix/tests/tests/lang/eval-fail-eol-3.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-eol-3.nix b/fix/tests/tests/lang/eval-fail-eol-3.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-eol-3.nix rename to fix/tests/tests/lang/eval-fail-eol-3.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fetchTree-negative.err.exp b/fix/tests/tests/lang/eval-fail-fetchTree-negative.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchTree-negative.err.exp rename to fix/tests/tests/lang/eval-fail-fetchTree-negative.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fetchTree-negative.nix b/fix/tests/tests/lang/eval-fail-fetchTree-negative.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchTree-negative.nix rename to fix/tests/tests/lang/eval-fail-fetchTree-negative.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.err.exp b/fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.err.exp rename to fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.nix b/fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.nix rename to fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs-name.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.err.exp b/fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.err.exp rename to fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.nix b/fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.nix rename to fix/tests/tests/lang/eval-fail-fetchurl-baseName-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp b/fix/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp rename to fix/tests/tests/lang/eval-fail-fetchurl-baseName.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fetchurl-baseName.nix b/fix/tests/tests/lang/eval-fail-fetchurl-baseName.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fetchurl-baseName.nix rename to fix/tests/tests/lang/eval-fail-fetchurl-baseName.nix diff --git a/nix-js/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.err.exp b/fix/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.err.exp rename to fix/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.nix b/fix/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.nix rename to fix/tests/tests/lang/eval-fail-flake-ref-to-string-negative-integer.nix diff --git a/nix-js/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.err.exp b/fix/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.err.exp rename to fix/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.nix b/fix/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.nix rename to fix/tests/tests/lang/eval-fail-foldlStrict-strict-op-application.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.err.exp b/fix/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.err.exp rename to fix/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.nix b/fix/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.nix rename to fix/tests/tests/lang/eval-fail-fromJSON-keyWithNullByte.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fromJSON-overflowing.err.exp b/fix/tests/tests/lang/eval-fail-fromJSON-overflowing.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromJSON-overflowing.err.exp rename to fix/tests/tests/lang/eval-fail-fromJSON-overflowing.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fromJSON-overflowing.nix b/fix/tests/tests/lang/eval-fail-fromJSON-overflowing.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromJSON-overflowing.nix rename to fix/tests/tests/lang/eval-fail-fromJSON-overflowing.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.err.exp b/fix/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.err.exp rename to fix/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.nix b/fix/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.nix rename to fix/tests/tests/lang/eval-fail-fromJSON-valueWithNullByte.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.err.exp b/fix/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.err.exp rename to fix/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.nix b/fix/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.nix rename to fix/tests/tests/lang/eval-fail-fromTOML-keyWithNullByte.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fromTOML-timestamps.err.exp b/fix/tests/tests/lang/eval-fail-fromTOML-timestamps.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromTOML-timestamps.err.exp rename to fix/tests/tests/lang/eval-fail-fromTOML-timestamps.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fromTOML-timestamps.nix b/fix/tests/tests/lang/eval-fail-fromTOML-timestamps.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromTOML-timestamps.nix rename to fix/tests/tests/lang/eval-fail-fromTOML-timestamps.nix diff --git a/nix-js/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.err.exp b/fix/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.err.exp rename to fix/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.nix b/fix/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.nix rename to fix/tests/tests/lang/eval-fail-fromTOML-valueWithNullByte.nix diff --git a/nix-js/tests/tests/lang/eval-fail-hashfile-missing.err.exp b/fix/tests/tests/lang/eval-fail-hashfile-missing.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-hashfile-missing.err.exp rename to fix/tests/tests/lang/eval-fail-hashfile-missing.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-hashfile-missing.nix b/fix/tests/tests/lang/eval-fail-hashfile-missing.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-hashfile-missing.nix rename to fix/tests/tests/lang/eval-fail-hashfile-missing.nix diff --git a/nix-js/tests/tests/lang/eval-fail-infinite-recursion-lambda.err.exp b/fix/tests/tests/lang/eval-fail-infinite-recursion-lambda.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-infinite-recursion-lambda.err.exp rename to fix/tests/tests/lang/eval-fail-infinite-recursion-lambda.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-infinite-recursion-lambda.nix b/fix/tests/tests/lang/eval-fail-infinite-recursion-lambda.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-infinite-recursion-lambda.nix rename to fix/tests/tests/lang/eval-fail-infinite-recursion-lambda.nix diff --git a/nix-js/tests/tests/lang/eval-fail-list.err.exp b/fix/tests/tests/lang/eval-fail-list.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-list.err.exp rename to fix/tests/tests/lang/eval-fail-list.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-list.nix b/fix/tests/tests/lang/eval-fail-list.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-list.nix rename to fix/tests/tests/lang/eval-fail-list.nix diff --git a/nix-js/tests/tests/lang/eval-fail-missing-arg.err.exp b/fix/tests/tests/lang/eval-fail-missing-arg.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-missing-arg.err.exp rename to fix/tests/tests/lang/eval-fail-missing-arg.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-missing-arg.nix b/fix/tests/tests/lang/eval-fail-missing-arg.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-missing-arg.nix rename to fix/tests/tests/lang/eval-fail-missing-arg.nix diff --git a/nix-js/tests/tests/lang/eval-fail-mutual-recursion.err.exp b/fix/tests/tests/lang/eval-fail-mutual-recursion.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-mutual-recursion.err.exp rename to fix/tests/tests/lang/eval-fail-mutual-recursion.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-mutual-recursion.nix b/fix/tests/tests/lang/eval-fail-mutual-recursion.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-mutual-recursion.nix rename to fix/tests/tests/lang/eval-fail-mutual-recursion.nix diff --git a/nix-js/tests/tests/lang/eval-fail-nested-list-items.err.exp b/fix/tests/tests/lang/eval-fail-nested-list-items.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-nested-list-items.err.exp rename to fix/tests/tests/lang/eval-fail-nested-list-items.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-nested-list-items.nix b/fix/tests/tests/lang/eval-fail-nested-list-items.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-nested-list-items.nix rename to fix/tests/tests/lang/eval-fail-nested-list-items.nix diff --git a/nix-js/tests/tests/lang/eval-fail-nonexist-path.err.exp b/fix/tests/tests/lang/eval-fail-nonexist-path.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-nonexist-path.err.exp rename to fix/tests/tests/lang/eval-fail-nonexist-path.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-nonexist-path.nix b/fix/tests/tests/lang/eval-fail-nonexist-path.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-nonexist-path.nix rename to fix/tests/tests/lang/eval-fail-nonexist-path.nix diff --git a/nix-js/tests/tests/lang/eval-fail-not-throws.err.exp b/fix/tests/tests/lang/eval-fail-not-throws.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-not-throws.err.exp rename to fix/tests/tests/lang/eval-fail-not-throws.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-not-throws.nix b/fix/tests/tests/lang/eval-fail-not-throws.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-not-throws.nix rename to fix/tests/tests/lang/eval-fail-not-throws.nix diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-add.err.exp b/fix/tests/tests/lang/eval-fail-overflowing-add.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-add.err.exp rename to fix/tests/tests/lang/eval-fail-overflowing-add.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-add.nix b/fix/tests/tests/lang/eval-fail-overflowing-add.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-add.nix rename to fix/tests/tests/lang/eval-fail-overflowing-add.nix diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-div.err.exp b/fix/tests/tests/lang/eval-fail-overflowing-div.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-div.err.exp rename to fix/tests/tests/lang/eval-fail-overflowing-div.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-div.nix b/fix/tests/tests/lang/eval-fail-overflowing-div.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-div.nix rename to fix/tests/tests/lang/eval-fail-overflowing-div.nix diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-mul.err.exp b/fix/tests/tests/lang/eval-fail-overflowing-mul.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-mul.err.exp rename to fix/tests/tests/lang/eval-fail-overflowing-mul.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-mul.nix b/fix/tests/tests/lang/eval-fail-overflowing-mul.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-mul.nix rename to fix/tests/tests/lang/eval-fail-overflowing-mul.nix diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-sub.err.exp b/fix/tests/tests/lang/eval-fail-overflowing-sub.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-sub.err.exp rename to fix/tests/tests/lang/eval-fail-overflowing-sub.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-overflowing-sub.nix b/fix/tests/tests/lang/eval-fail-overflowing-sub.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-overflowing-sub.nix rename to fix/tests/tests/lang/eval-fail-overflowing-sub.nix diff --git a/nix-js/tests/tests/lang/eval-fail-path-slash.err.exp b/fix/tests/tests/lang/eval-fail-path-slash.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-path-slash.err.exp rename to fix/tests/tests/lang/eval-fail-path-slash.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-path-slash.nix b/fix/tests/tests/lang/eval-fail-path-slash.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-path-slash.nix rename to fix/tests/tests/lang/eval-fail-path-slash.nix diff --git a/nix-js/tests/tests/lang/eval-fail-pipe-operators.err.exp b/fix/tests/tests/lang/eval-fail-pipe-operators.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-pipe-operators.err.exp rename to fix/tests/tests/lang/eval-fail-pipe-operators.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-pipe-operators.nix b/fix/tests/tests/lang/eval-fail-pipe-operators.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-pipe-operators.nix rename to fix/tests/tests/lang/eval-fail-pipe-operators.nix diff --git a/nix-js/tests/tests/lang/eval-fail-recursion.err.exp b/fix/tests/tests/lang/eval-fail-recursion.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-recursion.err.exp rename to fix/tests/tests/lang/eval-fail-recursion.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-recursion.nix b/fix/tests/tests/lang/eval-fail-recursion.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-recursion.nix rename to fix/tests/tests/lang/eval-fail-recursion.nix diff --git a/nix-js/tests/tests/lang/eval-fail-remove.err.exp b/fix/tests/tests/lang/eval-fail-remove.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-remove.err.exp rename to fix/tests/tests/lang/eval-fail-remove.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-remove.nix b/fix/tests/tests/lang/eval-fail-remove.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-remove.nix rename to fix/tests/tests/lang/eval-fail-remove.nix diff --git a/nix-js/tests/tests/lang/eval-fail-scope-5.err.exp b/fix/tests/tests/lang/eval-fail-scope-5.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-scope-5.err.exp rename to fix/tests/tests/lang/eval-fail-scope-5.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-scope-5.nix b/fix/tests/tests/lang/eval-fail-scope-5.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-scope-5.nix rename to fix/tests/tests/lang/eval-fail-scope-5.nix diff --git a/nix-js/tests/tests/lang/eval-fail-seq.err.exp b/fix/tests/tests/lang/eval-fail-seq.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-seq.err.exp rename to fix/tests/tests/lang/eval-fail-seq.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-seq.nix b/fix/tests/tests/lang/eval-fail-seq.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-seq.nix rename to fix/tests/tests/lang/eval-fail-seq.nix diff --git a/nix-js/tests/tests/lang/eval-fail-set-override.err.exp b/fix/tests/tests/lang/eval-fail-set-override.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-set-override.err.exp rename to fix/tests/tests/lang/eval-fail-set-override.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-set-override.nix b/fix/tests/tests/lang/eval-fail-set-override.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-set-override.nix rename to fix/tests/tests/lang/eval-fail-set-override.nix diff --git a/nix-js/tests/tests/lang/eval-fail-set.err.exp b/fix/tests/tests/lang/eval-fail-set.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-set.err.exp rename to fix/tests/tests/lang/eval-fail-set.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-set.nix b/fix/tests/tests/lang/eval-fail-set.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-set.nix rename to fix/tests/tests/lang/eval-fail-set.nix diff --git a/nix-js/tests/tests/lang/eval-fail-string-nul-1.err.exp b/fix/tests/tests/lang/eval-fail-string-nul-1.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-string-nul-1.err.exp rename to fix/tests/tests/lang/eval-fail-string-nul-1.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-string-nul-1.nix b/fix/tests/tests/lang/eval-fail-string-nul-1.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-string-nul-1.nix rename to fix/tests/tests/lang/eval-fail-string-nul-1.nix diff --git a/nix-js/tests/tests/lang/eval-fail-string-nul-2.err.exp b/fix/tests/tests/lang/eval-fail-string-nul-2.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-string-nul-2.err.exp rename to fix/tests/tests/lang/eval-fail-string-nul-2.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-string-nul-2.nix b/fix/tests/tests/lang/eval-fail-string-nul-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-string-nul-2.nix rename to fix/tests/tests/lang/eval-fail-string-nul-2.nix diff --git a/nix-js/tests/tests/lang/eval-fail-substring.err.exp b/fix/tests/tests/lang/eval-fail-substring.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-substring.err.exp rename to fix/tests/tests/lang/eval-fail-substring.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-substring.nix b/fix/tests/tests/lang/eval-fail-substring.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-substring.nix rename to fix/tests/tests/lang/eval-fail-substring.nix diff --git a/nix-js/tests/tests/lang/eval-fail-to-path.err.exp b/fix/tests/tests/lang/eval-fail-to-path.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-to-path.err.exp rename to fix/tests/tests/lang/eval-fail-to-path.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-to-path.nix b/fix/tests/tests/lang/eval-fail-to-path.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-to-path.nix rename to fix/tests/tests/lang/eval-fail-to-path.nix diff --git a/nix-js/tests/tests/lang/eval-fail-toJSON-non-utf-8.err.exp b/fix/tests/tests/lang/eval-fail-toJSON-non-utf-8.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-toJSON-non-utf-8.err.exp rename to fix/tests/tests/lang/eval-fail-toJSON-non-utf-8.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-toJSON-non-utf-8.nix b/fix/tests/tests/lang/eval-fail-toJSON-non-utf-8.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-toJSON-non-utf-8.nix rename to fix/tests/tests/lang/eval-fail-toJSON-non-utf-8.nix diff --git a/nix-js/tests/tests/lang/eval-fail-toJSON.err.exp b/fix/tests/tests/lang/eval-fail-toJSON.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-toJSON.err.exp rename to fix/tests/tests/lang/eval-fail-toJSON.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-toJSON.nix b/fix/tests/tests/lang/eval-fail-toJSON.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-toJSON.nix rename to fix/tests/tests/lang/eval-fail-toJSON.nix diff --git a/nix-js/tests/tests/lang/eval-fail-undeclared-arg.err.exp b/fix/tests/tests/lang/eval-fail-undeclared-arg.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-undeclared-arg.err.exp rename to fix/tests/tests/lang/eval-fail-undeclared-arg.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-undeclared-arg.nix b/fix/tests/tests/lang/eval-fail-undeclared-arg.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-undeclared-arg.nix rename to fix/tests/tests/lang/eval-fail-undeclared-arg.nix diff --git a/nix-js/tests/tests/lang/eval-fail-using-set-as-attr-name.err.exp b/fix/tests/tests/lang/eval-fail-using-set-as-attr-name.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-using-set-as-attr-name.err.exp rename to fix/tests/tests/lang/eval-fail-using-set-as-attr-name.err.exp diff --git a/nix-js/tests/tests/lang/eval-fail-using-set-as-attr-name.nix b/fix/tests/tests/lang/eval-fail-using-set-as-attr-name.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-fail-using-set-as-attr-name.nix rename to fix/tests/tests/lang/eval-fail-using-set-as-attr-name.nix diff --git a/nix-js/tests/tests/lang/eval-okay-any-all.exp b/fix/tests/tests/lang/eval-okay-any-all.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-any-all.exp rename to fix/tests/tests/lang/eval-okay-any-all.exp diff --git a/nix-js/tests/tests/lang/eval-okay-any-all.nix b/fix/tests/tests/lang/eval-okay-any-all.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-any-all.nix rename to fix/tests/tests/lang/eval-okay-any-all.nix diff --git a/nix-js/tests/tests/lang/eval-okay-arithmetic.exp b/fix/tests/tests/lang/eval-okay-arithmetic.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-arithmetic.exp rename to fix/tests/tests/lang/eval-okay-arithmetic.exp diff --git a/nix-js/tests/tests/lang/eval-okay-arithmetic.nix b/fix/tests/tests/lang/eval-okay-arithmetic.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-arithmetic.nix rename to fix/tests/tests/lang/eval-okay-arithmetic.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrnames.exp b/fix/tests/tests/lang/eval-okay-attrnames.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrnames.exp rename to fix/tests/tests/lang/eval-okay-attrnames.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrnames.nix b/fix/tests/tests/lang/eval-okay-attrnames.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrnames.nix rename to fix/tests/tests/lang/eval-okay-attrnames.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrs.exp b/fix/tests/tests/lang/eval-okay-attrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs.exp rename to fix/tests/tests/lang/eval-okay-attrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrs.nix b/fix/tests/tests/lang/eval-okay-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs.nix rename to fix/tests/tests/lang/eval-okay-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrs2.exp b/fix/tests/tests/lang/eval-okay-attrs2.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs2.exp rename to fix/tests/tests/lang/eval-okay-attrs2.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrs2.nix b/fix/tests/tests/lang/eval-okay-attrs2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs2.nix rename to fix/tests/tests/lang/eval-okay-attrs2.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrs3.exp b/fix/tests/tests/lang/eval-okay-attrs3.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs3.exp rename to fix/tests/tests/lang/eval-okay-attrs3.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrs3.nix b/fix/tests/tests/lang/eval-okay-attrs3.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs3.nix rename to fix/tests/tests/lang/eval-okay-attrs3.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrs4.exp b/fix/tests/tests/lang/eval-okay-attrs4.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs4.exp rename to fix/tests/tests/lang/eval-okay-attrs4.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrs4.nix b/fix/tests/tests/lang/eval-okay-attrs4.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs4.nix rename to fix/tests/tests/lang/eval-okay-attrs4.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrs5.exp b/fix/tests/tests/lang/eval-okay-attrs5.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs5.exp rename to fix/tests/tests/lang/eval-okay-attrs5.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrs5.nix b/fix/tests/tests/lang/eval-okay-attrs5.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs5.nix rename to fix/tests/tests/lang/eval-okay-attrs5.nix diff --git a/nix-js/tests/tests/lang/eval-okay-attrs6.exp b/fix/tests/tests/lang/eval-okay-attrs6.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs6.exp rename to fix/tests/tests/lang/eval-okay-attrs6.exp diff --git a/nix-js/tests/tests/lang/eval-okay-attrs6.nix b/fix/tests/tests/lang/eval-okay-attrs6.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-attrs6.nix rename to fix/tests/tests/lang/eval-okay-attrs6.nix diff --git a/nix-js/tests/tests/lang/eval-okay-autoargs.exp b/fix/tests/tests/lang/eval-okay-autoargs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-autoargs.exp rename to fix/tests/tests/lang/eval-okay-autoargs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-autoargs.nix b/fix/tests/tests/lang/eval-okay-autoargs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-autoargs.nix rename to fix/tests/tests/lang/eval-okay-autoargs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-backslash-newline-1.exp b/fix/tests/tests/lang/eval-okay-backslash-newline-1.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-backslash-newline-1.exp rename to fix/tests/tests/lang/eval-okay-backslash-newline-1.exp diff --git a/nix-js/tests/tests/lang/eval-okay-backslash-newline-1.nix b/fix/tests/tests/lang/eval-okay-backslash-newline-1.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-backslash-newline-1.nix rename to fix/tests/tests/lang/eval-okay-backslash-newline-1.nix diff --git a/nix-js/tests/tests/lang/eval-okay-backslash-newline-2.exp b/fix/tests/tests/lang/eval-okay-backslash-newline-2.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-backslash-newline-2.exp rename to fix/tests/tests/lang/eval-okay-backslash-newline-2.exp diff --git a/nix-js/tests/tests/lang/eval-okay-backslash-newline-2.nix b/fix/tests/tests/lang/eval-okay-backslash-newline-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-backslash-newline-2.nix rename to fix/tests/tests/lang/eval-okay-backslash-newline-2.nix diff --git a/nix-js/tests/tests/lang/eval-okay-baseNameOf.exp b/fix/tests/tests/lang/eval-okay-baseNameOf.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-baseNameOf.exp rename to fix/tests/tests/lang/eval-okay-baseNameOf.exp diff --git a/nix-js/tests/tests/lang/eval-okay-baseNameOf.nix b/fix/tests/tests/lang/eval-okay-baseNameOf.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-baseNameOf.nix rename to fix/tests/tests/lang/eval-okay-baseNameOf.nix diff --git a/nix-js/tests/tests/lang/eval-okay-builtins-add.exp b/fix/tests/tests/lang/eval-okay-builtins-add.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-builtins-add.exp rename to fix/tests/tests/lang/eval-okay-builtins-add.exp diff --git a/nix-js/tests/tests/lang/eval-okay-builtins-add.nix b/fix/tests/tests/lang/eval-okay-builtins-add.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-builtins-add.nix rename to fix/tests/tests/lang/eval-okay-builtins-add.nix diff --git a/nix-js/tests/tests/lang/eval-okay-builtins.exp b/fix/tests/tests/lang/eval-okay-builtins.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-builtins.exp rename to fix/tests/tests/lang/eval-okay-builtins.exp diff --git a/nix-js/tests/tests/lang/eval-okay-builtins.nix b/fix/tests/tests/lang/eval-okay-builtins.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-builtins.nix rename to fix/tests/tests/lang/eval-okay-builtins.nix diff --git a/nix-js/tests/tests/lang/eval-okay-callable-attrs.exp b/fix/tests/tests/lang/eval-okay-callable-attrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-callable-attrs.exp rename to fix/tests/tests/lang/eval-okay-callable-attrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-callable-attrs.nix b/fix/tests/tests/lang/eval-okay-callable-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-callable-attrs.nix rename to fix/tests/tests/lang/eval-okay-callable-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-catattrs.exp b/fix/tests/tests/lang/eval-okay-catattrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-catattrs.exp rename to fix/tests/tests/lang/eval-okay-catattrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-catattrs.nix b/fix/tests/tests/lang/eval-okay-catattrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-catattrs.nix rename to fix/tests/tests/lang/eval-okay-catattrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-closure.exp b/fix/tests/tests/lang/eval-okay-closure.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-closure.exp rename to fix/tests/tests/lang/eval-okay-closure.exp diff --git a/nix-js/tests/tests/lang/eval-okay-closure.nix b/fix/tests/tests/lang/eval-okay-closure.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-closure.nix rename to fix/tests/tests/lang/eval-okay-closure.nix diff --git a/nix-js/tests/tests/lang/eval-okay-comments.exp b/fix/tests/tests/lang/eval-okay-comments.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-comments.exp rename to fix/tests/tests/lang/eval-okay-comments.exp diff --git a/nix-js/tests/tests/lang/eval-okay-comments.nix b/fix/tests/tests/lang/eval-okay-comments.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-comments.nix rename to fix/tests/tests/lang/eval-okay-comments.nix diff --git a/nix-js/tests/tests/lang/eval-okay-concat.exp b/fix/tests/tests/lang/eval-okay-concat.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-concat.exp rename to fix/tests/tests/lang/eval-okay-concat.exp diff --git a/nix-js/tests/tests/lang/eval-okay-concat.nix b/fix/tests/tests/lang/eval-okay-concat.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-concat.nix rename to fix/tests/tests/lang/eval-okay-concat.nix diff --git a/nix-js/tests/tests/lang/eval-okay-concatmap.exp b/fix/tests/tests/lang/eval-okay-concatmap.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-concatmap.exp rename to fix/tests/tests/lang/eval-okay-concatmap.exp diff --git a/nix-js/tests/tests/lang/eval-okay-concatmap.nix b/fix/tests/tests/lang/eval-okay-concatmap.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-concatmap.nix rename to fix/tests/tests/lang/eval-okay-concatmap.nix diff --git a/nix-js/tests/tests/lang/eval-okay-concatstringssep.exp b/fix/tests/tests/lang/eval-okay-concatstringssep.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-concatstringssep.exp rename to fix/tests/tests/lang/eval-okay-concatstringssep.exp diff --git a/nix-js/tests/tests/lang/eval-okay-concatstringssep.nix b/fix/tests/tests/lang/eval-okay-concatstringssep.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-concatstringssep.nix rename to fix/tests/tests/lang/eval-okay-concatstringssep.nix diff --git a/nix-js/tests/tests/lang/eval-okay-context-introspection.exp b/fix/tests/tests/lang/eval-okay-context-introspection.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-context-introspection.exp rename to fix/tests/tests/lang/eval-okay-context-introspection.exp diff --git a/nix-js/tests/tests/lang/eval-okay-context-introspection.nix b/fix/tests/tests/lang/eval-okay-context-introspection.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-context-introspection.nix rename to fix/tests/tests/lang/eval-okay-context-introspection.nix diff --git a/nix-js/tests/tests/lang/eval-okay-context.exp b/fix/tests/tests/lang/eval-okay-context.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-context.exp rename to fix/tests/tests/lang/eval-okay-context.exp diff --git a/nix-js/tests/tests/lang/eval-okay-context.nix b/fix/tests/tests/lang/eval-okay-context.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-context.nix rename to fix/tests/tests/lang/eval-okay-context.nix diff --git a/nix-js/tests/tests/lang/eval-okay-convertHash.err.exp b/fix/tests/tests/lang/eval-okay-convertHash.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-convertHash.err.exp rename to fix/tests/tests/lang/eval-okay-convertHash.err.exp diff --git a/nix-js/tests/tests/lang/eval-okay-convertHash.exp b/fix/tests/tests/lang/eval-okay-convertHash.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-convertHash.exp rename to fix/tests/tests/lang/eval-okay-convertHash.exp diff --git a/nix-js/tests/tests/lang/eval-okay-convertHash.nix b/fix/tests/tests/lang/eval-okay-convertHash.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-convertHash.nix rename to fix/tests/tests/lang/eval-okay-convertHash.nix diff --git a/nix-js/tests/tests/lang/eval-okay-curpos.exp b/fix/tests/tests/lang/eval-okay-curpos.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-curpos.exp rename to fix/tests/tests/lang/eval-okay-curpos.exp diff --git a/nix-js/tests/tests/lang/eval-okay-curpos.nix b/fix/tests/tests/lang/eval-okay-curpos.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-curpos.nix rename to fix/tests/tests/lang/eval-okay-curpos.nix diff --git a/nix-js/tests/tests/lang/eval-okay-deepseq.exp b/fix/tests/tests/lang/eval-okay-deepseq.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-deepseq.exp rename to fix/tests/tests/lang/eval-okay-deepseq.exp diff --git a/nix-js/tests/tests/lang/eval-okay-deepseq.nix b/fix/tests/tests/lang/eval-okay-deepseq.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-deepseq.nix rename to fix/tests/tests/lang/eval-okay-deepseq.nix diff --git a/nix-js/tests/tests/lang/eval-okay-delayed-with-inherit.exp b/fix/tests/tests/lang/eval-okay-delayed-with-inherit.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-delayed-with-inherit.exp rename to fix/tests/tests/lang/eval-okay-delayed-with-inherit.exp diff --git a/nix-js/tests/tests/lang/eval-okay-delayed-with-inherit.nix b/fix/tests/tests/lang/eval-okay-delayed-with-inherit.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-delayed-with-inherit.nix rename to fix/tests/tests/lang/eval-okay-delayed-with-inherit.nix diff --git a/nix-js/tests/tests/lang/eval-okay-delayed-with.exp b/fix/tests/tests/lang/eval-okay-delayed-with.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-delayed-with.exp rename to fix/tests/tests/lang/eval-okay-delayed-with.exp diff --git a/nix-js/tests/tests/lang/eval-okay-delayed-with.nix b/fix/tests/tests/lang/eval-okay-delayed-with.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-delayed-with.nix rename to fix/tests/tests/lang/eval-okay-delayed-with.nix diff --git a/nix-js/tests/tests/lang/eval-okay-deprecate-cursed-or.err.exp b/fix/tests/tests/lang/eval-okay-deprecate-cursed-or.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-deprecate-cursed-or.err.exp rename to fix/tests/tests/lang/eval-okay-deprecate-cursed-or.err.exp diff --git a/nix-js/tests/tests/lang/eval-okay-deprecate-cursed-or.exp b/fix/tests/tests/lang/eval-okay-deprecate-cursed-or.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-deprecate-cursed-or.exp rename to fix/tests/tests/lang/eval-okay-deprecate-cursed-or.exp diff --git a/nix-js/tests/tests/lang/eval-okay-deprecate-cursed-or.nix b/fix/tests/tests/lang/eval-okay-deprecate-cursed-or.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-deprecate-cursed-or.nix rename to fix/tests/tests/lang/eval-okay-deprecate-cursed-or.nix diff --git a/nix-js/tests/tests/lang/eval-okay-derivation-legacy.err.exp b/fix/tests/tests/lang/eval-okay-derivation-legacy.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-derivation-legacy.err.exp rename to fix/tests/tests/lang/eval-okay-derivation-legacy.err.exp diff --git a/nix-js/tests/tests/lang/eval-okay-derivation-legacy.exp b/fix/tests/tests/lang/eval-okay-derivation-legacy.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-derivation-legacy.exp rename to fix/tests/tests/lang/eval-okay-derivation-legacy.exp diff --git a/nix-js/tests/tests/lang/eval-okay-derivation-legacy.nix b/fix/tests/tests/lang/eval-okay-derivation-legacy.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-derivation-legacy.nix rename to fix/tests/tests/lang/eval-okay-derivation-legacy.nix diff --git a/nix-js/tests/tests/lang/eval-okay-dynamic-attrs-2.exp b/fix/tests/tests/lang/eval-okay-dynamic-attrs-2.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-dynamic-attrs-2.exp rename to fix/tests/tests/lang/eval-okay-dynamic-attrs-2.exp diff --git a/nix-js/tests/tests/lang/eval-okay-dynamic-attrs-2.nix b/fix/tests/tests/lang/eval-okay-dynamic-attrs-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-dynamic-attrs-2.nix rename to fix/tests/tests/lang/eval-okay-dynamic-attrs-2.nix diff --git a/nix-js/tests/tests/lang/eval-okay-dynamic-attrs-bare.exp b/fix/tests/tests/lang/eval-okay-dynamic-attrs-bare.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-dynamic-attrs-bare.exp rename to fix/tests/tests/lang/eval-okay-dynamic-attrs-bare.exp diff --git a/nix-js/tests/tests/lang/eval-okay-dynamic-attrs-bare.nix b/fix/tests/tests/lang/eval-okay-dynamic-attrs-bare.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-dynamic-attrs-bare.nix rename to fix/tests/tests/lang/eval-okay-dynamic-attrs-bare.nix diff --git a/nix-js/tests/tests/lang/eval-okay-dynamic-attrs.exp b/fix/tests/tests/lang/eval-okay-dynamic-attrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-dynamic-attrs.exp rename to fix/tests/tests/lang/eval-okay-dynamic-attrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-dynamic-attrs.nix b/fix/tests/tests/lang/eval-okay-dynamic-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-dynamic-attrs.nix rename to fix/tests/tests/lang/eval-okay-dynamic-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-elem.exp b/fix/tests/tests/lang/eval-okay-elem.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-elem.exp rename to fix/tests/tests/lang/eval-okay-elem.exp diff --git a/nix-js/tests/tests/lang/eval-okay-elem.nix b/fix/tests/tests/lang/eval-okay-elem.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-elem.nix rename to fix/tests/tests/lang/eval-okay-elem.nix diff --git a/nix-js/tests/tests/lang/eval-okay-empty-args.exp b/fix/tests/tests/lang/eval-okay-empty-args.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-empty-args.exp rename to fix/tests/tests/lang/eval-okay-empty-args.exp diff --git a/nix-js/tests/tests/lang/eval-okay-empty-args.nix b/fix/tests/tests/lang/eval-okay-empty-args.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-empty-args.nix rename to fix/tests/tests/lang/eval-okay-empty-args.nix diff --git a/nix-js/tests/tests/lang/eval-okay-eq-derivations.exp b/fix/tests/tests/lang/eval-okay-eq-derivations.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-eq-derivations.exp rename to fix/tests/tests/lang/eval-okay-eq-derivations.exp diff --git a/nix-js/tests/tests/lang/eval-okay-eq-derivations.nix b/fix/tests/tests/lang/eval-okay-eq-derivations.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-eq-derivations.nix rename to fix/tests/tests/lang/eval-okay-eq-derivations.nix diff --git a/nix-js/tests/tests/lang/eval-okay-eq.exp b/fix/tests/tests/lang/eval-okay-eq.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-eq.exp rename to fix/tests/tests/lang/eval-okay-eq.exp diff --git a/nix-js/tests/tests/lang/eval-okay-eq.nix b/fix/tests/tests/lang/eval-okay-eq.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-eq.nix rename to fix/tests/tests/lang/eval-okay-eq.nix diff --git a/nix-js/tests/tests/lang/eval-okay-filter.exp b/fix/tests/tests/lang/eval-okay-filter.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-filter.exp rename to fix/tests/tests/lang/eval-okay-filter.exp diff --git a/nix-js/tests/tests/lang/eval-okay-filter.nix b/fix/tests/tests/lang/eval-okay-filter.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-filter.nix rename to fix/tests/tests/lang/eval-okay-filter.nix diff --git a/nix-js/tests/tests/lang/eval-okay-flake-ref-to-string.exp b/fix/tests/tests/lang/eval-okay-flake-ref-to-string.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-flake-ref-to-string.exp rename to fix/tests/tests/lang/eval-okay-flake-ref-to-string.exp diff --git a/nix-js/tests/tests/lang/eval-okay-flake-ref-to-string.nix b/fix/tests/tests/lang/eval-okay-flake-ref-to-string.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-flake-ref-to-string.nix rename to fix/tests/tests/lang/eval-okay-flake-ref-to-string.nix diff --git a/nix-js/tests/tests/lang/eval-okay-flatten.exp b/fix/tests/tests/lang/eval-okay-flatten.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-flatten.exp rename to fix/tests/tests/lang/eval-okay-flatten.exp diff --git a/nix-js/tests/tests/lang/eval-okay-flatten.nix b/fix/tests/tests/lang/eval-okay-flatten.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-flatten.nix rename to fix/tests/tests/lang/eval-okay-flatten.nix diff --git a/nix-js/tests/tests/lang/eval-okay-float.exp b/fix/tests/tests/lang/eval-okay-float.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-float.exp rename to fix/tests/tests/lang/eval-okay-float.exp diff --git a/nix-js/tests/tests/lang/eval-okay-float.nix b/fix/tests/tests/lang/eval-okay-float.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-float.nix rename to fix/tests/tests/lang/eval-okay-float.nix diff --git a/nix-js/tests/tests/lang/eval-okay-floor-ceil.exp b/fix/tests/tests/lang/eval-okay-floor-ceil.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-floor-ceil.exp rename to fix/tests/tests/lang/eval-okay-floor-ceil.exp diff --git a/nix-js/tests/tests/lang/eval-okay-floor-ceil.nix b/fix/tests/tests/lang/eval-okay-floor-ceil.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-floor-ceil.nix rename to fix/tests/tests/lang/eval-okay-floor-ceil.nix diff --git a/nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.exp b/fix/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.exp rename to fix/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.exp diff --git a/nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.nix b/fix/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.nix rename to fix/tests/tests/lang/eval-okay-foldlStrict-lazy-elements.nix diff --git a/nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp b/fix/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp rename to fix/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.exp diff --git a/nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix b/fix/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix rename to fix/tests/tests/lang/eval-okay-foldlStrict-lazy-initial-accumulator.nix diff --git a/nix-js/tests/tests/lang/eval-okay-foldlStrict.exp b/fix/tests/tests/lang/eval-okay-foldlStrict.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-foldlStrict.exp rename to fix/tests/tests/lang/eval-okay-foldlStrict.exp diff --git a/nix-js/tests/tests/lang/eval-okay-foldlStrict.nix b/fix/tests/tests/lang/eval-okay-foldlStrict.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-foldlStrict.nix rename to fix/tests/tests/lang/eval-okay-foldlStrict.nix diff --git a/nix-js/tests/tests/lang/eval-okay-fromTOML-timestamps.exp b/fix/tests/tests/lang/eval-okay-fromTOML-timestamps.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromTOML-timestamps.exp rename to fix/tests/tests/lang/eval-okay-fromTOML-timestamps.exp diff --git a/nix-js/tests/tests/lang/eval-okay-fromTOML-timestamps.nix b/fix/tests/tests/lang/eval-okay-fromTOML-timestamps.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromTOML-timestamps.nix rename to fix/tests/tests/lang/eval-okay-fromTOML-timestamps.nix diff --git a/nix-js/tests/tests/lang/eval-okay-fromTOML.exp b/fix/tests/tests/lang/eval-okay-fromTOML.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromTOML.exp rename to fix/tests/tests/lang/eval-okay-fromTOML.exp diff --git a/nix-js/tests/tests/lang/eval-okay-fromTOML.nix b/fix/tests/tests/lang/eval-okay-fromTOML.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromTOML.nix rename to fix/tests/tests/lang/eval-okay-fromTOML.nix diff --git a/nix-js/tests/tests/lang/eval-okay-fromjson-escapes.exp b/fix/tests/tests/lang/eval-okay-fromjson-escapes.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromjson-escapes.exp rename to fix/tests/tests/lang/eval-okay-fromjson-escapes.exp diff --git a/nix-js/tests/tests/lang/eval-okay-fromjson-escapes.nix b/fix/tests/tests/lang/eval-okay-fromjson-escapes.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromjson-escapes.nix rename to fix/tests/tests/lang/eval-okay-fromjson-escapes.nix diff --git a/nix-js/tests/tests/lang/eval-okay-fromjson.exp b/fix/tests/tests/lang/eval-okay-fromjson.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromjson.exp rename to fix/tests/tests/lang/eval-okay-fromjson.exp diff --git a/nix-js/tests/tests/lang/eval-okay-fromjson.nix b/fix/tests/tests/lang/eval-okay-fromjson.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-fromjson.nix rename to fix/tests/tests/lang/eval-okay-fromjson.nix diff --git a/nix-js/tests/tests/lang/eval-okay-functionargs.exp b/fix/tests/tests/lang/eval-okay-functionargs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-functionargs.exp rename to fix/tests/tests/lang/eval-okay-functionargs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-functionargs.nix b/fix/tests/tests/lang/eval-okay-functionargs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-functionargs.nix rename to fix/tests/tests/lang/eval-okay-functionargs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-getattrpos-functionargs.exp b/fix/tests/tests/lang/eval-okay-getattrpos-functionargs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getattrpos-functionargs.exp rename to fix/tests/tests/lang/eval-okay-getattrpos-functionargs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-getattrpos-functionargs.nix b/fix/tests/tests/lang/eval-okay-getattrpos-functionargs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getattrpos-functionargs.nix rename to fix/tests/tests/lang/eval-okay-getattrpos-functionargs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-getattrpos-undefined.exp b/fix/tests/tests/lang/eval-okay-getattrpos-undefined.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getattrpos-undefined.exp rename to fix/tests/tests/lang/eval-okay-getattrpos-undefined.exp diff --git a/nix-js/tests/tests/lang/eval-okay-getattrpos-undefined.nix b/fix/tests/tests/lang/eval-okay-getattrpos-undefined.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getattrpos-undefined.nix rename to fix/tests/tests/lang/eval-okay-getattrpos-undefined.nix diff --git a/nix-js/tests/tests/lang/eval-okay-getattrpos.exp b/fix/tests/tests/lang/eval-okay-getattrpos.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getattrpos.exp rename to fix/tests/tests/lang/eval-okay-getattrpos.exp diff --git a/nix-js/tests/tests/lang/eval-okay-getattrpos.nix b/fix/tests/tests/lang/eval-okay-getattrpos.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getattrpos.nix rename to fix/tests/tests/lang/eval-okay-getattrpos.nix diff --git a/nix-js/tests/tests/lang/eval-okay-getenv.exp b/fix/tests/tests/lang/eval-okay-getenv.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getenv.exp rename to fix/tests/tests/lang/eval-okay-getenv.exp diff --git a/nix-js/tests/tests/lang/eval-okay-getenv.nix b/fix/tests/tests/lang/eval-okay-getenv.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-getenv.nix rename to fix/tests/tests/lang/eval-okay-getenv.nix diff --git a/nix-js/tests/tests/lang/eval-okay-groupBy.exp b/fix/tests/tests/lang/eval-okay-groupBy.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-groupBy.exp rename to fix/tests/tests/lang/eval-okay-groupBy.exp diff --git a/nix-js/tests/tests/lang/eval-okay-groupBy.nix b/fix/tests/tests/lang/eval-okay-groupBy.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-groupBy.nix rename to fix/tests/tests/lang/eval-okay-groupBy.nix diff --git a/nix-js/tests/tests/lang/readDir/bar b/fix/tests/tests/lang/eval-okay-hash.exp similarity index 100% rename from nix-js/tests/tests/lang/readDir/bar rename to fix/tests/tests/lang/eval-okay-hash.exp diff --git a/nix-js/tests/tests/lang/eval-okay-hashfile.exp b/fix/tests/tests/lang/eval-okay-hashfile.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-hashfile.exp rename to fix/tests/tests/lang/eval-okay-hashfile.exp diff --git a/nix-js/tests/tests/lang/eval-okay-hashfile.nix b/fix/tests/tests/lang/eval-okay-hashfile.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-hashfile.nix rename to fix/tests/tests/lang/eval-okay-hashfile.nix diff --git a/nix-js/tests/tests/lang/eval-okay-hashstring.exp b/fix/tests/tests/lang/eval-okay-hashstring.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-hashstring.exp rename to fix/tests/tests/lang/eval-okay-hashstring.exp diff --git a/nix-js/tests/tests/lang/eval-okay-hashstring.nix b/fix/tests/tests/lang/eval-okay-hashstring.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-hashstring.nix rename to fix/tests/tests/lang/eval-okay-hashstring.nix diff --git a/nix-js/tests/tests/lang/eval-okay-if.exp b/fix/tests/tests/lang/eval-okay-if.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-if.exp rename to fix/tests/tests/lang/eval-okay-if.exp diff --git a/nix-js/tests/tests/lang/eval-okay-if.nix b/fix/tests/tests/lang/eval-okay-if.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-if.nix rename to fix/tests/tests/lang/eval-okay-if.nix diff --git a/nix-js/tests/tests/lang/eval-okay-import.exp b/fix/tests/tests/lang/eval-okay-import.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-import.exp rename to fix/tests/tests/lang/eval-okay-import.exp diff --git a/nix-js/tests/tests/lang/eval-okay-import.nix b/fix/tests/tests/lang/eval-okay-import.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-import.nix rename to fix/tests/tests/lang/eval-okay-import.nix diff --git a/nix-js/tests/tests/lang/eval-okay-ind-string.exp b/fix/tests/tests/lang/eval-okay-ind-string.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-ind-string.exp rename to fix/tests/tests/lang/eval-okay-ind-string.exp diff --git a/nix-js/tests/tests/lang/eval-okay-ind-string.nix b/fix/tests/tests/lang/eval-okay-ind-string.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-ind-string.nix rename to fix/tests/tests/lang/eval-okay-ind-string.nix diff --git a/nix-js/tests/tests/lang/eval-okay-inherit-attr-pos.exp b/fix/tests/tests/lang/eval-okay-inherit-attr-pos.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-inherit-attr-pos.exp rename to fix/tests/tests/lang/eval-okay-inherit-attr-pos.exp diff --git a/nix-js/tests/tests/lang/eval-okay-inherit-attr-pos.nix b/fix/tests/tests/lang/eval-okay-inherit-attr-pos.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-inherit-attr-pos.nix rename to fix/tests/tests/lang/eval-okay-inherit-attr-pos.nix diff --git a/nix-js/tests/tests/lang/eval-okay-inherit-from.err.exp b/fix/tests/tests/lang/eval-okay-inherit-from.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-inherit-from.err.exp rename to fix/tests/tests/lang/eval-okay-inherit-from.err.exp diff --git a/nix-js/tests/tests/lang/eval-okay-inherit-from.exp b/fix/tests/tests/lang/eval-okay-inherit-from.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-inherit-from.exp rename to fix/tests/tests/lang/eval-okay-inherit-from.exp diff --git a/nix-js/tests/tests/lang/eval-okay-inherit-from.nix b/fix/tests/tests/lang/eval-okay-inherit-from.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-inherit-from.nix rename to fix/tests/tests/lang/eval-okay-inherit-from.nix diff --git a/nix-js/tests/tests/lang/eval-okay-intersectAttrs.exp b/fix/tests/tests/lang/eval-okay-intersectAttrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-intersectAttrs.exp rename to fix/tests/tests/lang/eval-okay-intersectAttrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-intersectAttrs.nix b/fix/tests/tests/lang/eval-okay-intersectAttrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-intersectAttrs.nix rename to fix/tests/tests/lang/eval-okay-intersectAttrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-let.exp b/fix/tests/tests/lang/eval-okay-let.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-let.exp rename to fix/tests/tests/lang/eval-okay-let.exp diff --git a/nix-js/tests/tests/lang/eval-okay-let.nix b/fix/tests/tests/lang/eval-okay-let.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-let.nix rename to fix/tests/tests/lang/eval-okay-let.nix diff --git a/nix-js/tests/tests/lang/eval-okay-list.exp b/fix/tests/tests/lang/eval-okay-list.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-list.exp rename to fix/tests/tests/lang/eval-okay-list.exp diff --git a/nix-js/tests/tests/lang/eval-okay-list.nix b/fix/tests/tests/lang/eval-okay-list.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-list.nix rename to fix/tests/tests/lang/eval-okay-list.nix diff --git a/nix-js/tests/tests/lang/eval-okay-listtoattrs.exp b/fix/tests/tests/lang/eval-okay-listtoattrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-listtoattrs.exp rename to fix/tests/tests/lang/eval-okay-listtoattrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-listtoattrs.nix b/fix/tests/tests/lang/eval-okay-listtoattrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-listtoattrs.nix rename to fix/tests/tests/lang/eval-okay-listtoattrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-logic.exp b/fix/tests/tests/lang/eval-okay-logic.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-logic.exp rename to fix/tests/tests/lang/eval-okay-logic.exp diff --git a/nix-js/tests/tests/lang/eval-okay-logic.nix b/fix/tests/tests/lang/eval-okay-logic.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-logic.nix rename to fix/tests/tests/lang/eval-okay-logic.nix diff --git a/nix-js/tests/tests/lang/eval-okay-map.exp b/fix/tests/tests/lang/eval-okay-map.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-map.exp rename to fix/tests/tests/lang/eval-okay-map.exp diff --git a/nix-js/tests/tests/lang/eval-okay-map.nix b/fix/tests/tests/lang/eval-okay-map.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-map.nix rename to fix/tests/tests/lang/eval-okay-map.nix diff --git a/nix-js/tests/tests/lang/eval-okay-mapattrs.exp b/fix/tests/tests/lang/eval-okay-mapattrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-mapattrs.exp rename to fix/tests/tests/lang/eval-okay-mapattrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-mapattrs.nix b/fix/tests/tests/lang/eval-okay-mapattrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-mapattrs.nix rename to fix/tests/tests/lang/eval-okay-mapattrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-merge-dynamic-attrs.exp b/fix/tests/tests/lang/eval-okay-merge-dynamic-attrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-merge-dynamic-attrs.exp rename to fix/tests/tests/lang/eval-okay-merge-dynamic-attrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-merge-dynamic-attrs.nix b/fix/tests/tests/lang/eval-okay-merge-dynamic-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-merge-dynamic-attrs.nix rename to fix/tests/tests/lang/eval-okay-merge-dynamic-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-nested-with.exp b/fix/tests/tests/lang/eval-okay-nested-with.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-nested-with.exp rename to fix/tests/tests/lang/eval-okay-nested-with.exp diff --git a/nix-js/tests/tests/lang/eval-okay-nested-with.nix b/fix/tests/tests/lang/eval-okay-nested-with.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-nested-with.nix rename to fix/tests/tests/lang/eval-okay-nested-with.nix diff --git a/nix-js/tests/tests/lang/eval-okay-new-let.exp b/fix/tests/tests/lang/eval-okay-new-let.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-new-let.exp rename to fix/tests/tests/lang/eval-okay-new-let.exp diff --git a/nix-js/tests/tests/lang/eval-okay-new-let.nix b/fix/tests/tests/lang/eval-okay-new-let.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-new-let.nix rename to fix/tests/tests/lang/eval-okay-new-let.nix diff --git a/nix-js/tests/tests/lang/eval-okay-null-dynamic-attrs.exp b/fix/tests/tests/lang/eval-okay-null-dynamic-attrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-null-dynamic-attrs.exp rename to fix/tests/tests/lang/eval-okay-null-dynamic-attrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-null-dynamic-attrs.nix b/fix/tests/tests/lang/eval-okay-null-dynamic-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-null-dynamic-attrs.nix rename to fix/tests/tests/lang/eval-okay-null-dynamic-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-overrides.exp b/fix/tests/tests/lang/eval-okay-overrides.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-overrides.exp rename to fix/tests/tests/lang/eval-okay-overrides.exp diff --git a/nix-js/tests/tests/lang/eval-okay-overrides.nix b/fix/tests/tests/lang/eval-okay-overrides.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-overrides.nix rename to fix/tests/tests/lang/eval-okay-overrides.nix diff --git a/nix-js/tests/tests/lang/eval-okay-parse-flake-ref.exp b/fix/tests/tests/lang/eval-okay-parse-flake-ref.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-parse-flake-ref.exp rename to fix/tests/tests/lang/eval-okay-parse-flake-ref.exp diff --git a/nix-js/tests/tests/lang/eval-okay-parse-flake-ref.nix b/fix/tests/tests/lang/eval-okay-parse-flake-ref.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-parse-flake-ref.nix rename to fix/tests/tests/lang/eval-okay-parse-flake-ref.nix diff --git a/nix-js/tests/tests/lang/eval-okay-partition.exp b/fix/tests/tests/lang/eval-okay-partition.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-partition.exp rename to fix/tests/tests/lang/eval-okay-partition.exp diff --git a/nix-js/tests/tests/lang/eval-okay-partition.nix b/fix/tests/tests/lang/eval-okay-partition.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-partition.nix rename to fix/tests/tests/lang/eval-okay-partition.nix diff --git a/nix-js/tests/tests/lang/eval-okay-path-string-interpolation.exp b/fix/tests/tests/lang/eval-okay-path-string-interpolation.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-path-string-interpolation.exp rename to fix/tests/tests/lang/eval-okay-path-string-interpolation.exp diff --git a/nix-js/tests/tests/lang/eval-okay-path-string-interpolation.nix b/fix/tests/tests/lang/eval-okay-path-string-interpolation.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-path-string-interpolation.nix rename to fix/tests/tests/lang/eval-okay-path-string-interpolation.nix diff --git a/nix-js/tests/tests/lang/eval-okay-path.exp b/fix/tests/tests/lang/eval-okay-path.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-path.exp rename to fix/tests/tests/lang/eval-okay-path.exp diff --git a/nix-js/tests/tests/lang/eval-okay-path.nix b/fix/tests/tests/lang/eval-okay-path.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-path.nix rename to fix/tests/tests/lang/eval-okay-path.nix diff --git a/nix-js/tests/tests/lang/eval-okay-pathexists.exp b/fix/tests/tests/lang/eval-okay-pathexists.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-pathexists.exp rename to fix/tests/tests/lang/eval-okay-pathexists.exp diff --git a/nix-js/tests/tests/lang/eval-okay-pathexists.nix b/fix/tests/tests/lang/eval-okay-pathexists.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-pathexists.nix rename to fix/tests/tests/lang/eval-okay-pathexists.nix diff --git a/nix-js/tests/tests/lang/eval-okay-patterns.exp b/fix/tests/tests/lang/eval-okay-patterns.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-patterns.exp rename to fix/tests/tests/lang/eval-okay-patterns.exp diff --git a/nix-js/tests/tests/lang/eval-okay-patterns.nix b/fix/tests/tests/lang/eval-okay-patterns.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-patterns.nix rename to fix/tests/tests/lang/eval-okay-patterns.nix diff --git a/nix-js/tests/tests/lang/eval-okay-print.err.exp b/fix/tests/tests/lang/eval-okay-print.err.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-print.err.exp rename to fix/tests/tests/lang/eval-okay-print.err.exp diff --git a/nix-js/tests/tests/lang/eval-okay-print.exp b/fix/tests/tests/lang/eval-okay-print.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-print.exp rename to fix/tests/tests/lang/eval-okay-print.exp diff --git a/nix-js/tests/tests/lang/eval-okay-print.nix b/fix/tests/tests/lang/eval-okay-print.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-print.nix rename to fix/tests/tests/lang/eval-okay-print.nix diff --git a/nix-js/tests/tests/lang/eval-okay-readDir.exp b/fix/tests/tests/lang/eval-okay-readDir.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-readDir.exp rename to fix/tests/tests/lang/eval-okay-readDir.exp diff --git a/nix-js/tests/tests/lang/eval-okay-readDir.nix b/fix/tests/tests/lang/eval-okay-readDir.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-readDir.nix rename to fix/tests/tests/lang/eval-okay-readDir.nix diff --git a/nix-js/tests/tests/lang/eval-okay-readFileType.exp b/fix/tests/tests/lang/eval-okay-readFileType.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-readFileType.exp rename to fix/tests/tests/lang/eval-okay-readFileType.exp diff --git a/nix-js/tests/tests/lang/eval-okay-readFileType.nix b/fix/tests/tests/lang/eval-okay-readFileType.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-readFileType.nix rename to fix/tests/tests/lang/eval-okay-readFileType.nix diff --git a/nix-js/tests/tests/lang/eval-okay-readfile.exp b/fix/tests/tests/lang/eval-okay-readfile.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-readfile.exp rename to fix/tests/tests/lang/eval-okay-readfile.exp diff --git a/nix-js/tests/tests/lang/eval-okay-readfile.nix b/fix/tests/tests/lang/eval-okay-readfile.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-readfile.nix rename to fix/tests/tests/lang/eval-okay-readfile.nix diff --git a/nix-js/tests/tests/lang/eval-okay-redefine-builtin.exp b/fix/tests/tests/lang/eval-okay-redefine-builtin.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-redefine-builtin.exp rename to fix/tests/tests/lang/eval-okay-redefine-builtin.exp diff --git a/nix-js/tests/tests/lang/eval-okay-redefine-builtin.nix b/fix/tests/tests/lang/eval-okay-redefine-builtin.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-redefine-builtin.nix rename to fix/tests/tests/lang/eval-okay-redefine-builtin.nix diff --git a/nix-js/tests/tests/lang/eval-okay-regex-match.exp b/fix/tests/tests/lang/eval-okay-regex-match.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regex-match.exp rename to fix/tests/tests/lang/eval-okay-regex-match.exp diff --git a/nix-js/tests/tests/lang/eval-okay-regex-match.nix b/fix/tests/tests/lang/eval-okay-regex-match.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regex-match.nix rename to fix/tests/tests/lang/eval-okay-regex-match.nix diff --git a/nix-js/tests/tests/lang/eval-okay-regex-split.exp b/fix/tests/tests/lang/eval-okay-regex-split.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regex-split.exp rename to fix/tests/tests/lang/eval-okay-regex-split.exp diff --git a/nix-js/tests/tests/lang/eval-okay-regex-split.nix b/fix/tests/tests/lang/eval-okay-regex-split.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regex-split.nix rename to fix/tests/tests/lang/eval-okay-regex-split.nix diff --git a/nix-js/tests/tests/lang/eval-okay-regression-20220122.exp b/fix/tests/tests/lang/eval-okay-regression-20220122.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regression-20220122.exp rename to fix/tests/tests/lang/eval-okay-regression-20220122.exp diff --git a/nix-js/tests/tests/lang/eval-okay-regression-20220122.nix b/fix/tests/tests/lang/eval-okay-regression-20220122.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regression-20220122.nix rename to fix/tests/tests/lang/eval-okay-regression-20220122.nix diff --git a/nix-js/tests/tests/lang/eval-okay-regression-20220125.exp b/fix/tests/tests/lang/eval-okay-regression-20220125.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regression-20220125.exp rename to fix/tests/tests/lang/eval-okay-regression-20220125.exp diff --git a/nix-js/tests/tests/lang/eval-okay-regression-20220125.nix b/fix/tests/tests/lang/eval-okay-regression-20220125.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regression-20220125.nix rename to fix/tests/tests/lang/eval-okay-regression-20220125.nix diff --git a/nix-js/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.exp b/fix/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.exp rename to fix/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.exp diff --git a/nix-js/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.nix b/fix/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.nix rename to fix/tests/tests/lang/eval-okay-regrettable-rec-attrset-merge.nix diff --git a/nix-js/tests/tests/lang/eval-okay-remove.exp b/fix/tests/tests/lang/eval-okay-remove.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-remove.exp rename to fix/tests/tests/lang/eval-okay-remove.exp diff --git a/nix-js/tests/tests/lang/eval-okay-remove.nix b/fix/tests/tests/lang/eval-okay-remove.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-remove.nix rename to fix/tests/tests/lang/eval-okay-remove.nix diff --git a/nix-js/tests/tests/lang/eval-okay-repeated-empty-attrs.exp b/fix/tests/tests/lang/eval-okay-repeated-empty-attrs.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-repeated-empty-attrs.exp rename to fix/tests/tests/lang/eval-okay-repeated-empty-attrs.exp diff --git a/nix-js/tests/tests/lang/eval-okay-repeated-empty-attrs.nix b/fix/tests/tests/lang/eval-okay-repeated-empty-attrs.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-repeated-empty-attrs.nix rename to fix/tests/tests/lang/eval-okay-repeated-empty-attrs.nix diff --git a/nix-js/tests/tests/lang/eval-okay-repeated-empty-list.exp b/fix/tests/tests/lang/eval-okay-repeated-empty-list.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-repeated-empty-list.exp rename to fix/tests/tests/lang/eval-okay-repeated-empty-list.exp diff --git a/nix-js/tests/tests/lang/eval-okay-repeated-empty-list.nix b/fix/tests/tests/lang/eval-okay-repeated-empty-list.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-repeated-empty-list.nix rename to fix/tests/tests/lang/eval-okay-repeated-empty-list.nix diff --git a/nix-js/tests/tests/lang/eval-okay-replacestrings.exp b/fix/tests/tests/lang/eval-okay-replacestrings.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-replacestrings.exp rename to fix/tests/tests/lang/eval-okay-replacestrings.exp diff --git a/nix-js/tests/tests/lang/eval-okay-replacestrings.nix b/fix/tests/tests/lang/eval-okay-replacestrings.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-replacestrings.nix rename to fix/tests/tests/lang/eval-okay-replacestrings.nix diff --git a/nix-js/tests/tests/lang/eval-okay-scope-1.exp b/fix/tests/tests/lang/eval-okay-scope-1.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-1.exp rename to fix/tests/tests/lang/eval-okay-scope-1.exp diff --git a/nix-js/tests/tests/lang/eval-okay-scope-1.nix b/fix/tests/tests/lang/eval-okay-scope-1.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-1.nix rename to fix/tests/tests/lang/eval-okay-scope-1.nix diff --git a/nix-js/tests/tests/lang/eval-okay-scope-2.exp b/fix/tests/tests/lang/eval-okay-scope-2.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-2.exp rename to fix/tests/tests/lang/eval-okay-scope-2.exp diff --git a/nix-js/tests/tests/lang/eval-okay-scope-2.nix b/fix/tests/tests/lang/eval-okay-scope-2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-2.nix rename to fix/tests/tests/lang/eval-okay-scope-2.nix diff --git a/nix-js/tests/tests/lang/eval-okay-scope-3.exp b/fix/tests/tests/lang/eval-okay-scope-3.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-3.exp rename to fix/tests/tests/lang/eval-okay-scope-3.exp diff --git a/nix-js/tests/tests/lang/eval-okay-scope-3.nix b/fix/tests/tests/lang/eval-okay-scope-3.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-3.nix rename to fix/tests/tests/lang/eval-okay-scope-3.nix diff --git a/nix-js/tests/tests/lang/eval-okay-scope-4.exp b/fix/tests/tests/lang/eval-okay-scope-4.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-4.exp rename to fix/tests/tests/lang/eval-okay-scope-4.exp diff --git a/nix-js/tests/tests/lang/eval-okay-scope-4.nix b/fix/tests/tests/lang/eval-okay-scope-4.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-4.nix rename to fix/tests/tests/lang/eval-okay-scope-4.nix diff --git a/nix-js/tests/tests/lang/eval-okay-scope-6.exp b/fix/tests/tests/lang/eval-okay-scope-6.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-6.exp rename to fix/tests/tests/lang/eval-okay-scope-6.exp diff --git a/nix-js/tests/tests/lang/eval-okay-scope-6.nix b/fix/tests/tests/lang/eval-okay-scope-6.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-6.nix rename to fix/tests/tests/lang/eval-okay-scope-6.nix diff --git a/nix-js/tests/tests/lang/eval-okay-scope-7.exp b/fix/tests/tests/lang/eval-okay-scope-7.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-7.exp rename to fix/tests/tests/lang/eval-okay-scope-7.exp diff --git a/nix-js/tests/tests/lang/eval-okay-scope-7.nix b/fix/tests/tests/lang/eval-okay-scope-7.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-scope-7.nix rename to fix/tests/tests/lang/eval-okay-scope-7.nix diff --git a/nix-js/tests/tests/lang/eval-okay-search-path.exp b/fix/tests/tests/lang/eval-okay-search-path.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-search-path.exp rename to fix/tests/tests/lang/eval-okay-search-path.exp diff --git a/nix-js/tests/tests/lang/eval-okay-search-path.nix b/fix/tests/tests/lang/eval-okay-search-path.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-search-path.nix rename to fix/tests/tests/lang/eval-okay-search-path.nix diff --git a/nix-js/tests/tests/lang/eval-okay-seq.exp b/fix/tests/tests/lang/eval-okay-seq.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-seq.exp rename to fix/tests/tests/lang/eval-okay-seq.exp diff --git a/nix-js/tests/tests/lang/eval-okay-seq.nix b/fix/tests/tests/lang/eval-okay-seq.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-seq.nix rename to fix/tests/tests/lang/eval-okay-seq.nix diff --git a/nix-js/tests/tests/lang/eval-okay-sort.exp b/fix/tests/tests/lang/eval-okay-sort.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-sort.exp rename to fix/tests/tests/lang/eval-okay-sort.exp diff --git a/nix-js/tests/tests/lang/eval-okay-sort.nix b/fix/tests/tests/lang/eval-okay-sort.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-sort.nix rename to fix/tests/tests/lang/eval-okay-sort.nix diff --git a/nix-js/tests/tests/lang/eval-okay-splitversion.exp b/fix/tests/tests/lang/eval-okay-splitversion.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-splitversion.exp rename to fix/tests/tests/lang/eval-okay-splitversion.exp diff --git a/nix-js/tests/tests/lang/eval-okay-splitversion.nix b/fix/tests/tests/lang/eval-okay-splitversion.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-splitversion.nix rename to fix/tests/tests/lang/eval-okay-splitversion.nix diff --git a/nix-js/tests/tests/lang/eval-okay-string.exp b/fix/tests/tests/lang/eval-okay-string.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-string.exp rename to fix/tests/tests/lang/eval-okay-string.exp diff --git a/nix-js/tests/tests/lang/eval-okay-string.nix b/fix/tests/tests/lang/eval-okay-string.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-string.nix rename to fix/tests/tests/lang/eval-okay-string.nix diff --git a/nix-js/tests/tests/lang/eval-okay-strings-as-attrs-names.exp b/fix/tests/tests/lang/eval-okay-strings-as-attrs-names.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-strings-as-attrs-names.exp rename to fix/tests/tests/lang/eval-okay-strings-as-attrs-names.exp diff --git a/nix-js/tests/tests/lang/eval-okay-strings-as-attrs-names.nix b/fix/tests/tests/lang/eval-okay-strings-as-attrs-names.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-strings-as-attrs-names.nix rename to fix/tests/tests/lang/eval-okay-strings-as-attrs-names.nix diff --git a/nix-js/tests/tests/lang/eval-okay-substring-context.exp b/fix/tests/tests/lang/eval-okay-substring-context.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-substring-context.exp rename to fix/tests/tests/lang/eval-okay-substring-context.exp diff --git a/nix-js/tests/tests/lang/eval-okay-substring-context.nix b/fix/tests/tests/lang/eval-okay-substring-context.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-substring-context.nix rename to fix/tests/tests/lang/eval-okay-substring-context.nix diff --git a/nix-js/tests/tests/lang/eval-okay-substring.exp b/fix/tests/tests/lang/eval-okay-substring.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-substring.exp rename to fix/tests/tests/lang/eval-okay-substring.exp diff --git a/nix-js/tests/tests/lang/eval-okay-substring.nix b/fix/tests/tests/lang/eval-okay-substring.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-substring.nix rename to fix/tests/tests/lang/eval-okay-substring.nix diff --git a/nix-js/tests/tests/lang/eval-okay-symlink-resolution.exp b/fix/tests/tests/lang/eval-okay-symlink-resolution.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-symlink-resolution.exp rename to fix/tests/tests/lang/eval-okay-symlink-resolution.exp diff --git a/nix-js/tests/tests/lang/eval-okay-symlink-resolution.nix b/fix/tests/tests/lang/eval-okay-symlink-resolution.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-symlink-resolution.nix rename to fix/tests/tests/lang/eval-okay-symlink-resolution.nix diff --git a/nix-js/tests/tests/lang/eval-okay-tail-call-1.nix b/fix/tests/tests/lang/eval-okay-tail-call-1.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-tail-call-1.nix rename to fix/tests/tests/lang/eval-okay-tail-call-1.nix diff --git a/nix-js/tests/tests/lang/eval-okay-tojson.exp b/fix/tests/tests/lang/eval-okay-tojson.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-tojson.exp rename to fix/tests/tests/lang/eval-okay-tojson.exp diff --git a/nix-js/tests/tests/lang/eval-okay-tojson.nix b/fix/tests/tests/lang/eval-okay-tojson.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-tojson.nix rename to fix/tests/tests/lang/eval-okay-tojson.nix diff --git a/nix-js/tests/tests/lang/eval-okay-toxml.exp b/fix/tests/tests/lang/eval-okay-toxml.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-toxml.exp rename to fix/tests/tests/lang/eval-okay-toxml.exp diff --git a/nix-js/tests/tests/lang/eval-okay-toxml.nix b/fix/tests/tests/lang/eval-okay-toxml.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-toxml.nix rename to fix/tests/tests/lang/eval-okay-toxml.nix diff --git a/nix-js/tests/tests/lang/eval-okay-toxml2.exp b/fix/tests/tests/lang/eval-okay-toxml2.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-toxml2.exp rename to fix/tests/tests/lang/eval-okay-toxml2.exp diff --git a/nix-js/tests/tests/lang/eval-okay-toxml2.nix b/fix/tests/tests/lang/eval-okay-toxml2.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-toxml2.nix rename to fix/tests/tests/lang/eval-okay-toxml2.nix diff --git a/nix-js/tests/tests/lang/eval-okay-tryeval.exp b/fix/tests/tests/lang/eval-okay-tryeval.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-tryeval.exp rename to fix/tests/tests/lang/eval-okay-tryeval.exp diff --git a/nix-js/tests/tests/lang/eval-okay-tryeval.nix b/fix/tests/tests/lang/eval-okay-tryeval.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-tryeval.nix rename to fix/tests/tests/lang/eval-okay-tryeval.nix diff --git a/nix-js/tests/tests/lang/eval-okay-types.exp b/fix/tests/tests/lang/eval-okay-types.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-types.exp rename to fix/tests/tests/lang/eval-okay-types.exp diff --git a/nix-js/tests/tests/lang/eval-okay-types.nix b/fix/tests/tests/lang/eval-okay-types.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-types.nix rename to fix/tests/tests/lang/eval-okay-types.nix diff --git a/nix-js/tests/tests/lang/eval-okay-versions.exp b/fix/tests/tests/lang/eval-okay-versions.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-versions.exp rename to fix/tests/tests/lang/eval-okay-versions.exp diff --git a/nix-js/tests/tests/lang/eval-okay-versions.nix b/fix/tests/tests/lang/eval-okay-versions.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-versions.nix rename to fix/tests/tests/lang/eval-okay-versions.nix diff --git a/nix-js/tests/tests/lang/eval-okay-with.exp b/fix/tests/tests/lang/eval-okay-with.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-with.exp rename to fix/tests/tests/lang/eval-okay-with.exp diff --git a/nix-js/tests/tests/lang/eval-okay-with.nix b/fix/tests/tests/lang/eval-okay-with.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-with.nix rename to fix/tests/tests/lang/eval-okay-with.nix diff --git a/nix-js/tests/tests/lang/eval-okay-xml.exp b/fix/tests/tests/lang/eval-okay-xml.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-xml.exp rename to fix/tests/tests/lang/eval-okay-xml.exp diff --git a/nix-js/tests/tests/lang/eval-okay-xml.nix b/fix/tests/tests/lang/eval-okay-xml.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-xml.nix rename to fix/tests/tests/lang/eval-okay-xml.nix diff --git a/nix-js/tests/tests/lang/eval-okay-zipAttrsWith.exp b/fix/tests/tests/lang/eval-okay-zipAttrsWith.exp similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-zipAttrsWith.exp rename to fix/tests/tests/lang/eval-okay-zipAttrsWith.exp diff --git a/nix-js/tests/tests/lang/eval-okay-zipAttrsWith.nix b/fix/tests/tests/lang/eval-okay-zipAttrsWith.nix similarity index 100% rename from nix-js/tests/tests/lang/eval-okay-zipAttrsWith.nix rename to fix/tests/tests/lang/eval-okay-zipAttrsWith.nix diff --git a/nix-js/tests/tests/lang/imported.nix b/fix/tests/tests/lang/imported.nix similarity index 100% rename from nix-js/tests/tests/lang/imported.nix rename to fix/tests/tests/lang/imported.nix diff --git a/nix-js/tests/tests/lang/imported2.nix b/fix/tests/tests/lang/imported2.nix similarity index 100% rename from nix-js/tests/tests/lang/imported2.nix rename to fix/tests/tests/lang/imported2.nix diff --git a/nix-js/tests/tests/lang/lib.nix b/fix/tests/tests/lang/lib.nix similarity index 100% rename from nix-js/tests/tests/lang/lib.nix rename to fix/tests/tests/lang/lib.nix diff --git a/nix-js/tests/tests/lang/readDir/foo/git-hates-directories b/fix/tests/tests/lang/readDir/bar similarity index 100% rename from nix-js/tests/tests/lang/readDir/foo/git-hates-directories rename to fix/tests/tests/lang/readDir/bar diff --git a/fix/tests/tests/lang/readDir/foo/git-hates-directories b/fix/tests/tests/lang/readDir/foo/git-hates-directories new file mode 100644 index 0000000..e69de29 diff --git a/nix-js/tests/tests/lang/readDir/ldir b/fix/tests/tests/lang/readDir/ldir similarity index 100% rename from nix-js/tests/tests/lang/readDir/ldir rename to fix/tests/tests/lang/readDir/ldir diff --git a/nix-js/tests/tests/lang/readDir/linked b/fix/tests/tests/lang/readDir/linked similarity index 100% rename from nix-js/tests/tests/lang/readDir/linked rename to fix/tests/tests/lang/readDir/linked diff --git a/nix-js/tests/tests/lang/symlink-resolution/broken b/fix/tests/tests/lang/symlink-resolution/broken similarity index 100% rename from nix-js/tests/tests/lang/symlink-resolution/broken rename to fix/tests/tests/lang/symlink-resolution/broken diff --git a/nix-js/tests/tests/lang/symlink-resolution/foo/lib/default.nix b/fix/tests/tests/lang/symlink-resolution/foo/lib/default.nix similarity index 100% rename from nix-js/tests/tests/lang/symlink-resolution/foo/lib/default.nix rename to fix/tests/tests/lang/symlink-resolution/foo/lib/default.nix diff --git a/nix-js/tests/tests/lang/symlink-resolution/foo/overlays b/fix/tests/tests/lang/symlink-resolution/foo/overlays similarity index 100% rename from nix-js/tests/tests/lang/symlink-resolution/foo/overlays rename to fix/tests/tests/lang/symlink-resolution/foo/overlays diff --git a/nix-js/tests/tests/lang/symlink-resolution/overlays/overlay.nix b/fix/tests/tests/lang/symlink-resolution/overlays/overlay.nix similarity index 100% rename from nix-js/tests/tests/lang/symlink-resolution/overlays/overlay.nix rename to fix/tests/tests/lang/symlink-resolution/overlays/overlay.nix diff --git a/nix-js/tests/tests/lang/utils b/fix/tests/tests/lang/utils similarity index 100% rename from nix-js/tests/tests/lang/utils rename to fix/tests/tests/lang/utils diff --git a/nix-js/tests/tests/main.rs b/fix/tests/tests/main.rs similarity index 100% rename from nix-js/tests/tests/main.rs rename to fix/tests/tests/main.rs diff --git a/nix-js/tests/tests/numeric_types.rs b/fix/tests/tests/numeric_types.rs similarity index 99% rename from nix-js/tests/tests/numeric_types.rs rename to fix/tests/tests/numeric_types.rs index a0465e7..14a1151 100644 --- a/nix-js/tests/tests/numeric_types.rs +++ b/fix/tests/tests/numeric_types.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::eval; diff --git a/nix-js/tests/tests/operators.rs b/fix/tests/tests/operators.rs similarity index 98% rename from nix-js/tests/tests/operators.rs rename to fix/tests/tests/operators.rs index fb9d66d..8438f7e 100644 --- a/nix-js/tests/tests/operators.rs +++ b/fix/tests/tests/operators.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use nix_js::value::{AttrSet, List, Symbol, Value}; +use fix::value::{AttrSet, List, Symbol, Value}; use crate::utils::eval; diff --git a/nix-js/tests/tests/path_operations.rs b/fix/tests/tests/path_operations.rs similarity index 99% rename from nix-js/tests/tests/path_operations.rs rename to fix/tests/tests/path_operations.rs index 609d3f7..06ad874 100644 --- a/nix-js/tests/tests/path_operations.rs +++ b/fix/tests/tests/path_operations.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::{eval, eval_result}; diff --git a/nix-js/tests/tests/regex.rs b/fix/tests/tests/regex.rs similarity index 99% rename from nix-js/tests/tests/regex.rs rename to fix/tests/tests/regex.rs index 358346c..d0c909b 100644 --- a/nix-js/tests/tests/regex.rs +++ b/fix/tests/tests/regex.rs @@ -1,4 +1,4 @@ -use nix_js::value::{List, Value}; +use fix::value::{List, Value}; use crate::utils::eval; use crate::utils::eval_result; diff --git a/nix-js/tests/tests/string_context.rs b/fix/tests/tests/string_context.rs similarity index 99% rename from nix-js/tests/tests/string_context.rs rename to fix/tests/tests/string_context.rs index 85ed1d0..079698a 100644 --- a/nix-js/tests/tests/string_context.rs +++ b/fix/tests/tests/string_context.rs @@ -1,5 +1,5 @@ -use nix_js::context::Context; -use nix_js::value::Value; +use fix::context::Context; +use fix::value::Value; use crate::utils::eval_result; diff --git a/nix-js/tests/tests/thunk_scope.rs b/fix/tests/tests/thunk_scope.rs similarity index 99% rename from nix-js/tests/tests/thunk_scope.rs rename to fix/tests/tests/thunk_scope.rs index dfc9f52..e6603a4 100644 --- a/nix-js/tests/tests/thunk_scope.rs +++ b/fix/tests/tests/thunk_scope.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::eval; diff --git a/nix-js/tests/tests/to_string.rs b/fix/tests/tests/to_string.rs similarity index 99% rename from nix-js/tests/tests/to_string.rs rename to fix/tests/tests/to_string.rs index e1a27bb..f0f4261 100644 --- a/nix-js/tests/tests/to_string.rs +++ b/fix/tests/tests/to_string.rs @@ -1,4 +1,4 @@ -use nix_js::value::Value; +use fix::value::Value; use crate::utils::{eval, eval_result}; diff --git a/nix-js/tests/tests/utils.rs b/fix/tests/tests/utils.rs similarity index 87% rename from nix-js/tests/tests/utils.rs rename to fix/tests/tests/utils.rs index 94b1f18..ecc10cc 100644 --- a/nix-js/tests/tests/utils.rs +++ b/fix/tests/tests/utils.rs @@ -1,8 +1,8 @@ #![allow(dead_code)] -use nix_js::context::Context; -use nix_js::error::{Result, Source}; -use nix_js::value::Value; +use fix::context::Context; +use fix::error::{Result, Source}; +use fix::value::Value; pub fn eval(expr: &str) -> Value { Context::new() diff --git a/nix-js-macros/Cargo.toml b/nix-js-macros/Cargo.toml deleted file mode 100644 index b37fd1c..0000000 --- a/nix-js-macros/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "nix-js-macros" -version = "0.1.0" -edition = "2024" - -[lib] -proc-macro = true - -[dependencies] -convert_case = "0.11" -proc-macro2 = "1.0" -quote = "1.0" -syn = { version = "2.0", features = ["full"] } diff --git a/nix-js-macros/src/ir.rs b/nix-js-macros/src/ir.rs deleted file mode 100644 index 7be10de..0000000 --- a/nix-js-macros/src/ir.rs +++ /dev/null @@ -1,241 +0,0 @@ -//! Implements the `ir!` procedural macro. -//! -//! This macro is designed to reduce the boilerplate associated with defining -//! an Intermediate Representation (IR) that follows a specific pattern. It generates: -//! 1. An enum representing the different kinds of IR nodes. -//! 2. Structs for each of the variants that have fields. -//! 3. `From` implementations to easily convert from a struct variant (e.g., `BinOp`) to the main enum (`Ir::BinOp`). -//! 4. A `To[IrName]` trait to provide a convenient `.to_ir()` method on the variant structs. - -use convert_case::{Case, Casing}; -use proc_macro::TokenStream; -use quote::{format_ident, quote}; -use syn::{ - Expr, ExprPath, FieldsNamed, GenericArgument, GenericParam, Generics, Ident, Path, PathSegment, - Token, Type, TypePath, parenthesized, - parse::{Parse, ParseStream, Result}, - punctuated::Punctuated, - token, -}; - -/// Represents one of the variants passed to the `ir!` macro. -enum VariantInput { - /// A unit-like variant, e.g., `Arg`. - Unit(Ident), - /// A tuple-like variant with one unnamed field, e.g., `ExprRef(ExprId)`. - Tuple(Ident, Type), - /// A struct-like variant with named fields, e.g., `BinOp { lhs: ExprId, rhs: ExprId, kind: BinOpKind }`. - Struct(Ident, FieldsNamed), -} - -/// The top-level input for the `ir!` macro. -struct MacroInput { - /// The name of the main IR enum to be generated (e.g., `Ir`). - base_name: Ident, - generics: Generics, - /// The list of variants for the enum. - variants: Punctuated, -} - -impl Parse for VariantInput { - fn parse(input: ParseStream) -> Result { - let name: Ident = input.parse()?; - - if input.peek(token::Paren) { - // Parse a tuple-like variant: `Variant(Type)` - let content; - parenthesized!(content in input); - let ty: Type = content.parse()?; - - if !content.is_empty() { - return Err(content.error("Expected a single type inside parentheses")); - } - - Ok(VariantInput::Tuple(name, ty)) - } else if input.peek(token::Brace) { - // Parse a struct-like variant: `Variant { field: Type, ... }` - let fields: FieldsNamed = input.parse()?; - Ok(VariantInput::Struct(name, fields)) - } else { - // Parse a unit-like variant: `Variant` - Ok(VariantInput::Unit(name)) - } - } -} - -impl Parse for MacroInput { - fn parse(input: ParseStream) -> Result { - let base_name = input.parse()?; - let generics = Generics::parse(input)?; - input.parse::()?; - let variants = Punctuated::parse_terminated(input)?; - - Ok(MacroInput { - base_name, - generics, - variants, - }) - } -} - -/// The implementation of the `ir!` macro. -pub fn ir_impl(input: TokenStream) -> TokenStream { - let parsed_input = syn::parse_macro_input!(input as MacroInput); - - let base_name = &parsed_input.base_name; - let generic_params = &parsed_input.generics.params; - let mk_ident_path = |ident| Path { - leading_colon: None, - segments: Punctuated::from_iter(std::iter::once(PathSegment { - ident, - arguments: Default::default(), - })), - }; - let generic_args = { - generic_params - .iter() - .map(|arg| match arg { - GenericParam::Lifetime(lifetime) => { - GenericArgument::Lifetime(lifetime.lifetime.clone()) - } - GenericParam::Const(cnst) => GenericArgument::Const(Expr::Path(ExprPath { - path: mk_ident_path(cnst.ident.clone()), - attrs: Vec::new(), - qself: None, - })), - GenericParam::Type(ty) => GenericArgument::Type(Type::Path(TypePath { - path: mk_ident_path(ty.ident.clone()), - qself: None, - })), - }) - .collect::>() - }; - let where_clause = &parsed_input.generics.where_clause; - let to_trait_name = format_ident!("To{}", base_name); - let to_trait_fn_name = format_ident!("to_{}", base_name.to_string().to_case(Case::Snake)); - - let mut enum_variants = Vec::new(); - let mut struct_defs = Vec::new(); - let mut span_arms = Vec::new(); - let mut from_impls = Vec::new(); - let mut to_trait_impls = Vec::new(); - - for variant in parsed_input.variants { - match variant { - VariantInput::Unit(name) => { - let inner_type = name.clone(); - - struct_defs.push(quote! { - #[derive(Debug)] - pub struct #name { - pub span: rnix::TextRange, - } - }); - - enum_variants.push(quote! { #name(#inner_type) }); - span_arms.push(quote! { Self::#name(inner) => inner.span }); - from_impls.push(quote! { - impl <#generic_params> From<#inner_type> for #base_name <#generic_args> #where_clause { - fn from(val: #inner_type) -> Self { #base_name::#name(val) } - } - }); - to_trait_impls.push(quote! { - impl <#generic_params> #to_trait_name <#generic_args> for #name #where_clause { - fn #to_trait_fn_name(self) -> #base_name <#generic_args> { #base_name::from(self) } - } - }); - } - VariantInput::Tuple(name, ty) => { - let field_name = format_ident!("inner"); - - struct_defs.push(quote! { - #[derive(Debug)] - pub struct #name { - pub #field_name: #ty, - pub span: rnix::TextRange, - } - }); - - let inner_type = name.clone(); - enum_variants.push(quote! { #name(#inner_type) }); - span_arms.push(quote! { Self::#name(inner) => inner.span }); - from_impls.push(quote! { - impl <#generic_params> From<#inner_type> for #base_name <#generic_args> #where_clause { - fn from(val: #inner_type) -> Self { #base_name::#name(val) } - } - }); - to_trait_impls.push(quote! { - impl <#generic_params> #to_trait_name <#generic_args> for #name #where_clause { - fn #to_trait_fn_name(self) -> #base_name <#generic_args> { #base_name::from(self) } - } - }); - } - VariantInput::Struct(name, mut fields) => { - let inner_type = name.clone(); - - fields.named.iter_mut().for_each(|field| { - field.vis = syn::Visibility::Public(syn::token::Pub::default()); - }); - fields.named.push(syn::Field { - attrs: vec![], - vis: syn::Visibility::Public(syn::token::Pub::default()), - mutability: syn::FieldMutability::None, - ident: Some(format_ident!("span")), - colon_token: Some(syn::token::Colon::default()), - ty: syn::parse_quote!(rnix::TextRange), - }); - - struct_defs.push(quote! { - #[derive(Debug)] - pub struct #name <#generic_params> #where_clause #fields - }); - enum_variants.push(quote! { #name(#inner_type <#generic_args>) }); - span_arms.push(quote! { Self::#name(inner) => inner.span }); - from_impls.push(quote! { - impl <#generic_params> From<#inner_type <#generic_args>> for #base_name <#generic_args> #where_clause { - fn from(val: #inner_type <#generic_args>) -> Self { #base_name::#name(val) } - } - }); - to_trait_impls.push(quote! { - impl <#generic_params> #to_trait_name <#generic_args> for #name <#generic_args> #where_clause { - fn #to_trait_fn_name(self) -> #base_name <#generic_args> { #base_name::from(self) } - } - }); - } - } - } - - // Assemble the final generated code. - let expanded = quote! { - /// The main IR enum, generated by the `ir!` macro. - #[derive(Debug)] - pub enum #base_name <#generic_params> #where_clause { - #( #enum_variants ),* - } - - // The struct definitions for the enum variants. - #( #struct_defs )* - - impl <#generic_params> #base_name <#generic_args> #where_clause { - pub fn span(&self) -> rnix::TextRange { - match self { - #( #span_arms ),* - } - } - } - - // `From` implementations for converting variant structs into the main enum. - #( #from_impls )* - - /// A trait for converting a variant struct into the main IR enum. - pub trait #to_trait_name <#generic_params> #where_clause { - /// Performs the conversion. - fn #to_trait_fn_name(self) -> #base_name <#generic_args>; - } - - // Implement the `ToIr` trait for each variant struct. - #( #to_trait_impls )* - }; - - TokenStream::from(expanded) -} diff --git a/nix-js-macros/src/lib.rs b/nix-js-macros/src/lib.rs deleted file mode 100644 index bee68f8..0000000 --- a/nix-js-macros/src/lib.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! This crate provides procedural macros for the nix-js project. -use proc_macro::TokenStream; - -mod ir; - -/// A procedural macro to reduce boilerplate when defining an Intermediate Representation (IR). -/// -/// It generates an enum for the IR, along with `Ref` and `Mut` variants, -/// `From` implementations, and a `ToIr` trait. -#[proc_macro] -pub fn ir(input: TokenStream) -> TokenStream { - ir::ir_impl(input) -} diff --git a/nix-js/benches/compile_time.rs b/nix-js/benches/compile_time.rs deleted file mode 100644 index fbfec20..0000000 --- a/nix-js/benches/compile_time.rs +++ /dev/null @@ -1,141 +0,0 @@ -mod utils; - -use std::hint::black_box; - -use criterion::{Criterion, criterion_group, criterion_main}; -use nix_js::context::Context; -use utils::compile; - -fn bench_parse_and_downgrade(c: &mut Criterion) { - let mut group = c.benchmark_group("parse_and_downgrade"); - - group.bench_function("simple_expression", |b| { - b.iter(|| { - compile(black_box("1 + 1")); - }) - }); - - group.bench_function("complex_function", |b| { - b.iter(|| { - compile(black_box( - "let fib = n: if n <= 1 then 1 else fib (n - 1) + fib (n - 2); in fib", - )); - }) - }); - - group.bench_function("large_attrset", |b| { - b.iter(|| { - compile(black_box( - "{ a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8; i = 9; j = 10; k = 11; l = 12; m = 13; n = 14; o = 15; }", - )); - }) - }); - - group.bench_function("nested_let_bindings", |b| { - b.iter(|| { - compile(black_box( - "let a = 1; b = 2; c = 3; in let d = a + b; e = b + c; in let f = d + e; in f", - )); - }) - }); - - group.finish(); -} - -fn bench_codegen(c: &mut Criterion) { - let mut group = c.benchmark_group("codegen"); - - group.bench_function("arithmetic_expression", |b| { - b.iter(|| compile(black_box("(1 + 2) * (3 - 4) / 5"))) - }); - - group.bench_function("function_with_closure", |b| { - b.iter(|| compile(black_box("let x = 10; f = y: x + y; in f 5"))) - }); - - group.bench_function("recursive_attrset", |b| { - b.iter(|| { - compile(black_box( - "rec { a = 1; b = a + 1; c = b + 1; d = c + 1; e = d + 1; }", - )) - }) - }); - - group.finish(); -} - -fn bench_full_pipeline(c: &mut Criterion) { - let mut group = c.benchmark_group("full_pipeline"); - - group.bench_function("simple_eval", |b| b.iter(|| compile(black_box("1 + 1")))); - - group.bench_function("fibonacci_10", |b| { - b.iter(|| { - compile(black_box( - "let fib = n: if n <= 1 then 1 else fib (n - 1) + fib (n - 2); in fib 10", - )) - }) - }); - - group.bench_function("map_operation", |b| { - b.iter(|| compile(black_box("map (x: x * 2) [1 2 3 4 5 6 7 8 9 10]"))) - }); - - group.bench_function("complex_attrset_access", |b| { - b.iter(|| { - compile(black_box( - "let attrs = { a.b.c = { d.e = 42; }; }; in attrs.a.b.c.d.e", - )) - }) - }); - - group.bench_function("with_expression", |b| { - b.iter(|| { - compile(black_box( - "let attrs = { x = 1; y = 2; z = 3; }; in with attrs; x + y + z", - )) - }) - }); - - group.finish(); -} - -fn bench_context_creation(c: &mut Criterion) { - c.bench_function("context_new", |b| { - b.iter(|| { - let _ = Context::new(); - }) - }); -} - -fn bench_symbol_interning(c: &mut Criterion) { - let mut group = c.benchmark_group("symbol_interning"); - - group.bench_function("many_unique_symbols", |b| { - b.iter(|| { - compile(black_box( - "let a1 = 1; a2 = 2; a3 = 3; a4 = 4; a5 = 5; a6 = 6; a7 = 7; a8 = 8; a9 = 9; a10 = 10; in a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10", - )) - }) - }); - - group.bench_function("repeated_symbols", |b| { - b.iter(|| { - compile(black_box( - "let x = 1; y = x; z = x; a = x; b = x; c = x; in x + y + z + a + b + c", - )) - }) - }); - - group.finish(); -} - -criterion_group!( - benches, - bench_parse_and_downgrade, - bench_codegen, - bench_full_pipeline, - bench_context_creation, - bench_symbol_interning -); -criterion_main!(benches); diff --git a/nix-js/build.rs b/nix-js/build.rs deleted file mode 100644 index 56e09e1..0000000 --- a/nix-js/build.rs +++ /dev/null @@ -1,70 +0,0 @@ -use std::path::Path; -use std::process::Command; - -fn main() { - let runtime_ts_dir = Path::new("runtime-ts"); - let dist_runtime = runtime_ts_dir.join("dist/runtime.js"); - - if !runtime_ts_dir.exists() { - println!("cargo::warning=runtime-ts directory not found, using existing runtime.js"); - return; - } - - println!("cargo::rerun-if-changed=runtime-ts/src"); - println!("cargo::rerun-if-changed=runtime-ts/package.json"); - println!("cargo::rerun-if-changed=runtime-ts/tsconfig.json"); - println!("cargo::rerun-if-changed=runtime-ts/build.mjs"); - - if !runtime_ts_dir.join("node_modules").exists() { - println!("Installing npm dependencies..."); - let npm_cmd = if cfg!(target_os = "windows") { - "npm.cmd" - } else { - "npm" - }; - let status = Command::new(npm_cmd) - .arg("install") - .current_dir(runtime_ts_dir) - .status() - .expect("Failed to run npm install. Is Node.js installed?"); - - if !status.success() { - panic!("npm install failed. Please check your Node.js installation."); - } - } - - println!("Running TypeScript type checking..."); - let npm_cmd = if cfg!(target_os = "windows") { - "npm.cmd" - } else { - "npm" - }; - let status = Command::new(npm_cmd) - .arg("run") - .arg("typecheck") - .current_dir(runtime_ts_dir) - .status() - .expect("Failed to run type checking"); - - if !status.success() { - panic!("TypeScript type checking failed! Fix type errors before building."); - } - - println!("Building runtime.js from TypeScript..."); - let status = Command::new(npm_cmd) - .arg("run") - .arg("build") - .current_dir(runtime_ts_dir) - .status() - .expect("Failed to build runtime"); - - if !status.success() { - panic!("Runtime build failed!"); - } - - if dist_runtime.exists() { - println!("Successfully built runtime.js",); - } else { - panic!("dist/runtime.js not found after build"); - } -} diff --git a/nix-js/runtime-ts/.gitignore b/nix-js/runtime-ts/.gitignore deleted file mode 100644 index 8225baa..0000000 --- a/nix-js/runtime-ts/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -/node_modules -/dist diff --git a/nix-js/runtime-ts/build.mjs b/nix-js/runtime-ts/build.mjs deleted file mode 100644 index 1e6c26c..0000000 --- a/nix-js/runtime-ts/build.mjs +++ /dev/null @@ -1,8 +0,0 @@ -import * as esbuild from "esbuild"; - -await esbuild.build({ - entryPoints: ["src/index.ts"], - outfile: "dist/runtime.js", - bundle: true, - // minify: true, -}); diff --git a/nix-js/runtime-ts/eslint.config.mts b/nix-js/runtime-ts/eslint.config.mts deleted file mode 100644 index 5a833f6..0000000 --- a/nix-js/runtime-ts/eslint.config.mts +++ /dev/null @@ -1,20 +0,0 @@ -import js from "@eslint/js"; -import { defineConfig } from "eslint/config"; -import globals from "globals"; -import tseslint from "typescript-eslint"; - -export default defineConfig([ - js.configs.recommended, - ...tseslint.configs.recommended, - { - files: ["**/*.{js,mjs,cjs,ts,mts,cts}"], - languageOptions: { globals: globals.es2022 }, - rules: { - "no-unused-vars": "off", - "@typescript-eslint/no-unused-vars": ["error", { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }], - }, - }, - { - ignores: ["dist/**/*"], - }, -]); diff --git a/nix-js/runtime-ts/package-lock.json b/nix-js/runtime-ts/package-lock.json deleted file mode 100644 index af4cafe..0000000 --- a/nix-js/runtime-ts/package-lock.json +++ /dev/null @@ -1,1966 +0,0 @@ -{ - "name": "nix-js-runtime", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "nix-js-runtime", - "version": "0.1.0", - "dependencies": { - "globals": "^17.3.0", - "jiti": "^2.6.1", - "js-sdsl": "^4.4.2" - }, - "devDependencies": { - "esbuild": "^0.24.2", - "eslint": "^9.39.2", - "typescript": "^5.7.2", - "typescript-eslint": "^8.55.0" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz", - "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.24.2.tgz", - "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz", - "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.24.2.tgz", - "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz", - "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz", - "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz", - "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz", - "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz", - "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz", - "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz", - "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz", - "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz", - "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz", - "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz", - "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz", - "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz", - "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz", - "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz", - "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz", - "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz", - "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz", - "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz", - "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz", - "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz", - "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmmirror.com/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmmirror.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers/node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmmirror.com/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmmirror.com/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.2", - "resolved": "https://registry.npmmirror.com/@eslint/js/-/js-9.39.2.tgz", - "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmmirror.com/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmmirror.com/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmmirror.com/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.55.0.tgz", - "integrity": "sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/type-utils": "8.55.0", - "@typescript-eslint/utils": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.55.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmmirror.com/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-8.55.0.tgz", - "integrity": "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/project-service/-/project-service-8.55.0.tgz", - "integrity": "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.55.0", - "@typescript-eslint/types": "^8.55.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-8.55.0.tgz", - "integrity": "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.55.0.tgz", - "integrity": "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-8.55.0.tgz", - "integrity": "sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0", - "@typescript-eslint/utils": "8.55.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/types/-/types-8.55.0.tgz", - "integrity": "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.55.0.tgz", - "integrity": "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.55.0", - "@typescript-eslint/tsconfig-utils": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/visitor-keys": "8.55.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-8.55.0.tgz", - "integrity": "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.55.0", - "@typescript-eslint/types": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.55.0.tgz", - "integrity": "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.55.0", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.24.2", - "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.24.2.tgz", - "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.24.2", - "@esbuild/android-arm": "0.24.2", - "@esbuild/android-arm64": "0.24.2", - "@esbuild/android-x64": "0.24.2", - "@esbuild/darwin-arm64": "0.24.2", - "@esbuild/darwin-x64": "0.24.2", - "@esbuild/freebsd-arm64": "0.24.2", - "@esbuild/freebsd-x64": "0.24.2", - "@esbuild/linux-arm": "0.24.2", - "@esbuild/linux-arm64": "0.24.2", - "@esbuild/linux-ia32": "0.24.2", - "@esbuild/linux-loong64": "0.24.2", - "@esbuild/linux-mips64el": "0.24.2", - "@esbuild/linux-ppc64": "0.24.2", - "@esbuild/linux-riscv64": "0.24.2", - "@esbuild/linux-s390x": "0.24.2", - "@esbuild/linux-x64": "0.24.2", - "@esbuild/netbsd-arm64": "0.24.2", - "@esbuild/netbsd-x64": "0.24.2", - "@esbuild/openbsd-arm64": "0.24.2", - "@esbuild/openbsd-x64": "0.24.2", - "@esbuild/sunos-x64": "0.24.2", - "@esbuild/win32-arm64": "0.24.2", - "@esbuild/win32-ia32": "0.24.2", - "@esbuild/win32-x64": "0.24.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.2", - "resolved": "https://registry.npmmirror.com/eslint/-/eslint-9.39.2.tgz", - "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.2", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmmirror.com/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/eslint/node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmmirror.com/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmmirror.com/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "17.3.0", - "resolved": "https://registry.npmmirror.com/globals/-/globals-17.3.0.tgz", - "integrity": "sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmmirror.com/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "license": "MIT", - "peer": true, - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-sdsl": { - "version": "4.4.2", - "resolved": "https://registry.npmmirror.com/js-sdsl/-/js-sdsl-4.4.2.tgz", - "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmmirror.com/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmmirror.com/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmmirror.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmmirror.com/typescript-eslint/-/typescript-eslint-8.55.0.tgz", - "integrity": "sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.55.0", - "@typescript-eslint/parser": "8.55.0", - "@typescript-eslint/typescript-estree": "8.55.0", - "@typescript-eslint/utils": "8.55.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/nix-js/runtime-ts/package.json b/nix-js/runtime-ts/package.json deleted file mode 100644 index f1bbace..0000000 --- a/nix-js/runtime-ts/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "nix-js-runtime", - "version": "0.1.0", - "private": true, - "scripts": { - "check": "tsc --noEmit && npx eslint && biome check", - "typecheck": "tsc --noEmit", - "build": "node build.mjs", - "dev": "npm run typecheck && npm run build" - }, - "devDependencies": { - "esbuild": "^0.24.2", - "eslint": "^9.39.2", - "typescript": "^5.7.2", - "typescript-eslint": "^8.55.0", - "jiti": "^2.6.1" - }, - "dependencies": { - "globals": "^17.3.0", - "js-sdsl": "^4.4.2" - } -} diff --git a/nix-js/runtime-ts/src/builtins/arithmetic.ts b/nix-js/runtime-ts/src/builtins/arithmetic.ts deleted file mode 100644 index 42d3f63..0000000 --- a/nix-js/runtime-ts/src/builtins/arithmetic.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { op } from "../operators"; -import { coerceNumeric, forceInt, forceNumeric } from "../type-assert"; -import type { NixBool, NixInt, NixNumber, NixValue } from "../types"; - -export const add = - (a: NixValue) => - (b: NixValue): bigint | number => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - return (av as never) + (bv as never); - }; - -export const sub = - (a: NixValue) => - (b: NixValue): bigint | number => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - return (av as never) - (bv as never); - }; - -export const mul = - (a: NixValue) => - (b: NixValue): bigint | number => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - return (av as never) * (bv as never); - }; - -export const div = - (a: NixValue) => - (b: NixValue): NixNumber => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - - if (bv === 0 || bv === 0n) { - throw new RangeError("Division by zero"); - } - - return (av as never) / (bv as never); - }; - -export const bitAnd = - (a: NixValue) => - (b: NixValue): NixInt => { - const av = forceInt(a); - const bv = forceInt(b); - return av & bv; - }; - -export const bitOr = - (a: NixValue) => - (b: NixValue): NixInt => { - const av = forceInt(a); - const bv = forceInt(b); - return av | bv; - }; - -export const bitXor = - (a: NixValue) => - (b: NixValue): NixInt => { - const av = forceInt(a); - const bv = forceInt(b); - return av ^ bv; - }; - -export const lessThan = - (a: NixValue) => - (b: NixValue): NixBool => - op.lt(a, b); diff --git a/nix-js/runtime-ts/src/builtins/attrs.ts b/nix-js/runtime-ts/src/builtins/attrs.ts deleted file mode 100644 index c975eea..0000000 --- a/nix-js/runtime-ts/src/builtins/attrs.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { mkPos, select } from "../helpers"; -import { createThunk } from "../thunk"; -import { forceAttrs, forceFunction, forceList, forceStringValue } from "../type-assert"; -import { ATTR_POSITIONS, type NixAttrs, type NixList, type NixValue } from "../types"; - -export const attrNames = (set: NixValue): string[] => Array.from(forceAttrs(set).keys()).sort(); - -export const attrValues = (set: NixValue): NixValue[] => - Array.from(forceAttrs(set).entries()) - .sort(([a], [b]) => { - if (a < b) { - return -1; - } else if (a === b) { - return 0; - } else { - return 1; - } - }) - .map(([_, val]) => val); - -export const getAttr = - (s: NixValue) => - (set: NixValue): NixValue => - select(forceAttrs(set), [s]); - -export const hasAttr = - (s: NixValue) => - (set: NixValue): boolean => - forceAttrs(set).has(forceStringValue(s)); - -export const mapAttrs = - (f: NixValue) => - (attrs: NixValue): NixAttrs => { - const forcedAttrs = forceAttrs(attrs); - const forcedF = forceFunction(f); - const newAttrs: NixAttrs = new Map(); - for (const [key, val] of forcedAttrs) { - newAttrs.set( - key, - createThunk(() => forceFunction(forcedF(key))(val), "created by mapAttrs"), - ); - } - return newAttrs; - }; - -export const removeAttrs = - (attrs: NixValue) => - (list: NixValue): NixAttrs => { - const newAttrs: NixAttrs = new Map(forceAttrs(attrs)); - const forcedList = forceList(list); - for (const item of forcedList) { - newAttrs.delete(forceStringValue(item)); - } - return newAttrs; - }; - -export const listToAttrs = (e: NixValue): NixAttrs => { - const attrs: NixAttrs = new Map(); - const forcedE = [...forceList(e)].reverse(); - for (const obj of forcedE) { - const item = forceAttrs(obj); - attrs.set(forceStringValue(select(item, ["name"])), select(item, ["value"])); - } - return attrs; -}; - -export const intersectAttrs = - (e1: NixValue) => - (e2: NixValue): NixAttrs => { - const f1 = forceAttrs(e1); - const f2 = forceAttrs(e2); - const attrs: NixAttrs = new Map(); - if (f1.size < f2.size) { - for (const [key] of f1) { - if (f2.has(key)) { - attrs.set(key, f2.get(key) as NixValue); - } - } - } else { - for (const [key] of f2) { - if (f1.has(key)) { - attrs.set(key, f2.get(key) as NixValue); - } - } - } - return attrs; - }; - -export const catAttrs = - (attr: NixValue) => - (list: NixValue): NixList => { - const key = forceStringValue(attr); - return forceList(list) - .map((set) => forceAttrs(set).get(key)) - .filter((val) => val !== undefined) as NixList; - }; - -export const groupBy = - (f: NixValue) => - (list: NixValue): NixAttrs => { - const attrs: NixAttrs = new Map(); - const forcedF = forceFunction(f); - const forcedList = forceList(list); - for (const elem of forcedList) { - const key = forceStringValue(forcedF(elem)); - if (!attrs.has(key)) attrs.set(key, []); - (attrs.get(key) as NixList).push(elem); - } - return attrs; - }; - -export const zipAttrsWith = - (f: NixValue) => - (list: NixValue): NixValue => { - const listForced = forceList(list); - - const attrMap = new Map(); - - for (const item of listForced) { - const attrs = forceAttrs(item); - - for (const [key, value] of attrs) { - if (!attrMap.has(key)) { - attrMap.set(key, []); - } - (attrMap.get(key) as NixValue[]).push(value); - } - } - - const result: NixAttrs = new Map(); - - for (const [name, values] of attrMap.entries()) { - result.set( - name, - createThunk(() => forceFunction(forceFunction(f)(name))(values)), - ); - } - - return result; - }; - -export const unsafeGetAttrPos = - (attrName: NixValue) => - (attrSet: NixValue): NixValue => { - const name = forceStringValue(attrName); - const attrs = forceAttrs(attrSet); - - if (!attrs.has(name)) { - return null; - } - - const positions = attrs[ATTR_POSITIONS]; - if (!positions || !positions.has(name)) { - return null; - } - - const span = positions.get(name) as number; - return mkPos(span); - }; diff --git a/nix-js/runtime-ts/src/builtins/context.ts b/nix-js/runtime-ts/src/builtins/context.ts deleted file mode 100644 index fa6fb40..0000000 --- a/nix-js/runtime-ts/src/builtins/context.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { - decodeContextElem, - getStringContext, - getStringValue, - mkStringWithContext, - type NixStringContext, - parseContextToInfoMap, -} from "../string-context"; -import { force } from "../thunk"; -import { forceAttrs, forceList, forceString, forceStringValue } from "../type-assert"; -import type { NixAttrs, NixString, NixValue } from "../types"; -import { isStringWithContext } from "../types"; - -/** - * builtins.hasContext - Check if string has context - * - * Returns true if the string has any store path references. - */ -export const hasContext = (value: NixValue): boolean => { - const s = forceString(value); - return isStringWithContext(s) && s.context.size > 0; -}; - -/** - * builtins.unsafeDiscardStringContext - Remove all context from string - * - * IMPORTANT: This discards string context, returning only the string value. - * Use with caution as it removes derivation dependencies. - */ -export const unsafeDiscardStringContext = (value: NixValue): string => { - const s = forceString(value); - return getStringValue(s); -}; - -/** - * builtins.unsafeDiscardOutputDependency - Convert DrvDeep to Opaque context - * - * IMPORTANT: Transforms "all outputs" references (=) to plain path references. - * Preserves other context types unchanged. - */ -export const unsafeDiscardOutputDependency = (value: NixValue): NixString => { - const s = forceString(value); - const strValue = getStringValue(s); - const context = getStringContext(s); - - if (context.size === 0) { - return strValue; - } - - const newContext: NixStringContext = new Set(); - for (const encoded of context) { - const elem = decodeContextElem(encoded); - if (elem.type === "drvDeep") { - newContext.add(elem.drvPath); - } else { - newContext.add(encoded); - } - } - - if (newContext.size === 0) { - return strValue; - } - - return mkStringWithContext(strValue, newContext); -}; - -/** - * builtins.addDrvOutputDependencies - Convert Opaque to DrvDeep context - * - * IMPORTANT: Transforms plain derivation path references to "all outputs" references (=). - * The string must have exactly one context element which must be a .drv path. - */ -export const addDrvOutputDependencies = (value: NixValue): NixString => { - const s = forceString(value); - const strValue = getStringValue(s); - const context = getStringContext(s); - - if (context.size !== 1) { - throw new Error(`context of string '${strValue}' must have exactly one element, but has ${context.size}`); - } - - const [encoded] = context; - const elem = decodeContextElem(encoded); - - if (elem.type === "drvDeep") { - return s; - } - - if (elem.type === "built") { - throw new Error( - `\`addDrvOutputDependencies\` can only act on derivations, not on a derivation output such as '${elem.output}'`, - ); - } - - if (!elem.path.endsWith(".drv")) { - throw new Error(`path '${elem.path}' is not a derivation`); - } - - const newContext: NixStringContext = new Set([`=${elem.path}`]); - return mkStringWithContext(strValue, newContext); -}; - -/** - * builtins.getContext - Extract context as structured attribute set - * - * Returns an attribute set mapping store paths to their context info: - * - path: true if it's a plain store path reference (opaque) - * - allOutputs: true if it references all derivation outputs (drvDeep, encoded as =path) - * - outputs: list of specific output names (built, encoded as !output!path) - */ -export const getContext = (value: NixValue): NixAttrs => { - const s = forceString(value); - const context = getStringContext(s); - - const infoMap = parseContextToInfoMap(context); - const result: NixAttrs = new Map(); - - for (const [path, info] of infoMap) { - const attrs: NixAttrs = new Map(); - if (info.path) { - attrs.set("path", true); - } - if (info.allOutputs) { - attrs.set("allOutputs", true); - } - if (info.outputs.length > 0) { - attrs.set("outputs", info.outputs); - } - result.set(path, attrs); - } - - return result; -}; - -/** - * builtins.appendContext - Add context to a string - * - * IMPORTANT: Merges the provided context attribute set with any existing context - * from the input string. Used to manually construct strings with specific - * derivation dependencies. - * - * Context format matches getContext output: - * - path: boolean - add as opaque reference - * - allOutputs: boolean - add as drvDeep reference (=) - * - outputs: [string] - add as built references (!output!) - */ -export const appendContext = - (strValue: NixValue) => - (ctxValue: NixValue): NixString => { - const s = forceString(strValue); - const strVal = getStringValue(s); - const existingContext = getStringContext(s); - - const ctxAttrs = forceAttrs(ctxValue); - const newContext: NixStringContext = new Set(existingContext); - - for (const [path, infoVal] of ctxAttrs) { - if (!path.startsWith("/nix/store/")) { - throw new Error(`context key '${path}' is not a store path`); - } - - const info = forceAttrs(infoVal as NixValue); - - if (info.has("path")) { - const pathVal = force(info.get("path") as NixValue); - if (pathVal === true) { - newContext.add(path); - } - } - - if (info.has("allOutputs")) { - const allOutputs = force(info.get("allOutputs") as NixValue); - if (allOutputs === true) { - if (!path.endsWith(".drv")) { - throw new Error( - `tried to add all-outputs context of ${path}, which is not a derivation, to a string`, - ); - } - newContext.add(`=${path}`); - } - } - - if (info.has("outputs")) { - const outputs = forceList(info.get("outputs") as NixValue); - if (outputs.length > 0 && !path.endsWith(".drv")) { - throw new Error( - `tried to add derivation output context of ${path}, which is not a derivation, to a string`, - ); - } - for (const output of outputs) { - const outputName = forceStringValue(output); - newContext.add(`!${outputName}!${path}`); - } - } - } - - if (newContext.size === 0) { - return strVal; - } - - return mkStringWithContext(strVal, newContext); - }; diff --git a/nix-js/runtime-ts/src/builtins/conversion.ts b/nix-js/runtime-ts/src/builtins/conversion.ts deleted file mode 100644 index 7592706..0000000 --- a/nix-js/runtime-ts/src/builtins/conversion.ts +++ /dev/null @@ -1,371 +0,0 @@ -/** - * Conversion and serialization builtin functions - */ - -import { - addBuiltContext, - mkStringWithContext, - type NixStringContext, - StringWithContext, -} from "../string-context"; -import { force, isThunk } from "../thunk"; -import { forceFunction, forceStringNoCtx } from "../type-assert"; -import type { NixString, NixValue } from "../types"; -import { isNixPath, isStringWithContext, NixPath } from "../types"; -import { isAttrs, isPath, typeOf } from "./type-check"; - -export const fromJSON = (e: NixValue): NixValue => { - const str = force(e); - if (typeof str !== "string" && !isStringWithContext(str)) { - throw new TypeError(`builtins.fromJSON: expected a string, got ${typeOf(str)}`); - } - const jsonStr = isStringWithContext(str) ? str.value : str; - return Deno.core.ops.op_from_json(jsonStr) as NixValue; -}; - -export const fromTOML = (e: NixValue): NixValue => { - const toml = forceStringNoCtx(e); - return Deno.core.ops.op_from_toml(toml) as NixValue; -}; - -export const toJSON = (e: NixValue): NixString => { - const context: Set = new Set(); - const string = JSON.stringify(nixValueToJson(e, true, context, true)); - if (context.size === 0) { - return string; - } - return mkStringWithContext(string, context); -}; - -export const toXML = (e: NixValue): NixString => { - const [xml, context] = Deno.core.ops.op_to_xml(force(e)); - if (context.length === 0) { - return xml; - } - return mkStringWithContext(xml, new Set(context)); -}; - -/** - * String coercion modes control which types can be coerced to strings - * - * - Base: Only strings are allowed (no coercion) - * - Interpolation: Used in string interpolation "${expr}" - allows strings and integers - * - ToString: Used in builtins.toString - allows all types (bools, floats, null, lists, etc.) - */ -export enum StringCoercionMode { - Base = 0, - Interpolation = 1, - ToString = 2, -} - -export interface CoerceResult { - value: string; - context: NixStringContext; -} - -/** - * Coerce a Nix value to a string according to the specified mode. - * This implements the same behavior as Lix's EvalState::coerceToString. - * - * IMPORTANT: String context preservation rules: - * - StringWithContext: Context is collected in outContext parameter - * - Derivations (with outPath): Built context is added for the drvPath/outputName - * - Lists (ToString mode): Context from all elements is merged - * - All other coercions: No context added - * - * @param value - The value to coerce - * @param mode - The coercion mode (controls which types are allowed) - * @param copyToStore - If true, paths should be copied to the Nix store (not implemented yet) - * @param outContext - Optional context set to collect string contexts - * @returns The string representation of the value - * @throws TypeError if the value cannot be coerced in the given mode - * - * Coercion rules by type: - * - String: Always returns as-is - * - Path: Returns the path string (copyToStore not implemented yet) - * - Integer: Only in Interpolation or ToString mode - * - Float: Only in ToString mode - * - Boolean: Only in ToString mode (true → "1", false → "") - * - Null: Only in ToString mode (→ "") - * - List: Only in ToString mode (recursively coerce elements, join with spaces) - * - Attrs: Check for __toString method or outPath attribute - * - Function: Never coercible (throws error) - */ -export const coerceToString = ( - value: NixValue, - mode: StringCoercionMode, - copyToStore: boolean = false, - outContext: NixStringContext, -): string => { - const v = force(value); - - // Strings are always returned as-is, regardless of mode - if (typeof v === "string") { - return v; - } - - if (isStringWithContext(v)) { - for (const elem of v.context) { - outContext.add(elem); - } - return v.value; - } - - // Paths coerce to their string value - if (isNixPath(v)) { - if (copyToStore) { - const pathStr = v.value; - const storePath = Deno.core.ops.op_copy_path_to_store(pathStr); - outContext.add(storePath); - return storePath; - } - return v.value; - } - - if (typeof v === "object" && v !== null && !Array.isArray(v)) { - if (v instanceof Map) { - if (v.has("__toString")) { - const toStringMethod = forceFunction(v.get("__toString") as NixValue); - const result = force(toStringMethod(v)); - return coerceToString(result, mode, copyToStore, outContext); - } - - if (v.has("outPath")) { - const outPath = coerceToString(v.get("outPath") as NixValue, mode, copyToStore, outContext); - if (v.has("type") && v.get("type") === "derivation" && v.has("drvPath") && outContext) { - const drvPathValue = force(v.get("drvPath") as NixValue); - const drvPathStr = isStringWithContext(drvPathValue) - ? drvPathValue.value - : typeof drvPathValue === "string" - ? drvPathValue - : null; - if (drvPathStr) { - const outputName = v.has("outputName") ? String(force(v.get("outputName") as NixValue)) : "out"; - addBuiltContext(outContext, drvPathStr, outputName); - } - } - return outPath; - } - } - - throw new TypeError(`cannot coerce ${typeOf(v)} to a string`); - } - - // Integer coercion is allowed in Interpolation and ToString modes - // This enables string interpolation like "value: ${42}" - if (mode >= StringCoercionMode.Interpolation) { - if (typeof v === "bigint") { - return v.toString(); - } - } - - // The following types are only coercible in ToString mode (builtins.toString) - if (mode >= StringCoercionMode.ToString) { - // Booleans: true → "1", false → "" - // This is for shell scripting convenience (same as null) - if (typeof v === "boolean") { - return v ? "1" : ""; - } - - // Floats are converted using JavaScript's default toString - if (typeof v === "number") { - return v.toString(); - } - - // Null becomes empty string (for shell scripting convenience) - if (v === null) { - return ""; - } - - // Lists are recursively converted and joined with spaces - // We cannot use Array.join() directly because of special spacing rules: - // - Elements are recursively coerced to strings - // - Spaces are added between elements, BUT: - // * No space is added after an element if it's an empty list - // * The last element never gets a trailing space - // - // Examples: - // - [ 1 2 3 ] → "1 2 3" - // - [ 1 [ ] 2 ] → "1 2" (empty list doesn't add space) - // - [ 1 [ [ ] ] 2 ] → "1 2" (nested empty list is not itself empty, so adds space) - // - [ [ 1 2 ] [ 3 4 ] ] → "1 2 3 4" (nested lists flatten) - if (Array.isArray(v)) { - let result = ""; - for (let i = 0; i < v.length; i++) { - const item = v[i]; - // Recursively convert element to string - const str = coerceToString(item, mode, copyToStore, outContext); - result += str; - - // Add space after this element if: - // 1. It's not the last element, AND - // 2. The element is not an empty list - // - // Note: We check if the ELEMENT is an empty list, not if its - // string representation is empty. - // For example, [[]] is not an empty list (length 1), so it gets - // a trailing space even though its toString is "". - if (i < v.length - 1) { - const forcedItem = force(item); - if (!Array.isArray(forcedItem) || forcedItem.length !== 0) { - result += " "; - } - } - } - return result; - } - } - - throw new TypeError(`cannot coerce ${typeOf(v)} to a string`); -}; - -/** - * Coerce a Nix value to a string with context tracking - */ -export const coerceToStringWithContext = ( - value: NixValue, - mode: StringCoercionMode = StringCoercionMode.ToString, - copyToStore: boolean = false, -): NixString => { - const context: NixStringContext = new Set(); - const str = coerceToString(value, mode, copyToStore, context); - - if (context.size === 0) { - return str; - } - return mkStringWithContext(str, context); -}; - -/** - * Coerce a Nix value to an absolute path string. - * This implements the same behavior as Lix's EvalState::coerceToPath. - * - * @param value - The value to coerce - * @param outContext - Optional context set to collect string contexts - * @returns The absolute path string - * @throws TypeError if the value cannot be coerced to a string - * @throws Error if the result is not an absolute path - * - * Semantics: - * - Coerces to string using Strict mode (same as coerceToString with Base mode) - * - Validates the result is non-empty and starts with '/' - * - Returns the path string (not a NixPath object) - * - Preserves string context if present - */ -export const coerceToPath = (value: NixValue, outContext: NixStringContext): string => { - const forced = force(value); - - if (isPath(forced)) { - return forced.value; - } - if (isAttrs(forced) && forced.has("__toString")) { - const toStringFunc = forceFunction(forced.get("__toString") as NixValue); - return coerceToPath(toStringFunc(forced), outContext); - } - - const pathStr = coerceToString(value, StringCoercionMode.Base, false, outContext); - - if (pathStr === "") { - throw new Error("string doesn't represent an absolute path: empty string"); - } - - if (pathStr[0] !== "/") { - throw new Error(`string '${pathStr}' doesn't represent an absolute path`); - } - - return pathStr; -}; - -/** - * builtins.toString - Convert a value to a string - * - * This is the public builtin function exposed to Nix code. - * It uses ToString mode, which allows coercing all types except functions. - * - * @param value - The value to convert to a string - * @returns The string representation - */ -export const toStringFunc = (value: NixValue): NixString => { - return coerceToStringWithContext(value, StringCoercionMode.ToString, false); -}; - -export type JsonValue = number | boolean | string | null | { [key: string]: JsonValue } | Array; -export const nixValueToJson = ( - value: NixValue, - strict: boolean, - outContext: NixStringContext, - copyToStore: boolean, - seen: Set = new Set(), -): JsonValue => { - const v = strict ? force(value) : value; - - if (isThunk(v) || typeof v === "function") - throw new Error(`cannot convert ${isThunk(v) ? "thunk" : "lambda"} to JSON`); - if (v === null) return null; - if (typeof v === "bigint") { - const num = Number(v); - if (v > Number.MAX_SAFE_INTEGER || v < Number.MIN_SAFE_INTEGER) { - console.warn(`integer ${v} exceeds safe range, precision may be lost`); - } - return num; - } - if (typeof v === "number") return v; - if (typeof v === "boolean") return v; - if (typeof v === "string") return v; - if (v instanceof StringWithContext) { - for (const elem of v.context) { - outContext.add(elem); - } - return v.value; - } - if (v instanceof NixPath) { - if (copyToStore) { - const storePath = Deno.core.ops.op_copy_path_to_store(v.value); - outContext.add(storePath); - return storePath; - } else { - return v.value; - } - } - - // FIXME: is this check necessary? - // if (seen.has(v)) { - // throw new Error("cycle detected in toJSON"); - // } else { - // seen.add(v) - // } - - if (Array.isArray(v)) { - return v.map((item) => nixValueToJson(item, strict, outContext, copyToStore, seen)); - } - - if (v instanceof Map) { - if (v.has("__toString") && typeof force(v.get("__toString") as NixValue) === "function") { - const toStringMethod = force(v.get("__toString") as NixValue) as (self: typeof v) => NixValue; - const result = force(toStringMethod(v)); - if (typeof result === "string") { - return result; - } - if (isStringWithContext(result)) { - for (const elem of result.context) { - outContext.add(elem); - } - return result.value; - } - return nixValueToJson(result, strict, outContext, copyToStore, seen); - } - - if (v.has("outPath")) { - return nixValueToJson(v.get("outPath") as NixValue, strict, outContext, copyToStore, seen); - } - - const result: { [key: string]: JsonValue } = {}; - const keys = Array.from(v.keys()).sort(); - for (const key of keys) { - result[key] = nixValueToJson(v.get(key) as NixValue, strict, outContext, copyToStore, seen); - } - return result; - } - - throw new Error(`cannot convert ${typeof v} to JSON`); -}; diff --git a/nix-js/runtime-ts/src/builtins/derivation.ts b/nix-js/runtime-ts/src/builtins/derivation.ts deleted file mode 100644 index c1c6132..0000000 --- a/nix-js/runtime-ts/src/builtins/derivation.ts +++ /dev/null @@ -1,408 +0,0 @@ -import { - addBuiltContext, - addDrvDeepContext, - mkStringWithContext, - type NixStringContext, -} from "../string-context"; -import { force } from "../thunk"; -import { forceAttrs, forceList, forceStringNoCtx, forceStringValue } from "../type-assert"; -import type { NixAttrs, NixValue } from "../types"; -import { coerceToString, type JsonValue, nixValueToJson, StringCoercionMode } from "./conversion"; - -export interface OutputInfo { - path: string; - hashAlgo: string; - hash: string; -} - -export interface DerivationData { - name: string; - outputs: Map; - inputDrvs: Map>; - inputSrcs: Set; - platform: string; - builder: string; - args: string[]; - env: Map; -} - -export const escapeString = (s: string): string => { - let result = ""; - for (const char of s) { - switch (char) { - case '"': - result += '\\"'; - break; - case "\\": - result += "\\\\"; - break; - case "\n": - result += "\\n"; - break; - case "\r": - result += "\\r"; - break; - case "\t": - result += "\\t"; - break; - default: - result += char; - } - } - return `"${result}"`; -}; - -const quoteString = (s: string): string => `"${s}"`; - -const cmpByKey = (a: [string, T], b: [string, T]): number => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0); - -export const generateAterm = (drv: DerivationData): string => { - const outputEntries: string[] = []; - const sortedOutputs = Array.from(drv.outputs.entries()).sort(cmpByKey); - for (const [name, info] of sortedOutputs) { - outputEntries.push( - `(${quoteString(name)},${quoteString(info.path)},${quoteString(info.hashAlgo)},${quoteString(info.hash)})`, - ); - } - const outputs = outputEntries.join(","); - - const inputDrvEntries: string[] = []; - const sortedInputDrvs = Array.from(drv.inputDrvs.entries()).sort(cmpByKey); - for (const [drvPath, outputs] of sortedInputDrvs) { - const sortedOuts = Array.from(outputs).sort(); - const outList = `[${sortedOuts.map(quoteString).join(",")}]`; - inputDrvEntries.push(`(${quoteString(drvPath)},${outList})`); - } - const inputDrvs = inputDrvEntries.join(","); - - const sortedInputSrcs = Array.from(drv.inputSrcs).sort(); - const inputSrcs = sortedInputSrcs.map(quoteString).join(","); - - const args = drv.args.map(escapeString).join(","); - const envs = Array.from(drv.env.entries()) - .sort(cmpByKey) - .map(([k, v]) => `(${escapeString(k)},${escapeString(v)})`); - - return `Derive([${outputs}],[${inputDrvs}],[${inputSrcs}],${quoteString(drv.platform)},${escapeString(drv.builder)},[${args}],[${envs}])`; -}; - -export const generateAtermModulo = (drv: DerivationData, inputDrvHashes: Map): string => { - const outputEntries: string[] = []; - const sortedOutputs = Array.from(drv.outputs.entries()).sort(cmpByKey); - for (const [name, info] of sortedOutputs) { - outputEntries.push( - `(${quoteString(name)},${quoteString(info.path)},${quoteString(info.hashAlgo)},${quoteString(info.hash)})`, - ); - } - const outputs = outputEntries.join(","); - - const inputDrvEntries: string[] = []; - const sortedInputDrvHashes = Array.from(inputDrvHashes.entries()).sort(cmpByKey); - for (const [drvHash, outputs] of sortedInputDrvHashes) { - const sortedOuts = outputs.split(",").sort(); - const outList = `[${sortedOuts.map(quoteString).join(",")}]`; - inputDrvEntries.push(`(${quoteString(drvHash)},${outList})`); - } - const inputDrvs = inputDrvEntries.join(","); - - const sortedInputSrcs = Array.from(drv.inputSrcs).sort(); - const inputSrcs = sortedInputSrcs.map(quoteString).join(","); - - const args = drv.args.map(escapeString).join(","); - const envs = Array.from(drv.env.entries()) - .sort(cmpByKey) - .map(([k, v]) => `(${escapeString(k)},${escapeString(v)})`); - - return `Derive([${outputs}],[${inputDrvs}],[${inputSrcs}],${quoteString(drv.platform)},${escapeString(drv.builder)},[${args}],[${envs}])`; -}; -const validateName = (attrs: NixAttrs): string => { - if (!attrs.has("name")) { - throw new Error("derivation: missing required attribute 'name'"); - } - const name = forceStringValue(attrs.get("name") as NixValue); - if (!name) { - throw new Error("derivation: 'name' cannot be empty"); - } - if (name.endsWith(".drv")) { - throw new Error(`derivation: invalid name '${name}' (cannot end with .drv)`); - } - return name; -}; - -const validateBuilder = (attrs: NixAttrs, outContext: NixStringContext): string => { - if (!attrs.has("builder")) { - throw new Error("derivation: missing required attribute 'builder'"); - } - return coerceToString(attrs.get("builder") as NixValue, StringCoercionMode.ToString, true, outContext); -}; - -const validateSystem = (attrs: NixAttrs): string => { - if (!attrs.has("system")) { - throw new Error("derivation: missing required attribute 'system'"); - } - return forceStringValue(attrs.get("system") as NixValue); -}; - -const validateOutputs = (outputs: string[]): void => { - if (outputs.length === 0) { - throw new Error("derivation: outputs list cannot be empty"); - } - - if (outputs.includes("drv")) { - throw new Error("derivation: invalid output name 'drv'"); - } - - const seen = new Set(); - for (const output of outputs) { - if (seen.has(output)) { - throw new Error(`derivation: duplicate output '${output}'`); - } - seen.add(output); - } -}; - -const extractOutputs = (attrs: NixAttrs, structuredAttrs: boolean): string[] => { - if (!attrs.has("outputs")) { - return ["out"]; - } - - let outputs: string[]; - if (structuredAttrs) { - const outputsList = forceList(attrs.get("outputs") as NixValue); - outputs = outputsList.map((o) => forceStringValue(o)); - } else { - const outputsStr = coerceToString( - attrs.get("outputs") as NixValue, - StringCoercionMode.ToString, - false, - new Set(), - ); - outputs = outputsStr - .trim() - .split(/\s+/) - .filter((s) => s.length > 0); - } - - validateOutputs(outputs); - return outputs; -}; - -const extractArgs = (attrs: NixAttrs, outContext: NixStringContext): string[] => { - if (!attrs.has("args")) { - return []; - } - const argsList = forceList(attrs.get("args") as NixValue); - return argsList.map((a) => coerceToString(a, StringCoercionMode.ToString, true, outContext)); -}; - -const structuredAttrsExcludedKeys = new Set([ - "__structuredAttrs", - "__ignoreNulls", - "__contentAddressed", - "__impure", - "args", -]); - -const specialAttrs = new Set(["args", "__ignoreNulls", "__contentAddressed", "__impure"]); - -const sortedJsonStringify = (obj: Record): string => { - const sortedKeys = Object.keys(obj).sort(); - const sortedObj: Record = {}; - for (const key of sortedKeys) { - sortedObj[key] = obj[key]; - } - return JSON.stringify(sortedObj); -}; - -const extractEnv = ( - attrs: NixAttrs, - structuredAttrs: boolean, - ignoreNulls: boolean, - outContext: NixStringContext, - drvName: string, -): Map => { - const env = new Map(); - - if (structuredAttrs) { - const jsonAttrs: Record = {}; - for (const [key, value] of attrs) { - if (!structuredAttrsExcludedKeys.has(key)) { - const forcedValue = force(value); - if (ignoreNulls && forcedValue === null) { - continue; - } - jsonAttrs[key] = nixValueToJson(value, true, outContext, true); - } - - if (key === "allowedReferences") { - console.warn( - `In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` + - `the derivation attribute 'allowedReferences'; use ` + - `'outputChecks..allowedReferences' instead`, - ); - } - if (key === "allowedRequisites") { - console.warn( - `In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` + - `the derivation attribute 'allowedRequisites'; use ` + - `'outputChecks..allowedRequisites' instead`, - ); - } - if (key === "disallowedReferences") { - console.warn( - `In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` + - `the derivation attribute 'disallowedReferences'; use ` + - `'outputChecks..disallowedReferences' instead`, - ); - } - if (key === "disallowedRequisites") { - console.warn( - `In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` + - `the derivation attribute 'disallowedRequisites'; use ` + - `'outputChecks..disallowedRequisites' instead`, - ); - } - if (key === "maxSize") { - console.warn( - `In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` + - `the derivation attribute 'maxSize'; use ` + - `'outputChecks..maxSize' instead`, - ); - } - if (key === "maxClosureSize") { - console.warn( - `In a derivation named '${drvName}', 'structuredAttrs' disables the effect of ` + - `the derivation attribute 'maxClosureSize'; use ` + - `'outputChecks..maxClosureSize' instead`, - ); - } - } - env.set("__json", sortedJsonStringify(jsonAttrs)); - } else { - for (const [key, value] of attrs) { - if (!specialAttrs.has(key)) { - const forcedValue = force(value as NixValue); - if (ignoreNulls && forcedValue === null) { - continue; - } - env.set(key, coerceToString(value as NixValue, StringCoercionMode.ToString, true, outContext)); - } - } - } - - return env; -}; - -interface FixedOutputInfo { - hash: string; - hashAlgo: string; - hashMode: string; -} - -const extractFixedOutputInfo = (attrs: NixAttrs, ignoreNulls: boolean): FixedOutputInfo | null => { - if (!attrs.has("outputHash")) { - return null; - } - - const hashValue = force(attrs.get("outputHash") as NixValue); - if (ignoreNulls && hashValue === null) { - return null; - } - const hashRaw = forceStringNoCtx(hashValue); - - let hashAlgo = null; - if (attrs.has("outputHashAlgo")) { - const algoValue = force(attrs.get("outputHashAlgo") as NixValue); - if (!(ignoreNulls && algoValue === null)) { - hashAlgo = forceStringNoCtx(algoValue); - } - } - - let hashMode = "flat"; - if (attrs.has("outputHashMode")) { - const modeValue = force(attrs.get("outputHashMode") as NixValue); - if (!(ignoreNulls && modeValue === null)) { - hashMode = forceStringValue(modeValue); - } - } - - if (hashMode !== "flat" && hashMode !== "recursive") { - throw new Error(`derivation: invalid outputHashMode '${hashMode}' (must be 'flat' or 'recursive')`); - } - - const parsed = Deno.core.ops.op_parse_hash(hashRaw, hashAlgo); - - return { hash: parsed.hex, hashAlgo: parsed.algo, hashMode }; -}; - -const validateFixedOutputConstraints = (fixedOutput: FixedOutputInfo | null, outputs: string[]) => { - if (fixedOutput && (outputs.length !== 1 || outputs[0] !== "out")) { - throw new Error("derivation: fixed-output derivations must have exactly one 'out' output"); - } -}; - -export const derivationStrict = (args: NixValue): NixAttrs => { - const attrs = forceAttrs(args); - - const drvName = validateName(attrs); - const collectedContext: NixStringContext = new Set(); - const builder = validateBuilder(attrs, collectedContext); - const platform = validateSystem(attrs); - - const structuredAttrs = attrs.has("__structuredAttrs") - ? force(attrs.get("__structuredAttrs") as NixValue) === true - : false; - const ignoreNulls = attrs.has("__ignoreNulls") - ? force(attrs.get("__ignoreNulls") as NixValue) === true - : false; - - const outputs = extractOutputs(attrs, structuredAttrs); - const fixedOutputInfo = extractFixedOutputInfo(attrs, ignoreNulls); - validateFixedOutputConstraints(fixedOutputInfo, outputs); - - if (attrs.has("__contentAddressed") && force(attrs.get("__contentAddressed") as NixValue) === true) { - throw new Error("ca derivations are not supported"); - } - - if (attrs.has("__impure") && force(attrs.get("__impure") as NixValue) === true) { - throw new Error("impure derivations are not supported"); - } - - const drvArgs = extractArgs(attrs, collectedContext); - const env = extractEnv(attrs, structuredAttrs, ignoreNulls, collectedContext, drvName); - - const envEntries: [string, string][] = Array.from(env.entries()); - const contextArray: string[] = Array.from(collectedContext); - - const rustResult: { - drvPath: string; - outputs: [string, string][]; - } = Deno.core.ops.op_finalize_derivation( - drvName, - builder, - platform, - outputs, - drvArgs, - envEntries, - contextArray, - fixedOutputInfo, - ); - - const result: NixAttrs = new Map(); - - const drvPathContext = new Set(); - addDrvDeepContext(drvPathContext, rustResult.drvPath); - result.set("drvPath", mkStringWithContext(rustResult.drvPath, drvPathContext)); - - for (const [outputName, outputPath] of rustResult.outputs) { - const outputContext = new Set(); - addBuiltContext(outputContext, rustResult.drvPath, outputName); - result.set(outputName, mkStringWithContext(outputPath, outputContext)); - } - - return result; -}; - -export const derivationStub = (_: NixValue): NixAttrs => { - throw new Error("unreachable: stub derivation implementation called"); -}; diff --git a/nix-js/runtime-ts/src/builtins/flake.ts b/nix-js/runtime-ts/src/builtins/flake.ts deleted file mode 100644 index d3f7480..0000000 --- a/nix-js/runtime-ts/src/builtins/flake.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { NixValue } from "../types"; - -export const getFlake = (_attrs: NixValue): never => { - throw new Error("Not implemented: getFlake"); -}; - -export const parseFlakeName = (_s: NixValue): never => { - throw new Error("Not implemented: parseFlakeName"); -}; - -export const parseFlakeRef = (_s: NixValue): never => { - throw new Error("Not implemented: parseFlakeRef"); -}; - -export const flakeRefToString = (_attrs: NixValue): never => { - throw new Error("Not implemented: flakeRefToString"); -}; diff --git a/nix-js/runtime-ts/src/builtins/functional.ts b/nix-js/runtime-ts/src/builtins/functional.ts deleted file mode 100644 index 45c18e5..0000000 --- a/nix-js/runtime-ts/src/builtins/functional.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { printValue } from "../print"; -import { force } from "../thunk"; -import { CatchableError, type NixValue } from "../types"; -import { coerceToString, StringCoercionMode } from "./conversion"; -import { isAttrs } from "./type-check"; - -export const seq = - (e1: NixValue) => - (e2: NixValue): NixValue => { - force(e1); // Force evaluation of e1 - return e2; - }; - -export const deepSeq = - (e1: NixValue) => - (e2: NixValue): NixValue => { - const seen: Set = new Set(); - const recurse = (e: NixValue) => { - if (!seen.has(e)) { - seen.add(e); - } else { - return; - } - const forced = force(e); - if (Array.isArray(forced)) { - for (const val of forced) { - recurse(val); - } - } else if (isAttrs(forced)) { - for (const [_, val] of forced.entries()) { - recurse(val); - } - } - }; - recurse(e1); - return e2; - }; - -export const abort = (s: NixValue): never => { - throw new Error(`evaluation aborted with the following error message: '${force(s)}'`); -}; - -export const throwFunc = (s: NixValue): never => { - throw new CatchableError(coerceToString(s, StringCoercionMode.Base, false, new Set())); -}; - -export const trace = - (e1: NixValue) => - (e2: NixValue): NixValue => { - console.error(`trace: ${printValue(force(e1))}`); - return e2; - }; - -export const warn = - (e1: NixValue) => - (e2: NixValue): NixValue => { - console.log(`evaluation warning: ${force(e1)}`); - return e2; - }; - -export const breakFunc = (v: NixValue): NixValue => v; diff --git a/nix-js/runtime-ts/src/builtins/hash.ts b/nix-js/runtime-ts/src/builtins/hash.ts deleted file mode 100644 index ffdd609..0000000 --- a/nix-js/runtime-ts/src/builtins/hash.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { select } from "../helpers"; -import { forceAttrs, forceStringNoCtx, forceStringValue } from "../type-assert"; -import type { NixValue } from "../types"; -import { realisePath } from "./io"; - -export const hashFile = - (type: NixValue) => - (p: NixValue): string => { - const algo = forceStringNoCtx(type); - const pathStr = realisePath(p); - return Deno.core.ops.op_hash_file(algo, pathStr); - }; - -export const hashString = - (type: NixValue) => - (s: NixValue): string => { - const algo = forceStringNoCtx(type); - const data = forceStringValue(s); - return Deno.core.ops.op_hash_string(algo, data); - }; - -export const convertHash = (args: NixValue): string => { - const attrs = forceAttrs(args); - const hash = forceStringNoCtx(select(attrs, ["hash"])); - - let hashAlgo: string | null = null; - if (attrs.has("hashAlgo")) { - hashAlgo = forceStringNoCtx(select(attrs, ["hashAlgo"])); - } - - const toHashFormat = forceStringNoCtx(select(attrs, ["toHashFormat"])); - - return Deno.core.ops.op_convert_hash(hash, hashAlgo, toHashFormat); -}; diff --git a/nix-js/runtime-ts/src/builtins/index.ts b/nix-js/runtime-ts/src/builtins/index.ts deleted file mode 100644 index 42fa65b..0000000 --- a/nix-js/runtime-ts/src/builtins/index.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { createThunk, force } from "../thunk"; -import type { NixAttrs, NixFunction, NixValue } from "../types"; -import * as arithmetic from "./arithmetic"; -import * as attrs from "./attrs"; -import * as conversion from "./conversion"; -import * as derivation from "./derivation"; -import * as flake from "./flake"; -import * as functional from "./functional"; -import * as hash from "./hash"; -import * as io from "./io"; -import * as list from "./list"; -import * as math from "./math"; -import * as misc from "./misc"; -import * as pathOps from "./path"; -import * as string from "./string"; -import * as typeCheck from "./type-check"; - -export const PRIMOP_METADATA = Symbol("primop_metadata"); - -export interface PrimopMetadata { - name: string; - arity: number; - applied: number; -} - -export const mkPrimop = ( - func: NixFunction, - name: string, - arity: number, - applied: number = 0, -): ((...args: NixValue[]) => NixValue) => { - func[PRIMOP_METADATA] = { - name, - arity, - applied, - } satisfies PrimopMetadata; - - if (applied < arity - 1) { - const wrappedFunc: NixFunction = ((arg: NixValue) => { - const result = func(arg); - if (typeof result === "function") { - return mkPrimop(result, name, arity, applied + 1); - } - return result; - }); - - wrappedFunc[PRIMOP_METADATA] = { - name, - arity, - applied, - }; - - return wrappedFunc; - } - - return func; -}; - -export const isPrimop = ( - value: NixValue, -): value is NixFunction & { [PRIMOP_METADATA]: PrimopMetadata } => { - return ( - typeof value === "function" && - PRIMOP_METADATA in value && - typeof value[PRIMOP_METADATA] === "object" && - value[PRIMOP_METADATA] !== null - ); -}; - -export const getPrimopMetadata = (func: NixValue): PrimopMetadata | undefined => { - if (isPrimop(func)) { - return func[PRIMOP_METADATA]; - } - return undefined; -}; - -export const builtins: NixAttrs = new Map( - Object.entries({ - add: mkPrimop(arithmetic.add, "add", 2), - sub: mkPrimop(arithmetic.sub, "sub", 2), - mul: mkPrimop(arithmetic.mul, "mul", 2), - div: mkPrimop(arithmetic.div, "div", 2), - bitAnd: mkPrimop(arithmetic.bitAnd, "bitAnd", 2), - bitOr: mkPrimop(arithmetic.bitOr, "bitOr", 2), - bitXor: mkPrimop(arithmetic.bitXor, "bitXor", 2), - lessThan: mkPrimop(arithmetic.lessThan, "lessThan", 2), - - ceil: mkPrimop(math.ceil, "ceil", 1), - floor: mkPrimop(math.floor, "floor", 1), - - isAttrs: mkPrimop((e: NixValue) => typeCheck.isAttrs(force(e)), "isAttrs", 1), - isBool: mkPrimop((e: NixValue) => typeCheck.isBool(force(e)), "isBool", 1), - isFloat: mkPrimop((e: NixValue) => typeCheck.isFloat(force(e)), "isFloat", 1), - isFunction: mkPrimop((e: NixValue) => typeCheck.isFunction(force(e)), "isFunction", 1), - isInt: mkPrimop((e: NixValue) => typeCheck.isInt(force(e)), "isInt", 1), - isList: mkPrimop((e: NixValue) => typeCheck.isList(force(e)), "isList", 1), - isNull: mkPrimop((e: NixValue) => typeCheck.isNull(force(e)), "isNull", 1), - isPath: mkPrimop((e: NixValue) => typeCheck.isPath(force(e)), "isPath", 1), - isString: mkPrimop((e: NixValue) => typeCheck.isString(force(e)), "isString", 1), - typeOf: mkPrimop((e: NixValue) => typeCheck.typeOf(force(e)), "typeOf", 1), - - map: mkPrimop(list.map, "map", 2), - filter: mkPrimop(list.filter, "filter", 2), - length: mkPrimop(list.length, "length", 1), - head: mkPrimop(list.head, "head", 1), - tail: mkPrimop(list.tail, "tail", 1), - elem: mkPrimop(list.elem, "elem", 2), - elemAt: mkPrimop(list.elemAt, "elemAt", 2), - concatLists: mkPrimop(list.concatLists, "concatLists", 1), - concatMap: mkPrimop(list.concatMap, "concatMap", 2), - "foldl'": mkPrimop(list.foldlPrime, "foldl'", 3), - sort: mkPrimop(list.sort, "sort", 2), - partition: mkPrimop(list.partition, "partition", 2), - genList: mkPrimop(list.genList, "genList", 2), - all: mkPrimop(list.all, "all", 2), - any: mkPrimop(list.any, "any", 2), - - attrNames: mkPrimop(attrs.attrNames, "attrNames", 1), - attrValues: mkPrimop(attrs.attrValues, "attrValues", 1), - getAttr: mkPrimop(attrs.getAttr, "getAttr", 2), - hasAttr: mkPrimop(attrs.hasAttr, "hasAttr", 2), - mapAttrs: mkPrimop(attrs.mapAttrs, "mapAttrs", 2), - removeAttrs: mkPrimop(attrs.removeAttrs, "removeAttrs", 2), - listToAttrs: mkPrimop(attrs.listToAttrs, "listToAttrs", 1), - intersectAttrs: mkPrimop(attrs.intersectAttrs, "intersectAttrs", 2), - catAttrs: mkPrimop(attrs.catAttrs, "catAttrs", 2), - groupBy: mkPrimop(attrs.groupBy, "groupBy", 2), - zipAttrsWith: mkPrimop(attrs.zipAttrsWith, "zipAttrsWith", 2), - unsafeGetAttrPos: mkPrimop(attrs.unsafeGetAttrPos, "unsafeGetAttrPos", 2), - - stringLength: mkPrimop(string.stringLength, "stringLength", 1), - substring: mkPrimop(string.substring, "substring", 3), - concatStringsSep: mkPrimop(string.concatStringsSep, "concatStringsSep", 2), - baseNameOf: mkPrimop(pathOps.baseNameOf, "baseNameOf", 1), - dirOf: mkPrimop(pathOps.dirOf, "dirOf", 1), - toPath: mkPrimop(pathOps.toPath, "toPath", 1), - match: mkPrimop(string.match, "match", 2), - split: mkPrimop(string.split, "split", 2), - - seq: mkPrimop(functional.seq, "seq", 2), - deepSeq: mkPrimop(functional.deepSeq, "deepSeq", 2), - abort: mkPrimop(functional.abort, "abort", 1), - throw: mkPrimop(functional.throwFunc, "throw", 1), - trace: mkPrimop(functional.trace, "trace", 2), - warn: mkPrimop(functional.warn, "warn", 2), - break: mkPrimop(functional.breakFunc, "break", 1), - - derivation: mkPrimop(derivation.derivationStub, "derivation", 1), - derivationStrict: mkPrimop(derivation.derivationStrict, "derivationStrict", 1), - - import: mkPrimop(io.importFunc, "import", 1), - scopedImport: mkPrimop(io.scopedImport, "scopedImport", 2), - storePath: mkPrimop(io.storePath, "storePath", 1), - fetchClosure: mkPrimop(io.fetchClosure, "fetchClosure", 1), - fetchMercurial: mkPrimop(io.fetchMercurial, "fetchMercurial", 1), - fetchGit: mkPrimop(io.fetchGit, "fetchGit", 1), - fetchTarball: mkPrimop(io.fetchTarball, "fetchTarball", 1), - fetchTree: mkPrimop(io.fetchTree, "fetchTree", 1), - fetchurl: mkPrimop(io.fetchurl, "fetchurl", 1), - readDir: mkPrimop(io.readDir, "readDir", 1), - readFile: mkPrimop(io.readFile, "readFile", 1), - readFileType: mkPrimop(io.readFileType, "readFileType", 1), - pathExists: mkPrimop(io.pathExists, "pathExists", 1), - path: mkPrimop(io.path, "path", 1), - toFile: mkPrimop(io.toFile, "toFile", 2), - filterSource: mkPrimop(io.filterSource, "filterSource", 2), - findFile: mkPrimop(io.findFile, "findFile", 2), - getEnv: mkPrimop(io.getEnv, "getEnv", 1), - - fromJSON: mkPrimop(conversion.fromJSON, "fromJSON", 1), - fromTOML: mkPrimop(conversion.fromTOML, "fromTOML", 1), - toJSON: mkPrimop(conversion.toJSON, "toJSON", 1), - toXML: mkPrimop(conversion.toXML, "toXML", 1), - toString: mkPrimop(conversion.toStringFunc, "toString", 1), - - hashFile: mkPrimop(hash.hashFile, "hashFile", 2), - hashString: mkPrimop(hash.hashString, "hashString", 2), - convertHash: mkPrimop(hash.convertHash, "convertHash", 2), - - flakeRefToString: mkPrimop(flake.flakeRefToString, "flakeRefToString", 1), - getFlake: mkPrimop(flake.getFlake, "getFlake", 1), - parseFlakeName: mkPrimop(flake.parseFlakeName, "parseFlakeName", 1), - parseFlakeRef: mkPrimop(flake.parseFlakeRef, "parseFlakeRef", 1), - - addErrorContext: mkPrimop(misc.addErrorContext, "addErrorContext", 1), - appendContext: mkPrimop(misc.appendContext, "appendContext", 1), - getContext: mkPrimop(misc.getContext, "getContext", 1), - hasContext: mkPrimop(misc.hasContext, "hasContext", 1), - unsafeDiscardOutputDependency: mkPrimop( - misc.unsafeDiscardOutputDependency, - "unsafeDiscardOutputDependency", - 1, - ), - unsafeDiscardStringContext: mkPrimop(misc.unsafeDiscardStringContext, "unsafeDiscardStringContext", 1), - addDrvOutputDependencies: mkPrimop(misc.addDrvOutputDependencies, "addDrvOutputDependencies", 2), - compareVersions: mkPrimop(misc.compareVersions, "compareVersions", 2), - functionArgs: mkPrimop(misc.functionArgs, "functionArgs", 1), - genericClosure: mkPrimop(misc.genericClosure, "genericClosure", 1), - outputOf: mkPrimop(misc.outputOf, "outputOf", 2), - parseDrvName: mkPrimop(misc.parseDrvName, "parseDrvName", 1), - placeholder: mkPrimop(misc.placeholder, "placeholder", 1), - replaceStrings: mkPrimop(misc.replaceStrings, "replaceStrings", 3), - splitVersion: mkPrimop(misc.splitVersion, "splitVersion", 1), - traceVerbose: mkPrimop(misc.traceVerbose, "traceVerbose", 2), - tryEval: mkPrimop(misc.tryEval, "tryEval", 1), - - builtins: createThunk(() => builtins, "builtins"), - currentSystem: createThunk(() => { - return "x86_64-linux"; - }, "currentSystem"), - currentTime: createThunk(() => Date.now(), "currentTime"), - - false: false, - true: true, - null: null, - - langVersion: 6, - nixPath: [], - nixVersion: "2.31.2", - storeDir: createThunk(() => { - throw new Error("stub storeDir evaluated"); - }), - }), -); diff --git a/nix-js/runtime-ts/src/builtins/io.ts b/nix-js/runtime-ts/src/builtins/io.ts deleted file mode 100644 index 510d207..0000000 --- a/nix-js/runtime-ts/src/builtins/io.ts +++ /dev/null @@ -1,486 +0,0 @@ -import { select } from "../helpers"; -import { getPathValue } from "../path"; -import type { NixStringContext, StringWithContext } from "../string-context"; -import { addOpaqueContext, decodeContextElem, mkStringWithContext } from "../string-context"; -import { force } from "../thunk"; -import { - forceAttrs, - forceBool, - forceFunction, - forceList, - forceStringNoCtx, - forceStringValue, -} from "../type-assert"; -import type { NixAttrs, NixString, NixValue } from "../types"; -import { CatchableError, isNixPath, NixPath } from "../types"; -import { coerceToPath, coerceToString, StringCoercionMode } from "./conversion"; -import { baseNameOf } from "./path"; -import { isAttrs, isPath, isString } from "./type-check"; -import { execBytecode, execBytecodeScoped } from "../vm"; - -const importCache = new Map(); - -const realiseContext = (context: NixStringContext): void => { - for (const encoded of context) { - const elem = decodeContextElem(encoded); - if (elem.type === "built") { - throw new Error( - `cannot build derivation '${elem.drvPath}' during evaluation because import-from-derivation is not supported`, - ); - } - } -}; - -export const realisePath = (value: NixValue): string => { - const context: NixStringContext = new Set(); - const pathStr = coerceToPath(value, context); - - if (context.size > 0) { - realiseContext(context); - } - - return pathStr; -}; - -export const importFunc = (path: NixValue): NixValue => { - const pathStr = realisePath(path); - - const cached = importCache.get(pathStr); - if (cached !== undefined) { - return cached; - } - - const [code, currentDir] = Deno.core.ops.op_import(pathStr); - const result = execBytecode(code, currentDir); - - importCache.set(pathStr, result); - return result; -}; - -export const scopedImport = - (scope: NixValue) => - (path: NixValue): NixValue => { - const scopeAttrs = forceAttrs(scope); - const scopeKeys = Array.from(scopeAttrs.keys()); - - const pathStr = realisePath(path); - - const [code, currentDir] = Deno.core.ops.op_scoped_import(pathStr, scopeKeys); - return execBytecodeScoped(code, currentDir, scopeAttrs); - }; - -export const storePath = (pathArg: NixValue): StringWithContext => { - const context: NixStringContext = new Set(); - const pathStr = coerceToPath(pathArg, context); - - const validatedPath: string = Deno.core.ops.op_store_path(pathStr); - - context.add(validatedPath); - return mkStringWithContext(validatedPath, context); -}; - -export const fetchClosure = (_args: NixValue): never => { - throw new Error("Not implemented: fetchClosure"); -}; - -export interface FetchUrlResult { - storePath: string; - hash: string; -} - -export interface FetchTarballResult { - storePath: string; - narHash: string; -} - -export interface FetchGitResult { - outPath: string; - rev: string; - shortRev: string; - revCount: number; - lastModified: number; - lastModifiedDate: string; - submodules: boolean; - narHash: string | null; -} - -const normalizeUrlInput = ( - args: NixValue, -): { url: string; hash?: string; name?: string; executable?: boolean } => { - const forced = force(args); - if (typeof forced === "string") { - return { url: forced }; - } - const attrs = forceAttrs(args); - const url = forceStringValue(select(attrs, ["url"])); - const hash = attrs.has("sha256") - ? forceStringValue(attrs.get("sha256") as NixValue) - : attrs.has("hash") - ? forceStringValue(attrs.get("hash") as NixValue) - : undefined; - const name = attrs.has("name") ? forceStringValue(attrs.get("name") as NixValue) : undefined; - const executable = attrs.has("executable") ? forceBool(attrs.get("executable") as NixValue) : false; - return { url, hash, name, executable }; -}; - -const normalizeTarballInput = (args: NixValue): { url: string; sha256?: string; name?: string } => { - const forced = force(args); - if (isAttrs(forced)) { - const url = resolvePseudoUrl(forceStringNoCtx(select(forced, ["url"]))); - const sha256 = forced.has("sha256") ? forceStringNoCtx(forced.get("sha256") as NixValue) : undefined; - const nameRaw = forced.has("name") ? forceStringNoCtx(forced.get("name") as NixValue) : undefined; - const name = nameRaw === "" ? (baseNameOf(nameRaw) as string) : nameRaw; - return { url, sha256, name }; - } else { - return { url: forceStringNoCtx(forced) }; - } -}; - -const resolvePseudoUrl = (url: string) => { - if (url.startsWith("channel:")) { - return `https://channels.nixos.org/${url.substring(8)}/nixexprs.tar.xz`; - } else { - return url; - } -}; - -export const fetchurl = (args: NixValue): NixString => { - const { url, hash, name, executable } = normalizeUrlInput(args); - const result: FetchUrlResult = Deno.core.ops.op_fetch_url( - url, - hash ?? null, - name ?? null, - executable ?? false, - ); - const context: NixStringContext = new Set(); - addOpaqueContext(context, result.storePath); - return mkStringWithContext(result.storePath, context); -}; - -export const fetchTarball = (args: NixValue): NixString => { - const { url, name, sha256 } = normalizeTarballInput(args); - const result: FetchTarballResult = Deno.core.ops.op_fetch_tarball(url, name ?? null, sha256 ?? null); - const context: NixStringContext = new Set(); - addOpaqueContext(context, result.storePath); - return mkStringWithContext(result.storePath, context); -}; - -export const fetchGit = (args: NixValue): NixAttrs => { - const forced = force(args); - const disposedContext: NixStringContext = new Set(); - if (isString(forced) || isPath(forced)) { - const url = coerceToString(forced, StringCoercionMode.Base, false, disposedContext); - const result = Deno.core.ops.op_fetch_git(url, null, null, false, false, false, null); - const outContext: NixStringContext = new Set(); - addOpaqueContext(outContext, result.outPath); - return new Map([ - ["outPath", mkStringWithContext(result.outPath, outContext)], - ["rev", result.rev], - ["shortRev", result.shortRev], - ["revCount", BigInt(result.revCount)], - ["lastModified", BigInt(result.lastModified)], - ["lastModifiedDate", result.lastModifiedDate], - ["submodules", result.submodules], - ["narHash", result.narHash], - ]); - } - const attrs = forceAttrs(args); - const url = forceStringValue(select(attrs, ["url"])); - const gitRef = attrs.has("ref") ? forceStringValue(attrs.get("ref") as NixValue) : null; - const rev = attrs.has("rev") ? forceStringValue(attrs.get("rev") as NixValue) : null; - const shallow = attrs.has("shallow") ? forceBool(attrs.get("shallow") as NixValue) : false; - const submodules = attrs.has("submodules") ? forceBool(attrs.get("submodules") as NixValue) : false; - const allRefs = attrs.has("allRefs") ? forceBool(attrs.get("allRefs") as NixValue) : false; - const name = attrs.has("name") ? forceStringValue(attrs.get("name") as NixValue) : null; - - const result: FetchGitResult = Deno.core.ops.op_fetch_git( - url, - gitRef, - rev, - shallow, - submodules, - allRefs, - name, - ); - - const outContext: NixStringContext = new Set(); - addOpaqueContext(outContext, result.outPath); - return new Map([ - ["outPath", mkStringWithContext(result.outPath, outContext)], - ["rev", result.rev], - ["shortRev", result.shortRev], - ["revCount", BigInt(result.revCount)], - ["lastModified", BigInt(result.lastModified)], - ["lastModifiedDate", result.lastModifiedDate], - ["submodules", result.submodules], - ["narHash", result.narHash], - ]); -}; - -export const fetchMercurial = (_args: NixValue): NixAttrs => { - throw new Error("Not implemented: fetchMercurial"); -}; - -export const fetchTree = (args: NixValue): NixAttrs => { - const attrs = forceAttrs(args); - const type = attrs.has("type") ? forceStringValue(attrs.get("type") as NixValue) : "auto"; - - switch (type) { - case "git": - return fetchGit(args); - case "hg": - case "mercurial": - return fetchMercurial(args); - case "tarball": - return new Map([["outPath", fetchTarball(args)]]); - case "file": - return new Map([["outPath", fetchurl(args)]]); - case "path": { - const path = forceStringValue(select(attrs, ["path"])); - return new Map([["outPath", path]]); - } - case "github": - case "gitlab": - case "sourcehut": - return fetchGitForge(type, attrs); - default: - return autoDetectAndFetch(attrs); - } -}; - -const fetchGitForge = (forge: string, attrs: NixAttrs): NixAttrs => { - const owner = forceStringValue(select(forge, ["owner"])); - const repo = forceStringValue(select(forge, ["repo"])); - const rev = attrs.has("rev") - ? forceStringValue(attrs.get("rev") as NixValue) - : attrs.has("ref") - ? forceStringValue(attrs.get("ref") as NixValue) - : "HEAD"; - const host = attrs.has("host") ? forceStringValue(attrs.get("host") as NixValue) : undefined; - - let tarballUrl: string; - switch (forge) { - case "github": { - const apiHost = host || "github.com"; - tarballUrl = `https://api.${apiHost}/repos/${owner}/${repo}/tarball/${rev}`; - break; - } - case "gitlab": { - const glHost = host || "gitlab.com"; - tarballUrl = `https://${glHost}/api/v4/projects/${owner}%2F${repo}/repository/archive.tar.gz?sha=${rev}`; - break; - } - case "sourcehut": { - const shHost = host || "git.sr.ht"; - tarballUrl = `https://${shHost}/${owner}/${repo}/archive/${rev}.tar.gz`; - break; - } - default: - throw new Error(`Unknown forge type: ${forge}`); - } - - const outPath = fetchTarball(new Map([["url", tarballUrl], ...attrs])); - - return new Map([ - ["outPath", outPath], - ["rev", rev], - ["shortRev", rev.substring(0, 7)], - ]); -}; - -const autoDetectAndFetch = (attrs: NixAttrs): NixAttrs => { - const url = forceStringValue(select(attrs, ["url"])); - if (url.endsWith(".git") || url.includes("github.com") || url.includes("gitlab.com")) { - return fetchGit(attrs); - } - if ( - url.endsWith(".tar.gz") || - url.endsWith(".tar.xz") || - url.endsWith(".tar.bz2") || - url.endsWith(".tgz") - ) { - return new Map([["outPath", fetchTarball(attrs)]]); - } - return new Map([["outPath", fetchurl(attrs)]]); -}; - -export const readDir = (path: NixValue): NixAttrs => { - const pathStr = realisePath(path); - return Deno.core.ops.op_read_dir(pathStr); -}; - -export const readFile = (path: NixValue): string => { - const pathStr = realisePath(path); - return Deno.core.ops.op_read_file(pathStr); -}; - -export const readFileType = (path: NixValue): string => { - const pathStr = realisePath(path); - return Deno.core.ops.op_read_file_type(pathStr); -}; - -export const pathExists = (path: NixValue): boolean => { - try { - const pathStr = realisePath(path); - return Deno.core.ops.op_path_exists(pathStr); - } catch { - return false; - } -}; - -/** - * builtins.path - * Add a path to the Nix store with fine-grained control - * - * Parameters (attribute set): - * - path (required): Path to add to the store - * - name (optional): Name to use in store path (defaults to basename) - * - filter (optional): Function (path, type) -> bool - * - recursive (optional): Boolean, default true (NAR vs flat hashing) - * - sha256 (optional): Expected SHA-256 hash (hex-encoded) - * - * Returns: Store path string - */ -export const path = (args: NixValue): NixString => { - const attrs = forceAttrs(args); - - if (!attrs.has("path")) { - throw new TypeError("builtins.path: 'path' attribute is required"); - } - - const pathValue = force(attrs.get("path") as NixValue); - let pathStr: string; - - if (isNixPath(pathValue)) { - pathStr = getPathValue(pathValue); - } else { - pathStr = forceStringValue(pathValue); - } - - const name = attrs.has("name") ? forceStringValue(attrs.get("name") as NixValue) : null; - const recursive = attrs.has("recursive") ? forceBool(attrs.get("recursive") as NixValue) : true; - const sha256 = attrs.has("sha256") ? forceStringValue(attrs.get("sha256") as NixValue) : null; - - let storePath: string; - - if (attrs.has("filter")) { - const filterFn = forceFunction(attrs.get("filter") as NixValue); - - const entries: [string, string][] = Deno.core.ops.op_walk_dir(pathStr); - - const includePaths: string[] = []; - for (const [relPath, fileType] of entries) { - const fullPath = `${pathStr}/${relPath}`; - const innerFn = forceFunction(filterFn(fullPath)); - const shouldInclude = force(innerFn(fileType)); - if (shouldInclude === true) { - includePaths.push(relPath); - } - } - - storePath = Deno.core.ops.op_add_filtered_path(pathStr, name, recursive, sha256, includePaths); - } else { - storePath = Deno.core.ops.op_add_path(pathStr, name, recursive, sha256); - } - - const context: NixStringContext = new Set(); - addOpaqueContext(context, storePath); - return mkStringWithContext(storePath, context); -}; - -export const toFile = - (nameArg: NixValue) => - (contentsArg: NixValue): StringWithContext => { - const name = forceStringValue(nameArg); - - if (name.includes("/")) { - throw new Error("builtins.toFile: name cannot contain '/'"); - } - if (name === "." || name === "..") { - throw new Error("builtins.toFile: invalid name"); - } - - const context: NixStringContext = new Set(); - const contents = coerceToString(contentsArg, StringCoercionMode.ToString, false, context); - - const references: string[] = Array.from(context); - - const storePath: string = Deno.core.ops.op_to_file(name, contents, references); - - return mkStringWithContext(storePath, new Set([storePath])); - }; - -export const filterSource = - (_filter: NixValue) => - (_path: NixValue): never => { - throw new Error("Not implemented: filterSource"); - }; - -const suffixIfPotentialMatch = (prefix: string, path: string): string | null => { - const n = prefix.length; - - const needSeparator = n > 0 && n < path.length; - - if (needSeparator && path[n] !== "/") { - return null; - } - - if (!path.startsWith(prefix)) { - return null; - } - - return needSeparator ? path.substring(n + 1) : path.substring(n); -}; - -export const findFile = - (searchPath: NixValue) => - (lookupPath: NixValue): NixPath => { - const forcedSearchPath = forceList(searchPath); - const lookupPathStr = forceStringNoCtx(lookupPath); - - for (const item of forcedSearchPath) { - const attrs = forceAttrs(item); - - const prefix = attrs.has("prefix") ? forceStringNoCtx(attrs.get("prefix") as NixValue) : ""; - - if (!attrs.has("path")) { - throw new Error("findFile: search path element is missing 'path' attribute"); - } - - const suffix = suffixIfPotentialMatch(prefix, lookupPathStr); - if (suffix === null) { - continue; - } - - const context: NixStringContext = new Set(); - const pathVal = coerceToString( - attrs.get("path") as NixValue, - StringCoercionMode.Interpolation, - false, - context, - ); - - if (context.size > 0) { - throw new Error("findFile: path with string context is not yet supported"); - } - - const resolvedPath = Deno.core.ops.op_resolve_path(pathVal, ""); - const candidatePath = - suffix.length > 0 ? Deno.core.ops.op_resolve_path(suffix, resolvedPath) : resolvedPath; - - if (Deno.core.ops.op_path_exists(candidatePath)) { - return new NixPath(candidatePath); - } - } - - if (lookupPathStr.startsWith("nix/")) { - // FIXME: special path type - return new NixPath(`<${lookupPathStr}>`); - } - - throw new CatchableError(`file '${lookupPathStr}' was not found in the Nix search path`); - }; - -export const getEnv = (s: NixValue): string => { - return Deno.core.ops.op_get_env(forceStringValue(s)); -}; diff --git a/nix-js/runtime-ts/src/builtins/list.ts b/nix-js/runtime-ts/src/builtins/list.ts deleted file mode 100644 index dc3f4e3..0000000 --- a/nix-js/runtime-ts/src/builtins/list.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { op } from "../operators"; -import { force } from "../thunk"; -import { forceBool, forceFunction, forceInt, forceList } from "../type-assert"; -import type { NixAttrs, NixList, NixValue } from "../types"; - -export const map = - (f: NixValue) => - (list: NixValue): NixList => { - const forcedList = forceList(list); - if (forcedList.length) { - const func = forceFunction(f); - return forcedList.map(func); - } - return []; - }; - -export const filter = - (f: NixValue) => - (list: NixValue): NixList => { - const forcedList = forceList(list); - if (forcedList.length) { - const func = forceFunction(f); - return forcedList.filter((e) => forceBool(func(e))); - } - return []; - }; - -export const length = (e: NixValue): bigint => { - const forced = force(e); - if (typeof forced === "string") return BigInt(forced.length); - return BigInt(forceList(forced).length); -}; - -export const head = (list: NixValue): NixValue => forceList(list)[0]; - -export const tail = (list: NixValue): NixList => forceList(list).slice(1); - -export const elem = - (x: NixValue) => - (xs: NixValue): boolean => - forceList(xs).find((e) => op.eq(x, e)) !== undefined; - -export const elemAt = - (xs: NixValue) => - (n: NixValue): NixValue => { - const list = forceList(xs); - const idx = Number(forceInt(n)); - - if (idx < 0 || idx >= list.length) { - throw new RangeError(`Index ${idx} out of bounds for list of length ${list.length}`); - } - - return list[idx]; - }; - -export const concatLists = (lists: NixValue): NixList => { - return forceList(lists).reduce((acc: NixList, cur: NixValue) => { - return acc.concat(forceList(cur)); - }, []); -}; - -export const concatMap = - (f: NixValue) => - (lists: NixValue): NixList => { - const fn = forceFunction(f); - return forceList(lists).reduce((acc: NixList, cur: NixValue) => { - return acc.concat(force(fn(cur)) as NixList); - }, []); - }; - -export const foldlPrime = - (opFn: NixValue) => - (nul: NixValue) => - (list: NixValue): NixValue => { - const forcedOp = forceFunction(opFn); - return forceList(list).reduce((acc: NixValue, cur: NixValue) => { - return forceFunction(forcedOp(acc))(cur); - }, nul); - }; - -export const sort = - (cmp: NixValue) => - (list: NixValue): NixList => { - const forcedList = [...forceList(list)]; - const forcedCmp = forceFunction(cmp); - return forcedList.sort((a, b) => { - if (force(forceFunction(forcedCmp(a))(b))) return -1; - if (force(forceFunction(forcedCmp(b))(a))) return 1; - return 0; - }); - }; - -export const partition = - (pred: NixValue) => - (list: NixValue): NixAttrs => { - const forcedList = forceList(list); - const forcedPred = forceFunction(pred); - const right: NixList = []; - const wrong: NixList = []; - for (const elem of forcedList) { - if (force(forcedPred(elem))) { - right.push(elem); - } else { - wrong.push(elem); - } - } - return new Map([ - ["right", right], - ["wrong", wrong], - ]); - }; - -export const genList = - (f: NixValue) => - (len: NixValue): NixList => { - const func = forceFunction(f); - const length = forceInt(len); - - if (length < 0) { - throw new TypeError(`genList length must be non-negative integer, got ${length}`); - } - - return [...Array(Number(length)).keys()].map((i) => func(BigInt(i))); - }; - -export const all = - (pred: NixValue) => - (list: NixValue): boolean => { - const forcedList = forceList(list); - if (forcedList.length) { - const f = forceFunction(pred); - return forcedList.every((e) => forceBool(f(e))); - } - return true; - }; - -export const any = - (pred: NixValue) => - (list: NixValue): boolean => { - // CppNix forces `pred` eagerly - const f = forceFunction(pred); - const forcedList = forceList(list); - // `false` when no element - return forcedList.some((e) => forceBool(f(e))); - }; diff --git a/nix-js/runtime-ts/src/builtins/math.ts b/nix-js/runtime-ts/src/builtins/math.ts deleted file mode 100644 index 4408a4d..0000000 --- a/nix-js/runtime-ts/src/builtins/math.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { forceNumeric } from "../type-assert"; -import type { NixValue } from "../types"; - -export const ceil = (x: NixValue): bigint => { - const val = forceNumeric(x); - if (typeof val === "bigint") return val; // Already an integer - return BigInt(Math.ceil(val)); // Convert to integer -}; - -export const floor = (x: NixValue): bigint => { - const val = forceNumeric(x); - if (typeof val === "bigint") return val; // Already an integer - return BigInt(Math.floor(val)); // Convert to integer -}; diff --git a/nix-js/runtime-ts/src/builtins/misc.ts b/nix-js/runtime-ts/src/builtins/misc.ts deleted file mode 100644 index fb8884c..0000000 --- a/nix-js/runtime-ts/src/builtins/misc.ts +++ /dev/null @@ -1,344 +0,0 @@ -import { OrderedSet } from "js-sdsl"; -import { select } from "../helpers"; -import { compareValues } from "../operators"; -import { - getStringContext, - getStringValue, - mkStringWithContext, - type NixStringContext, -} from "../string-context"; -import { force } from "../thunk"; -import { - forceAttrs, - forceFunction, - forceList, - forceString, - forceStringNoCtx, - forceStringValue, -} from "../type-assert"; -import type { NixAttrs, NixStrictValue, NixValue } from "../types"; -import { ATTR_POSITIONS, CatchableError } from "../types"; -import * as context from "./context"; -import { isBool, isFloat, isInt, isList, isString, typeOf } from "./type-check"; - -export const addErrorContext = - (_e1: NixValue) => - (e2: NixValue): NixValue => { - // FIXME: - // console.log("[WARNING]: addErrorContext not implemented"); - return e2; - }; - -export const appendContext = context.appendContext; - -export const getContext = context.getContext; - -export const hasContext = context.hasContext; - -export const unsafeDiscardOutputDependency = context.unsafeDiscardOutputDependency; - -export const unsafeDiscardStringContext = context.unsafeDiscardStringContext; - -export const addDrvOutputDependencies = context.addDrvOutputDependencies; - -export const compareVersions = - (s1: NixValue) => - (s2: NixValue): NixValue => { - const str1 = forceStringValue(s1); - const str2 = forceStringValue(s2); - - let i1 = 0; - let i2 = 0; - - while (i1 < str1.length || i2 < str2.length) { - const c1 = nextComponent(str1, i1); - const c2 = nextComponent(str2, i2); - - i1 = c1.nextIndex; - i2 = c2.nextIndex; - - if (componentsLt(c1.component, c2.component)) { - return -1n; - } else if (componentsLt(c2.component, c1.component)) { - return 1n; - } - } - - return 0n; - }; - -interface ComponentResult { - component: string; - nextIndex: number; -} - -function nextComponent(s: string, startIdx: number): ComponentResult { - let p = startIdx; - - // Skip any dots and dashes (component separators) - while (p < s.length && (s[p] === "." || s[p] === "-")) { - p++; - } - - if (p >= s.length) { - return { component: "", nextIndex: p }; - } - - const start = p; - - // If the first character is a digit, consume the longest sequence of digits - if (s[p] >= "0" && s[p] <= "9") { - while (p < s.length && s[p] >= "0" && s[p] <= "9") { - p++; - } - } else { - // Otherwise, consume the longest sequence of non-digit, non-separator characters - while (p < s.length && !(s[p] >= "0" && s[p] <= "9") && s[p] !== "." && s[p] !== "-") { - p++; - } - } - - return { component: s.substring(start, p), nextIndex: p }; -} - -function componentsLt(c1: string, c2: string): boolean { - const n1 = c1.match(/^[0-9]+$/) ? BigInt(c1) : null; - const n2 = c2.match(/^[0-9]+$/) ? BigInt(c2) : null; - - // Both are numbers: compare numerically - if (n1 !== null && n2 !== null) { - return n1 < n2; - } - - // Empty string < number - if (c1 === "" && n2 !== null) { - return true; - } - - // Special case: "pre" comes before everything except another "pre" - if (c1 === "pre" && c2 !== "pre") { - return true; - } - if (c2 === "pre") { - return false; - } - - // Assume that `2.3a' < `2.3.1' - if (n2 !== null) { - return true; - } - if (n1 !== null) { - return false; - } - - // Both are strings: compare lexicographically - return c1 < c2; -} - -export const functionArgs = (f: NixValue): NixAttrs => { - const func = forceFunction(f); - if (func.args) { - const ret: NixAttrs = new Map(); - for (const key of func.args.required) { - ret.set(key, false); - } - for (const key of func.args.optional) { - ret.set(key, true); - } - const positions = func.args.positions; - if (positions) { - ret[ATTR_POSITIONS] = positions; - } - return ret; - } - return new Map(); -}; - -const checkComparable = (value: NixStrictValue): void => { - if (isString(value) || isInt(value) || isFloat(value) || isBool(value) || isList(value)) { - return; - } - throw new Error(`Unsupported key type for genericClosure: ${typeOf(value)}`); -}; - -export const genericClosure = (args: NixValue): NixValue => { - const forcedArgs = forceAttrs(args); - const startSet = select(forcedArgs, ["startSet"]); - const operator = select(forcedArgs, ["operator"]); - - const initialList = forceList(startSet); - const opFunction = forceFunction(operator); - - const resultSet = new OrderedSet(undefined, compareValues); - const resultList: NixStrictValue[] = []; - const queue: NixStrictValue[] = []; - - for (const item of initialList) { - const itemAttrs = forceAttrs(item); - const key = force(select(itemAttrs, ["key"])); - checkComparable(key); - if (resultSet.find(key).equals(resultSet.end())) { - resultSet.insert(key); - resultList.push(itemAttrs); - queue.push(itemAttrs); - } - } - - let head = 0; - while (head < queue.length) { - const currentItem = queue[head++]; - const newItems = forceList(opFunction(currentItem)); - - for (const newItem of newItems) { - const newItemAttrs = forceAttrs(newItem); - const key = force(select(newItemAttrs, ["key"])); - checkComparable(key); - if (resultSet.find(key).equals(resultSet.end())) { - resultSet.insert(key); - resultList.push(newItemAttrs); - queue.push(newItemAttrs); - } - } - } - - return resultList; -}; - -export const outputOf = - (_drv: NixValue) => - (_out: NixValue): never => { - throw new Error("Not implemented: outputOf (part of dynamic-derivation)"); - }; - -export const parseDrvName = (s: NixValue): NixAttrs => { - const fullName = forceStringNoCtx(s); - let name = fullName; - let version = ""; - for (let i = 0; i < fullName.length; ++i) { - if (fullName[i] === "-" && i + 1 < fullName.length && !/[a-zA-Z]/.test(fullName[i + 1])) { - name = fullName.substring(0, i); - version = fullName.substring(i + 1); - break; - } - } - return new Map([ - ["name", name], - ["version", version], - ]); -}; - -export const placeholder = (output: NixValue): NixValue => { - const outputStr = forceStringNoCtx(output); - return Deno.core.ops.op_make_placeholder(outputStr); -}; - -export const replaceStrings = - (from: NixValue) => - (to: NixValue) => - (s: NixValue): NixValue => { - const fromList = forceList(from); - const toList = forceList(to); - const inputStr = forceString(s); - const inputStrValue = getStringValue(inputStr); - const resultContext: NixStringContext = getStringContext(inputStr); - - if (fromList.length !== toList.length) { - throw new Error("'from' and 'to' arguments passed to builtins.replaceStrings have different lengths"); - } - - const toCache = new Map(); - const toContextCache = new Map(); - - let result = ""; - let pos = 0; - - while (pos <= inputStrValue.length) { - let found = false; - - for (let i = 0; i < fromList.length; i++) { - const pattern = forceStringValue(fromList[i]); - - if (inputStrValue.substring(pos).startsWith(pattern)) { - found = true; - - if (!toCache.has(i)) { - const replacementStr = forceString(toList[i]); - const replacementValue = getStringValue(replacementStr); - const replacementContext = getStringContext(replacementStr); - toCache.set(i, replacementValue); - toContextCache.set(i, replacementContext); - for (const elem of replacementContext) { - resultContext.add(elem); - } - } - const replacement = toCache.get(i) as string; - - result += replacement; - - if (pattern.length === 0) { - if (pos < inputStrValue.length) { - result += inputStrValue[pos]; - } - pos++; - } else { - pos += pattern.length; - } - break; - } - } - - if (!found) { - if (pos < inputStrValue.length) { - result += inputStrValue[pos]; - } - pos++; - } - } - - if (resultContext.size === 0) { - return result; - } - return mkStringWithContext(result, resultContext); - }; - -export const splitVersion = (s: NixValue): NixValue => { - const version = forceStringValue(s); - const components: string[] = []; - let idx = 0; - - while (idx < version.length) { - const result = nextComponent(version, idx); - if (result.component === "") { - break; - } - components.push(result.component); - idx = result.nextIndex; - } - - return components; -}; - -export const traceVerbose = - (_e1: NixValue) => - (e2: NixValue): NixStrictValue => { - // TODO: implement traceVerbose - return force(e2); - }; - -export const tryEval = (e: NixValue): NixAttrs => { - try { - return new Map([ - ["success", true], - ["value", force(e)], - ]); - } catch (err) { - if (err instanceof CatchableError) { - return new Map([ - ["success", false], - ["value", false], - ]); - } else { - throw err; - } - } -}; diff --git a/nix-js/runtime-ts/src/builtins/path.ts b/nix-js/runtime-ts/src/builtins/path.ts deleted file mode 100644 index 4d3d3bc..0000000 --- a/nix-js/runtime-ts/src/builtins/path.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { mkPath } from "../path"; -import { mkStringWithContext, type NixStringContext } from "../string-context"; -import { force } from "../thunk"; -import type { NixPath, NixString, NixValue } from "../types"; -import { isNixPath } from "../types"; -import { coerceToPath, coerceToString, StringCoercionMode } from "./conversion"; - -/** - * builtins.baseNameOf - * Get the last component of a path or string - * Always returns a string (coerces paths) - * Preserves string context if present - * - * Implements Nix's legacyBaseNameOf logic: - * - If string ends with '/', removes only the final slash - * - Then returns everything after the last remaining '/' - * - * Examples: - * - baseNameOf ./foo/bar → "bar" - * - baseNameOf "/foo/bar/" → "bar" (trailing slash removed first) - * - baseNameOf "foo" → "foo" - */ -export const baseNameOf = (s: NixValue): NixString => { - const context: NixStringContext = new Set(); - const pathStr = coerceToString(s, StringCoercionMode.Base, false, context); - - if (pathStr.length === 0) { - if (context.size === 0) { - return ""; - } - return mkStringWithContext("", context); - } - - let last = pathStr.length - 1; - if (pathStr[last] === "/" && last > 0) { - last -= 1; - } - - let pos = last; - while (pos >= 0 && pathStr[pos] !== "/") { - pos -= 1; - } - - if (pos === -1) { - pos = 0; - } else { - pos += 1; - } - - const result = pathStr.substring(pos, last + 1); - - // Preserve string context if present - if (context.size > 0) { - return mkStringWithContext(result, context); - } - - return result; -}; - -/** - * builtins.dirOf - * Get the directory part of a path or string - * TYPE-PRESERVING: path → path, string → string - * - * Examples: - * - dirOf ./foo/bar → ./foo (path) - * - dirOf "/foo/bar" → "/foo" (string) - * - dirOf "/" → "/" (same type as input) - */ -export const dirOf = (s: NixValue): NixPath | NixString => { - const forced = force(s); - - // Path input → path output - if (isNixPath(forced)) { - const pathStr = forced.value; - const lastSlash = pathStr.lastIndexOf("/"); - - if (lastSlash === -1) { - return mkPath("."); - } - if (lastSlash === 0) { - return mkPath("/"); - } - - return mkPath(pathStr.slice(0, lastSlash)); - } - - // String input → string output - const outContext: NixStringContext = new Set(); - const pathStr = coerceToString(s, StringCoercionMode.Base, false, outContext); - - const lastSlash = pathStr.lastIndexOf("/"); - - if (lastSlash === -1) { - return "."; - } - if (lastSlash === 0) { - return "/"; - } - - const result = pathStr.slice(0, lastSlash); - - if (outContext.size > 0) { - return mkStringWithContext(result, outContext); - } - - return result; -}; - -/** - * builtins.toPath - * Convert a value to an absolute path string. - * DEPRECATED: Use `/. + "/path"` to convert a string into an absolute path. - * - * This validates that the input can be coerced to an absolute path. - * Returns a **string** (not a NixPath), with context preserved. - * - * Examples: - * - toPath "/foo" → "/foo" (string) - * - toPath "/foo/bar" → "/foo/bar" (string) - * - toPath "foo" → ERROR (not absolute) - * - toPath "" → ERROR (empty) - */ -export const toPath = (s: NixValue): NixString => { - const context: NixStringContext = new Set(); - const pathStr = coerceToPath(s, context); - - if (context.size === 0) { - return pathStr; - } - - return mkStringWithContext(pathStr, context); -}; diff --git a/nix-js/runtime-ts/src/builtins/string.ts b/nix-js/runtime-ts/src/builtins/string.ts deleted file mode 100644 index 2d2282b..0000000 --- a/nix-js/runtime-ts/src/builtins/string.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { - getStringContext, - getStringValue, - mkStringWithContext, - type NixStringContext, -} from "../string-context"; -import { forceInt, forceList, forceString, forceStringValue } from "../type-assert"; -import type { NixInt, NixString, NixValue } from "../types"; -import { coerceToString, StringCoercionMode } from "./conversion"; - -export const stringLength = (e: NixValue): NixInt => BigInt(forceStringValue(e).length); - -export const substring = - (start: NixValue) => - (len: NixValue) => - (s: NixValue): NixString => { - const startPos = Number(forceInt(start)); - const length = Number(forceInt(len)); - - if (startPos < 0) { - throw new Error("negative start position in 'substring'"); - } - - const str = forceString(s); - const strValue = getStringValue(str); - const context = getStringContext(str); - - if (length === 0) { - if (context.size === 0) { - return ""; - } - return mkStringWithContext("", context); - } - - const actualLength = length < 0 ? Number.MAX_SAFE_INTEGER : length; - const result = startPos >= strValue.length ? "" : strValue.substring(startPos, startPos + actualLength); - - if (context.size === 0) { - return result; - } - return mkStringWithContext(result, context); - }; - -export const concatStringsSep = - (sep: NixValue) => - (list: NixValue): NixString => { - const context: NixStringContext = new Set(); - const separator = coerceToString(sep, StringCoercionMode.Interpolation, false, context); - - const parts = forceList(list).map((elem) => - coerceToString(elem, StringCoercionMode.Interpolation, false, context), - ); - - const result = parts.join(separator); - - if (context.size === 0) { - return result; - } - return mkStringWithContext(result, context); - }; - -export const match = - (regex: NixValue) => - (str: NixValue): NixValue => { - const regexStr = forceStringValue(regex); - const inputStr = forceStringValue(str); - - const result = Deno.core.ops.op_match(regexStr, inputStr); - if (result === null) { - return null; - } - return result.map((g) => (g !== null ? g : null)); - }; - -export const split = - (regex: NixValue) => - (str: NixValue): NixValue => { - const regexStr = forceStringValue(regex); - const inputStr = forceString(str); - const inputStrValue = getStringValue(inputStr); - - const result = Deno.core.ops.op_split(regexStr, inputStrValue); - - if (result.length === 1 && typeof result[0] === "string") { - return [inputStr]; - } - - return result.map((item) => { - if (typeof item === "string") { - return item; - } - return item.map((g) => (g !== null ? g : null)); - }); - }; diff --git a/nix-js/runtime-ts/src/builtins/type-check.ts b/nix-js/runtime-ts/src/builtins/type-check.ts deleted file mode 100644 index 274e89c..0000000 --- a/nix-js/runtime-ts/src/builtins/type-check.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { - isNixPath, - isStringWithContext, - type NixAttrs, - type NixBool, - type NixFloat, - type NixFunction, - type NixInt, - type NixList, - type NixNull, - type NixPath, - type NixStrictValue, - type NixString, -} from "../types"; - -export const isNixString = (v: NixStrictValue): v is NixString => { - return typeof v === "string" || isStringWithContext(v); -}; - -export const isAttrs = (e: NixStrictValue): e is NixAttrs => { - return e instanceof Map; -}; - -export const isBool = (e: NixStrictValue): e is NixBool => typeof e === "boolean"; - -export const isFloat = (e: NixStrictValue): e is NixFloat => { - const val = e; - return typeof val === "number"; // Only number is float -}; - -export const isFunction = (e: NixStrictValue): e is NixFunction => typeof e === "function"; - -export const isInt = (e: NixStrictValue): e is NixInt => { - const val = e; - return typeof val === "bigint"; // Only bigint is int -}; - -export const isList = (e: NixStrictValue): e is NixList => Array.isArray(e); - -export const isNull = (e: NixStrictValue): e is NixNull => e === null; - -export const isPath = (e: NixStrictValue): e is NixPath => { - const val = e; - return isNixPath(val); -}; - -export const isString = (e: NixStrictValue): e is NixString => - typeof e === "string" || isStringWithContext(e); - -export type NixType = "int" | "float" | "bool" | "string" | "path" | "null" | "list" | "lambda" | "set"; -export const typeOf = (e: NixStrictValue): NixType => { - if (typeof e === "bigint") return "int"; - if (typeof e === "number") return "float"; - if (typeof e === "boolean") return "bool"; - if (e === null) return "null"; - if (isNixString(e)) return "string"; - if (isNixPath(e)) return "path"; - if (Array.isArray(e)) return "list"; - if (e instanceof Map) return "set"; - if (typeof e === "function") return "lambda"; - - throw new TypeError(`Unknown Nix type: ${typeof e}`); -}; diff --git a/nix-js/runtime-ts/src/helpers.ts b/nix-js/runtime-ts/src/helpers.ts deleted file mode 100644 index 3056cf0..0000000 --- a/nix-js/runtime-ts/src/helpers.ts +++ /dev/null @@ -1,326 +0,0 @@ -import { coerceToString, StringCoercionMode } from "./builtins/conversion"; -import { isAttrs, typeOf } from "./builtins/type-check"; -import { mkPath } from "./path"; -import { isStringWithContext, mkStringWithContext, type NixStringContext } from "./string-context"; -import { force } from "./thunk"; -import { forceAttrs, forceBool, forceFunction, forceStringNoCtx, forceStringValue } from "./type-assert"; -import type { NixAttrs, NixBool, NixPath, NixString, NixValue } from "./types"; -import { CatchableError, isNixPath } from "./types"; - -interface StackFrame { - span: number; - message: string; -} - -const callStack: StackFrame[] = []; -const MAX_STACK_DEPTH = 1000; - -function enrichError(error: unknown): Error { - const err = error instanceof Error ? error : new Error(String(error)); - - if (callStack.length === 0) { - return err; - } - - const nixStackLines = callStack.map((frame) => { - return `NIX_STACK_FRAME:${frame.span}:${frame.message}`; - }); - - // Prepend stack frames to error stack - err.stack = `${nixStackLines.join("\n")}\n${err.stack || ""}`; - - return err; -} - -const pushContext = (message: string, span: number): void => { - if (callStack.length >= MAX_STACK_DEPTH) { - callStack.shift(); - } - callStack.push({ span, message }); -}; - -const popContext = (): void => { - callStack.pop(); -}; - -export const withContext = (message: string, span: number, fn: () => T): T => { - pushContext(message, span); - try { - return fn(); - } catch (error) { - throw enrichError(error); - } finally { - popContext(); - } -}; - -/** - * Concatenate multiple values into a string or path with context - * This is used for string interpolation like "hello ${world}" - * - * IMPORTANT: String context handling: - * - All contexts from interpolated values are merged into the result - * - Path mode: Store contexts are forbidden (will throw error) - * - String mode: All contexts are preserved and merged - * - * @param parts - Array of values to concatenate - * @param forceString - If true, result is always a string (paths are copied to store) - * @returns String or Path with merged contexts from all parts - */ -export const concatStringsWithContext = (parts: NixValue[], forceString: boolean): NixString | NixPath => { - if (parts.length === 0) { - return ""; - } - - const forced = parts.map(force); - - const firstIsPath = !forceString && isNixPath(forced[0]); - - if (firstIsPath) { - let result = (forced[0] as NixPath).value; - - for (let i = 1; i < forced.length; i++) { - const part = forced[i]; - - if (isNixPath(part)) { - result += part.value; - } else if (typeof part === "string") { - result += part; - } else if (isStringWithContext(part)) { - if (part.context.size > 0) { - throw new TypeError("a string that refers to a store path cannot be appended to a path"); - } - result += part.value; - } else { - const tempContext: NixStringContext = new Set(); - const coerced = coerceToString(part, StringCoercionMode.Interpolation, false, tempContext); - - if (tempContext.size > 0) { - throw new TypeError("a string that refers to a store path cannot be appended to a path"); - } - - result += coerced; - } - } - - return mkPath(result); - } - - const context: NixStringContext = new Set(); - const strParts: string[] = []; - - for (const part of forced) { - if (isNixPath(part)) { - const str = coerceToString(part, StringCoercionMode.Interpolation, true, context); - strParts.push(str); - } else { - const str = coerceToString(part, StringCoercionMode.Interpolation, false, context); - strParts.push(str); - } - } - - const value = strParts.join(""); - - if (context.size === 0) { - return value; - } - - return mkStringWithContext(value, context); -}; - -export const resolvePath = (currentDir: string, path: NixValue): NixPath => { - const forced = force(path); - let pathStr: string; - - if (isNixPath(forced)) { - pathStr = forced.value; - } else { - pathStr = forceStringValue(path); - } - - const resolved = Deno.core.ops.op_resolve_path(currentDir, pathStr); - return mkPath(resolved); -}; - -export const select = (obj: NixValue, attrpath: NixValue[], span?: number): NixValue => { - if (span !== undefined) { - if (callStack.length >= MAX_STACK_DEPTH) { - callStack.shift(); - } - const frame: StackFrame = { span, message: "while selecting attribute" }; - callStack.push(frame); - try { - return selectImpl(obj, attrpath); - } catch (error) { - try { - const path = attrpath.map((a) => forceStringValue(a)).join("."); - if (path) frame.message = `while selecting attribute [${path}]`; - } catch { - throw enrichError(error); - } - throw enrichError(error); - } finally { - callStack.pop(); - } - } else { - return selectImpl(obj, attrpath); - } -}; - -function selectImpl(obj: NixValue, attrpath: NixValue[]): NixValue { - let attrs = forceAttrs(obj); - - for (let i = 0; i < attrpath.length - 1; i++) { - const key = forceStringValue(attrpath[i]); - if (!attrs.has(key)) { - throw new Error(`Attribute '${key}' not found`); - } - const cur = forceAttrs(attrs.get(key) as NixValue); - attrs = cur; - } - - const last = forceStringValue(attrpath[attrpath.length - 1]); - if (!attrs.has(last)) { - throw new Error(`Attribute '${last}' not found`); - } - return attrs.get(last) as NixValue; -} - -export const selectWithDefault = ( - obj: NixValue, - attrpath: NixValue[], - defaultVal: NixValue, - span?: number, -): NixValue => { - if (span !== undefined) { - if (callStack.length >= MAX_STACK_DEPTH) { - callStack.shift(); - } - const frame: StackFrame = { span, message: "while selecting attribute" }; - callStack.push(frame); - try { - return selectWithDefaultImpl(obj, attrpath, defaultVal); - } catch (error) { - try { - const path = attrpath.map((a) => forceStringValue(a)).join("."); - if (path) frame.message = `while selecting attribute [${path}]`; - } catch { - throw enrichError(error); - } - throw enrichError(error); - } finally { - callStack.pop(); - } - } else { - return selectWithDefaultImpl(obj, attrpath, defaultVal); - } -}; - -function selectWithDefaultImpl(obj: NixValue, attrpath: NixValue[], defaultVal: NixValue): NixValue { - let attrs = force(obj); - if (!isAttrs(attrs)) { - return defaultVal; - } - - for (let i = 0; i < attrpath.length - 1; i++) { - const key = forceStringValue(attrpath[i]); - if (!attrs.has(key)) { - return defaultVal; - } - const cur = force(attrs.get(key) as NixValue); - if (!isAttrs(cur)) { - return defaultVal; - } - attrs = cur; - } - - const last = forceStringValue(attrpath[attrpath.length - 1]); - if (attrs.has(last)) { - return attrs.get(last) as NixValue; - } - return defaultVal; -} - -export const hasAttr = (obj: NixValue, attrpath: NixValue[]): NixBool => { - const forced = force(obj); - if (!isAttrs(forced)) { - return false; - } - let attrs = forced; - - for (let i = 0; i < attrpath.length - 1; i++) { - const key = forceStringNoCtx(attrpath[i]); - if (!attrs.has(key)) { - return false; - } - const cur = force(attrs.get(key) as NixValue); - if (!isAttrs(cur)) { - return false; - } - attrs = cur; - } - - return attrs.has(forceStringValue(attrpath[attrpath.length - 1])); -}; - -export const call = (func: NixValue, arg: NixValue, span?: number): NixValue => { - if (span !== undefined) { - if (callStack.length >= MAX_STACK_DEPTH) { - callStack.shift(); - } - callStack.push({ span, message: "from call site" }); - try { - return callImpl(func, arg); - } catch (error) { - throw enrichError(error); - } finally { - callStack.pop(); - } - } else { - return callImpl(func, arg); - } -}; - -function callImpl(func: NixValue, arg: NixValue): NixValue { - const forced = force(func); - if (typeof forced === "function") { - forced.args?.check(arg); - return forced(arg); - } - if (forced instanceof Map && forced.has("__functor")) { - const functor = forceFunction(forced.get("__functor") as NixValue); - return call(callImpl(functor, forced), arg); - } - throw new Error(`attempt to call something which is not a function but ${typeOf(forced)}`); -} - -export const assert = (assertion: NixValue, expr: NixValue, assertionRaw: string, span: number): NixValue => { - if (forceBool(assertion)) { - return expr; - } - withContext("while evaluating assertion", span, () => { - throw new CatchableError(`assertion '${assertionRaw}' failed`); - }); - throw "unreachable"; -}; - -export const mkPos = (span: number): NixAttrs => { - return Deno.core.ops.op_decode_span(span); -}; - -interface WithScope { - env: NixValue; - last: WithScope | null; -} - -export const lookupWith = (name: string, withScope: WithScope): NixValue => { - let current: WithScope | null = withScope; - while (current !== null) { - const attrs = forceAttrs(current.env); - if (attrs.has(name)) { - return attrs.get(name) as NixValue; - } - current = current.last; - } - throw new Error(`undefined variable '${name}'`); -}; diff --git a/nix-js/runtime-ts/src/index.ts b/nix-js/runtime-ts/src/index.ts deleted file mode 100644 index 3e4cb5a..0000000 --- a/nix-js/runtime-ts/src/index.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * nix-js Runtime Entry Point - * - * All functionality is exported via the global `Nix` object - */ - -import { builtins, PRIMOP_METADATA } from "./builtins"; -import { - assert, - call, - concatStringsWithContext, - hasAttr, - lookupWith, - mkPos, - resolvePath, - select, - selectWithDefault, -} from "./helpers"; -import { op } from "./operators"; -import { HAS_CONTEXT } from "./string-context"; -import { createThunk, DEBUG_THUNKS, force, forceDeep, forceShallow, IS_CYCLE, IS_THUNK } from "./thunk"; -import { forceBool } from "./type-assert"; -import { IS_PATH, mkAttrs, mkFunction, type NixValue } from "./types"; -import { execBytecode, execBytecodeScoped, vmStrings, vmConstants } from "./vm"; - -export type NixRuntime = typeof Nix; - -const replBindings: Map = new Map(); - -export const Nix = { - IS_THUNK, - IS_CYCLE, - HAS_CONTEXT, - IS_PATH, - PRIMOP_METADATA, - DEBUG_THUNKS, - - createThunk, - force, - forceBool, - forceShallow, - forceDeep, - - assert, - call, - hasAttr, - select, - selectWithDefault, - lookupWith, - resolvePath, - concatStringsWithContext, - mkAttrs, - mkFunction, - mkPos, - - op, - builtins, - - strings: vmStrings, - constants: vmConstants, - execBytecode, - execBytecodeScoped, - - replBindings, - setReplBinding: (name: string, value: NixValue) => { - replBindings.set(name, value); - }, - getReplBinding: (name: string) => replBindings.get(name), -}; - -globalThis.Nix = Nix; -globalThis.$t = createThunk; -globalThis.$f = force; -globalThis.$fb = forceBool; -globalThis.$a = assert; -globalThis.$c = call; -globalThis.$h = hasAttr; -globalThis.$s = select; -globalThis.$sd = selectWithDefault; -globalThis.$l = lookupWith; -globalThis.$r = resolvePath; -globalThis.$cs = concatStringsWithContext; -globalThis.$ma = mkAttrs; -globalThis.$mf = mkFunction; -globalThis.$mp = mkPos; -globalThis.$gb = Nix.getReplBinding; - -globalThis.$oa = op.add; -globalThis.$os = op.sub; -globalThis.$om = op.mul; -globalThis.$od = op.div; -globalThis.$oe = op.eq; -globalThis.$ol = op.lt; -globalThis.$og = op.gt; -globalThis.$oc = op.concat; -globalThis.$ou = op.update; -globalThis.$b = builtins; -globalThis.$e = new Map(); diff --git a/nix-js/runtime-ts/src/operators.ts b/nix-js/runtime-ts/src/operators.ts deleted file mode 100644 index 75ab841..0000000 --- a/nix-js/runtime-ts/src/operators.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { coerceToString, StringCoercionMode } from "./builtins/conversion"; -import { isNixString, typeOf } from "./builtins/type-check"; -import { mkPath } from "./path"; -import { - getStringContext, - getStringValue, - mergeContexts, - mkStringWithContext, - type NixStringContext, -} from "./string-context"; -import { force } from "./thunk"; -import { coerceNumeric, forceAttrs, forceBool, forceList, forceNumeric } from "./type-assert"; -import type { NixAttrs, NixList, NixPath, NixString, NixValue } from "./types"; -import { isNixPath } from "./types"; - -const canCoerceToString = (v: NixValue): boolean => { - const forced = force(v); - if (isNixString(forced)) return true; - if (forced instanceof Map) { - if (forced.has("outPath") || forced.has("__toString")) return true; - } - return false; -}; - -export const compareValues = (a: NixValue, b: NixValue): -1 | 0 | 1 => { - const av = force(a); - const bv = force(b); - - // Handle float/int mixed comparisons - if (typeof av === "number" && typeof bv === "bigint") { - const cmp = av - Number(bv); - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; - } - if (typeof av === "bigint" && typeof bv === "number") { - const cmp = Number(av) - bv; - return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; - } - - const typeA = typeOf(av); - const typeB = typeOf(bv); - - // Types must match (except float/int which is handled above) - if (typeA !== typeB) { - throw new TypeError(`cannot compare ${typeOf(av)} with ${typeOf(bv)}`); - } - - if (typeA === "int" || typeA === "float") { - return (av as never) < (bv as never) ? -1 : av === bv ? 0 : 1; - } - - if (typeA === "string") { - const strA = getStringValue(av as NixString); - const strB = getStringValue(bv as NixString); - return strA < strB ? -1 : strA > strB ? 1 : 0; - } - - if (typeA === "path") { - const aPath = av as NixPath; - const bPath = bv as NixPath; - return aPath.value < bPath.value ? -1 : aPath.value > bPath.value ? 1 : 0; - } - - if (typeA === "list") { - const aList = av as NixList; - const bList = bv as NixList; - for (let i = 0; ; i++) { - // Equal if same length, else aList > bList - if (i === bList.length) { - return i === aList.length ? 0 : 1; - } else if (i === aList.length) { - return -1; // aList < bList - } else if (!op.eq(aList[i], bList[i])) { - return compareValues(aList[i], bList[i]); - } - } - } - - // Other types are incomparable - throw new TypeError( - `cannot compare ${typeOf(av)} with ${typeOf(bv)}; values of that type are incomparable`, - ); -}; - -export const op = { - add: (a: NixValue, b: NixValue): bigint | number | NixString | NixPath => { - const av = force(a); - const bv = force(b); - - // Path concatenation: path + string = path - if (isNixPath(av)) { - if (isNixString(bv)) { - const strB = getStringValue(bv); - const ctxB = getStringContext(bv); - - if (ctxB.size > 0) { - throw new TypeError("a string that refers to a store path cannot be appended to a path"); - } - - return mkPath(av.value + strB); - } - - // FIXME: handle corepkgs - // path + path: concatenate - if (isNixPath(bv)) { - return mkPath(av.value + bv.value); - } - } - - // String + path: result is string (path coerces to string) - if (isNixString(av) && isNixPath(bv)) { - const strA = getStringValue(av); - const ctxA = getStringContext(av); - const result = strA + bv.value; - - if (ctxA.size === 0) { - return result; - } - return mkStringWithContext(result, ctxA); - } - - // String concatenation - if (isNixString(av) && isNixString(bv)) { - // Merge string context - const strA = getStringValue(av); - const strB = getStringValue(bv); - const ctxA = getStringContext(av); - const ctxB = getStringContext(bv); - - if (ctxA.size === 0 && ctxB.size === 0) { - return strA + strB; - } - - return mkStringWithContext(strA + strB, mergeContexts(ctxA, ctxB)); - } - - // Auto-coerce to string if possible - if (canCoerceToString(a) && canCoerceToString(b)) { - const context: NixStringContext = new Set(); - const strA = coerceToString(a, StringCoercionMode.Interpolation, false, context); - const strB = coerceToString(b, StringCoercionMode.Interpolation, false, context); - const result = strA + strB; - if (context.size === 0) { - return result; - } - return mkStringWithContext(result, context); - } - - // Perform numeric addition otherwise - const [numA, numB] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - return (numA as never) + (numB as never); - }, - - sub: (a: NixValue, b: NixValue): bigint | number => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - return (av as never) - (bv as never); - }, - - mul: (a: NixValue, b: NixValue): bigint | number => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - return (av as never) * (bv as never); - }, - - div: (a: NixValue, b: NixValue): bigint | number => { - const [av, bv] = coerceNumeric(forceNumeric(a), forceNumeric(b)); - - if (bv === 0 || bv === 0n) { - throw new RangeError("Division by zero"); - } - - return (av as never) / (bv as never); - }, - - eq: (a: NixValue, b: NixValue): boolean => { - const av = force(a); - const bv = force(b); - - // Pointer equality - if (av === bv) return true; - - // Special case: int == float type compatibility - if (typeof av === "bigint" && typeof bv === "number") { - return Number(av) === bv; - } - if (typeof av === "number" && typeof bv === "bigint") { - return av === Number(bv); - } - - const typeA = typeOf(av); - const typeB = typeOf(bv); - - // All other types must match exactly - if (typeA !== typeB) return false; - - if (typeA === "int" || typeA === "float" || typeA === "bool" || typeA === "null") { - return av === bv; - } - - // String comparison (handles both plain strings and StringWithContext) - if (typeA === "string") { - return getStringValue(av as NixString) === getStringValue(bv as NixString); - } - - // Path comparison - if (typeA === "path") { - return (av as NixPath).value === (bv as NixPath).value; - } - - if (typeA === "list") { - const aList = av as NixList; - const bList = bv as NixList; - if (aList.length !== bList.length) return false; - for (let i = 0; i < aList.length; i++) { - if (!op.eq(aList[i], bList[i])) return false; - } - return true; - } - - if (typeA === "set") { - const attrsA = av as NixAttrs; - const attrsB = bv as NixAttrs; - - if (attrsA.has("type") && attrsB.has("type")) { - const typeValA = force(attrsA.get("type") as NixValue); - const typeValB = force(attrsB.get("type") as NixValue); - if (typeValA === "derivation" && typeValB === "derivation") { - if (attrsA.has("outPath") && attrsB.has("outPath")) { - return op.eq(attrsA.get("outPath") as NixValue, attrsB.get("outPath") as NixValue); - } - } - } - - const keysA = Array.from(attrsA.keys()).sort(); - const keysB = Array.from(attrsB.keys()).sort(); - - if (keysA.length !== keysB.length) return false; - - for (let i = 0; i < keysA.length; i++) { - if (keysA[i] !== keysB[i]) return false; - if (!op.eq(attrsA.get(keysA[i]) as NixValue, attrsB.get(keysB[i]) as NixValue)) return false; - } - - return true; - } - - // Other types are incomparable - return false; - }, - neq: (a: NixValue, b: NixValue): boolean => { - return !op.eq(a, b); - }, - lt: (a: NixValue, b: NixValue): boolean => { - return compareValues(a, b) < 0; - }, - lte: (a: NixValue, b: NixValue): boolean => { - return compareValues(a, b) <= 0; - }, - gt: (a: NixValue, b: NixValue): boolean => { - return compareValues(a, b) > 0; - }, - gte: (a: NixValue, b: NixValue): boolean => { - return compareValues(a, b) >= 0; - }, - - bnot: (a: NixValue): boolean => !forceBool(a), - - concat: (a: NixValue, b: NixValue): NixList => { - return forceList(a).concat(forceList(b)); - }, - - update: (a: NixValue, b: NixValue): NixAttrs => { - const mapA = forceAttrs(a); - const mapB = forceAttrs(b); - if (mapA.size === 0) { - return mapB; - } - if (mapB.size === 0) { - return mapA; - } - const result: NixAttrs = new Map(mapA); - for (const [k, v] of mapB) { - result.set(k, v); - } - return result; - }, -}; diff --git a/nix-js/runtime-ts/src/path.ts b/nix-js/runtime-ts/src/path.ts deleted file mode 100644 index a91c834..0000000 --- a/nix-js/runtime-ts/src/path.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { NixPath } from "./types"; - -const canonicalizePath = (path: string): string => { - const parts: string[] = []; - let i = 0; - const len = path.length; - - while (i < len) { - while (i < len && path[i] === "/") i++; - if (i >= len) break; - - let j = i; - while (j < len && path[j] !== "/") j++; - const component = path.slice(i, j); - i = j; - - if (component === "..") { - if (parts.length > 0) { - parts.pop(); - } - } else if (component !== ".") { - parts.push(component); - } - } - - if (parts.length === 0) { - return "/"; - } - return `/${parts.join("/")}`; -}; - -export const mkPath = (value: string): NixPath => { - return new NixPath(canonicalizePath(value)); -}; - -export const getPathValue = (p: NixPath): string => { - return p.value; -}; diff --git a/nix-js/runtime-ts/src/print.ts b/nix-js/runtime-ts/src/print.ts deleted file mode 100644 index 4dba4d3..0000000 --- a/nix-js/runtime-ts/src/print.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { getPrimopMetadata, isPrimop } from "./builtins/index"; -import { isStringWithContext } from "./string-context"; -import { IS_CYCLE, isThunk } from "./thunk"; -import { isNixPath, type NixValue } from "./types"; - -export const printValue = (value: NixValue, seen: WeakSet = new WeakSet()): string => { - if (isThunk(value)) { - return "«thunk»"; - } - - if (value === null) { - return "null"; - } - - if (typeof value === "boolean") { - return value ? "true" : "false"; - } - - if (typeof value === "bigint") { - return value.toString(); - } - - if (typeof value === "number") { - return value.toString(); - } - - if (typeof value === "string") { - return printString(value); - } - - if (typeof value === "function") { - if (isPrimop(value)) { - const meta = getPrimopMetadata(value); - if (meta && meta.applied > 0) { - return ""; - } - return ""; - } - return ""; - } - - if (IS_CYCLE in value) { - return "«repeated»"; - } - - if (isNixPath(value)) { - return value.value; - } - - if (isStringWithContext(value)) { - return printString(value.value); - } - - if (Array.isArray(value)) { - if (value.length > 0) { - if (seen.has(value)) { - return "«repeated»"; - } - seen.add(value); - } - const items = value.map((v) => printValue(v, seen)).join(" "); - return `[ ${items} ]`; - } - - if (seen.has(value)) { - return "«repeated»"; - } - if (value.size > 0) { - seen.add(value); - } - - const entries = [...value.entries()] - .map(([k, v]) => `${printSymbol(k)} = ${printValue(v, seen)};`) - .join(" "); - return `{${entries ? ` ${entries} ` : " "}}`; -}; - -const printString = (s: string): string => { - let result = '"'; - for (const c of s) { - switch (c) { - case "\\": - result += "\\\\"; - break; - case '"': - result += '\\"'; - break; - case "\n": - result += "\\n"; - break; - case "\r": - result += "\\r"; - break; - case "\t": - result += "\\t"; - break; - default: - result += c; - } - } - return `${result}"`; -}; - -const SYMBOL_REGEX = /^[a-zA-Z_][a-zA-Z0-9_'-]*$/; - -const printSymbol = (s: string): string => { - if (SYMBOL_REGEX.test(s)) { - return s; - } - return printString(s); -}; diff --git a/nix-js/runtime-ts/src/string-context.ts b/nix-js/runtime-ts/src/string-context.ts deleted file mode 100644 index ef6d38a..0000000 --- a/nix-js/runtime-ts/src/string-context.ts +++ /dev/null @@ -1,153 +0,0 @@ -import type { NixStrictValue } from "./types"; - -export const HAS_CONTEXT = Symbol("HAS_CONTEXT"); - -export interface StringContextOpaque { - type: "opaque"; - path: string; -} - -export interface StringContextDrvDeep { - type: "drvDeep"; - drvPath: string; -} - -export interface StringContextBuilt { - type: "built"; - drvPath: string; - output: string; -} - -export type StringContextElem = StringContextOpaque | StringContextDrvDeep | StringContextBuilt; - -export type NixStringContext = Set; - -export class StringWithContext { - readonly [HAS_CONTEXT] = true as const; - value: string; - context: NixStringContext; - constructor(value: string, context: NixStringContext) { - this.value = value; - this.context = context; - } -} - -export const isStringWithContext = (v: NixStrictValue): v is StringWithContext => { - return v instanceof StringWithContext; -}; - -export const mkStringWithContext = (value: string, context: NixStringContext): StringWithContext => { - return new StringWithContext(value, context); -}; - -export const mkPlainString = (value: string): string => value; - -export const getStringValue = (s: string | StringWithContext): string => { - if (isStringWithContext(s)) { - return s.value; - } - return s; -}; - -const emptyContext: NixStringContext = new Set(); -export const getStringContext = (s: string | StringWithContext): NixStringContext => { - if (isStringWithContext(s)) { - return s.context; - } - return emptyContext; -}; - -export const mergeContexts = (...contexts: NixStringContext[]): NixStringContext => { - const result = new Set(); - for (const ctx of contexts) { - for (const elem of ctx) { - result.add(elem); - } - } - return result; -}; - -export const encodeContextElem = (elem: StringContextElem): string => { - switch (elem.type) { - case "opaque": - return elem.path; - case "drvDeep": - return `=${elem.drvPath}`; - case "built": - return `!${elem.output}!${elem.drvPath}`; - } -}; - -export const decodeContextElem = (encoded: string): StringContextElem => { - if (encoded.startsWith("=")) { - return { type: "drvDeep", drvPath: encoded.slice(1) }; - } else if (encoded.startsWith("!")) { - const secondBang = encoded.indexOf("!", 1); - if (secondBang === -1) { - throw new Error(`Invalid context element: ${encoded}`); - } - return { - type: "built", - output: encoded.slice(1, secondBang), - drvPath: encoded.slice(secondBang + 1), - }; - } else { - return { type: "opaque", path: encoded }; - } -}; - -export const addContextElem = (context: NixStringContext, elem: StringContextElem): void => { - context.add(encodeContextElem(elem)); -}; - -export const addOpaqueContext = (context: NixStringContext, path: string): void => { - context.add(path); -}; - -export const addDrvDeepContext = (context: NixStringContext, drvPath: string): void => { - context.add(`=${drvPath}`); -}; - -export const addBuiltContext = (context: NixStringContext, drvPath: string, output: string): void => { - context.add(`!${output}!${drvPath}`); -}; - -export interface ParsedContextInfo { - path: boolean; - allOutputs: boolean; - outputs: string[]; -} - -export const parseContextToInfoMap = (context: NixStringContext): Map => { - const result = new Map(); - - const getOrCreate = (path: string): ParsedContextInfo => { - let info = result.get(path); - if (!info) { - info = { path: false, allOutputs: false, outputs: [] }; - result.set(path, info); - } - return info; - }; - - for (const encoded of context) { - const elem = decodeContextElem(encoded); - switch (elem.type) { - case "opaque": - getOrCreate(elem.path).path = true; - break; - case "drvDeep": - getOrCreate(elem.drvPath).allOutputs = true; - break; - case "built": - getOrCreate(elem.drvPath).outputs.push(elem.output); - break; - } - } - - for (const info of result.values()) { - info.outputs.sort(); - } - - return result; -}; diff --git a/nix-js/runtime-ts/src/thunk.ts b/nix-js/runtime-ts/src/thunk.ts deleted file mode 100644 index 5ad2b38..0000000 --- a/nix-js/runtime-ts/src/thunk.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { isAttrs, isList } from "./builtins/type-check"; -import { StringWithContext } from "./string-context"; -import type { NixAttrs, NixStrictValue, NixValue } from "./types"; -import { NixPath } from "./types"; - -export const IS_THUNK = Symbol("is_thunk"); - -const forceStack: NixThunk[] = []; -const MAX_FORCE_DEPTH = 1000; - -export const DEBUG_THUNKS = { enabled: true }; - -/** - * NixThunk class - represents a lazy, unevaluated expression - * - * A thunk wraps a function that produces a value when called. - * Once evaluated, the result is cached to avoid recomputation. - * - * Thunk states: - * - Unevaluated: func is defined, result is undefined - * - Evaluating (blackhole): func is undefined, result is undefined - * - Evaluated: func is undefined, result is defined - */ -export class NixThunk { - readonly [IS_THUNK] = true as const; - func: (() => NixValue) | undefined; - result: NixStrictValue | undefined; - readonly label: string | undefined; - - constructor(func: () => NixValue, label?: string) { - this.func = func; - this.result = undefined; - this.label = label; - } - - toString(): string { - if (this.label) { - return `«thunk ${this.label}»`; - } - return `«thunk»`; - } -} - -export const isThunk = (value: NixValue): value is NixThunk => { - return value instanceof NixThunk; -}; - -/** - * Force evaluation of a value - * If the value is a thunk, evaluate it and cache the result - * If already evaluated or not a thunk, return as-is - * - * Uses "blackhole" detection to catch infinite recursion: - * - Before evaluating, set func to undefined (entering blackhole state) - * - If we encounter a thunk with func=undefined and result=undefined, it's a blackhole - * - * @param value - Value to force (may be a thunk) - * @returns The forced/evaluated value - * @throws Error if infinite recursion is detected - */ -export const force = (value: NixValue): NixStrictValue => { - if (!isThunk(value)) { - return value; - } - - if (value.func === undefined) { - if (value.result === undefined) { - const thunk = value as NixThunk; - let msg = `infinite recursion encountered at ${thunk}\n`; - if (DEBUG_THUNKS.enabled) { - msg += "Force chain (most recent first):\n"; - for (let i = forceStack.length - 1; i >= 0; i--) { - const t = forceStack[i]; - msg += ` ${i + 1}. ${t}`; - msg += "\n"; - } - } - throw new Error(msg); - } - return value.result; - } - - const thunk = value as NixThunk; - const func = thunk.func as () => NixValue; - thunk.func = undefined; - - if (DEBUG_THUNKS.enabled) { - forceStack.push(thunk); - if (forceStack.length > MAX_FORCE_DEPTH) { - let msg = `force depth exceeded ${MAX_FORCE_DEPTH} at ${thunk}\n`; - msg += "Force chain (most recent first):\n"; - for (let i = forceStack.length - 1; i >= Math.max(0, forceStack.length - 20); i--) { - const t = forceStack[i]; - msg += ` ${i + 1}. ${t}`; - msg += "\n"; - } - throw new Error(msg); - } - } - try { - const result = force(func()); - thunk.result = result; - return result; - } catch (e) { - thunk.func = func; - throw e; - } finally { - if (DEBUG_THUNKS.enabled) { - forceStack.pop(); - } - } -}; - -export const createThunk = (func: () => NixValue, label?: string): NixThunk => { - return new NixThunk(func, label); -}; - -export const IS_CYCLE = Symbol("is_cycle"); -export const CYCLE_MARKER = { [IS_CYCLE]: true as const }; - -/** - * Deeply force a value, handling cycles by returning a special marker. - * Uses WeakSet to track seen objects and avoid infinite recursion. - * Returns a fully forced value where thunks are replaced with their results. - * Cyclic references are replaced with CYCLE_MARKER, preserving the container type. - */ -export const forceDeep = (value: NixValue, seen: WeakSet = new WeakSet()): NixStrictValue => { - const forced = force(value); - - if (forced === null || typeof forced !== "object") { - return forced; - } - - if (seen.has(forced)) { - return CYCLE_MARKER; - } - if ((isAttrs(forced) && forced.size > 0) || (isList(forced) && forced.length > 0)) { - seen.add(forced); - } - - if (forced instanceof StringWithContext || forced instanceof NixPath) { - return forced; - } - - if (Array.isArray(forced)) { - return forced.map((item) => forceDeep(item, seen)); - } - - if (forced instanceof Map) { - const result: NixAttrs = new Map(); - for (const [key, val] of forced) { - result.set(key, forceDeep(val, seen)); - } - return result; - } - - return forced; -}; - -export const forceShallow = (value: NixValue): NixStrictValue => { - const forced = force(value); - - if (forced === null || typeof forced !== "object") { - return forced; - } - - if (Array.isArray(forced)) { - return forced.map((item) => { - const forcedItem = force(item); - if (typeof forcedItem === "object" && forcedItem === forced) { - return CYCLE_MARKER; - } else { - return forcedItem; - } - }); - } - - if (isAttrs(forced)) { - const result: NixAttrs = new Map(); - for (const [key, val] of forced) { - const forcedVal = force(val as NixValue); - result.set(key, forcedVal === forced ? CYCLE_MARKER : forcedVal); - } - return result; - } - - return forced; -}; diff --git a/nix-js/runtime-ts/src/type-assert.ts b/nix-js/runtime-ts/src/type-assert.ts deleted file mode 100644 index a82624c..0000000 --- a/nix-js/runtime-ts/src/type-assert.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { isAttrs, isFunction, typeOf } from "./builtins/type-check"; -import { force } from "./thunk"; -import type { - NixAttrs, - NixFloat, - NixFunction, - NixInt, - NixList, - NixNumber, - NixPath, - NixString, - NixValue, -} from "./types"; -import { isNixPath, isStringWithContext } from "./types"; - -export const forceList = (value: NixValue): NixList => { - const forced = force(value); - if (!Array.isArray(forced)) { - throw new TypeError(`Expected list, got ${typeOf(forced)}`); - } - return forced; -}; - -export const forceFunction = (value: NixValue): NixFunction => { - const forced = force(value); - if (isFunction(forced)) { - return forced; - } - if (forced instanceof Map && forced.has("__functor")) { - const functorSet = forced as NixAttrs; - const functor = forceFunction(functorSet.get("__functor") as NixValue); - return (arg: NixValue) => forceFunction(functor(functorSet))(arg); - } - throw new TypeError(`Expected function, got ${typeOf(forced)}`); -}; - -export const forceAttrs = (value: NixValue): NixAttrs => { - const forced = force(value); - if (!isAttrs(forced)) { - throw new TypeError(`Expected attribute set, got ${typeOf(forced)}`); - } - return forced; -}; - -export const forceStringValue = (value: NixValue): string => { - const forced = force(value); - if (typeof forced === "string") { - return forced; - } - if (isStringWithContext(forced)) { - return forced.value; - } - throw new TypeError(`Expected string, got ${typeOf(forced)}`); -}; - -export const forceString = (value: NixValue): NixString => { - const forced = force(value); - if (typeof forced === "string") { - return forced; - } - if (isStringWithContext(forced)) { - return forced; - } - throw new TypeError(`Expected string, got ${typeOf(forced)}`); -}; - -export const forceStringNoCtx = (value: NixValue): string => { - const forced = force(value); - if (typeof forced === "string") { - return forced; - } - if (isStringWithContext(forced)) { - throw new TypeError(`the string '${forced.value}' is not allowed to refer to a store path`); - } - throw new TypeError(`Expected string, got ${typeOf(forced)}`); -}; - -export const forceBool = (value: NixValue): boolean => { - const forced = force(value); - if (typeof forced !== "boolean") { - throw new TypeError(`Expected boolean, got ${typeOf(forced)}`); - } - return forced; -}; - -export const forceInt = (value: NixValue): NixInt => { - const forced = force(value); - if (typeof forced === "bigint") { - return forced; - } - throw new TypeError(`Expected int, got ${typeOf(forced)}`); -}; - -export const forceFloat = (value: NixValue): NixFloat => { - const forced = force(value); - if (typeof forced === "number") { - return forced; - } - throw new TypeError(`Expected float, got ${typeOf(forced)}`); -}; - -export const forceNumeric = (value: NixValue): NixNumber => { - const forced = force(value); - if (typeof forced === "bigint" || typeof forced === "number") { - return forced; - } - throw new TypeError(`Expected numeric type, got ${typeOf(forced)}`); -}; - -export const coerceNumeric = (a: NixNumber, b: NixNumber): [NixFloat, NixFloat] | [NixInt, NixInt] => { - const aIsInt = typeof a === "bigint"; - const bIsInt = typeof b === "bigint"; - - if (!aIsInt || !bIsInt) { - return [Number(a), Number(b)]; - } - - return [a, b]; -}; - -export const forceNixPath = (value: NixValue): NixPath => { - const forced = force(value); - if (isNixPath(forced)) { - return forced; - } - throw new TypeError(`Expected path, got ${typeOf(forced)}`); -}; diff --git a/nix-js/runtime-ts/src/types.ts b/nix-js/runtime-ts/src/types.ts deleted file mode 100644 index 68d0937..0000000 --- a/nix-js/runtime-ts/src/types.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { PRIMOP_METADATA, type PrimopMetadata } from "./builtins"; -import { HAS_CONTEXT, isStringWithContext, type StringWithContext } from "./string-context"; -import { type CYCLE_MARKER, force, type NixThunk } from "./thunk"; -import { forceAttrs, forceStringNoCtx } from "./type-assert"; -export { HAS_CONTEXT, isStringWithContext }; -export type { StringWithContext }; - -export const IS_PATH = Symbol("IS_PATH"); - -export class NixPath { - readonly [IS_PATH] = true as const; - value: string; - constructor(value: string) { - this.value = value; - } -} - -export const isNixPath = (v: NixStrictValue): v is NixPath => { - return v instanceof NixPath; -}; - -export type NixInt = bigint; -export type NixFloat = number; -export type NixNumber = NixInt | NixFloat; -export type NixBool = boolean; -export type NixString = string | StringWithContext; -export type NixNull = null; - -export const ATTR_POSITIONS = Symbol("attrPositions"); -export type NixList = NixValue[]; -export type NixAttrs = Map & { [ATTR_POSITIONS]?: Map }; -export type NixFunction = ((arg: NixValue) => NixValue) & { - args?: NixArgs; - [PRIMOP_METADATA]?: PrimopMetadata; -}; -export class NixArgs { - required: string[]; - optional: string[]; - allowed: Set; - ellipsis: boolean; - positions: Map; - constructor(required: string[], optional: string[], positions: Map, ellipsis: boolean) { - this.required = required; - this.optional = optional; - this.positions = positions; - this.ellipsis = ellipsis; - this.allowed = new Set(required.concat(optional)); - } - check(arg: NixValue) { - const attrs = forceAttrs(arg); - - for (const key of this.required) { - if (!attrs.has(key)) { - throw new Error(`Function called without required argument '${key}'`); - } - } - - if (!this.ellipsis) { - for (const key of attrs.keys()) { - if (!this.allowed.has(key)) { - throw new Error(`Function called with unexpected argument '${key}'`); - } - } - } - } -} -export const mkFunction = ( - f: (arg: NixValue) => NixValue, - required: string[], - optional: string[], - positions: Map, - ellipsis: boolean, -): NixFunction => { - const func: NixFunction = f; - func.args = new NixArgs(required, optional, positions, ellipsis); - return func; -}; - -export const mkAttrs = ( - attrs: NixAttrs, - positions: Map, - dyns?: { dynKeys: NixValue[]; dynVals: NixValue[]; dynSpans: number[] }, -): NixAttrs => { - if (dyns) { - const len = dyns.dynKeys.length; - for (let i = 0; i < len; i++) { - const key = force(dyns.dynKeys[i]); - if (key === null) { - continue; - } - const str = forceStringNoCtx(key); - attrs.set(str, dyns.dynVals[i]); - positions.set(str, dyns.dynSpans[i]); - } - } - - if (positions.size > 0) { - attrs[ATTR_POSITIONS] = positions; - } - - return attrs; -}; - -export type NixPrimitive = NixNull | NixBool | NixInt | NixFloat | NixString; -export type NixValue = - | NixPrimitive - | NixPath - | NixList - | NixAttrs - | NixFunction - | NixThunk - | typeof CYCLE_MARKER; -export type NixStrictValue = Exclude; - -export class CatchableError extends Error {} diff --git a/nix-js/runtime-ts/src/types/global.d.ts b/nix-js/runtime-ts/src/types/global.d.ts deleted file mode 100644 index 4988ebb..0000000 --- a/nix-js/runtime-ts/src/types/global.d.ts +++ /dev/null @@ -1,134 +0,0 @@ -import type { NixRuntime } from ".."; -import type { builtins } from "../builtins"; -import type { FetchGitResult, FetchTarballResult, FetchUrlResult } from "../builtins/io"; -import type { - assert, - call, - concatStringsWithContext, - hasAttr, - lookupWith, - mkPos, - resolvePath, - select, - selectWithDefault, -} from "../helpers"; -import type { op } from "../operators"; -import type { createThunk, force } from "../thunk"; -import type { forceBool } from "../type-assert"; -import type { mkAttrs, mkFunction, NixAttrs, NixStrictValue } from "../types"; - -declare global { - var Nix: NixRuntime; - var $t: typeof createThunk; - var $f: typeof force; - var $fb: typeof forceBool; - var $a: typeof assert; - var $c: typeof call; - var $h: typeof hasAttr; - var $s: typeof select; - var $sd: typeof selectWithDefault; - var $l: typeof lookupWith; - var $r: typeof resolvePath; - var $cs: typeof concatStringsWithContext; - var $ma: typeof mkAttrs; - var $mf: typeof mkFunction; - var $mp: typeof mkPos; - var $oa: typeof op.add; - var $os: typeof op.sub; - var $om: typeof op.mul; - var $od: typeof op.div; - var $oe: typeof op.eq; - var $ol: typeof op.lt; - var $og: typeof op.gt; - var $oc: typeof op.concat; - var $ou: typeof op.update; - var $b: typeof builtins; - var $e: NixAttrs; - var $gb: typeof Nix.getReplBinding; - - namespace Deno { - namespace core { - namespace ops { - function op_import(path: string): [Uint8Array, string]; - function op_scoped_import(path: string, scopeKeys: string[]): [Uint8Array, string]; - - function op_resolve_path(currentDir: string, path: string): string; - - function op_read_file(path: string): string; - function op_read_file_type(path: string): string; - function op_read_dir(path: string): Map; - function op_path_exists(path: string): boolean; - function op_walk_dir(path: string): [string, string][]; - - function op_make_placeholder(output: string): string; - function op_store_path(path: string): string; - - function op_convert_hash(hash: string, hashAlgo: string | null, toHashFormat: string): string; - function op_hash_string(algo: string, data: string): string; - function op_hash_file(algo: string, path: string): string; - function op_parse_hash(hashStr: string, algo: string | null): { hex: string; algo: string }; - - function op_add_path( - path: string, - name: string | null, - recursive: boolean, - sha256: string | null, - ): string; - function op_add_filtered_path( - path: string, - name: string | null, - recursive: boolean, - sha256: string | null, - includePaths: string[], - ): string; - - function op_decode_span(span: number): NixAttrs; - - function op_to_file(name: string, contents: string, references: string[]): string; - - function op_copy_path_to_store(path: string): string; - - function op_get_env(key: string): string; - - function op_match(regex: string, text: string): (string | null)[] | null; - function op_split(regex: string, text: string): (string | (string | null)[])[]; - - function op_from_json(json: string): NixStrictValue; - function op_from_toml(toml: string): NixStrictValue; - function op_to_xml(e: NixValue): [string, string[]]; - - function op_finalize_derivation( - name: string, - builder: string, - platform: string, - outputs: string[], - args: string[], - env: [string, string][], - context: string[], - fixedOutput: { hashAlgo: string; hash: string; hashMode: string } | null, - ): { drvPath: string; outputs: [string, string][] }; - - function op_fetch_url( - url: string, - expectedHash: string | null, - name: string | null, - executable: boolean, - ): FetchUrlResult; - function op_fetch_tarball( - url: string, - name: string | null, - sha256: string | null, - ): FetchTarballResult; - function op_fetch_git( - url: string, - ref: string | null, - rev: string | null, - shallow: boolean, - submodules: boolean, - allRefs: boolean, - name: string | null, - ): FetchGitResult; - } - } - } -} diff --git a/nix-js/runtime-ts/src/vm.ts b/nix-js/runtime-ts/src/vm.ts deleted file mode 100644 index 9b63916..0000000 --- a/nix-js/runtime-ts/src/vm.ts +++ /dev/null @@ -1,617 +0,0 @@ -import { - assert, - call, - concatStringsWithContext, - hasAttr, - lookupWith, - mkPos, - resolvePath, - select, - selectWithDefault, -} from "./helpers"; -import { op } from "./operators"; -import { NixThunk } from "./thunk"; -import { forceBool } from "./type-assert"; -import { mkAttrs, NixArgs, type NixAttrs, type NixFunction, type NixValue } from "./types"; -import { builtins } from "./builtins"; - -enum Op { - PushConst = 0x01, - PushString = 0x02, - PushNull = 0x03, - PushTrue = 0x04, - PushFalse = 0x05, - - LoadLocal = 0x06, - LoadOuter = 0x07, - StoreLocal = 0x08, - AllocLocals = 0x09, - - MakeThunk = 0x0A, - MakeClosure = 0x0B, - MakePatternClosure = 0x0C, - - Call = 0x0D, - CallNoSpan = 0x0E, - - MakeAttrs = 0x0F, - MakeAttrsDyn = 0x10, - MakeEmptyAttrs = 0x11, - Select = 0x12, - SelectDefault = 0x13, - HasAttr = 0x14, - - MakeList = 0x15, - - OpAdd = 0x16, - OpSub = 0x17, - OpMul = 0x18, - OpDiv = 0x19, - OpEq = 0x20, - OpNeq = 0x21, - OpLt = 0x22, - OpGt = 0x23, - OpLeq = 0x24, - OpGeq = 0x25, - OpConcat = 0x26, - OpUpdate = 0x27, - - OpNeg = 0x28, - OpNot = 0x29, - - ForceBool = 0x30, - JumpIfFalse = 0x31, - JumpIfTrue = 0x32, - Jump = 0x33, - - ConcatStrings = 0x34, - ResolvePath = 0x35, - - Assert = 0x36, - - PushWith = 0x37, - PopWith = 0x38, - WithLookup = 0x39, - - LoadBuiltins = 0x40, - LoadBuiltin = 0x41, - - MkPos = 0x43, - - LoadReplBinding = 0x44, - LoadScopedBinding = 0x45, - - Return = 0x46, -} - -interface ScopeChain { - locals: NixValue[]; - parent: ScopeChain | null; -} - -interface WithScope { - env: NixValue; - last: WithScope | null; -} - -const strings: string[] = []; -const constants: NixValue[] = []; - -const $e: NixAttrs = new Map(); - -function readU16(code: Uint8Array, offset: number): number { - return code[offset] | (code[offset + 1] << 8); -} - -function readU32(code: Uint8Array, offset: number): number { - return ( - code[offset] | - (code[offset + 1] << 8) | - (code[offset + 2] << 16) | - (code[offset + 3] << 24) - ) >>> 0; -} - -function readI32(code: Uint8Array, offset: number): number { - return code[offset] | (code[offset + 1] << 8) | (code[offset + 2] << 16) | (code[offset + 3] << 24); -} - -export function execBytecode(code: Uint8Array, currentDir: string): NixValue { - const chain: ScopeChain = { locals: [], parent: null }; - return execFrame(code, 0, chain, currentDir, null, null); -} - -export function execBytecodeScoped( - code: Uint8Array, - currentDir: string, - scopeMap: NixAttrs, -): NixValue { - const chain: ScopeChain = { locals: [], parent: null }; - return execFrame(code, 0, chain, currentDir, null, scopeMap); -} - -function execFrame( - code: Uint8Array, - startPc: number, - chain: ScopeChain, - currentDir: string, - withScope: WithScope | null, - scopeMap: NixAttrs | null, -): NixValue { - const locals = chain.locals; - const stack: NixValue[] = []; - let pc = startPc; - - for (;;) { - const opcode = code[pc++]; - switch (opcode) { - case Op.PushConst: { - const idx = readU32(code, pc); - pc += 4; - stack.push(constants[idx]); - break; - } - case Op.PushString: { - const idx = readU32(code, pc); - pc += 4; - stack.push(strings[idx]); - break; - } - case Op.PushNull: - stack.push(null); - break; - case Op.PushTrue: - stack.push(true); - break; - case Op.PushFalse: - stack.push(false); - break; - - case Op.LoadLocal: { - const idx = readU32(code, pc); - pc += 4; - stack.push(locals[idx]); - break; - } - case Op.LoadOuter: { - const layer = code[pc++]; - const idx = readU32(code, pc); - pc += 4; - let c: ScopeChain = chain; - for (let i = 0; i < layer; i++) c = c.parent!; - stack.push(c.locals[idx]); - break; - } - case Op.StoreLocal: { - const idx = readU32(code, pc); - pc += 4; - locals[idx] = stack.pop()!; - break; - } - case Op.AllocLocals: { - const n = readU32(code, pc); - pc += 4; - for (let i = 0; i < n; i++) locals.push(null); - break; - } - - case Op.MakeThunk: { - const bodyPc = readU32(code, pc); - pc += 4; - const labelIdx = readU32(code, pc); - pc += 4; - const label = strings[labelIdx]; - const scopeChain = chain; - const scopeCode = code; - const scopeDir = currentDir; - const scopeWith = withScope; - stack.push( - new NixThunk( - () => execFrame(scopeCode, bodyPc, scopeChain, scopeDir, scopeWith, null), - label, - ), - ); - break; - } - case Op.MakeClosure: { - const bodyPc = readU32(code, pc); - pc += 4; - const nSlots = readU32(code, pc); - pc += 4; - const closureChain = chain; - const closureCode = code; - const closureDir = currentDir; - const closureWith = withScope; - const func: NixFunction = (arg: NixValue) => { - const innerLocals = new Array(1 + nSlots).fill(null); - innerLocals[0] = arg; - const innerChain: ScopeChain = { locals: innerLocals, parent: closureChain }; - return execFrame(closureCode, bodyPc, innerChain, closureDir, closureWith, null); - }; - stack.push(func); - break; - } - case Op.MakePatternClosure: { - const bodyPc = readU32(code, pc); - pc += 4; - const nSlots = readU32(code, pc); - pc += 4; - const nRequired = readU16(code, pc); - pc += 2; - const nOptional = readU16(code, pc); - pc += 2; - const hasEllipsis = code[pc++] !== 0; - - const required: string[] = []; - for (let i = 0; i < nRequired; i++) { - required.push(strings[readU32(code, pc)]); - pc += 4; - } - const optional: string[] = []; - for (let i = 0; i < nOptional; i++) { - optional.push(strings[readU32(code, pc)]); - pc += 4; - } - const positions = new Map(); - const nTotal = nRequired + nOptional; - for (let i = 0; i < nTotal; i++) { - const nameIdx = readU32(code, pc); - pc += 4; - const spanId = readU32(code, pc); - pc += 4; - positions.set(strings[nameIdx], spanId); - } - - const closureChain = chain; - const closureCode = code; - const closureDir = currentDir; - const closureWith = withScope; - const func: NixFunction = (arg: NixValue) => { - const innerLocals = new Array(1 + nSlots).fill(null); - innerLocals[0] = arg; - const innerChain: ScopeChain = { locals: innerLocals, parent: closureChain }; - return execFrame(closureCode, bodyPc, innerChain, closureDir, closureWith, null); - }; - func.args = new NixArgs(required, optional, positions, hasEllipsis); - stack.push(func); - break; - } - - case Op.Call: { - const spanId = readU32(code, pc); - pc += 4; - const arg = stack.pop()!; - const func = stack.pop()!; - stack.push(call(func, arg, spanId)); - break; - } - case Op.CallNoSpan: { - const arg = stack.pop()!; - const func = stack.pop()!; - stack.push(call(func, arg)); - break; - } - - case Op.MakeAttrs: { - const n = readU32(code, pc); - pc += 4; - const spanValues: number[] = []; - for (let i = 0; i < n; i++) { - spanValues.push(stack.pop() as number); - } - spanValues.reverse(); - const map: NixAttrs = new Map(); - const posMap = new Map(); - const pairs: [string, NixValue][] = []; - for (let i = 0; i < n; i++) { - const val = stack.pop()!; - const key = stack.pop() as string; - pairs.push([key, val]); - } - pairs.reverse(); - for (let i = 0; i < n; i++) { - map.set(pairs[i][0], pairs[i][1]); - posMap.set(pairs[i][0], spanValues[i]); - } - stack.push(mkAttrs(map, posMap)); - break; - } - case Op.MakeAttrsDyn: { - const nStatic = readU32(code, pc); - pc += 4; - const nDyn = readU32(code, pc); - pc += 4; - - const dynTriples: [NixValue, NixValue, number][] = []; - for (let i = 0; i < nDyn; i++) { - const dynSpan = stack.pop() as number; - const dynVal = stack.pop()!; - const dynKey = stack.pop()!; - dynTriples.push([dynKey, dynVal, dynSpan]); - } - dynTriples.reverse(); - - const spanValues: number[] = []; - for (let i = 0; i < nStatic; i++) { - spanValues.push(stack.pop() as number); - } - spanValues.reverse(); - - const map: NixAttrs = new Map(); - const posMap = new Map(); - const pairs: [string, NixValue][] = []; - for (let i = 0; i < nStatic; i++) { - const val = stack.pop()!; - const key = stack.pop() as string; - pairs.push([key, val]); - } - pairs.reverse(); - for (let i = 0; i < nStatic; i++) { - map.set(pairs[i][0], pairs[i][1]); - posMap.set(pairs[i][0], spanValues[i]); - } - - const dynKeys: NixValue[] = []; - const dynVals: NixValue[] = []; - const dynSpans: number[] = []; - for (const [k, v, s] of dynTriples) { - dynKeys.push(k); - dynVals.push(v); - dynSpans.push(s); - } - - stack.push(mkAttrs(map, posMap, { dynKeys, dynVals, dynSpans })); - break; - } - case Op.MakeEmptyAttrs: - stack.push($e); - break; - - case Op.Select: { - const nKeys = readU16(code, pc); - pc += 2; - const spanId = readU32(code, pc); - pc += 4; - const keys: NixValue[] = []; - for (let i = 0; i < nKeys; i++) keys.push(stack.pop()!); - keys.reverse(); - const obj = stack.pop()!; - stack.push(select(obj, keys, spanId)); - break; - } - case Op.SelectDefault: { - const nKeys = readU16(code, pc); - pc += 2; - const spanId = readU32(code, pc); - pc += 4; - const defaultVal = stack.pop()!; - const keys: NixValue[] = []; - for (let i = 0; i < nKeys; i++) keys.push(stack.pop()!); - keys.reverse(); - const obj = stack.pop()!; - stack.push(selectWithDefault(obj, keys, defaultVal, spanId)); - break; - } - case Op.HasAttr: { - const nKeys = readU16(code, pc); - pc += 2; - const keys: NixValue[] = []; - for (let i = 0; i < nKeys; i++) keys.push(stack.pop()!); - keys.reverse(); - const obj = stack.pop()!; - stack.push(hasAttr(obj, keys)); - break; - } - - case Op.MakeList: { - const count = readU32(code, pc); - pc += 4; - const items: NixValue[] = new Array(count); - for (let i = count - 1; i >= 0; i--) { - items[i] = stack.pop()!; - } - stack.push(items); - break; - } - - case Op.OpAdd: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.add(a, b)); - break; - } - case Op.OpSub: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.sub(a, b)); - break; - } - case Op.OpMul: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.mul(a, b)); - break; - } - case Op.OpDiv: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.div(a, b)); - break; - } - case Op.OpEq: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.eq(a, b)); - break; - } - case Op.OpNeq: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(!op.eq(a, b)); - break; - } - case Op.OpLt: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.lt(a, b)); - break; - } - case Op.OpGt: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.gt(a, b)); - break; - } - case Op.OpLeq: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(!op.gt(a, b)); - break; - } - case Op.OpGeq: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(!op.lt(a, b)); - break; - } - case Op.OpConcat: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.concat(a, b)); - break; - } - case Op.OpUpdate: { - const b = stack.pop()!; - const a = stack.pop()!; - stack.push(op.update(a, b)); - break; - } - - case Op.OpNeg: { - const a = stack.pop()!; - stack.push(op.sub(0n, a)); - break; - } - case Op.OpNot: { - const a = stack.pop()!; - stack.push(!forceBool(a)); - break; - } - - case Op.ForceBool: { - const val = stack.pop()!; - stack.push(forceBool(val)); - break; - } - case Op.JumpIfFalse: { - const offset = readI32(code, pc); - pc += 4; - const val = stack.pop()!; - if (val === false) { - pc += offset; - } - break; - } - case Op.JumpIfTrue: { - const offset = readI32(code, pc); - pc += 4; - const val = stack.pop()!; - if (val === true) { - pc += offset; - } - break; - } - case Op.Jump: { - const offset = readI32(code, pc); - pc += 4; - pc += offset; - break; - } - - case Op.ConcatStrings: { - const nParts = readU16(code, pc); - pc += 2; - const forceString = code[pc++] !== 0; - const parts: NixValue[] = new Array(nParts); - for (let i = nParts - 1; i >= 0; i--) { - parts[i] = stack.pop()!; - } - stack.push(concatStringsWithContext(parts, forceString)); - break; - } - case Op.ResolvePath: { - const pathExpr = stack.pop()!; - stack.push(resolvePath(currentDir, pathExpr)); - break; - } - - case Op.Assert: { - const rawIdx = readU32(code, pc); - pc += 4; - const spanId = readU32(code, pc); - pc += 4; - const expr = stack.pop()!; - const assertion = stack.pop()!; - stack.push(assert(assertion, expr, strings[rawIdx], spanId)); - break; - } - - case Op.PushWith: { - const namespace = stack.pop()!; - withScope = { env: namespace, last: withScope }; - break; - } - case Op.PopWith: - withScope = withScope!.last; - break; - case Op.WithLookup: { - const nameIdx = readU32(code, pc); - pc += 4; - stack.push(lookupWith(strings[nameIdx], withScope!)); - break; - } - - case Op.LoadBuiltins: - stack.push(builtins); - break; - case Op.LoadBuiltin: { - const idx = readU32(code, pc); - pc += 4; - stack.push(builtins.get(strings[idx])!); - break; - } - - case Op.MkPos: { - const spanId = readU32(code, pc); - pc += 4; - stack.push(mkPos(spanId)); - break; - } - - case Op.LoadReplBinding: { - const idx = readU32(code, pc); - pc += 4; - stack.push(Nix.getReplBinding(strings[idx])); - break; - } - case Op.LoadScopedBinding: { - const idx = readU32(code, pc); - pc += 4; - stack.push(scopeMap!.get(strings[idx])!); - break; - } - - case Op.Return: - return stack.pop()!; - - default: - throw new Error(`Unknown bytecode opcode: ${opcode ? `0x${opcode.toString(16)}` : "undefined"} at pc=${pc - 1}`); - } - } -} - -declare const Nix: { - getReplBinding: (name: string) => NixValue; -}; - -export { strings as vmStrings, constants as vmConstants }; diff --git a/nix-js/runtime-ts/tsconfig.json b/nix-js/runtime-ts/tsconfig.json deleted file mode 100644 index b4bb5e7..0000000 --- a/nix-js/runtime-ts/tsconfig.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "lib": ["ES2022", "DOM"], - "moduleResolution": "bundler", - "strict": true, - "noUnusedLocals": false, - "noUnusedParameters": false, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "declaration": false, - "outDir": "./dist", - "rootDir": "./src", - "typeRoots": ["./src/types"] - }, - "include": ["src/**/*"], - "exclude": ["node_modules", "dist"] -} diff --git a/nix-js/src/codegen.rs b/nix-js/src/codegen.rs deleted file mode 100644 index d327fbf..0000000 --- a/nix-js/src/codegen.rs +++ /dev/null @@ -1,618 +0,0 @@ -use std::fmt::{self, Write as _}; -use std::ops::Deref; -use std::path::Path; - -use rnix::TextRange; - -use crate::ir::*; -use crate::value::Symbol; - -macro_rules! code { - ($buf:expr, $ctx:expr; $($item:expr)*) => {{ - $( - ($item).compile($ctx, $buf); - )* - }}; - - ($buf:expr, $ctx:expr; $($item:expr)*) => {{ - $( - ($item).compile($ctx, $buf); - )* - }}; - - ($buf:expr, $fmt:literal, $($arg:tt)*) => { - write!($buf, $fmt, $($arg)*).unwrap() - }; - - ($buf:expr, $fmt:literal) => { - write!($buf, $fmt).unwrap() - }; -} - -pub(crate) fn compile(expr: RawIrRef<'_>, ctx: &impl CodegenContext) -> String { - let mut buf = CodeBuffer::with_capacity(8192); - - code!( - &mut buf, ctx; - "((" { if SCOPED { "_s" } else { "" } } ")=>{" - "const _d=" - quoted(&ctx.get_current_dir().display().to_string()) - ",_w=null;" - "return " expr - "})" { if SCOPED { "" } else { "()" } } - ); - - buf.into_string() -} - -struct CodeBuffer { - buf: String, -} - -impl fmt::Write for CodeBuffer { - #[inline] - fn write_str(&mut self, s: &str) -> fmt::Result { - self.buf.push_str(s); - Ok(()) - } -} - -impl CodeBuffer { - #[inline] - fn with_capacity(capacity: usize) -> Self { - Self { - buf: String::with_capacity(capacity), - } - } - - #[inline] - fn push_str(&mut self, s: &str) { - self.buf.push_str(s); - } - - #[inline] - fn into_string(self) -> String { - self.buf - } -} - -struct Quoted<'a>(&'a str); - -#[inline] -fn quoted(s: &str) -> Quoted<'_> { - Quoted(s) -} - -struct Escaped<'a>(&'a str); - -impl Compile for Escaped<'_> { - fn compile(&self, _ctx: &Ctx, buf: &mut CodeBuffer) { - for c in self.0.chars() { - let _ = match c { - '\\' => buf.write_str("\\\\"), - '"' => buf.write_str("\\\""), - '\n' => buf.write_str("\\n"), - '\r' => buf.write_str("\\r"), - '\t' => buf.write_str("\\t"), - _ => buf.write_char(c), - }; - } - } -} - -#[inline] -fn escaped(s: &str) -> Escaped<'_> { - Escaped(s) -} - -struct Joined { - items: I, - sep: &'static str, - write_fn: F, -} - -#[inline] -fn joined( - items: I, - sep: &'static str, - write_fn: F, -) -> Joined { - Joined { - items, - sep, - write_fn, - } -} - -trait Compile { - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer); -} - -impl Compile for str { - fn compile(&self, _ctx: &Ctx, buf: &mut CodeBuffer) { - buf.push_str(self); - } -} - -impl Compile for usize { - fn compile(&self, _ctx: &Ctx, buf: &mut CodeBuffer) { - let _ = write!(buf, "{self}"); - } -} - -impl Compile for bool { - fn compile(&self, _ctx: &Ctx, buf: &mut CodeBuffer) { - let _ = write!(buf, "{self}"); - } -} - -impl Compile for Quoted<'_> { - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) { - code!(buf, ctx; "\"" escaped(self.0) "\"") - } -} - -impl Compile for Joined -where - I: IntoIterator + Clone, - F: Fn(&Ctx, &mut CodeBuffer, I::Item) + Clone, -{ - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) { - let mut iter = self.items.clone().into_iter(); - if let Some(first) = iter.next() { - (self.write_fn)(ctx, buf, first); - for item in iter { - buf.push_str(self.sep); - (self.write_fn)(ctx, buf, item); - } - } - } -} - -impl Compile for rnix::TextRange { - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) { - code!(buf, "{}", ctx.register_span(*self)); - } -} - -pub(crate) trait CodegenContext { - fn get_sym(&self, id: SymId) -> Symbol<'_>; - fn get_current_dir(&self) -> &Path; - fn get_store_dir(&self) -> &str; - fn get_current_source_id(&self) -> usize; - fn register_span(&self, range: rnix::TextRange) -> usize; -} - -impl Compile for Symbol<'_> { - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) { - quoted(self).compile(ctx, buf); - } -} - -impl Compile for RawIrRef<'_> { - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) { - match self.deref() { - Ir::Int(int) => { - code!(buf, "{}n", int); - } - Ir::Float(float) => { - code!(buf, "{}", float); - } - Ir::Bool(bool) => { - code!(buf, "{}", bool); - } - Ir::Null => { - code!(buf, ctx; "null"); - } - Ir::Str(s) => { - code!(buf, ctx; quoted(s)); - } - Ir::Path(p) => { - // Nix.resolvePath - code!(buf, ctx; "$r(_d," p ")"); - } - Ir::If { cond, consq, alter } => { - code!(buf, ctx; "$fb(" cond ")?(" consq "):(" alter ")"); - } - &Ir::BinOp { lhs, rhs, kind } => compile_binop(lhs, rhs, kind, ctx, buf), - &Ir::UnOp { rhs, kind } => compile_unop(rhs, kind, ctx, buf), - &Ir::Func { - body, - ref param, - arg, - ref thunks, - } => compile_func(arg, thunks, param, body, ctx, buf), - Ir::AttrSet { stcs, dyns } => compile_attrset(stcs, dyns, ctx, buf), - Ir::List { items } => compile_list(items, ctx, buf), - Ir::Call { func, arg, span } => { - code!(buf, ctx; - "$c(" - func - "," - arg - "," - span - ")" - ); - } - Ir::Arg(x) => { - code!(buf, "a{}", x.0); - } - &Ir::TopLevel { body, ref thunks } => compile_toplevel(body, thunks, ctx, buf), - &Ir::Select { - expr, - ref attrpath, - default, - span, - } => compile_select(expr, attrpath, default, span, ctx, buf), - Ir::Thunk(ThunkId(id)) => { - code!(buf, "e{}", id); - } - Ir::Builtins => { - // Nix.builtins - code!(buf, ctx; "$b"); - } - &Ir::Builtin(name) => { - // Nix.builtins - code!(buf, ctx; "$b.get(" ctx.get_sym(name) ")"); - } - &Ir::ConcatStrings { - ref parts, - force_string, - } => compile_concat_strings(parts, force_string, ctx, buf), - &Ir::HasAttr { lhs, ref rhs } => compile_has_attr(lhs, rhs, ctx, buf), - Ir::Assert { - assertion, - expr, - assertion_raw, - span: assert_span, - } => { - // Nix.assert - code!(buf, ctx; - "$a(" - assertion - "," - expr - "," - quoted(assertion_raw) - "," - assert_span - ")" - ); - } - Ir::CurPos(span) => { - // Nix.mkPos - code!(buf, ctx; "$mp(" span ")"); - } - &Ir::ReplBinding(name) => { - // Nix.getReplBinding - code!(buf, ctx; "$gb(" ctx.get_sym(name) ")"); - } - &Ir::ScopedImportBinding(name) => { - code!(buf, ctx; "_s.get(" ctx.get_sym(name) ")"); - } - &Ir::With { - namespace, - body, - ref thunks, - } => compile_with(namespace, body, thunks, ctx, buf), - &Ir::WithLookup(name) => { - // Nix.lookupWith - code!(buf, ctx; "$l(" ctx.get_sym(name) ",_w)"); - } - } - } -} - -fn compile_binop<'ir>( - lhs: RawIrRef<'ir>, - rhs: RawIrRef<'ir>, - kind: BinOpKind, - ctx: &impl CodegenContext, - buf: &mut CodeBuffer, -) { - use BinOpKind::*; - match kind { - Add | Sub | Mul | Div | Eq | Neq | Lt | Gt | Leq | Geq | Con | Upd => { - let op_func = match kind { - Add => "$oa", - Sub => "$os", - Mul => "$om", - Div => "$od", - Eq => "$oe", - Neq => "!$oe", - Lt => "$ol", - Gt => "$og", - Leq => "!$og", - Geq => "!$ol", - Con => "$oc", - Upd => "$ou", - _ => unreachable!(), - }; - - code!( - buf, ctx; - op_func "(" lhs "," rhs ")" - ); - } - And => { - code!( - buf, ctx; - "$fb(" lhs ")" "&&" "$fb(" rhs ")" - ); - } - Or => { - code!( - buf, ctx; - "$fb(" lhs ")" "||" "$fb(" rhs ")" - ); - } - Impl => { - code!( - buf, ctx; - "!$fb(" lhs ")" "||" "$fb(" rhs ")" - ); - } - PipeL => { - code!(buf, ctx; "$c(" rhs "," lhs ")"); - } - PipeR => { - code!(buf, ctx; "$c(" lhs "," rhs ")"); - } - } -} - -fn compile_unop( - rhs: RawIrRef<'_>, - kind: UnOpKind, - ctx: &impl CodegenContext, - buf: &mut CodeBuffer, -) { - use UnOpKind::*; - match kind { - Neg => { - // 0 - rhs - code!(buf, ctx; "$os(0n," rhs ")"); - } - Not => { - code!(buf, ctx; "!$fb(" rhs ")"); - } - } -} - -fn compile_func<'ir, Ctx: CodegenContext>( - ArgId(id): ArgId, - thunks: &[(ThunkId, RawIrRef<'ir>)], - param: &Option>, - body: RawIrRef<'ir>, - ctx: &Ctx, - buf: &mut CodeBuffer, -) { - let has_thunks = !thunks.is_empty(); - - if let Some(Param { - required, - optional, - ellipsis, - }) = ¶m - { - code!(buf, "$mf(a{}=>", id); - if has_thunks { - code!(buf, ctx; "{" thunks "return " body "}"); - } else { - code!(buf, ctx; "(" body ")"); - } - code!(buf, ctx; - ",[" - joined(required.iter(), ",", |ctx: &Ctx, buf, &(sym, _)| { - code!(buf, ctx; ctx.get_sym(sym)); - }) - "],[" - joined(optional.iter(), ",", |ctx: &Ctx, buf, &(sym, _)| { - code!(buf, ctx; ctx.get_sym(sym)); - }) - "],new Map([" - joined(required.iter().chain(optional.iter()), ",", |ctx: &Ctx, buf, &(sym, span)| { - code!(buf, ctx; "[" ctx.get_sym(sym) "," span "]"); - }) - "])," - ellipsis - ")" - ); - } else { - code!(buf, "a{}=>", id); - if has_thunks { - code!(buf, ctx; "{" thunks "return " body "}"); - } else { - code!(buf, ctx; "(" body ")"); - } - } -} - -impl<'ir, Ctx: CodegenContext> Compile for [(ThunkId, RawIrRef<'ir>)] { - fn compile(&self, ctx: &Ctx, buf: &mut CodeBuffer) { - if self.is_empty() { - return; - } - - code!( - buf, ctx; - "const " - joined(self.iter(), ",", |ctx: &Ctx, buf, &(slot, inner)| { - code!(buf, ctx; "e" slot.0 "=$t(()=>(" inner ")," "'e" slot.0 "')"); - }) - ";" - ); - } -} - -fn compile_toplevel<'ir, Ctx: CodegenContext>( - body: RawIrRef<'ir>, - thunks: &[(ThunkId, RawIrRef<'ir>)], - ctx: &Ctx, - buf: &mut CodeBuffer, -) { - if thunks.is_empty() { - body.compile(ctx, buf); - } else { - code!(buf, ctx; "(()=>{" thunks "return " body "})()"); - } -} - -fn compile_with<'ir>( - namespace: RawIrRef<'ir>, - body: RawIrRef<'ir>, - thunks: &[(ThunkId, RawIrRef<'ir>)], - ctx: &impl CodegenContext, - buf: &mut CodeBuffer, -) { - let has_thunks = !thunks.is_empty(); - if has_thunks { - code!(buf, ctx; "((_w)=>{" thunks "return " body "})({env:" namespace ",last:_w})"); - } else { - code!(buf, ctx; "((_w)=>(" body "))({env:" namespace ",last:_w})"); - } -} - -fn compile_select<'ir, Ctx: CodegenContext>( - expr: RawIrRef<'ir>, - attrpath: &[Attr>], - default: Option>, - span: TextRange, - ctx: &Ctx, - buf: &mut CodeBuffer, -) { - if let Some(default) = default { - code!(buf, ctx; - "$sd(" - expr - ",[" - joined(attrpath.iter(), ",", |ctx: &Ctx, buf, attr| { - match attr { - Attr::Str(sym, _) => code!(buf, ctx; ctx.get_sym(*sym)), - Attr::Dynamic(expr_id, _) => code!(buf, ctx; *expr_id), - } - }) - "]," - default - "," - span - ")" - ); - } else { - code!(buf, ctx; - "$s(" - expr - ",[" - joined(attrpath.iter(), ",", |ctx: &Ctx, buf, attr| { - match attr { - Attr::Str(sym, _) => code!(buf, ctx; ctx.get_sym(*sym)), - Attr::Dynamic(expr, _) => code!(buf, ctx; expr), - } - }) - "]," - span - ")" - ); - } -} - -fn compile_attrset<'ir, Ctx: CodegenContext>( - stcs: &HashMap<'ir, SymId, (RawIrRef<'ir>, TextRange)>, - dyns: &[(RawIrRef<'ir>, RawIrRef<'ir>, TextRange)], - ctx: &Ctx, - buf: &mut CodeBuffer, -) { - if !dyns.is_empty() { - code!(buf, ctx; - "$ma(new Map([" - joined(stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(val, _))| { - let key = ctx.get_sym(sym); - code!( - buf, ctx; - "[" key "," val "]" - ); - }) - "]),new Map([" - joined(stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(_, span))| { - code!(buf, ctx; "[" ctx.get_sym(sym) "," span "]"); - }) - "]),{dynKeys:[" - joined(dyns.iter(), ",", |ctx: &Ctx, buf, (key, _, _)| { - code!(buf, ctx; key); - }) - "],dynVals:[" - joined(dyns.iter(), ",", |ctx: &Ctx, buf, (_, val, _)| { - code!(buf, ctx; val); - }) - "],dynSpans:[" - joined(dyns.iter(), ",", |ctx: &Ctx, buf, (_, _, attr_span)| { - code!(buf, ctx; attr_span); - }) - "]})" - ); - } else if !stcs.is_empty() { - code!(buf, ctx; - "$ma(new Map([" - joined(stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(val, _))| { - let key = ctx.get_sym(sym); - code!( - buf, ctx; - "[" key "," val "]" - ); - }) - "]),new Map([" - joined(stcs.iter(), ",", |ctx: &Ctx, buf, (&sym, &(_, span))| { - code!(buf, ctx; "[" ctx.get_sym(sym) "," span "]"); - }) - "]))" - ); - } else { - code!(buf, ctx; "$e"); - } -} - -fn compile_list(items: &[RawIrRef<'_>], ctx: &Ctx, buf: &mut CodeBuffer) { - code!(buf, ctx; - "[" - joined(items.iter(), ",", |ctx: &Ctx, buf, item| { - code!(buf, ctx; item); - }) - "]" - ); -} - -fn compile_concat_strings( - parts: &[RawIrRef<'_>], - force_string: bool, - ctx: &Ctx, - buf: &mut CodeBuffer, -) { - code!(buf, ctx; - "$cs([" - joined(parts.iter(), ",", |ctx: &Ctx, buf, part| { - code!(buf, ctx; part); - }) - "]," force_string ")" - ); -} - -fn compile_has_attr<'ir, Ctx: CodegenContext>( - lhs: RawIrRef<'ir>, - rhs: &[Attr>], - ctx: &Ctx, - buf: &mut CodeBuffer, -) { - code!(buf, ctx; - "$h(" - lhs - ",[" - joined(rhs.iter(), ",", |ctx: &Ctx, buf, attr| { - match attr { - Attr::Str(sym, _) => code!(buf, ctx; ctx.get_sym(*sym)), - Attr::Dynamic(expr, _) => code!(buf, ctx; expr), - } - }) - "])" - ); -} diff --git a/nix-js/src/runtime.rs b/nix-js/src/runtime.rs deleted file mode 100644 index f45227c..0000000 --- a/nix-js/src/runtime.rs +++ /dev/null @@ -1,687 +0,0 @@ -use std::borrow::Cow; -use std::marker::PhantomData; -use std::path::Path; - -#[cfg(feature = "inspector")] -use deno_core::PollEventLoopOptions; -use deno_core::{Extension, ExtensionFileSource, JsRuntime, OpState, RuntimeOptions, v8}; - -use crate::bytecode::{Bytecode, Constant}; -use crate::error::{Error, Result, Source}; -use crate::store::DaemonStore; -use crate::value::{AttrSet, List, Symbol, Value}; - -#[cfg(feature = "inspector")] -pub(crate) mod inspector; -mod ops; -use ops::*; - -type ScopeRef<'p, 's> = v8::PinnedRef<'p, v8::HandleScope<'s>>; -type LocalValue<'a> = v8::Local<'a, v8::Value>; -type LocalSymbol<'a> = v8::Local<'a, v8::Symbol>; - -pub(crate) trait RuntimeContext: 'static { - fn get_current_dir(&self) -> &Path; - fn add_source(&mut self, path: Source); - fn compile(&mut self, source: Source) -> Result; - fn compile_scoped(&mut self, source: Source, scope: Vec) -> Result; - fn compile_bytecode(&mut self, source: Source) -> Result; - fn compile_bytecode_scoped(&mut self, source: Source, scope: Vec) -> Result; - fn get_source(&self, id: usize) -> Source; - fn get_store(&self) -> &DaemonStore; - fn get_span(&self, id: usize) -> (usize, rnix::TextRange); - fn get_unsynced(&mut self) -> (&[String], &[Constant], usize, usize); -} - -pub(crate) trait OpStateExt { - fn get_ctx(&self) -> &Ctx; - fn get_ctx_mut(&mut self) -> &mut Ctx; -} - -impl OpStateExt for OpState { - fn get_ctx(&self) -> &Ctx { - self.try_borrow::<&'static mut Ctx>() - .expect("RuntimeContext not set") - } - fn get_ctx_mut(&mut self) -> &mut Ctx { - self.try_borrow_mut::<&'static mut Ctx>() - .expect("RuntimeContext not set") - } -} - -fn runtime_extension() -> Extension { - const ESM: &[ExtensionFileSource] = - &deno_core::include_js_files!(nix_runtime dir "runtime-ts/dist", "runtime.js"); - let mut ops = vec![ - op_import::(), - op_scoped_import::(), - op_resolve_path(), - op_read_file(), - op_read_file_type(), - op_read_dir(), - op_path_exists(), - op_walk_dir(), - op_make_placeholder(), - op_store_path::(), - op_convert_hash(), - op_hash_string(), - op_hash_file(), - op_parse_hash(), - op_add_path::(), - op_add_filtered_path::(), - op_decode_span::(), - op_to_file::(), - op_copy_path_to_store::(), - op_get_env(), - op_match(), - op_split(), - op_from_json(), - op_from_toml(), - op_finalize_derivation::(), - op_to_xml(), - ]; - ops.extend(crate::fetcher::register_ops::()); - - Extension { - name: "nix_runtime", - esm_files: Cow::Borrowed(ESM), - esm_entry_point: Some("ext:nix_runtime/runtime.js"), - ops: Cow::Owned(ops), - enabled: true, - ..Default::default() - } -} - -mod private { - use deno_error::js_error_wrapper; - #[derive(Debug)] - pub struct SimpleErrorWrapper(String); - impl std::fmt::Display for SimpleErrorWrapper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - std::fmt::Display::fmt(&self.0, f) - } - } - impl std::error::Error for SimpleErrorWrapper {} - - js_error_wrapper!(SimpleErrorWrapper, NixRuntimeError, "Error"); - - impl From for NixRuntimeError { - fn from(value: String) -> Self { - NixRuntimeError(SimpleErrorWrapper(value)) - } - } - impl From<&str> for NixRuntimeError { - fn from(value: &str) -> Self { - NixRuntimeError(SimpleErrorWrapper(value.to_string())) - } - } -} -pub(crate) use private::NixRuntimeError; - -pub(crate) struct Runtime { - js_runtime: JsRuntime, - #[cfg(feature = "inspector")] - rt: tokio::runtime::Runtime, - #[cfg(feature = "inspector")] - wait_for_inspector: bool, - symbols: GlobalSymbols, - cached_fns: CachedFunctions, - _marker: PhantomData, -} - -#[cfg(feature = "inspector")] -#[derive(Debug, Clone, Copy, Default)] -pub(crate) struct InspectorOptions { - pub(crate) enable: bool, - pub(crate) wait: bool, -} - -impl Runtime { - pub(crate) fn new( - #[cfg(feature = "inspector")] inspector_options: InspectorOptions, - ) -> Result { - use std::sync::Once; - - static INIT: Once = Once::new(); - INIT.call_once(|| { - assert_eq!( - deno_core::v8_set_flags(vec![ - "".into(), - format!("--stack-size={}", 8 * 1024), - #[cfg(feature = "prof")] - ("--prof".into()) - ]), - [""] - ); - JsRuntime::init_platform(Some(v8::new_default_platform(0, false).make_shared())); - }); - - let mut js_runtime = JsRuntime::new(RuntimeOptions { - extensions: vec![runtime_extension::()], - #[cfg(feature = "inspector")] - inspector: inspector_options.enable, - is_main: true, - ..Default::default() - }); - - js_runtime.op_state().borrow_mut().put(RegexCache::new()); - js_runtime.op_state().borrow_mut().put(DrvHashCache::new()); - - let (symbols, cached_fns) = { - deno_core::scope!(scope, &mut js_runtime); - let symbols = Self::get_symbols(scope)?; - let cached_fns = Self::get_cached_functions(scope)?; - (symbols, cached_fns) - }; - - Ok(Self { - js_runtime, - #[cfg(feature = "inspector")] - rt: tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("failed to build tokio runtime"), - #[cfg(feature = "inspector")] - wait_for_inspector: inspector_options.wait, - symbols, - cached_fns, - _marker: PhantomData, - }) - } - - #[cfg(feature = "inspector")] - pub(crate) fn inspector(&self) -> std::rc::Rc { - self.js_runtime.inspector() - } - - #[cfg(feature = "inspector")] - pub(crate) fn wait_for_inspector_disconnect(&mut self) { - let _ = self - .rt - .block_on(self.js_runtime.run_event_loop(PollEventLoopOptions { - wait_for_inspector: true, - ..Default::default() - })); - } - - pub(crate) fn eval(&mut self, script: String, ctx: &mut Ctx) -> Result { - let ctx: &'static mut Ctx = unsafe { &mut *(ctx as *mut Ctx) }; - self.js_runtime.op_state().borrow_mut().put(ctx); - - #[cfg(feature = "inspector")] - if self.wait_for_inspector { - self.js_runtime - .inspector() - .wait_for_session_and_break_on_next_statement(); - } else { - self.js_runtime.inspector().wait_for_session(); - } - let global_value = self - .js_runtime - .execute_script("", script) - .map_err(|error| { - let op_state = self.js_runtime.op_state(); - let op_state_borrow = op_state.borrow(); - let ctx: &Ctx = op_state_borrow.get_ctx(); - - crate::error::parse_js_error(error, ctx) - })?; - - // Retrieve scope from JsRuntime - deno_core::scope!(scope, self.js_runtime); - let local_value = v8::Local::new(scope, &global_value); - let symbols = &self.symbols.local(scope); - - Ok(to_value(local_value, scope, symbols)) - } - - pub(crate) fn eval_bytecode( - &mut self, - result: Bytecode, - ctx: &mut Ctx, - force_mode: ForceMode, - ) -> Result { - let ctx: &'static mut Ctx = unsafe { &mut *(ctx as *mut Ctx) }; - { - deno_core::scope!(scope, self.js_runtime); - sync_global_tables(scope, &self.cached_fns, ctx); - } - let op_state = self.js_runtime.op_state(); - op_state.borrow_mut().put(ctx); - - #[cfg(feature = "inspector")] - if self.wait_for_inspector { - self.js_runtime - .inspector() - .wait_for_session_and_break_on_next_statement(); - } else { - self.js_runtime.inspector().wait_for_session(); - } - - deno_core::scope!(scope, self.js_runtime); - - let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(result.code); - let ab = v8::ArrayBuffer::with_backing_store(scope, &store.make_shared()); - let u8a = v8::Uint8Array::new(scope, ab, 0, ab.byte_length()) - .ok_or_else(|| Error::internal("failed to create Uint8Array".into()))?; - - let dir = v8::String::new(scope, &result.current_dir) - .ok_or_else(|| Error::internal("failed to create dir string".into()))?; - - let undef = v8::undefined(scope); - let tc = std::pin::pin!(v8::TryCatch::new(scope)); - let scope = &mut tc.init(); - - let exec_bytecode = v8::Local::new(scope, &self.cached_fns.exec_bytecode); - let raw_result = exec_bytecode - .call(scope, undef.into(), &[u8a.into(), dir.into()]) - .ok_or_else(|| { - scope - .exception() - .map(|e| { - let op_state_borrow = op_state.borrow(); - let ctx: &Ctx = op_state_borrow.get_ctx(); - Box::new(crate::error::parse_js_error( - deno_core::error::JsError::from_v8_exception(scope, e), - ctx, - )) - }) - .unwrap_or_else(|| Error::internal("bytecode execution failed".into())) - })?; - - let force_fn = match force_mode { - ForceMode::Force => &self.cached_fns.force_fn, - ForceMode::ForceShallow => &self.cached_fns.force_shallow_fn, - ForceMode::ForceDeep => &self.cached_fns.force_deep_fn, - }; - let force_fn = v8::Local::new(scope, force_fn); - - let forced = force_fn - .call(scope, undef.into(), &[raw_result]) - .ok_or_else(|| { - scope - .exception() - .map(|e| { - let op_state_borrow = op_state.borrow(); - let ctx: &Ctx = op_state_borrow.get_ctx(); - Box::new(crate::error::parse_js_error( - deno_core::error::JsError::from_v8_exception(scope, e), - ctx, - )) - }) - .unwrap_or_else(|| Error::internal("force failed".into())) - })?; - - let symbols = &self.symbols.local(scope); - Ok(to_value(forced, scope, symbols)) - } - - fn get_symbols(scope: &ScopeRef) -> Result { - let global = scope.get_current_context().global(scope); - let nix_key = v8::String::new(scope, "Nix") - .ok_or_else(|| Error::internal("failed to create V8 String".into()))?; - let nix_obj = global - .get(scope, nix_key.into()) - .ok_or_else(|| Error::internal("failed to get global Nix object".into()))? - .to_object(scope) - .ok_or_else(|| { - Error::internal("failed to convert global Nix Value to object".into()) - })?; - - let get_symbol = |symbol| { - let key = v8::String::new(scope, symbol) - .ok_or_else(|| Error::internal("failed to create V8 String".into()))?; - let val = nix_obj - .get(scope, key.into()) - .ok_or_else(|| Error::internal(format!("failed to get {symbol} Symbol")))?; - let sym = val.try_cast::().map_err(|err| { - Error::internal(format!( - "failed to convert {symbol} Value to Symbol ({err})" - )) - })?; - Result::Ok(v8::Global::new(scope, sym)) - }; - - let is_thunk = get_symbol("IS_THUNK")?; - let primop_metadata = get_symbol("PRIMOP_METADATA")?; - let has_context = get_symbol("HAS_CONTEXT")?; - let is_path = get_symbol("IS_PATH")?; - let is_cycle = get_symbol("IS_CYCLE")?; - - Ok(GlobalSymbols { - is_thunk, - primop_metadata, - has_context, - is_path, - is_cycle, - }) - } - - fn get_cached_functions(scope: &ScopeRef) -> Result { - let global = scope.get_current_context().global(scope); - let nix_key = v8::String::new(scope, "Nix") - .ok_or_else(|| Error::internal("failed to create V8 String".into()))?; - let nix_obj = global - .get(scope, nix_key.into()) - .ok_or_else(|| Error::internal("failed to get global Nix object".into()))? - .to_object(scope) - .ok_or_else(|| { - Error::internal("failed to convert global Nix Value to object".into()) - })?; - - let get_fn = |name: &str| -> Result> { - let key = v8::String::new(scope, name) - .ok_or_else(|| Error::internal("failed to create V8 String".into()))?; - let val = nix_obj - .get(scope, key.into()) - .ok_or_else(|| Error::internal(format!("failed to get Nix.{name}")))?; - let func = val - .try_cast::() - .map_err(|err| Error::internal(format!("Nix.{name} is not a function ({err})")))?; - Ok(v8::Global::new(scope, func)) - }; - - let exec_bytecode = get_fn("execBytecode")?; - let force_fn = get_fn("force")?; - let force_shallow_fn = get_fn("forceShallow")?; - let force_deep_fn = get_fn("forceDeep")?; - - let strings_key = v8::String::new(scope, "strings") - .ok_or_else(|| Error::internal("failed to create V8 String".into()))?; - let strings_array = nix_obj - .get(scope, strings_key.into()) - .ok_or_else(|| Error::internal("failed to get Nix.strings".into()))? - .try_cast::() - .map_err(|err| Error::internal(format!("Nix.strings is not an array ({err})")))?; - - let constants_key = v8::String::new(scope, "constants") - .ok_or_else(|| Error::internal("failed to create V8 String".into()))?; - let constants_array = nix_obj - .get(scope, constants_key.into()) - .ok_or_else(|| Error::internal("failed to get Nix.constants".into()))? - .try_cast::() - .map_err(|err| Error::internal(format!("Nix.constants is not an array ({err})")))?; - - Ok(CachedFunctions { - exec_bytecode, - force_fn, - force_shallow_fn, - force_deep_fn, - strings_array: v8::Global::new(scope, strings_array), - constants_array: v8::Global::new(scope, constants_array), - }) - } -} - -struct GlobalSymbols { - is_thunk: v8::Global, - primop_metadata: v8::Global, - has_context: v8::Global, - is_path: v8::Global, - is_cycle: v8::Global, -} - -impl GlobalSymbols { - fn local<'a>(&self, scope: &ScopeRef<'a, '_>) -> LocalSymbols<'a> { - LocalSymbols { - is_thunk: v8::Local::new(scope, &self.is_thunk), - primop_metadata: v8::Local::new(scope, &self.primop_metadata), - has_context: v8::Local::new(scope, &self.has_context), - is_path: v8::Local::new(scope, &self.is_path), - is_cycle: v8::Local::new(scope, &self.is_cycle), - } - } -} - -struct LocalSymbols<'a> { - is_thunk: v8::Local<'a, v8::Symbol>, - primop_metadata: v8::Local<'a, v8::Symbol>, - has_context: v8::Local<'a, v8::Symbol>, - is_path: v8::Local<'a, v8::Symbol>, - is_cycle: v8::Local<'a, v8::Symbol>, -} - -struct CachedFunctions { - exec_bytecode: v8::Global, - force_fn: v8::Global, - force_shallow_fn: v8::Global, - force_deep_fn: v8::Global, - strings_array: v8::Global, - constants_array: v8::Global, -} - -pub(crate) enum ForceMode { - Force, - ForceShallow, - ForceDeep, -} - -fn sync_global_tables( - scope: &ScopeRef, - cached: &CachedFunctions, - ctx: &mut Ctx, -) { - let (new_strings, new_constants, strings_base, constants_base) = ctx.get_unsynced(); - - if !new_strings.is_empty() { - let s_array = v8::Local::new(scope, &cached.strings_array); - for (i, s) in new_strings.iter().enumerate() { - let idx = (strings_base + i) as u32; - #[allow(clippy::unwrap_used)] - let val = v8::String::new(scope, s).unwrap(); - s_array.set_index(scope, idx, val.into()); - } - } - - if !new_constants.is_empty() { - let k_array = v8::Local::new(scope, &cached.constants_array); - for (i, c) in new_constants.iter().enumerate() { - let idx = (constants_base + i) as u32; - let val: v8::Local = match c { - Constant::Int(n) => v8::BigInt::new_from_i64(scope, *n).into(), - Constant::Float(bits) => v8::Number::new(scope, f64::from_bits(*bits)).into(), - }; - k_array.set_index(scope, idx, val); - } - } -} - -fn to_value<'a>( - val: LocalValue<'a>, - scope: &ScopeRef<'a, '_>, - symbols: &LocalSymbols<'a>, -) -> Value { - match () { - _ if val.is_big_int() => { - let (val, lossless) = val - .to_big_int(scope) - .expect("infallible conversion") - .i64_value(); - if !lossless { - panic!("BigInt value out of i64 range: conversion lost precision"); - } - Value::Int(val) - } - _ if val.is_number() => { - let val = val.to_number(scope).expect("infallible conversion").value(); - Value::Float(val) - } - _ if val.is_true() => Value::Bool(true), - _ if val.is_false() => Value::Bool(false), - _ if val.is_null() => Value::Null, - _ if val.is_string() => { - let val = val.to_string(scope).expect("infallible conversion"); - Value::String(val.to_rust_string_lossy(scope)) - } - _ if val.is_array() => { - let val = val.try_cast::().expect("infallible conversion"); - let len = val.length(); - let list = (0..len) - .map(|i| { - let val = val.get_index(scope, i).expect("infallible index operation"); - to_value(val, scope, symbols) - }) - .collect(); - Value::List(List::new(list)) - } - _ if val.is_function() => { - if let Some(primop) = to_primop(val, scope, symbols.primop_metadata) { - primop - } else { - Value::Func - } - } - _ if val.is_map() => { - let val = val.try_cast::().expect("infallible conversion"); - let size = val.size() as u32; - let array = val.as_array(scope); - let attrs = (0..size) - .map(|i| { - let key = array - .get_index(scope, i * 2) - .expect("infallible index operation"); - let key = key.to_rust_string_lossy(scope); - let val = array - .get_index(scope, i * 2 + 1) - .expect("infallible index operation"); - let val = to_value(val, scope, symbols); - (Symbol::new(Cow::Owned(key)), val) - }) - .collect(); - Value::AttrSet(AttrSet::new(attrs)) - } - _ if val.is_object() => { - if is_thunk(val, scope, symbols.is_thunk) { - return Value::Thunk; - } - - if is_cycle(val, scope, symbols.is_cycle) { - return Value::Repeated; - } - - if let Some(path_val) = extract_path(val, scope, symbols.is_path) { - return Value::Path(path_val); - } - - if let Some(string_val) = extract_string_with_context(val, scope, symbols.has_context) { - return Value::String(string_val); - } - - let val = val.to_object(scope).expect("infallible conversion"); - let keys = val - .get_own_property_names(scope, v8::GetPropertyNamesArgsBuilder::new().build()) - .expect("infallible operation"); - let len = keys.length(); - let attrs = (0..len) - .map(|i| { - let key = keys - .get_index(scope, i) - .expect("infallible index operation"); - let val = val.get(scope, key).expect("infallible operation"); - let key = key.to_rust_string_lossy(scope); - (Symbol::from(key), to_value(val, scope, symbols)) - }) - .collect(); - Value::AttrSet(AttrSet::new(attrs)) - } - _ => unimplemented!("can not convert {} to NixValue", val.type_repr()), - } -} - -fn is_thunk<'a>(val: LocalValue<'a>, scope: &ScopeRef<'a, '_>, symbol: LocalSymbol<'a>) -> bool { - if !val.is_object() { - return false; - } - - let obj = val.to_object(scope).expect("infallible conversion"); - matches!(obj.get(scope, symbol.into()), Some(v) if v.is_true()) -} - -fn is_cycle<'a>(val: LocalValue<'a>, scope: &ScopeRef<'a, '_>, symbol: LocalSymbol<'a>) -> bool { - if !val.is_object() { - return false; - } - - let obj = val.to_object(scope).expect("infallible conversion"); - matches!(obj.get(scope, symbol.into()), Some(v) if v.is_true()) -} - -fn extract_string_with_context<'a>( - val: LocalValue<'a>, - scope: &ScopeRef<'a, '_>, - symbol: LocalSymbol<'a>, -) -> Option { - if !val.is_object() { - return None; - } - - let obj = val.to_object(scope).expect("infallible conversion"); - let has_context = obj.get(scope, symbol.into())?; - - if !has_context.is_true() { - return None; - } - - let value_key = v8::String::new(scope, "value")?; - let value = obj.get(scope, value_key.into())?; - - if value.is_string() { - Some(value.to_rust_string_lossy(scope)) - } else { - None - } -} - -fn extract_path<'a>( - val: LocalValue<'a>, - scope: &ScopeRef<'a, '_>, - symbol: LocalSymbol<'a>, -) -> Option { - if !val.is_object() { - return None; - } - - let obj = val.to_object(scope).expect("infallible conversion"); - let is_path = obj.get(scope, symbol.into())?; - - if !is_path.is_true() { - return None; - } - - let value_key = v8::String::new(scope, "value")?; - let value = obj.get(scope, value_key.into())?; - - if value.is_string() { - Some(value.to_rust_string_lossy(scope)) - } else { - None - } -} - -fn to_primop<'a>( - val: LocalValue<'a>, - scope: &ScopeRef<'a, '_>, - symbol: LocalSymbol<'a>, -) -> Option { - if !val.is_function() { - return None; - } - - let obj = val.to_object(scope).expect("infallible conversion"); - let metadata = obj.get(scope, symbol.into())?.to_object(scope)?; - - let name_key = v8::String::new(scope, "name")?; - let name = metadata - .get(scope, name_key.into())? - .to_rust_string_lossy(scope); - - let applied_key = v8::String::new(scope, "applied")?; - let applied_val = metadata.get(scope, applied_key.into())?; - let applied = applied_val.to_number(scope)?.value(); - - if applied == 0.0 { - Some(Value::PrimOp(name)) - } else { - Some(Value::PrimOpApp(name)) - } -} diff --git a/nix-js/src/runtime/inspector.rs b/nix-js/src/runtime/inspector.rs deleted file mode 100644 index 781278f..0000000 --- a/nix-js/src/runtime/inspector.rs +++ /dev/null @@ -1,493 +0,0 @@ -// Copyright 2018-2025 the Deno authors. MIT license. - -// Alias for the future `!` type. -use core::convert::Infallible as Never; -use std::cell::RefCell; -use std::net::SocketAddr; -use std::pin::pin; -use std::process; -use std::rc::Rc; -use std::task::Poll; -use std::thread; - -use deno_core::InspectorMsg; -use deno_core::InspectorSessionChannels; -use deno_core::InspectorSessionKind; -use deno_core::InspectorSessionProxy; -use deno_core::JsRuntimeInspector; -use deno_core::anyhow::Context; -use deno_core::futures::channel::mpsc; -use deno_core::futures::channel::mpsc::UnboundedReceiver; -use deno_core::futures::channel::mpsc::UnboundedSender; -use deno_core::futures::channel::oneshot; -use deno_core::futures::prelude::*; -use deno_core::futures::stream::StreamExt; -use deno_core::serde_json::Value; -use deno_core::serde_json::json; -use deno_core::unsync::spawn; -use deno_core::url::Url; -use fastwebsockets::Frame; -use fastwebsockets::OpCode; -use fastwebsockets::WebSocket; -use hashbrown::HashMap; -use hyper::body::Bytes; -use hyper_util::rt::TokioIo; -use tokio::net::TcpListener; -use tokio::sync::broadcast; -use uuid::Uuid; - -/// Websocket server that is used to proxy connections from -/// devtools to the inspector. -pub struct InspectorServer { - pub host: SocketAddr, - register_inspector_tx: UnboundedSender, - shutdown_server_tx: Option>, - thread_handle: Option>, -} - -impl InspectorServer { - pub fn new(host: SocketAddr, name: &'static str) -> Result { - let (register_inspector_tx, register_inspector_rx) = mpsc::unbounded::(); - - let (shutdown_server_tx, shutdown_server_rx) = broadcast::channel(1); - - let tcp_listener = std::net::TcpListener::bind(host) - .with_context(|| format!("Failed to bind inspector server socket at {}", host))?; - tcp_listener.set_nonblocking(true)?; - - let thread_handle = thread::spawn(move || { - let rt = tokio::runtime::Builder::new_current_thread() - .enable_all() - .build() - .expect("failed to build tokio runtime"); - let local = tokio::task::LocalSet::new(); - local.block_on( - &rt, - server( - tcp_listener, - register_inspector_rx, - shutdown_server_rx, - name, - ), - ) - }); - - Ok(Self { - host, - register_inspector_tx, - shutdown_server_tx: Some(shutdown_server_tx), - thread_handle: Some(thread_handle), - }) - } - - pub fn register_inspector( - &self, - module_url: String, - inspector: Rc, - wait_for_session: bool, - ) { - let session_sender = inspector.get_session_sender(); - let deregister_rx = inspector.add_deregister_handler(); - - let info = InspectorInfo::new( - self.host, - session_sender, - deregister_rx, - module_url, - wait_for_session, - ); - self.register_inspector_tx - .unbounded_send(info) - .expect("unreachable"); - } -} - -impl Drop for InspectorServer { - fn drop(&mut self) { - if let Some(shutdown_server_tx) = self.shutdown_server_tx.take() { - shutdown_server_tx - .send(()) - .expect("unable to send shutdown signal"); - } - - if let Some(thread_handle) = self.thread_handle.take() { - thread_handle.join().expect("unable to join thread"); - } - } -} - -fn handle_ws_request( - req: http::Request, - inspector_map_rc: Rc>>, -) -> http::Result>>> { - let (parts, body) = req.into_parts(); - let req = http::Request::from_parts(parts, ()); - - let maybe_uuid = req - .uri() - .path() - .strip_prefix("/ws/") - .and_then(|s| Uuid::parse_str(s).ok()); - - let Some(uuid) = maybe_uuid else { - return http::Response::builder() - .status(http::StatusCode::BAD_REQUEST) - .body(Box::new(Bytes::from("Malformed inspector UUID").into())); - }; - - // run in a block to not hold borrow to `inspector_map` for too long - let new_session_tx = { - let inspector_map = inspector_map_rc.borrow(); - let maybe_inspector_info = inspector_map.get(&uuid); - - let Some(info) = maybe_inspector_info else { - return http::Response::builder() - .status(http::StatusCode::NOT_FOUND) - .body(Box::new(Bytes::from("Invalid inspector UUID").into())); - }; - info.new_session_tx.clone() - }; - let (parts, _) = req.into_parts(); - let mut req = http::Request::from_parts(parts, body); - - let Ok((resp, upgrade_fut)) = fastwebsockets::upgrade::upgrade(&mut req) else { - return http::Response::builder() - .status(http::StatusCode::BAD_REQUEST) - .body(Box::new( - Bytes::from("Not a valid Websocket Request").into(), - )); - }; - - // spawn a task that will wait for websocket connection and then pump messages between - // the socket and inspector proxy - spawn(async move { - let websocket = match upgrade_fut.await { - Ok(w) => w, - Err(err) => { - eprintln!( - "Inspector server failed to upgrade to WS connection: {:?}", - err - ); - return; - } - }; - - // The 'outbound' channel carries messages sent to the websocket. - let (outbound_tx, outbound_rx) = mpsc::unbounded(); - // The 'inbound' channel carries messages received from the websocket. - let (inbound_tx, inbound_rx) = mpsc::unbounded(); - - let inspector_session_proxy = InspectorSessionProxy { - channels: InspectorSessionChannels::Regular { - tx: outbound_tx, - rx: inbound_rx, - }, - kind: InspectorSessionKind::NonBlocking { - wait_for_disconnect: true, - }, - }; - - eprintln!("Debugger session started."); - let _ = new_session_tx.unbounded_send(inspector_session_proxy); - pump_websocket_messages(websocket, inbound_tx, outbound_rx).await; - }); - - let (parts, _body) = resp.into_parts(); - let resp = http::Response::from_parts(parts, Box::new(http_body_util::Full::new(Bytes::new()))); - Ok(resp) -} - -fn handle_json_request( - inspector_map: Rc>>, - host: Option, -) -> http::Result>>> { - let data = inspector_map - .borrow() - .values() - .map(move |info| info.get_json_metadata(&host)) - .collect::>(); - let body: http_body_util::Full = - Bytes::from(serde_json::to_string(&data).expect("unreachable")).into(); - http::Response::builder() - .status(http::StatusCode::OK) - .header(http::header::CONTENT_TYPE, "application/json") - .body(Box::new(body)) -} - -fn handle_json_version_request( - version_response: Value, -) -> http::Result>>> { - let body = Box::new(http_body_util::Full::from( - serde_json::to_string(&version_response).expect("unreachable"), - )); - - http::Response::builder() - .status(http::StatusCode::OK) - .header(http::header::CONTENT_TYPE, "application/json") - .body(body) -} - -async fn server( - listener: std::net::TcpListener, - register_inspector_rx: UnboundedReceiver, - shutdown_server_rx: broadcast::Receiver<()>, - name: &str, -) { - let inspector_map_ = Rc::new(RefCell::new(HashMap::::new())); - - let inspector_map = Rc::clone(&inspector_map_); - let register_inspector_handler = - listen_for_new_inspectors(register_inspector_rx, inspector_map.clone()).boxed_local(); - - let inspector_map = Rc::clone(&inspector_map_); - let deregister_inspector_handler = future::poll_fn(|cx| { - inspector_map - .borrow_mut() - .retain(|_, info| info.deregister_rx.poll_unpin(cx) == Poll::Pending); - Poll::::Pending - }) - .boxed_local(); - - let json_version_response = json!({ - "Browser": name, - "Protocol-Version": "1.3", - "V8-Version": deno_core::v8::VERSION_STRING, - }); - - // Create the server manually so it can use the Local Executor - let listener = match TcpListener::from_std(listener) { - Ok(l) => l, - Err(err) => { - eprintln!("Cannot create async listener from std listener: {:?}", err); - return; - } - }; - - let server_handler = async move { - loop { - let mut rx = shutdown_server_rx.resubscribe(); - let mut shutdown_rx = pin!(rx.recv()); - let mut accept = pin!(listener.accept()); - - let stream = tokio::select! { - accept_result = - &mut accept => { - match accept_result { - Ok((s, _)) => s, - Err(err) => { - eprintln!("Failed to accept inspector connection: {:?}", err); - continue; - } - } - }, - - _ = &mut shutdown_rx => { - break; - } - }; - let io = TokioIo::new(stream); - - let inspector_map = Rc::clone(&inspector_map_); - let json_version_response = json_version_response.clone(); - let mut shutdown_server_rx = shutdown_server_rx.resubscribe(); - - let service = - hyper::service::service_fn(move |req: http::Request| { - future::ready({ - // If the host header can make a valid URL, use it - let host = req - .headers() - .get("host") - .and_then(|host| host.to_str().ok()) - .and_then(|host| Url::parse(&format!("http://{host}")).ok()) - .and_then(|url| match (url.host(), url.port()) { - (Some(host), Some(port)) => Some(format!("{host}:{port}")), - (Some(host), None) => Some(format!("{host}")), - _ => None, - }); - match (req.method(), req.uri().path()) { - (&http::Method::GET, path) if path.starts_with("/ws/") => { - handle_ws_request(req, Rc::clone(&inspector_map)) - } - (&http::Method::GET, "/json/version") => { - handle_json_version_request(json_version_response.clone()) - } - (&http::Method::GET, "/json") => { - handle_json_request(Rc::clone(&inspector_map), host) - } - (&http::Method::GET, "/json/list") => { - handle_json_request(Rc::clone(&inspector_map), host) - } - _ => http::Response::builder() - .status(http::StatusCode::NOT_FOUND) - .body(Box::new(http_body_util::Full::new(Bytes::from( - "Not Found", - )))), - } - }) - }); - - deno_core::unsync::spawn(async move { - let server = hyper::server::conn::http1::Builder::new(); - - let mut conn = pin!(server.serve_connection(io, service).with_upgrades()); - let mut shutdown_rx = pin!(shutdown_server_rx.recv()); - - tokio::select! { - result = conn.as_mut() => { - if let Err(err) = result { - eprintln!("Failed to serve connection: {:?}", err); - } - }, - _ = &mut shutdown_rx => { - conn.as_mut().graceful_shutdown(); - let _ = conn.await; - } - } - }); - } - } - .boxed_local(); - - tokio::select! { - _ = register_inspector_handler => {}, - _ = deregister_inspector_handler => unreachable!(), - _ = server_handler => {}, - } -} - -async fn listen_for_new_inspectors( - mut register_inspector_rx: UnboundedReceiver, - inspector_map: Rc>>, -) { - while let Some(info) = register_inspector_rx.next().await { - eprintln!( - "Debugger listening on {}", - info.get_websocket_debugger_url(&info.host.to_string()) - ); - eprintln!("Visit chrome://inspect to connect to the debugger."); - if info.wait_for_session { - eprintln!("nix-js is waiting for debugger to connect."); - } - if inspector_map.borrow_mut().insert(info.uuid, info).is_some() { - panic!("Inspector UUID already in map"); - } - } -} - -/// The pump future takes care of forwarding messages between the websocket -/// and channels. It resolves when either side disconnects, ignoring any -/// errors. -/// -/// The future proxies messages sent and received on a WebSocket -/// to a UnboundedSender/UnboundedReceiver pair. We need these "unbounded" channel ends to sidestep -/// Tokio's task budget, which causes issues when JsRuntimeInspector::poll_sessions() -/// needs to block the thread because JavaScript execution is paused. -/// -/// This works because UnboundedSender/UnboundedReceiver are implemented in the -/// 'futures' crate, therefore they can't participate in Tokio's cooperative -/// task yielding. -async fn pump_websocket_messages( - mut websocket: WebSocket>, - inbound_tx: UnboundedSender, - mut outbound_rx: UnboundedReceiver, -) { - 'pump: loop { - tokio::select! { - Some(msg) = outbound_rx.next() => { - let msg = Frame::text(msg.content.into_bytes().into()); - let _ = websocket.write_frame(msg).await; - } - Ok(msg) = websocket.read_frame() => { - match msg.opcode { - OpCode::Text => { - if let Ok(s) = String::from_utf8(msg.payload.to_vec()) { - let _ = inbound_tx.unbounded_send(s); - } - } - OpCode::Close => { - // Users don't care if there was an error coming from debugger, - // just about the fact that debugger did disconnect. - eprintln!("Debugger session ended"); - break 'pump; - } - _ => { - // Ignore other messages. - } - } - } - else => { - break 'pump; - } - } - } -} - -/// Inspector information that is sent from the isolate thread to the server -/// thread when a new inspector is created. -pub struct InspectorInfo { - pub host: SocketAddr, - pub uuid: Uuid, - pub thread_name: Option, - pub new_session_tx: UnboundedSender, - pub deregister_rx: oneshot::Receiver<()>, - pub url: String, - pub wait_for_session: bool, -} - -impl InspectorInfo { - pub fn new( - host: SocketAddr, - new_session_tx: mpsc::UnboundedSender, - deregister_rx: oneshot::Receiver<()>, - url: String, - wait_for_session: bool, - ) -> Self { - Self { - host, - uuid: Uuid::new_v4(), - thread_name: thread::current().name().map(|n| n.to_owned()), - new_session_tx, - deregister_rx, - url, - wait_for_session, - } - } - - fn get_json_metadata(&self, host: &Option) -> Value { - let host_listen = format!("{}", self.host); - let host = host.as_ref().unwrap_or(&host_listen); - json!({ - "description": "nix-js", - "devtoolsFrontendUrl": self.get_frontend_url(host), - "faviconUrl": "https://deno.land/favicon.ico", - "id": self.uuid.to_string(), - "title": self.get_title(), - "type": "node", - "url": self.url.to_string(), - "webSocketDebuggerUrl": self.get_websocket_debugger_url(host), - }) - } - - pub fn get_websocket_debugger_url(&self, host: &str) -> String { - format!("ws://{}/ws/{}", host, &self.uuid) - } - - fn get_frontend_url(&self, host: &str) -> String { - format!( - "devtools://devtools/bundled/js_app.html?ws={}/ws/{}&experiments=true&v8only=true", - host, &self.uuid - ) - } - - fn get_title(&self) -> String { - format!( - "nix-js{} [pid: {}]", - self.thread_name - .as_ref() - .map(|n| format!(" - {n}")) - .unwrap_or_default(), - process::id(), - ) - } -} diff --git a/nix-js/src/runtime/ops.rs b/nix-js/src/runtime/ops.rs deleted file mode 100644 index 9651251..0000000 --- a/nix-js/src/runtime/ops.rs +++ /dev/null @@ -1,1896 +0,0 @@ -use std::collections::BTreeMap; -use std::convert::Infallible; -use std::path::{Component, Path, PathBuf}; -use std::str::FromStr; - -use deno_core::error::JsError; -use deno_core::{FromV8, OpState, ToV8, v8}; -use hashbrown::{HashMap, HashSet, hash_map::Entry}; -use regex::Regex; -use rust_embed::Embed; - -use super::{NixRuntimeError, OpStateExt, RuntimeContext}; -use crate::bytecode::{Bytecode, Constant}; -use crate::error::Source; -use crate::store::Store as _; - -type Result = std::result::Result; - -#[derive(Debug, Default)] -pub(super) struct RegexCache { - cache: HashMap, -} - -impl RegexCache { - pub(super) fn new() -> Self { - Self { - cache: HashMap::new(), - } - } - - fn get_regex(&mut self, pattern: &str) -> std::result::Result { - Ok(match self.cache.entry(pattern.to_string()) { - Entry::Occupied(occupied) => occupied.get().clone(), - Entry::Vacant(vacant) => { - let re = Regex::new(pattern)?; - vacant.insert(re).clone() - } - }) - } -} - -pub(super) struct Map(HashMap); -impl<'a, K, V> ToV8<'a> for Map -where - K: ToV8<'a>, - K::Error: ToString, - V: ToV8<'a>, - V::Error: ToString, -{ - type Error = NixRuntimeError; - fn to_v8<'i>(self, scope: &mut v8::PinScope<'a, 'i>) -> Result> { - let map = v8::Map::new(scope); - for (k, v) in self.0 { - let k = k.to_v8(scope).map_err(|err| err.to_string())?; - let v = v.to_v8(scope).map_err(|err| err.to_string())?; - map.set(scope, k, v).ok_or("Failed to set V8 Map KV")?; - } - Ok(map.into()) - } -} - -#[derive(Embed)] -#[folder = "src/runtime/corepkgs"] -struct CorePkgs; - -fn new_simple_jserror(msg: String) -> Box { - JsError { - message: Some(msg.clone()), - - name: None, - stack: None, - cause: None, - exception_message: msg, - frames: Vec::new(), - source_line: None, - source_line_frame_index: None, - aggregated: None, - additional_properties: Vec::new(), - } - .into() -} - -struct BytecodeRet { - bytecode: Bytecode, - new_strings: *const [String], - new_constants: *const [Constant], - strings_base: usize, - constants_base: usize, -} - -impl<'a> ToV8<'a> for BytecodeRet { - type Error = Box; - #[allow(clippy::unwrap_used)] - fn to_v8<'i>( - self, - scope: &mut v8::PinScope<'a, 'i>, - ) -> std::result::Result, Self::Error> { - let global = scope.get_current_context().global(scope); - let nix_key = v8::String::new(scope, "Nix") - .ok_or_else(|| new_simple_jserror("failed to create v8 string".into()))?; - let nix_obj = global - .get(scope, nix_key.into()) - .ok_or_else(|| new_simple_jserror("failed to get Nix global".into()))? - .to_object(scope) - .ok_or_else(|| new_simple_jserror("Nix is not an object".into()))?; - - let s_key = v8::String::new(scope, "strings").unwrap(); - let s_array: v8::Local = nix_obj - .get(scope, s_key.into()) - .unwrap() - .try_into() - .unwrap(); - for (i, s) in unsafe { &*self.new_strings }.iter().enumerate() { - let idx = (self.strings_base + i) as u32; - let val = v8::String::new(scope, s).unwrap(); - s_array.set_index(scope, idx, val.into()); - } - - let k_key = v8::String::new(scope, "constants").unwrap(); - let k_array: v8::Local = nix_obj - .get(scope, k_key.into()) - .unwrap() - .try_into() - .unwrap(); - for (i, c) in unsafe { &*self.new_constants }.iter().enumerate() { - let idx = (self.constants_base + i) as u32; - let val: v8::Local = match c { - Constant::Int(n) => v8::BigInt::new_from_i64(scope, *n).into(), - Constant::Float(bits) => v8::Number::new(scope, f64::from_bits(*bits)).into(), - }; - k_array.set_index(scope, idx, val); - } - - let store = v8::ArrayBuffer::new_backing_store_from_boxed_slice(self.bytecode.code); - let ab = v8::ArrayBuffer::with_backing_store(scope, &store.make_shared()); - let u8a = v8::Uint8Array::new(scope, ab, 0, ab.byte_length()) - .ok_or_else(|| new_simple_jserror("failed to create Uint8Array".into()))?; - - let dir = v8::String::new(scope, &self.bytecode.current_dir) - .ok_or_else(|| new_simple_jserror("failed to create dir string".into()))?; - - let arr = v8::Array::new_with_elements(scope, &[u8a.into(), dir.into()]); - Ok(arr.into()) - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_import( - state: &mut OpState, - #[string] path: String, -) -> Result { - let _span = tracing::info_span!("op_import", path = %path).entered(); - let ctx: &mut Ctx = state.get_ctx_mut(); - - // FIXME: special path type - if path.starts_with("") { - let corepkg_name = &path[5..path.len() - 1]; - if let Some(file) = CorePkgs::get(corepkg_name) { - tracing::info!("Importing corepkg: {}", corepkg_name); - let source = Source::new_virtual( - path.into(), - str::from_utf8(&file.data) - .expect("corrupted corepkgs file") - .into(), - ); - ctx.add_source(source.clone()); - let bytecode = ctx - .compile_bytecode(source) - .map_err(|err| err.to_string())?; - let (new_strings, new_constants, strings_base, constants_base) = ctx.get_unsynced(); - return Ok(BytecodeRet { - bytecode, - new_strings, - new_constants, - strings_base, - constants_base, - }); - } else { - return Err(format!("Corepkg not found: {}", corepkg_name).into()); - } - } - - let current_dir = ctx.get_current_dir(); - let mut absolute_path = current_dir.join(&path); - // Do NOT resolve symlinks (eval-okay-symlink-resolution) - // TODO: is this correct? - // .canonicalize() - // .map_err(|e| format!("Failed to resolve path {}: {}", path, e))?; - if absolute_path.is_dir() { - absolute_path.push("default.nix") - } - - tracing::info!("Importing file: {}", absolute_path.display()); - - let source = Source::new_file(absolute_path.clone()) - .map_err(|e| format!("Failed to read {}: {}", absolute_path.display(), e))?; - - tracing::debug!("Compiling file"); - ctx.add_source(source.clone()); - - let bytecode = ctx - .compile_bytecode(source) - .map_err(|err| err.to_string())?; - let (new_strings, new_constants, strings_base, constants_base) = ctx.get_unsynced(); - Ok(BytecodeRet { - bytecode, - new_strings, - new_constants, - strings_base, - constants_base, - }) -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_scoped_import( - state: &mut OpState, - #[string] path: String, - #[serde] scope: Vec, -) -> Result { - let _span = tracing::info_span!("op_scoped_import", path = %path).entered(); - let ctx: &mut Ctx = state.get_ctx_mut(); - - let current_dir = ctx.get_current_dir(); - let mut absolute_path = current_dir.join(&path); - - if absolute_path.is_dir() { - absolute_path.push("default.nix") - } - - tracing::info!("Scoped importing file: {}", absolute_path.display()); - - let source = Source::new_file(absolute_path.clone()) - .map_err(|e| format!("Failed to read {}: {}", absolute_path.display(), e))?; - - tracing::debug!("Compiling file for scoped import"); - ctx.add_source(source.clone()); - - let bytecode = ctx - .compile_bytecode_scoped(source, scope) - .map_err(|err| err.to_string())?; - let (new_strings, new_constants, strings_base, constants_base) = ctx.get_unsynced(); - Ok(BytecodeRet { - bytecode, - new_strings, - new_constants, - strings_base, - constants_base, - }) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_read_file(#[string] path: String) -> Result { - Ok(std::fs::read_to_string(&path).map_err(|e| format!("Failed to read {}: {}", path, e))?) -} - -#[deno_core::op2(fast, reentrant)] -pub(super) fn op_path_exists(#[string] path: String) -> bool { - let must_be_dir = path.ends_with('/') || path.ends_with("/."); - let p = Path::new(&path); - - if must_be_dir { - match std::fs::metadata(p) { - Ok(m) => m.is_dir(), - Err(_) => false, - } - } else { - std::fs::symlink_metadata(p).is_ok() - } -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_read_file_type(#[string] path: String) -> Result { - let path = Path::new(&path); - let metadata = std::fs::symlink_metadata(path) - .map_err(|e| format!("Failed to read file type for {}: {}", path.display(), e))?; - - let file_type = metadata.file_type(); - let type_str = if file_type.is_dir() { - "directory" - } else if file_type.is_symlink() { - "symlink" - } else if file_type.is_file() { - "regular" - } else { - "unknown" - }; - - Ok(type_str.to_string()) -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_read_dir(#[string] path: String) -> Result> { - let path = Path::new(&path); - - if !path.is_dir() { - return Err(format!("{} is not a directory", path.display()).into()); - } - - let entries = std::fs::read_dir(path) - .map_err(|e| format!("Failed to read directory {}: {}", path.display(), e))?; - - let mut result = HashMap::new(); - - for entry in entries { - let entry = entry.map_err(|e| format!("Failed to read directory entry: {}", e))?; - let file_name = entry.file_name().to_string_lossy().to_string(); - - let file_type = entry.file_type().map_err(|e| { - format!( - "Failed to read file type for {}: {}", - entry.path().display(), - e - ) - })?; - - let type_str = if file_type.is_dir() { - "directory" - } else if file_type.is_symlink() { - "symlink" - } else if file_type.is_file() { - "regular" - } else { - "unknown" - }; - - result.insert(file_name, type_str); - } - - Ok(Map(result)) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_resolve_path( - #[string] current_dir: String, - #[string] path: String, -) -> Result { - let _span = tracing::debug_span!("op_resolve_path").entered(); - tracing::debug!(current_dir, path); - - // If already absolute, return as-is - if path.starts_with('/') { - return Ok(path); - } - // Resolve relative path against current file directory (or CWD) - let current_dir = if !path.starts_with("~/") { - let mut dir = PathBuf::from(current_dir); - dir.push(path); - dir - } else { - let mut dir = std::env::home_dir().ok_or("home dir not defined")?; - dir.push(&path[2..]); - dir - }; - let mut normalized = PathBuf::new(); - for component in current_dir.components() { - match component { - Component::Prefix(p) => normalized.push(p.as_os_str()), - Component::RootDir => normalized.push("/"), - Component::CurDir => {} - Component::ParentDir => { - normalized.pop(); - } - Component::Normal(c) => normalized.push(c), - } - } - tracing::debug!(normalized = normalized.display().to_string()); - Ok(normalized.to_string_lossy().to_string()) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_make_placeholder(#[string] output: String) -> String { - use sha2::{Digest, Sha256}; - let input = format!("nix-output:{}", output); - let mut hasher = Sha256::new(); - hasher.update(input.as_bytes()); - let hash: [u8; 32] = hasher.finalize().into(); - let encoded = nix_compat::nixbase32::encode(&hash); - format!("/{}", encoded) -} - -enum StringOrU32 { - String(String), - U32(u32), -} -impl<'a> ToV8<'a> for StringOrU32 { - type Error = Infallible; - fn to_v8<'i>( - self, - scope: &mut v8::PinScope<'a, 'i>, - ) -> std::result::Result, Self::Error> { - match self { - Self::String(x) => x.to_v8(scope), - Self::U32(x) => x.to_v8(scope), - } - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_decode_span( - state: &mut OpState, - #[smi] span_id: u32, -) -> Map<&'static str, StringOrU32> { - let ctx: &Ctx = state.get_ctx(); - let (source_id, range) = ctx.get_span(span_id as usize); - let source = ctx.get_source(source_id); - let start = u32::from(range.start()); - - let (line, column) = byte_offset_to_line_col(&source.src, start as usize); - - Map(HashMap::from([ - ("file", StringOrU32::String(source.get_name())), - ("line", StringOrU32::U32(line)), - ("column", StringOrU32::U32(column)), - ])) -} - -fn byte_offset_to_line_col(content: &str, offset: usize) -> (u32, u32) { - let mut line = 1u32; - let mut col = 1u32; - - for (idx, ch) in content.char_indices() { - if idx >= offset { - break; - } - if ch == '\n' { - line += 1; - col = 1; - } else { - col += 1; - } - } - - (line, col) -} - -mod private { - use deno_core::ToV8; - - #[derive(ToV8)] - pub(super) struct ParsedHash { - pub(super) hex: String, - pub(super) algo: String, - } -} -use private::*; - -#[deno_core::op2(reentrant)] -pub(super) fn op_parse_hash( - #[string] hash_str: String, - #[string] algo: Option, -) -> Result { - use nix_compat::nixhash::{HashAlgo, NixHash}; - - let hash_algo = algo - .as_deref() - .and_then(|algo| HashAlgo::from_str(algo).ok()); - - let hash = NixHash::from_str(&hash_str, hash_algo).map_err(|e| { - NixRuntimeError::from(format!( - "invalid hash '{}'{}: {}", - hash_str, - algo.map_or("".to_string(), |algo| format!(" for algorithm '{algo}'")), - e - )) - })?; - - Ok(ParsedHash { - hex: hex::encode(hash.digest_as_bytes()), - algo: hash.algo().to_string(), - }) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_add_path( - state: &mut OpState, - #[string] path: String, - #[string] name: Option, - recursive: bool, - #[string] sha256: Option, -) -> Result { - use std::fs; - use std::path::Path; - - use nix_compat::nixhash::{HashAlgo, NixHash}; - use sha2::{Digest, Sha256}; - - let path_obj = Path::new(&path); - - if !path_obj.exists() { - return Err(NixRuntimeError::from(format!( - "path '{}' does not exist", - path - ))); - } - - let computed_name = name.unwrap_or_else(|| { - path_obj - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or("source") - .to_string() - }); - - let computed_hash = if recursive { - crate::nar::compute_nar_hash(path_obj) - .map_err(|e| NixRuntimeError::from(format!("failed to compute NAR hash: {}", e)))? - } else { - if !path_obj.is_file() { - return Err(NixRuntimeError::from( - "when 'recursive' is false, path must be a regular file", - )); - } - let contents = fs::read(path_obj) - .map_err(|e| NixRuntimeError::from(format!("failed to read '{}': {}", path, e)))?; - - let mut hasher = Sha256::new(); - hasher.update(&contents); - hasher.finalize().into() - }; - - if let Some(ref expected_hash) = sha256 { - let expected_hex = NixHash::from_str(expected_hash, Some(HashAlgo::Sha256)) - .map_err(|err| err.to_string())?; - if computed_hash != expected_hex.digest_as_bytes() { - return Err(NixRuntimeError::from(format!( - "hash mismatch for path '{}': expected {}, got {}", - path, - hex::encode(expected_hex.digest_as_bytes()), - hex::encode(computed_hash) - ))); - } - } - - let ctx: &Ctx = state.get_ctx(); - let store = ctx.get_store(); - - let store_path = if recursive { - store - .add_to_store_from_path(&computed_name, path_obj, vec![]) - .map_err(|e| NixRuntimeError::from(format!("failed to add path to store: {}", e)))? - } else { - let contents = fs::read(path_obj) - .map_err(|e| NixRuntimeError::from(format!("failed to read '{}': {}", path, e)))?; - store - .add_to_store(&computed_name, &contents, false, vec![]) - .map_err(|e| NixRuntimeError::from(format!("failed to add to store: {}", e)))? - }; - - Ok(store_path) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_store_path( - state: &mut OpState, - #[string] path: String, -) -> Result { - use crate::store::validate_store_path; - - let ctx: &Ctx = state.get_ctx(); - let store = ctx.get_store(); - let store_dir = store.get_store_dir(); - - validate_store_path(store_dir, &path).map_err(|e| NixRuntimeError::from(e.to_string()))?; - - store - .ensure_path(&path) - .map_err(|e| NixRuntimeError::from(e.to_string()))?; - - Ok(path) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_to_file( - state: &mut OpState, - #[string] name: String, - #[string] contents: String, - #[scoped] references: Vec, -) -> Result { - let ctx: &Ctx = state.get_ctx(); - let store = ctx.get_store(); - let store_path = store - .add_text_to_store(&name, &contents, references) - .map_err(|e| NixRuntimeError::from(format!("builtins.toFile failed: {}", e)))?; - - Ok(store_path) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_copy_path_to_store( - state: &mut OpState, - #[string] path: String, -) -> Result { - use std::path::Path; - - let path_obj = Path::new(&path); - - if !path_obj.exists() { - return Err(NixRuntimeError::from(format!( - "path '{}' does not exist", - path - ))); - } - - let name = path_obj - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or("source") - .to_string(); - - let ctx: &Ctx = state.get_ctx(); - let store = ctx.get_store(); - let store_path = store - .add_to_store_from_path(&name, path_obj, vec![]) - .map_err(|e| NixRuntimeError::from(format!("failed to copy path to store: {}", e)))?; - - Ok(store_path) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_get_env(#[string] key: String) -> Result { - match std::env::var(key) { - Ok(val) => Ok(val), - Err(std::env::VarError::NotPresent) => Ok("".into()), - Err(err) => Err(format!("Failed to read env var: {err}").into()), - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_walk_dir(#[string] path: String) -> Result> { - fn walk_recursive( - base: &Path, - current: &Path, - results: &mut Vec<(String, String)>, - ) -> Result<()> { - let entries = std::fs::read_dir(current) - .map_err(|e| NixRuntimeError::from(format!("failed to read directory: {}", e)))?; - - for entry in entries { - let entry = - entry.map_err(|e| NixRuntimeError::from(format!("failed to read entry: {}", e)))?; - let path = entry.path(); - let rel_path = path - .strip_prefix(base) - .map_err(|e| NixRuntimeError::from(format!("failed to get relative path: {}", e)))? - .to_string_lossy() - .to_string(); - - let file_type = entry - .file_type() - .map_err(|e| NixRuntimeError::from(format!("failed to get file type: {}", e)))?; - - let type_str = if file_type.is_dir() { - "directory" - } else if file_type.is_symlink() { - "symlink" - } else { - "regular" - }; - - results.push((rel_path.clone(), type_str.to_string())); - - if file_type.is_dir() { - walk_recursive(base, &path, results)?; - } - } - Ok(()) - } - - let path = Path::new(&path); - if !path.is_dir() { - return Err(NixRuntimeError::from(format!( - "{} is not a directory", - path.display() - ))); - } - - let mut results = Vec::new(); - walk_recursive(path, path, &mut results)?; - Ok(results) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_add_filtered_path( - state: &mut OpState, - #[string] src_path: String, - #[string] name: Option, - recursive: bool, - #[string] sha256: Option, - #[scoped] include_paths: Vec, -) -> Result { - use std::fs; - - use nix_compat::nixhash::{HashAlgo, NixHash}; - use sha2::{Digest, Sha256}; - - let src = Path::new(&src_path); - if !src.exists() { - return Err(NixRuntimeError::from(format!( - "path '{}' does not exist", - src_path - ))); - } - - let computed_name = name.unwrap_or_else(|| { - src.file_name() - .and_then(|n| n.to_str()) - .unwrap_or("source") - .to_string() - }); - - let temp_dir = tempfile::tempdir() - .map_err(|e| NixRuntimeError::from(format!("failed to create temp dir: {}", e)))?; - let dest = temp_dir.path().join(&computed_name); - - fs::create_dir_all(&dest) - .map_err(|e| NixRuntimeError::from(format!("failed to create dest dir: {}", e)))?; - - for rel_path in &include_paths { - let src_file = src.join(rel_path); - let dest_file = dest.join(rel_path); - - if let Some(parent) = dest_file.parent() { - fs::create_dir_all(parent) - .map_err(|e| NixRuntimeError::from(format!("failed to create dir: {}", e)))?; - } - - let metadata = fs::symlink_metadata(&src_file) - .map_err(|e| NixRuntimeError::from(format!("failed to read metadata: {}", e)))?; - - if metadata.is_symlink() { - let target = fs::read_link(&src_file) - .map_err(|e| NixRuntimeError::from(format!("failed to read symlink: {}", e)))?; - #[cfg(unix)] - std::os::unix::fs::symlink(&target, &dest_file) - .map_err(|e| NixRuntimeError::from(format!("failed to create symlink: {}", e)))?; - #[cfg(not(unix))] - return Err(NixRuntimeError::from( - "symlinks not supported on this platform", - )); - } else if metadata.is_dir() { - fs::create_dir_all(&dest_file) - .map_err(|e| NixRuntimeError::from(format!("failed to create dir: {}", e)))?; - } else { - fs::copy(&src_file, &dest_file) - .map_err(|e| NixRuntimeError::from(format!("failed to copy file: {}", e)))?; - } - } - - let computed_hash = if recursive { - crate::nar::compute_nar_hash(&dest) - .map_err(|e| NixRuntimeError::from(format!("failed to compute NAR hash: {}", e)))? - } else { - if !dest.is_file() { - return Err(NixRuntimeError::from( - "when 'recursive' is false, path must be a regular file", - )); - } - let contents = fs::read(&dest) - .map_err(|e| NixRuntimeError::from(format!("failed to read file: {}", e)))?; - let mut hasher = Sha256::new(); - hasher.update(&contents); - hasher.finalize().into() - }; - - if let Some(ref expected_hash) = sha256 { - let expected_hex = NixHash::from_str(expected_hash, Some(HashAlgo::Sha256)) - .map_err(|err| err.to_string())?; - if computed_hash != expected_hex.digest_as_bytes() { - return Err(NixRuntimeError::from(format!( - "hash mismatch for path '{}': expected {}, got {}", - src_path, - hex::encode(expected_hex.digest_as_bytes()), - hex::encode(computed_hash) - ))); - } - } - - let ctx: &Ctx = state.get_ctx(); - let store = ctx.get_store(); - - let store_path = store - .add_to_store_from_path(&computed_name, &dest, vec![]) - .map_err(|e| NixRuntimeError::from(format!("failed to add path to store: {}", e)))?; - - Ok(store_path) -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_match( - state: &mut OpState, - #[string] regex: String, - #[string] text: String, -) -> Result>>> { - let cache = state.borrow_mut::(); - let re = cache - .get_regex(&format!("^{}$", regex)) - .map_err(|_| NixRuntimeError::from(format!("invalid regular expression '{}'", regex)))?; - - match re.captures(&text) { - Some(caps) => { - let groups: Vec> = caps - .iter() - .skip(1) - .map(|grp| grp.map(|g| g.as_str().to_string())) - .collect(); - Ok(Some(groups)) - } - None => Ok(None), - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_split( - state: &mut OpState, - #[string] regex: String, - #[string] text: String, -) -> Result> { - let cache = state.borrow_mut::(); - let re = cache - .get_regex(®ex) - .map_err(|_| NixRuntimeError::from(format!("invalid regular expression '{}'", regex)))?; - - let mut capture_locations = re.capture_locations(); - let num_captures = capture_locations.len(); - let mut ret: Vec = Vec::new(); - let mut pos = 0; - - while let Some(thematch) = re.captures_read_at(&mut capture_locations, &text, pos) { - ret.push(SplitResult::Text(text[pos..thematch.start()].to_string())); - - let captures: Vec> = (1..num_captures) - .map(|i| capture_locations.get(i)) - .map(|o| o.map(|(start, end)| text[start..end].to_string())) - .collect(); - ret.push(SplitResult::Captures(captures)); - - if pos == text.len() { - break; - } - pos = thematch.end(); - } - - ret.push(SplitResult::Text(text[pos..].to_string())); - - Ok(ret) -} - -pub(super) enum SplitResult { - Text(String), - Captures(Vec>), -} - -impl<'a> ToV8<'a> for SplitResult { - type Error = Infallible; - fn to_v8<'i>( - self, - scope: &mut v8::PinScope<'a, 'i>, - ) -> std::result::Result, Self::Error> { - Ok(match self { - Self::Text(text) => { - let Ok(value) = text.to_v8(scope); - value - } - Self::Captures(captures) => { - let Ok(value) = captures.to_v8(scope); - value - } - }) - } -} - -pub(super) enum NixJsonValue { - Null, - Bool(bool), - Int(i64), - Float(f64), - Str(String), - Arr(Vec), - Obj(Vec<(String, NixJsonValue)>), -} - -impl<'a> deno_core::convert::ToV8<'a> for NixJsonValue { - type Error = NixRuntimeError; - - fn to_v8<'i>( - self, - scope: &mut v8::PinScope<'a, 'i>, - ) -> std::result::Result, Self::Error> { - Ok(match self { - Self::Null => v8::null(scope).into(), - Self::Bool(b) => v8::Boolean::new(scope, b).into(), - Self::Int(i) => v8::BigInt::new_from_i64(scope, i).into(), - Self::Float(f) => v8::Number::new(scope, f).into(), - Self::Str(s) => v8::String::new(scope, &s) - .map(|s| s.into()) - .ok_or("failed to create v8 string")?, - Self::Arr(arr) => { - let elements = arr - .into_iter() - .map(|v| v.to_v8(scope)) - .collect::, _>>()?; - v8::Array::new_with_elements(scope, &elements).into() - } - Self::Obj(entries) => { - let map = v8::Map::new(scope); - for (k, v) in entries { - let key: v8::Local = v8::String::new(scope, &k) - .ok_or("failed to create v8 string")? - .into(); - let val = v.to_v8(scope)?; - map.set(scope, key, val); - } - map.into() - } - }) - } -} - -fn json_to_nix(value: serde_json::Value) -> NixJsonValue { - match value { - serde_json::Value::Null => NixJsonValue::Null, - serde_json::Value::Bool(b) => NixJsonValue::Bool(b), - serde_json::Value::Number(n) => { - if let Some(i) = n.as_i64() { - NixJsonValue::Int(i) - } else if let Some(f) = n.as_f64() { - NixJsonValue::Float(f) - } else { - NixJsonValue::Float(n.as_u64().unwrap_or(0) as f64) - } - } - serde_json::Value::String(s) => NixJsonValue::Str(s), - serde_json::Value::Array(arr) => { - NixJsonValue::Arr(arr.into_iter().map(json_to_nix).collect()) - } - serde_json::Value::Object(map) => { - NixJsonValue::Obj(map.into_iter().map(|(k, v)| (k, json_to_nix(v))).collect()) - } - } -} - -#[derive(Debug, Default)] -pub(super) struct DrvHashCache { - cache: HashMap, -} - -impl DrvHashCache { - pub(super) fn new() -> Self { - Self { - cache: HashMap::new(), - } - } -} - -fn toml_to_nix(value: toml::Value) -> Result { - match value { - toml::Value::String(s) => Ok(NixJsonValue::Str(s)), - toml::Value::Integer(i) => Ok(NixJsonValue::Int(i)), - toml::Value::Float(f) => Ok(NixJsonValue::Float(f)), - toml::Value::Boolean(b) => Ok(NixJsonValue::Bool(b)), - toml::Value::Datetime(_) => Err(NixRuntimeError::from( - "while parsing TOML: Dates and times are not supported", - )), - toml::Value::Array(arr) => { - let items: std::result::Result, _> = arr.into_iter().map(toml_to_nix).collect(); - Ok(NixJsonValue::Arr(items?)) - } - toml::Value::Table(table) => { - let entries: std::result::Result, _> = table - .into_iter() - .map(|(k, v)| toml_to_nix(v).map(|v| (k, v))) - .collect(); - Ok(NixJsonValue::Obj(entries?)) - } - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_from_json(#[string] json_str: String) -> Result { - let parsed: serde_json::Value = serde_json::from_str(&json_str) - .map_err(|e| NixRuntimeError::from(format!("builtins.fromJSON: {e}")))?; - Ok(json_to_nix(parsed)) -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_from_toml(#[string] toml_str: String) -> Result { - let parsed: toml::Value = toml::from_str(&toml_str) - .map_err(|e| NixRuntimeError::from(format!("while parsing TOML: {e}")))?; - toml_to_nix(parsed) -} - -mod scope { - use deno_core::{FromV8, ToV8}; - - #[derive(FromV8)] - pub(super) struct FixedOutputInput { - pub(super) hash_algo: String, - pub(super) hash: String, - pub(super) hash_mode: String, - } - - #[derive(ToV8)] - pub(super) struct FinalizeDerivationOutput { - // renamed to `drvPath` automatically - pub(super) drv_path: String, - pub(super) outputs: Vec<(String, String)>, - } -} -use scope::*; - -fn output_path_name(drv_name: &str, output: &str) -> String { - if output == "out" { - drv_name.to_string() - } else { - format!("{}-{}", drv_name, output) - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_finalize_derivation( - state: &mut OpState, - #[string] name: String, - #[string] builder: String, - #[string] platform: String, - #[scoped] outputs: Vec, - #[scoped] args: Vec, - #[scoped] env: Vec<(String, String)>, - #[scoped] context: Vec, - #[scoped] fixed_output: Option, -) -> Result { - use crate::derivation::{DerivationData, OutputInfo}; - use crate::string_context::extract_input_drvs_and_srcs; - - let ctx: &Ctx = state.get_ctx(); - let store = ctx.get_store(); - let store_dir = store.get_store_dir().to_string(); - - let (input_drvs, input_srcs) = - extract_input_drvs_and_srcs(&context).map_err(NixRuntimeError::from)?; - - let env: BTreeMap = env.into_iter().collect(); - - let drv_path; - let output_paths: Vec<(String, String)>; - - if let Some(fixed) = &fixed_output { - let path_name = output_path_name(&name, "out"); - let out_path = crate::runtime::ops::op_make_fixed_output_path_impl( - &store_dir, - &fixed.hash_algo, - &fixed.hash, - &fixed.hash_mode, - &path_name, - ); - - let hash_algo_prefix = if fixed.hash_mode == "recursive" { - "r:" - } else { - "" - }; - - let mut final_outputs = BTreeMap::new(); - final_outputs.insert( - "out".to_string(), - OutputInfo { - path: out_path.clone(), - hash_algo: format!("{}{}", hash_algo_prefix, fixed.hash_algo), - hash: fixed.hash.clone(), - }, - ); - - let mut final_env = env; - final_env.insert("out".to_string(), out_path.clone()); - - let drv = DerivationData { - name: name.clone(), - outputs: final_outputs, - input_drvs: input_drvs.clone(), - input_srcs: input_srcs.clone(), - platform, - builder, - args, - env: final_env, - }; - - let final_aterm = drv.generate_aterm(); - let references = drv.collect_references(); - - drv_path = store - .add_text_to_store(&format!("{}.drv", name), &final_aterm, references) - .map_err(|e| NixRuntimeError::from(format!("failed to write derivation: {}", e)))?; - - let fixed_hash_fingerprint = format!( - "fixed:out:{}{}:{}:{}", - hash_algo_prefix, fixed.hash_algo, fixed.hash, out_path, - ); - let fixed_modulo_hash = crate::nix_utils::sha256_hex(fixed_hash_fingerprint.as_bytes()); - - let cache = state.borrow_mut::(); - cache.cache.insert(drv_path.clone(), fixed_modulo_hash); - - output_paths = vec![("out".to_string(), out_path)]; - } else { - let masked_outputs: std::collections::BTreeMap = outputs - .iter() - .map(|o| { - ( - o.clone(), - OutputInfo { - path: String::new(), - hash_algo: String::new(), - hash: String::new(), - }, - ) - }) - .collect(); - - let mut masked_env = env.clone(); - for output in &outputs { - masked_env.insert(output.clone(), String::new()); - } - - let masked_drv = DerivationData { - name: name.clone(), - outputs: masked_outputs, - input_drvs: input_drvs.clone(), - input_srcs: input_srcs.clone(), - platform: platform.clone(), - builder: builder.clone(), - args: args.clone(), - env: masked_env, - }; - - let mut input_drv_hashes = std::collections::BTreeMap::new(); - { - let cache = state.borrow::(); - for (dep_drv_path, output_names) in &input_drvs { - let cached_hash = cache.cache.get(dep_drv_path).ok_or_else(|| { - NixRuntimeError::from(format!( - "Missing modulo hash for input derivation: {}", - dep_drv_path - )) - })?; - let mut sorted_outs: Vec<&String> = output_names.iter().collect(); - sorted_outs.sort(); - let outputs_csv: Vec<&str> = sorted_outs.iter().map(|s| s.as_str()).collect(); - input_drv_hashes.insert(cached_hash.clone(), outputs_csv.join(",")); - } - } - - let masked_aterm = masked_drv.generate_aterm_modulo(&input_drv_hashes); - let drv_modulo_hash = crate::nix_utils::sha256_hex(masked_aterm.as_bytes()); - - let mut final_outputs = std::collections::BTreeMap::new(); - let mut final_env = env; - let mut result_output_paths = Vec::new(); - - for output_name in &outputs { - let path_name = output_path_name(&name, output_name); - let out_path = crate::nix_utils::make_store_path( - &store_dir, - &format!("output:{}", output_name), - &drv_modulo_hash, - &path_name, - ); - final_outputs.insert( - output_name.clone(), - OutputInfo { - path: out_path.clone(), - hash_algo: String::new(), - hash: String::new(), - }, - ); - final_env.insert(output_name.clone(), out_path.clone()); - result_output_paths.push((output_name.clone(), out_path)); - } - - let final_drv = DerivationData { - name, - outputs: final_outputs, - input_drvs, - input_srcs, - platform, - builder, - args, - env: final_env, - }; - - let final_aterm = final_drv.generate_aterm(); - let references = final_drv.collect_references(); - - drv_path = store - .add_text_to_store(&format!("{}.drv", final_drv.name), &final_aterm, references) - .map_err(|e| NixRuntimeError::from(format!("failed to write derivation: {}", e)))?; - - let final_aterm_modulo = final_drv.generate_aterm_modulo(&input_drv_hashes); - let cached_modulo_hash = crate::nix_utils::sha256_hex(final_aterm_modulo.as_bytes()); - - let cache = state.borrow_mut::(); - cache.cache.insert(drv_path.clone(), cached_modulo_hash); - - output_paths = result_output_paths; - } - - Ok(FinalizeDerivationOutput { - drv_path, - outputs: output_paths, - }) -} - -fn op_make_fixed_output_path_impl( - store_dir: &str, - hash_algo: &str, - hash: &str, - hash_mode: &str, - name: &str, -) -> String { - use sha2::{Digest, Sha256}; - - if hash_algo == "sha256" && hash_mode == "recursive" { - crate::nix_utils::make_store_path(store_dir, "source", hash, name) - } else { - let prefix = if hash_mode == "recursive" { "r:" } else { "" }; - let inner_input = format!("fixed:out:{}{}:{}:", prefix, hash_algo, hash); - let mut hasher = Sha256::new(); - hasher.update(inner_input.as_bytes()); - let inner_hash = hex::encode(hasher.finalize()); - - crate::nix_utils::make_store_path(store_dir, "output:out", &inner_hash, name) - } -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_hash_string(#[string] algo: String, #[string] data: String) -> Result { - use sha2::{Digest, Sha256, Sha512}; - - let hash_bytes: Vec = match algo.as_str() { - "sha256" => { - let mut hasher = Sha256::new(); - hasher.update(data.as_bytes()); - hasher.finalize().to_vec() - } - "sha512" => { - let mut hasher = Sha512::new(); - hasher.update(data.as_bytes()); - hasher.finalize().to_vec() - } - "sha1" => { - use sha1::Digest as _; - let mut hasher = sha1::Sha1::new(); - hasher.update(data.as_bytes()); - hasher.finalize().to_vec() - } - "md5" => { - let digest = md5::compute(data.as_bytes()); - digest.to_vec() - } - _ => { - return Err(NixRuntimeError::from(format!( - "unknown hash algorithm '{}'", - algo - ))); - } - }; - - Ok(hex::encode(hash_bytes)) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_hash_file(#[string] algo: String, #[string] path: String) -> Result { - let data = std::fs::read(&path) - .map_err(|e| NixRuntimeError::from(format!("cannot read '{}': {}", path, e)))?; - - use sha2::{Digest, Sha256, Sha512}; - - let hash_bytes: Vec = match algo.as_str() { - "sha256" => { - let mut hasher = Sha256::new(); - hasher.update(&data); - hasher.finalize().to_vec() - } - "sha512" => { - let mut hasher = Sha512::new(); - hasher.update(&data); - hasher.finalize().to_vec() - } - "sha1" => { - use sha1::Digest as _; - let mut hasher = sha1::Sha1::new(); - hasher.update(&data); - hasher.finalize().to_vec() - } - "md5" => { - let digest = md5::compute(&data); - digest.to_vec() - } - _ => { - return Err(NixRuntimeError::from(format!( - "unknown hash algorithm '{}'", - algo - ))); - } - }; - - Ok(hex::encode(hash_bytes)) -} - -#[deno_core::op2(reentrant)] -#[string] -pub(super) fn op_convert_hash( - #[string] hash: &str, - #[string] algo: Option, - #[string] format: &str, -) -> Result { - use nix_compat::nixhash::{HashAlgo, NixHash}; - - let hash_algo = algo.as_deref().and_then(|a| HashAlgo::from_str(a).ok()); - - let hash = NixHash::from_str(hash, hash_algo) - .map_err(|e| NixRuntimeError::from(format!("cannot convert hash '{}': {}", hash, e)))?; - - let bytes = hash.digest_as_bytes(); - - match format { - "base16" => Ok(hex::encode(bytes)), - "nix32" | "base32" => Ok(nix_compat::nixbase32::encode(bytes)), - "base64" => { - use base64::Engine as _; - Ok(base64::engine::general_purpose::STANDARD.encode(bytes)) - } - "sri" => Ok(format!("{}-{}", hash.algo(), { - use base64::Engine as _; - base64::engine::general_purpose::STANDARD.encode(bytes) - })), - _ => Err(NixRuntimeError::from(format!( - "unknown hash format '{}'", - format - ))), - } -} - -struct XmlCtx<'s> { - force_fn: v8::Local<'s, v8::Function>, - is_thunk: v8::Local<'s, v8::Symbol>, - has_context: v8::Local<'s, v8::Symbol>, - is_path: v8::Local<'s, v8::Symbol>, - primop_meta: v8::Local<'s, v8::Symbol>, -} - -impl<'s> XmlCtx<'s> { - fn new<'i>( - scope: &mut v8::PinScope<'s, 'i>, - nix_obj: v8::Local<'s, v8::Object>, - ) -> Result { - let get_fn = |scope: &v8::PinScope<'s, 'i>, name: &str| { - let key = v8::String::new(scope, name).ok_or("v8 string")?; - let val = nix_obj - .get(scope, key.into()) - .ok_or_else(|| format!("no {name}"))?; - v8::Local::::try_from(val) - .map_err(|e| format!("{name} not function: {e}")) - }; - let get_sym = |scope: &v8::PinScope<'s, 'i>, name: &str| { - let key = v8::String::new(scope, name).ok_or("v8 string")?; - let val = nix_obj - .get(scope, key.into()) - .ok_or_else(|| format!("no {name}"))?; - v8::Local::::try_from(val).map_err(|e| format!("{name} not symbol: {e}")) - }; - Ok(Self { - force_fn: get_fn(scope, "force")?, - is_thunk: get_sym(scope, "IS_THUNK")?, - has_context: get_sym(scope, "HAS_CONTEXT")?, - is_path: get_sym(scope, "IS_PATH")?, - primop_meta: get_sym(scope, "PRIMOP_METADATA")?, - }) - } -} - -struct XmlWriter { - buf: String, - context: Vec, - drvs_seen: HashSet, -} - -impl XmlWriter { - fn new() -> Self { - Self { - buf: String::with_capacity(4096), - context: Vec::new(), - drvs_seen: HashSet::new(), - } - } - - fn indent(&mut self, depth: usize) { - for _ in 0..depth { - self.buf.push_str(" "); - } - } - - fn escape_attr(&mut self, s: &str) { - for ch in s.chars() { - match ch { - '"' => self.buf.push_str("""), - '<' => self.buf.push_str("<"), - '>' => self.buf.push_str(">"), - '&' => self.buf.push_str("&"), - '\n' => self.buf.push_str(" "), - '\r' => self.buf.push_str(" "), - '\t' => self.buf.push_str(" "), - c => self.buf.push(c), - } - } - } - - fn force<'s>( - &self, - val: v8::Local<'s, v8::Value>, - scope: &mut v8::PinScope<'s, '_>, - ctx: &XmlCtx<'s>, - ) -> Result> { - let undef = v8::undefined(scope); - ctx.force_fn - .call(scope, undef.into(), &[val]) - .ok_or_else(|| ("force() threw an exception").into()) - } - - fn has_sym<'s>( - obj: v8::Local<'s, v8::Object>, - scope: &mut v8::PinScope<'s, '_>, - sym: v8::Local<'s, v8::Symbol>, - ) -> bool { - matches!(obj.get(scope, sym.into()), Some(v) if v.is_true()) - } - - fn extract_str<'s>( - &self, - val: v8::Local<'s, v8::Value>, - scope: &mut v8::PinScope<'s, '_>, - ctx: &XmlCtx<'s>, - ) -> Option { - if val.is_string() { - return Some(val.to_rust_string_lossy(scope)); - } - if val.is_object() { - let obj = val.to_object(scope)?; - if Self::has_sym(obj, scope, ctx.has_context) { - let key = v8::String::new(scope, "value")?; - let s = obj.get(scope, key.into())?; - return Some(s.to_rust_string_lossy(scope)); - } - } - None - } - - fn collect_context<'s>( - &mut self, - obj: v8::Local<'s, v8::Object>, - scope: &mut v8::PinScope<'s, '_>, - ) { - let context_key = match v8::String::new(scope, "context") { - Some(k) => k, - None => return, - }; - let ctx_val = match obj.get(scope, context_key.into()) { - Some(v) => v, - None => return, - }; - let global = scope.get_current_context().global(scope); - let array_key = match v8::String::new(scope, "Array") { - Some(k) => k, - None => return, - }; - let array_obj = match global - .get(scope, array_key.into()) - .and_then(|v| v.to_object(scope)) - { - Some(o) => o, - None => return, - }; - let from_key = match v8::String::new(scope, "from") { - Some(k) => k, - None => return, - }; - let from_fn = match array_obj - .get(scope, from_key.into()) - .and_then(|v| v8::Local::::try_from(v).ok()) - { - Some(f) => f, - None => return, - }; - let arr_val = match from_fn.call(scope, array_obj.into(), &[ctx_val]) { - Some(v) => v, - None => return, - }; - let arr = match v8::Local::::try_from(arr_val) { - Ok(a) => a, - Err(_) => return, - }; - for i in 0..arr.length() { - if let Some(elem) = arr.get_index(scope, i) { - self.context.push(elem.to_rust_string_lossy(scope)); - } - } - } - - fn is_derivation<'s>(map: v8::Local<'s, v8::Map>, scope: &mut v8::PinScope<'s, '_>) -> bool { - let key = match v8::String::new(scope, "type") { - Some(k) => k, - None => return false, - }; - match map.get(scope, key.into()) { - Some(v) if v.is_string() => v.to_rust_string_lossy(scope) == "derivation", - _ => false, - } - } - - fn write_value<'s>( - &mut self, - val: v8::Local<'s, v8::Value>, - scope: &mut v8::PinScope<'s, '_>, - ctx: &XmlCtx<'s>, - depth: usize, - ) -> Result<()> { - let val = self.force(val, scope, ctx)?; - - if val.is_null() { - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_true() { - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_false() { - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_big_int() { - let bi = val.to_big_int(scope).ok_or("bigint")?; - let (i, _) = bi.i64_value(); - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_number() { - let n = val.number_value(scope).ok_or("number")?; - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_string() { - let s = val.to_rust_string_lossy(scope); - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_array() { - let arr = v8::Local::::try_from(val).map_err(|e| e.to_string())?; - self.indent(depth); - self.buf.push_str("\n"); - for i in 0..arr.length() { - let elem = arr.get_index(scope, i).ok_or("array elem")?; - self.write_value(elem, scope, ctx, depth + 1)?; - } - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if val.is_function() { - return self.write_function(val, scope, ctx, depth); - } - if val.is_map() { - let map = v8::Local::::try_from(val).map_err(|e| e.to_string())?; - return self.write_attrs(map, scope, ctx, depth); - } - if val.is_object() { - let obj = val.to_object(scope).ok_or("to_object")?; - - if Self::has_sym(obj, scope, ctx.has_context) { - let key = v8::String::new(scope, "value").ok_or("v8 str")?; - let s = obj - .get(scope, key.into()) - .ok_or("value")? - .to_rust_string_lossy(scope); - self.collect_context(obj, scope); - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if Self::has_sym(obj, scope, ctx.is_path) { - let key = v8::String::new(scope, "value").ok_or("v8 str")?; - let s = obj - .get(scope, key.into()) - .ok_or("value")? - .to_rust_string_lossy(scope); - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - if Self::has_sym(obj, scope, ctx.is_thunk) { - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - } - - self.indent(depth); - self.buf.push_str("\n"); - Ok(()) - } - - fn write_attrs<'s>( - &mut self, - map: v8::Local<'s, v8::Map>, - scope: &mut v8::PinScope<'s, '_>, - ctx: &XmlCtx<'s>, - depth: usize, - ) -> Result<()> { - if Self::is_derivation(map, scope) { - self.indent(depth); - self.buf.push_str(" = - v8::String::new(scope, "drvPath").ok_or("v8 str")?.into(); - let drv_str = if let Some(drv_val) = map.get(scope, drv_path_key) { - if drv_val.is_undefined() { - None - } else { - let forced = self.force(drv_val, scope, ctx)?; - let s = self.extract_str(forced, scope, ctx); - if let Some(ref s) = s { - self.buf.push_str(" drvPath=\""); - self.escape_attr(s); - self.buf.push('"'); - } - s - } - } else { - None - }; - - let out_path_key: v8::Local = - v8::String::new(scope, "outPath").ok_or("v8 str")?.into(); - if let Some(out_val) = map.get(scope, out_path_key) - && !out_val.is_undefined() - { - let forced = self.force(out_val, scope, ctx)?; - if let Some(ref s) = self.extract_str(forced, scope, ctx) { - self.buf.push_str(" outPath=\""); - self.escape_attr(s); - self.buf.push('"'); - } - } - - self.buf.push_str(">\n"); - - let is_repeated = if let Some(ref dp) = drv_str { - !self.drvs_seen.insert(dp.clone()) - } else { - false - }; - - if is_repeated { - self.indent(depth + 1); - self.buf.push_str("\n"); - } else { - self.write_attrs_sorted(map, scope, ctx, depth + 1)?; - } - - self.indent(depth); - self.buf.push_str("\n"); - } else { - self.indent(depth); - self.buf.push_str("\n"); - self.write_attrs_sorted(map, scope, ctx, depth + 1)?; - self.indent(depth); - self.buf.push_str("\n"); - } - Ok(()) - } - - fn write_attrs_sorted<'s>( - &mut self, - map: v8::Local<'s, v8::Map>, - scope: &mut v8::PinScope<'s, '_>, - ctx: &XmlCtx<'s>, - depth: usize, - ) -> Result<()> { - let arr = map.as_array(scope); - let len = arr.length(); - - let mut entries: Vec<(String, v8::Local<'s, v8::Value>)> = - Vec::with_capacity((len / 2) as usize); - let mut i = 0; - while i < len { - let key = arr.get_index(scope, i).ok_or("map key")?; - let val = arr.get_index(scope, i + 1).ok_or("map value")?; - entries.push((key.to_rust_string_lossy(scope), val)); - i += 2; - } - entries.sort_by(|a, b| a.0.cmp(&b.0)); - - for (key_str, val) in &entries { - self.indent(depth); - self.buf.push_str("\n"); - - self.write_value(*val, scope, ctx, depth + 1)?; - - self.indent(depth); - self.buf.push_str("\n"); - } - Ok(()) - } - - fn write_function<'s>( - &mut self, - val: v8::Local<'s, v8::Value>, - scope: &mut v8::PinScope<'s, '_>, - ctx: &XmlCtx<'s>, - depth: usize, - ) -> Result<()> { - let obj = val.to_object(scope).ok_or("fn to_object")?; - - if let Some(meta) = obj.get(scope, ctx.primop_meta.into()) - && meta.is_object() - && !meta.is_null_or_undefined() - { - self.indent(depth); - self.buf.push_str("\n"); - return Ok(()); - } - - let args_key = v8::String::new(scope, "args").ok_or("v8 str")?; - let args_val = obj.get(scope, args_key.into()); - - match args_val { - Some(args) if args.is_object() && !args.is_null_or_undefined() => { - let args_obj = args.to_object(scope).ok_or("args to_object")?; - - let req_key = v8::String::new(scope, "required").ok_or("v8 str")?; - let opt_key = v8::String::new(scope, "optional").ok_or("v8 str")?; - let ellipsis_key = v8::String::new(scope, "ellipsis").ok_or("v8 str")?; - - let mut all_formals: Vec = Vec::new(); - if let Some(req) = args_obj.get(scope, req_key.into()) - && let Ok(arr) = v8::Local::::try_from(req) - { - for i in 0..arr.length() { - if let Some(elem) = arr.get_index(scope, i) { - all_formals.push(elem.to_rust_string_lossy(scope)); - } - } - } - if let Some(opt) = args_obj.get(scope, opt_key.into()) - && let Ok(arr) = v8::Local::::try_from(opt) - { - for i in 0..arr.length() { - if let Some(elem) = arr.get_index(scope, i) { - all_formals.push(elem.to_rust_string_lossy(scope)); - } - } - } - all_formals.sort(); - - let has_ellipsis = matches!( - args_obj.get(scope, ellipsis_key.into()), - Some(v) if v.is_true() - ); - - self.indent(depth); - self.buf.push_str("\n"); - self.indent(depth + 1); - if has_ellipsis { - self.buf.push_str("\n"); - } else { - self.buf.push_str("\n"); - } - for formal in &all_formals { - self.indent(depth + 2); - self.buf.push_str("\n"); - } - self.indent(depth + 1); - self.buf.push_str("\n"); - self.indent(depth); - self.buf.push_str("\n"); - } - _ => { - let source = val - .to_detail_string(scope) - .map(|s| s.to_rust_string_lossy(scope)); - let param = source.as_deref().and_then(extract_lambda_param); - self.indent(depth); - self.buf.push_str("\n"); - self.indent(depth + 1); - self.buf.push_str("\n"); - self.indent(depth); - self.buf.push_str("\n"); - } - } - Ok(()) - } -} - -fn extract_lambda_param(source: &str) -> Option<&str> { - let s = source.trim(); - let arrow_pos = s.find("=>")?; - let before = s[..arrow_pos].trim(); - if before.starts_with('(') && before.ends_with(')') { - let inner = before[1..before.len() - 1].trim(); - if !inner.is_empty() && !inner.contains(',') { - return Some(inner); - } - } else if !before.is_empty() - && !before.contains(' ') - && !before.contains('(') - && before - .chars() - .all(|c| c.is_alphanumeric() || c == '_' || c == '$') - { - return Some(before); - } - None -} - -pub(super) struct ToXmlResult { - pub xml: String, - pub context: Vec, -} - -impl<'a> FromV8<'a> for ToXmlResult { - type Error = NixRuntimeError; - - fn from_v8( - scope: &mut v8::PinScope<'a, '_>, - value: v8::Local<'a, v8::Value>, - ) -> std::result::Result { - let global = scope.get_current_context().global(scope); - let nix_key = v8::String::new(scope, "Nix").ok_or("v8 string")?; - let nix_obj = global - .get(scope, nix_key.into()) - .ok_or("no Nix global")? - .to_object(scope) - .ok_or("Nix not object")?; - - let ctx = XmlCtx::new(scope, nix_obj)?; - - let mut writer = XmlWriter::new(); - writer - .buf - .push_str("\n\n"); - writer.write_value(value, scope, &ctx, 1)?; - writer.buf.push_str("\n"); - - Ok(ToXmlResult { - xml: writer.buf, - context: writer.context, - }) - } -} - -#[deno_core::op2(reentrant)] -pub(super) fn op_to_xml(#[scoped] value: ToXmlResult) -> (String, Vec) { - (value.xml, value.context) -}