diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md index e327eb43ea40f..91d2ee0d551a8 100644 --- a/doc/languages-frameworks/javascript.section.md +++ b/doc/languages-frameworks/javascript.section.md @@ -879,6 +879,399 @@ stdenv.mkDerivation (finalAttrs: { }) ``` +### buildDenoPackage {#javascript-buildDenoPackage} + +`buildDenoPackage` allows you to package [Deno](https://deno.com/) projects in Nixpkgs without the use of an auto-generated dependencies file (as used in [node2nix](#javascript-node2nix)). +It works by utilizing Deno's cache functionality -- creating a reproducible cache that contains the dependencies of a project, and pointing Deno to it. + +#### buildDenoDeps {#javascript-buildDenoPackage-buildDenoDeps} + +For every `buildDenoPackage`, first, a [fixed output derivation](https://nix.dev/manual/nix/2.18/language/advanced-attributes.html#adv-attr-outputHash) is +created with all the dependencies mentioned in the `deno.lock`. +This works as follows: +1. They are installed using `deno install`. +1. All non-reproducible data is pruned. +1. The directories `.deno`, `node_modules` and `vendor` are copied to `$out`. +1. The output of the FOD is checked against the `denoDepsHash`. +1. The output is copied into the build of `buildDenoPackage`, which is not an FOD. +1. The dependencies are installed again using `deno install`, this time from the local cache only. + +The `buildDenoDeps` derivation is in `passthru`, so it can be accessed from a `buildDenoPackage` derivation with `.denoDeps` + +Related options: + +*`denoDepsHash`* (String) + +: The output hash of the `buildDenoDeps` fixed output derivation. + +*`denoInstallFlags`* (Array of strings; optional) + +: The Flags passed to `deno install`. + +: _Default:_ `[ "--allow-scripts" "--frozen" "--cached-only" ]` for `buildDenoPackage` +: _Default:_ `[ "--allow-scripts" "--frozen" ]` for `buildDenoDeps` (`"--cached-only"` is filtered out) + +::: {.tip} +If you receive errors like these: + +``` +error: The lockfile is out of date. Run `deno install --frozen=false`, or rerun with `--frozen=false` to update it. +``` + +or + +``` +error: Import '' failed. + 0: error sending request for url (): client error (Connect): dns error: failed to lookup address information: Temporary failure in name resolution: failed to lookup address information:Temporary failure in name resolution + 1: client error (Connect) + 2: dns error: failed to lookup address information: Temporary failure in name resolution + 3: failed to lookup address information: Temporary failure in name resolution + at file:///build/source/src/lib/helpers/verifyRequest.ts:2:21 +build for failed in buildPhase with exit code 1 +``` + +or + +``` +error: Specifier not found in cache: "", --cached-only is specified. + +ERROR: deno failed to install dependencies +``` + +This can happen due to the `deno install` command deducing different packages than what the actual package needs. + +To fix this, add the entrypoint to the install flags: + +```nix +{ buildDenoPackage, nix-gitignore }: +buildDenoPackage { + pname = "myPackage"; + version = "0.1.0"; + denoDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + src = nix-gitignore.gitignoreSource [ ] ./.; + binaryEntrypointPath = "main.ts"; + denoInstallFlags = [ + "--allow-scripts" + "--frozen" + "--cached-only" + "--entrypoint" + "" + ]; +} +``` + +::: + +#### Private registries {#javascript-buildDenoPackage-private-registries} +There are currently 2 options, which enable the use of private registries in a `buildDenoPackage` derivation. + +*`denoDepsImpureEnvVars`* (Array of strings; optional) + +: Names of impure environment variables passed to the `buildDenoDeps` derivation. They are forwarded to `deno install`. + +: _Example:_ `[ "NPM_TOKEN" ]` + +: It can be used to set tokens for private NPM registries (in a `.npmrc` file). + +: In a single-user installation of Nix, you can put the variables into the environment, when running the nix build. + +: In multi-user installations of Nix, it's necessary to set the environment variables in the nix-daemon, probably with systemd. + +:::{.example} + +##### configure nix-daemon {#javascript-buildDenoPackage-private-registries-daemon-example} +In NixOS: + +```nix +# configuration.nix +{ + config, + lib, + pkgs, + ... +}: +{ + systemd.services.nix-daemon.environment.NPM_TOKEN = ""; +} +``` + +In other Linux distributions use + +``` +$ sudo systemctl edit nix-daemon +$ sudo systemctl cat nix-daemon +$ sudo systemctl restart nix-daemon +``` + +::: + +*`denoDepsInjectedEnvVars`* (Attrset; optional) + +: Environment variables as key value pairs. They are forwarded to `deno install`. + +: _Example:_ `{ "NPM_TOKEN" = ""; }` + +: It can be used to set tokens for private NPM registries (in a `.npmrc` file). +You could pass these tokens from the Nix CLI with `--arg`, +however this can hurt the reproducibility of your builds and such an injected +token will also need to be injected in every build that depends on this build. + +:::{.example} + +##### example `.npmrc` {#javascript-buildDenoPackage-private-registries-npmrc-example} + +```ini +@:registry=https:/// +///:_authToken=${NPM_TOKEN} +``` + +::: + +::: {.caution} + +Hardcoding a token into your NixOS configuration or some other nix build, will as a consequence write that token into `/nix/store`, which is considered world readable. + +::: + +::: {.note} +Neither approach is ideal. For `buildNpmPackage`, there exists a third +option called `sourceOverrides`, which allows the user to inject Nix packages into +the output `node_modules` folder. +Since a Nix build implicitly uses the SSH keys of the machine, +this offers a third option to access private packages. +But this creates the requirement, that the imported package is packaged with nix first, +and that the source code can be retrieved with SSH. +This is possible for Deno, too, albeit it not +completely analogous to `buildNpmPackage`'s solution. +However, it has not been implemented yet. +::: + +#### Compile to binary {#javascript-buildDenoPackage-compile-to-binary} + +It's possible to compile a Deno project to a single binary using `deno compile`. +The binary will be named like the `.name` property in `deno.json`, if available, +or the `name` attribute of the derivation. + +:::{.caution} +When using packages with a `npm:` specifier, the resulting binary will not be reproducible. +See [this issue](https://github.com/denoland/deno/issues/29619) for more information. +::: + +Related options: + +*`hostPlatform`* (String; optional) + +: The [host platform](#ssec-cross-platform-parameters) the binary is built for. + +: _Default:_ `builtins.currentSystem`. + +: _Supported values:_ + - `"x86_64-darwin"` + - `"aarch64-darwin"` + - `"x86_64-linux"` + - `"aarch64-linux"` + +*`denoCompileFlags`* (Array of string; optional) + +: Flags passed to `deno compile [denoTaskFlags] ${binaryEntrypointPath} [extraCompileFlags]`. + +*`extraCompileFlags`* (Array of string; optional) + +: Flags passed to `deno compile [denoTaskFlags] ${binaryEntrypointPath} [extraCompileFlags]`. + +*`binaryEntrypointPath`* (String or null; optional) + +: If not `null`, a binary is created using the specified path as the entry point. +The binary is copied to `$out/bin` in the `installPhase`. + +: _Default:_ `null` + +: It's prefixed by `denoWorkspacePath`. + +*`denortPackage`* (Derivation; optional) + +: The package used as the Deno runtime, which is bundled with the JavaScript code to create the binary. + +: _Default:_ `pkgs.denort` + +: Don't use `pkgs.deno` for this, since that is the full Deno CLI, with all the development tooling. + +: If you're cross compiling, this needs to be the `denort` of the `hostPlatform`. + +::: {.note} +The binary will be dynamically linked and not executable on NixOS without [nix-ld](https://github.com/nix-community/nix-ld) +or [other methods](https://unix.stackexchange.com/questions/522822/different-methods-to-run-a-non-nixos-executable-on-nixos). + +```nix +# configuration.nix +{ + config, + lib, + pkgs, + ... +}: +{ + programs.nix-ld.enable = true; + programs.nix-ld.libraries = with pkgs; [ + glibc + gcc-unwrapped + ]; +} +``` + +::: + +:::{.example} + +##### example binary build {#javascript-buildDenoPackage-compile-to-binary-example} + +```nix +{ buildDenoPackage, nix-gitignore }: +buildDenoPackage { + pname = "myPackage"; + version = "0.1.0"; + denoDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + src = nix-gitignore.gitignoreSource [ ] ./.; + binaryEntrypointPath = "main.ts"; +} +``` + +::: + +#### Create artifacts in the build {#javascript-buildDenoPackage-artifacts-in-build} + +Instead of compiling to a binary, `deno task` can be executed inside the build +to produce some artifact, which can then be copied out in the `installPhase`. + +Related options: + +*`denoTaskScript`* (String; optional) + +: The task in `deno.json` that's executed with `deno task`. + +: _Default:_ `"build"` + +*`denoTaskFlags`* (Array of strings; optional) + +: The flags passed to `deno task [denoTaskFlags] ${denoTaskScript} [extraTaskFlags]`. + +*`extraTaskFlags`* (Array of strings; optional) + +: The flags passed to `deno task [denoTaskFlags] ${denoTaskScript} [extraTaskFlags]`. + +*`denoTaskPrefix`* (String; optional) + +: An unquoted string injected before `deno task`. + +*`denoTaskSuffix`* (String; optional) + +: An unquoted string injected after `deno task` and all its flags. For example to pipe stdout to a file. + +:::{.example} + +##### example artifact build {#javascript-buildDenoPackage-artifacts-in-build-example} + +`deno.json` + +```json +{ + "tasks": { + "build": "deno run --allow-all main.ts" + } +} +``` + +```nix +{ buildDenoPackage, nix-gitignore }: +buildDenoPackage { + pname = "myPackage"; + version = "0.1.0"; + denoDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + src = nix-gitignore.gitignoreSource [ ] ./.; + denoTaskSuffix = ">out.txt"; + installPhase = '' + cp ./out.txt $out + ''; +} +``` + +::: + +#### Workspaces {#javascript-buildDenoPackage-workspaces} + +Deno's workspaces are supported. + +To make them work, the whole project needs to be added as source, since the `deno.lock` +is always in the root of the project and contains all dependencies. + +This means a build with only the required dependencies of a workspace is not possible. +Also, the `denoDepsHash` for all workspaces is the same, since they +all share the same dependencies. + +When [running a task inside the build](#javascript-buildDenoPackage-artifacts-in-build), +`denoWorkspacePath` can be used to let the task run inside a workspace. + +When [compiling to a binary](#javascript-buildDenoPackage-compile-to-binary), +`binaryEntrypointPath` is prefixed by `denoWorkspacePath`. + +Related options: + +*`denoWorkspacePath`* (String; optional) + +: The path to a workspace. + +:::{.example} + +##### example workspaces {#javascript-buildDenoPackage-workspaces-example} + +```nix +{ buildDenoPackage, nix-gitignore }: +rec { + sub1 = buildDenoPackage { + pname = "sub1"; + version = "0.1.0"; + denoDepsHash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; + src = nix-gitignore.gitignoreSource [ ] ./.; + denoWorkspacePath = "./sub1"; + denoTaskFlags = [ + "--text" + "sub1" + ]; + denoTaskSuffix = ">out.txt"; + installPhase = '' + cp out.txt $out + ''; + }; + sub2 = buildDenoPackage { + # Note that we are reusing denoDeps and src, + # since they must be the same for both workspaces. + inherit (sub1) denoDeps src; + pname = "sub2"; + version = "0.1.0"; + denoWorkspacePath = "./sub2"; + binaryEntrypointPath = "./main.ts"; + }; +} +``` + +::: + +#### Other Options {#javascript-buildDenoPackage-other-options} + +*`denoDir`* (String; optional) + +: `DENO_DIR` will be set to this value for all `deno` commands. + +*`denoFlags`* (Array of string; optional) + +: The flags passed to all `deno` commands. + +*`denoPackage`* (Derivation; optional) + +: The Deno CLI used for all `deno` commands inside the build. + +: _Default:_ `pkgs.deno` + ## Outside Nixpkgs {#javascript-outside-nixpkgs} There are some other tools available, which are written in the Nix language. diff --git a/doc/redirects.json b/doc/redirects.json index 33bb47fbc5e59..56d7653904a26 100644 --- a/doc/redirects.json +++ b/doc/redirects.json @@ -3378,6 +3378,42 @@ "javascript-nix-npm-buildpackage-pitfalls": [ "index.html#javascript-nix-npm-buildpackage-pitfalls" ], + "javascript-buildDenoPackage-workspaces-example": [ + "index.html#javascript-buildDenoPackage-workspaces-example" + ], + "javascript-buildDenoPackage-private-registries": [ + "index.html#javascript-buildDenoPackage-private-registries" + ], + "javascript-buildDenoPackage-buildDenoDeps": [ + "index.html#javascript-buildDenoPackage-buildDenoDeps" + ], + "javascript-buildDenoPackage-artifacts-in-build": [ + "index.html#javascript-buildDenoPackage-artifacts-in-build" + ], + "javascript-buildDenoPackage-artifacts-in-build-example": [ + "index.html#javascript-buildDenoPackage-artifacts-in-build-example" + ], + "javascript-buildDenoPackage-private-registries-daemon-example": [ + "index.html#javascript-buildDenoPackage-private-registries-daemon-example" + ], + "javascript-buildDenoPackage-private-registries-npmrc-example": [ + "index.html#javascript-buildDenoPackage-private-registries-npmrc-example" + ], + "javascript-buildDenoPackage-compile-to-binary-example": [ + "index.html#javascript-buildDenoPackage-compile-to-binary-example" + ], + "javascript-buildDenoPackage-workspaces": [ + "index.html#javascript-buildDenoPackage-workspaces" + ], + "javascript-buildDenoPackage": [ + "index.html#javascript-buildDenoPackage" + ], + "javascript-buildDenoPackage-other-options": [ + "index.html#javascript-buildDenoPackage-other-options" + ], + "javascript-buildDenoPackage-compile-to-binary": [ + "index.html#javascript-buildDenoPackage-compile-to-binary" + ], "language-julia": [ "index.html#language-julia" ], diff --git a/doc/release-notes/rl-2505.section.md b/doc/release-notes/rl-2505.section.md index 11d54b19159f9..01d952655ad5f 100644 --- a/doc/release-notes/rl-2505.section.md +++ b/doc/release-notes/rl-2505.section.md @@ -551,6 +551,8 @@ - `ddclient` was updated from 3.11.2 to 4.0.0 [Release notes](https://github.com/ddclient/ddclient/releases/tag/v4.0.0) +- `buildDenoPackage` was added [see docs](https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/javascript.section.md#avascript-buildDenoPackage) for more details + ## Nixpkgs Library {#sec-nixpkgs-release-25.05-lib} ### Breaking changes {#sec-nixpkgs-release-25.05-lib-breaking} diff --git a/pkgs/build-support/deno/build-deno-package/default.nix b/pkgs/build-support/deno/build-deno-package/default.nix new file mode 100644 index 0000000000000..4059843ac4214 --- /dev/null +++ b/pkgs/build-support/deno/build-deno-package/default.nix @@ -0,0 +1,172 @@ +# NOTE: much of this structure is inspired from https://github.com/NixOS/nixpkgs/tree/fff29a3e5f7991512e790617d1a693df5f3550f6/pkgs/build-support/node +{ + stdenvNoCC, + deno, + denort, + diffutils, + zip, + jq, + fetchDenoDeps, + buildPackages, + lib, +}: +{ + name ? "${args.pname}-${args.version}", + src ? null, + # The output hash of the dependencies for this project. + denoDepsHash ? lib.fakeHash, + # The host platform, the output binary is compiled for. + hostPlatform ? stdenvNoCC.hostPlatform.system, + # A list of strings, which are names of impure env vars passed to the deps build. + # Example: + # `[ "NPM_TOKEN" ]` + # They will be forwarded to `deno install`. + # It can be used to set tokens for private NPM registries (in an `.npmrc` file). + # In multi user installations of Nix, you need to set the env vars in the daemon (probably with systemd). + # In nixos: `systemd.services.nix-daemon.environment.NPM_TOKEN = "";` + denoDepsImpureEnvVars ? [ ], + # An attr set with env vars as key value pairs. + # Example: + # `{ "NPM_TOKEN" = ""; }` + # They will be forwarded to `deno install`. + # It can be used to set tokens for private NPM registries (in an `.npmrc` file). + # You could pass these tokens from the cli with `--arg` (this can make your builds painful). + denoDepsInjectedEnvVars ? { }, + # TODO: source overrides like in buildNpmPackage, i.e. injecting nix packages into the denoDeps + # this is more involved, since they can't directly be injected into the fixed output derivation + # of fetchDenoDeps. Instead we need to patch the lock file and remove the packages we intend to + # inject, then we need to build the rest of the packages like before and in a + # second step create normal derivation with the injected packages. + # then the two need to be merged into a single denoDeps derivation and finally the lock file needs + # to be reverted back to it's original form. + # It is possible to manipulate the registry.json files of the injected packages so that deno accepts them as is. + denoDeps ? fetchDenoDeps { + inherit + src + denoDepsInjectedEnvVars + denoDepsImpureEnvVars + denoFlags + denoDir + ; + denoInstallFlags = builtins.filter (e: e != "--cached-only") denoInstallFlags; + name = "${name}-deno-deps"; + hash = denoDepsHash; + }, + # The package used for every deno command in the build + denoPackage ? deno, + # The package used as the runtime that is bundled with the the src to create the binary. + denortPackage ? denort, + # The script to run to build the project. + # You still need to specify in the installPhase, what artifacts to copy to `$out`. + denoTaskScript ? "build", + # If not null, create a binary using the specified path as the entrypoint, + # copy it to `$out/bin` in installPhase and fix it in fixupPhase. + binaryEntrypointPath ? null, + # Flags to pass to all deno commands. + denoFlags ? [ ], + # Flags to pass to `deno task [denoTaskFlags] ${denoTaskScript}`. + denoTaskFlags ? [ ], + # Flags to pass to `deno compile [denoTaskFlags] ${binaryEntrypointPath}`. + denoCompileFlags ? [ ], + # Flags to pass to `deno install [denoInstallFlags]`. + denoInstallFlags ? [ + "--allow-scripts" + "--frozen" + "--cached-only" + ], + # Flags to pass to `deno task [denoTaskFlags] ${denoTaskScript} [extraTaskFlags]`. + extraTaskFlags ? [ ], + # Flags to pass to `deno compile [denoTaskFlags] ${binaryEntrypointPath} [extraCompileFlags]`. + extraCompileFlags ? [ ], + nativeBuildInputs ? [ ], + dontFixup ? true, + # Custom denoConfigHook + denoConfigHook ? null, + # Custom denoBuildHook + denoBuildHook ? null, + # Custom denoInstallHook + denoInstallHook ? null, + # Path to deno workspace, where the denoTaskScript should be run + denoWorkspacePath ? null, + # Unquoted string injected before `deno task` + denoTaskPrefix ? "", + # Unquoted string injected after `deno task` and all its flags + denoTaskSuffix ? "", + # Used as the name of the local DENO_DIR + denoDir ? "./.deno", + ... +}@args: +let + denoFlags_ = builtins.concatStringsSep " " denoFlags; + denoTaskFlags_ = builtins.concatStringsSep " " denoTaskFlags; + denoCompileFlags_ = builtins.concatStringsSep " " denoCompileFlags; + denoInstallFlags_ = builtins.concatStringsSep " " denoInstallFlags; + extraTaskFlags_ = builtins.concatStringsSep " " extraTaskFlags; + extraCompileFlags_ = builtins.concatStringsSep " " extraCompileFlags; + + args' = builtins.removeAttrs args [ "denoDepsInjectedEnvVars" ]; + + denoHooks = + (buildPackages.denoHooks.override { + denort = denortPackage; + }) + { + inherit denoTaskSuffix denoTaskPrefix binaryEntrypointPath; + }; + systemLookupTable = { + "x86_64-darwin" = "x86_64-apple-darwin"; + "arm64-darwin" = "aarch64-apple-darwin"; + "aarch64-darwin" = "aarch64-apple-darwin"; + "x86_64-linux" = "x86_64-unknown-linux-gnu"; + "arm64-linux" = "aarch64-unknown-linux-gnu"; + "aarch64-linux" = "aarch64-unknown-linux-gnu"; + }; + hostPlatform_ = + if builtins.hasAttr hostPlatform systemLookupTable then + systemLookupTable."${hostPlatform}" + else + (lib.systems.elaborate hostPlatform).config; +in +stdenvNoCC.mkDerivation ( + args' + // { + inherit + name + denoDeps + src + denoFlags_ + denoTaskFlags_ + denoCompileFlags_ + denoInstallFlags_ + extraTaskFlags_ + extraCompileFlags_ + binaryEntrypointPath + hostPlatform_ + denoWorkspacePath + denoTaskScript + ; + + nativeBuildInputs = nativeBuildInputs ++ [ + # Prefer passed hooks + (if denoConfigHook != null then denoConfigHook else denoHooks.denoConfigHook) + (if denoBuildHook != null then denoBuildHook else denoHooks.denoBuildHook) + (if denoInstallHook != null then denoInstallHook else denoHooks.denoInstallHook) + denoPackage + diffutils + zip + jq + ]; + + DENO_DIR = denoDir; + + dontFixup = if binaryEntrypointPath != null then false else dontFixup; + + passthru = { + inherit denoDeps; + }; + + meta = (args.meta or { }) // { + platforms = args.meta.platforms or denoPackage.meta.platforms; + }; + } +) diff --git a/pkgs/build-support/deno/build-deno-package/hooks/default.nix b/pkgs/build-support/deno/build-deno-package/hooks/default.nix new file mode 100644 index 0000000000000..7ece1943a3cff --- /dev/null +++ b/pkgs/build-support/deno/build-deno-package/hooks/default.nix @@ -0,0 +1,29 @@ +{ + makeSetupHook, + denort, + lib, +}: +{ + denoTaskSuffix, + denoTaskPrefix, + binaryEntrypointPath, +}: +{ + denoConfigHook = makeSetupHook { + name = "deno-config-hook"; + substitutions = { + denortBinary = lib.optionalString (binaryEntrypointPath != null) (lib.getExe denort); + }; + } ./deno-config-hook.sh; + + denoBuildHook = makeSetupHook { + name = "deno-build-hook"; + substitutions = { + inherit denoTaskSuffix denoTaskPrefix; + }; + } ./deno-build-hook.sh; + + denoInstallHook = makeSetupHook { + name = "deno-install-hook"; + } ./deno-install-hook.sh; +} diff --git a/pkgs/build-support/deno/build-deno-package/hooks/deno-build-hook.sh b/pkgs/build-support/deno/build-deno-package/hooks/deno-build-hook.sh new file mode 100644 index 0000000000000..66ffb51d3efaf --- /dev/null +++ b/pkgs/build-support/deno/build-deno-package/hooks/deno-build-hook.sh @@ -0,0 +1,58 @@ +# shellcheck shell=bash + +denoBuildHook() { + echo "Executing denoBuildHook" + + runHook preBuild + + if [ -n "${binaryEntrypointPath-}" ]; then + echo "Creating binary" + + package_name=$(jq -r '.name' deno.json) + if [ "$package_name" == "null" ]; then + package_name="$name" + fi + + deno compile \ + --output "$package_name" \ + --target "$hostPlatform_" \ + $denoCompileFlags \ + $denoFlags \ + "${denoWorkspacePath+$denoWorkspacePath/}$binaryEntrypointPath" + $extraCompileFlags \ + + elif [ -n "${denoTaskScript-}" ]; then + if ! @denoTaskPrefix@ \ + deno task \ + ${denoWorkspacePath+--cwd=$denoWorkspacePath} \ + $denoTaskFlags \ + $denoFlags \ + "$denoTaskScript" \ + $extraTaskFlags \ + @denoTaskSuffix@; then + echo + echo 'ERROR: `deno task` failed' + echo + echo "Here are a few things you can try, depending on the error:" + echo "1. Make sure your task script ($denoTaskScript) exists" + echo + + exit 1 + fi + else + echo + echo "ERROR: nothing to do in buildPhase" + echo "Specify either 'binaryEntrypointPath' or 'denoTaskScript' or override 'buildPhase'" + echo + + exit 1 + fi + + runHook postBuild + + echo "Finished denoBuildHook" +} + +if [ -z "${buildPhase-}" ]; then + buildPhase=denoBuildHook +fi diff --git a/pkgs/build-support/deno/build-deno-package/hooks/deno-config-hook.sh b/pkgs/build-support/deno/build-deno-package/hooks/deno-config-hook.sh new file mode 100644 index 0000000000000..28b6304c6ca4a --- /dev/null +++ b/pkgs/build-support/deno/build-deno-package/hooks/deno-config-hook.sh @@ -0,0 +1,108 @@ +# shellcheck shell=bash + +denoConfigHook() { + echo "Executing denoConfigHook" + + if [ -z "${denoDeps-}" ]; then + echo + echo "ERROR: no dependencies were specified" + echo 'Hint: set `denoDeps` if using these hooks individually. If this is happening with `buildDenoPackage`, please open an issue.' + echo + + exit 1 + fi + + local -r cacheLockfile="$denoDeps/deno.lock" + local -r srcLockfile="$PWD/deno.lock" + + echo "Validating consistency between $srcLockfile and $cacheLockfile" + + if ! diff "$srcLockfile" "$cacheLockfile"; then + # If the diff failed, first double-check that the file exists, so we can + # give a friendlier error msg. + if ! [ -e "$srcLockfile" ]; then + echo + echo "ERROR: Missing deno.lock from src. Expected to find it at: $srcLockfile" + echo + + exit 1 + fi + + if ! [ -e "$cacheLockfile" ]; then + echo + echo "ERROR: Missing lockfile from cache. Expected to find it at: $cacheLockfile" + echo + + exit 1 + fi + + echo + echo "ERROR: denoDepsHash is out of date" + echo + echo "The deno.lock in src is not the same as the in $denoDeps." + echo + echo "To fix the issue:" + echo '1. Use `lib.fakeHash` as the denoDepsHash value' + echo "2. Build the derivation and wait for it to fail with a hash mismatch" + echo "3. Copy the 'got: sha256-' value back into the denoDepsHash field" + echo + + exit 1 + fi + + # NOTE: we need to use vendor in the build too, since we used it for the deps + useVendor() { + jq '.vendor = true' deno.json >temp.json && + rm -f deno.json && + mv temp.json deno.json + } + echo "Adding vendor to deno.json" + useVendor + + echo "Installing dependencies" + + export DENO_DIR="$(pwd)"/"$DENO_DIR" + + installDeps() { + if [[ -d "$denoDeps/.deno" ]]; then + cp -r --no-preserve=mode "$denoDeps/.deno" "$DENO_DIR" + fi + if [[ -d "$denoDeps/vendor" ]]; then + cp -r --no-preserve=mode "$denoDeps/vendor" ./vendor + fi + if [[ -d "$denoDeps/node_modules" ]]; then + cp -r --no-preserve=mode "$denoDeps/node_modules" ./node_modules + fi + } + installDeps + + if ! deno install $denoInstallFlags_ $denoFlags_; then + echo + echo "ERROR: deno failed to install dependencies" + echo + + exit 1 + fi + + installDenort() { + version="$(deno --version | head -1 | awk '{print $2}')" + zipfile=denort-"$hostPlatform_".zip + dir="$DENO_DIR"/dl/release/v"$version" + mkdir -p "$dir" + cp "@denortBinary@" ./denort + zip "$dir"/"$zipfile" ./denort + rm ./denort + } + if [ -n "${binaryEntrypointPath-}" ]; then + echo "Installing denort for binary build" + installDenort + fi + + patchShebangs .deno + patchShebangs node_modules + patchShebangs vendor + + echo "Finished denoConfigHook" +} + +postPatchHooks+=(denoConfigHook) diff --git a/pkgs/build-support/deno/build-deno-package/hooks/deno-install-hook.sh b/pkgs/build-support/deno/build-deno-package/hooks/deno-install-hook.sh new file mode 100644 index 0000000000000..969c59da5809f --- /dev/null +++ b/pkgs/build-support/deno/build-deno-package/hooks/deno-install-hook.sh @@ -0,0 +1,32 @@ +# shellcheck shell=bash + +denoInstallHook() { + echo "Executing denoInstallHook" + + runHook preInstall + + if [ -n "${binaryEntrypointPath-}" ]; then + package_name=$(jq -r '.name' deno.json) + if [ "$package_name" == "null" ]; then + package_name="$name" + fi + + mkdir -p "$out/bin" + cp "$package_name"* "$out/bin" + else + echo + echo "ERROR: nothing to do in installPhase" + echo "Specify either 'binaryEntrypointPath' or override 'installPhase'" + echo + + exit 1 + fi + + runHook postInstall + + echo "Finished denoInstallHook" +} + +if [ -z "${dontDenoInstall-}" ] && [ -z "${installPhase-}" ]; then + installPhase=denoInstallHook +fi diff --git a/pkgs/build-support/deno/fetch-deno-deps/.gitignore b/pkgs/build-support/deno/fetch-deno-deps/.gitignore new file mode 100644 index 0000000000000..95aecda46ec1c --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/.gitignore @@ -0,0 +1,4 @@ +.deno/ +vendor/ +node_modules/ +.direnv diff --git a/pkgs/build-support/deno/fetch-deno-deps/default.nix b/pkgs/build-support/deno/fetch-deno-deps/default.nix new file mode 100644 index 0000000000000..a676deeb6d922 --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/default.nix @@ -0,0 +1,185 @@ +# NOTE: much of this structure is inspired from https://github.com/NixOS/nixpkgs/tree/fff29a3e5f7991512e790617d1a693df5f3550f6/pkgs/build-support/node +{ + lib, + stdenvNoCC, + deno, + jq, + cacert, +}: +{ + fetchDenoDeps = + { + name ? "deno-deps", + src, + hash ? lib.fakeHash, + denoPackage ? deno, + denoFlags ? [ ], + denoInstallFlags ? [ + "--allow-scripts" + "--frozen" + ], + nativeBuildInputs ? [ ], + denoDepsImpureEnvVars ? [ ], + denoDepsInjectedEnvVars ? { }, + denoDir ? "./.deno", + ... + }@args: + let + hash_ = + if hash != "" then + { outputHash = hash; } + else + { + outputHash = ""; + outputHashAlgo = "sha256"; + }; + denoInstallFlags_ = builtins.concatStringsSep " " denoInstallFlags; + denoFlags_ = builtins.concatStringsSep " " denoFlags; + denoDepsInjectedEnvVarsString = + if denoDepsInjectedEnvVars != { } then + lib.attrsets.foldlAttrs ( + acc: name: value: + "${acc} ${name}=${value}" + ) "" denoDepsInjectedEnvVars + else + ""; + # need to remove denoDepsInjectedEnvVars, since it's an attrset and + # stdenv.mkDerivation would try to convert it to string + args' = builtins.removeAttrs args [ "denoDepsInjectedEnvVars" ]; + in + stdenvNoCC.mkDerivation ( + args' + // { + inherit name src; + + nativeBuildInputs = nativeBuildInputs ++ [ + denoPackage + jq + ]; + + DENO_DIR = denoDir; + + buildPhase = '' + runHook preBuild + + if [[ ! -e "deno.json" ]]; then + echo "" + echo "ERROR: deno.json required, but not found" + echo "" + exit 1 + fi + + if [[ ! -e "deno.lock" ]]; then + echo "" + echo "ERROR: deno.lock required, but not found" + echo "" + exit 1 + fi + + # NOTE: using vendor reduces the pruning effort a little + useVendor() { + jq '.vendor = true' deno.json >temp.json && \ + rm -f deno.json && \ + mv temp.json deno.json + } + useVendor + + # uses $DENO_DIR + ${denoDepsInjectedEnvVarsString} deno install ${denoInstallFlags_} ${denoFlags_} + + echo "pruning non reproducible files" + + # `node_modules` is used when there are install scripts in a dependencies' package.json. + # these install scripts can also require internet, so they should also be executed in this fetcher + pruneNonReproducibles() { + export tempDenoDir="$DENO_DIR" + + # `registry.json` files can't just be deleted, else deno install won't work, + # but they contain non reproducible data, + # which needs to be pruned, leaving only the necessary data behind. + # This pruning is done with a helper script written in typescript and executed with deno + DENO_DIR=./extra_deno_cache deno run \ + --lock="${./deno.lock}" \ + --config="${./deno.json}" \ + --allow-all \ + "${./prune-registries.ts}" \ + --lock-json="./deno.lock" \ + --cache-path="$tempDenoDir" \ + --vendor-path="./vendor" + + # Keys in `registry.json` files are not deterministically sorted, + # so we do it here. + for file in $(find -L "$DENO_DIR" -name registry.json -type f); do + jq --sort-keys '.' "$file" >temp.json && \ + rm -f "$file" && \ + mv temp.json "$file" + done + + # There are various small databases used by deno for caching that + # we can simply delete. + if [[ -d "./node_modules" ]]; then + find -L ./node_modules -name '*cache_v2-shm' -type f | xargs rm -f + find -L ./node_modules -name '*cache_v2-wal' -type f | xargs rm -f + find -L ./node_modules -name 'dep_analysis_cache_v2' -type f | xargs rm -f + find -L ./node_modules -name 'node_analysis_cache_v2' -type f | xargs rm -f + find -L ./node_modules -name v8_code_cache_v2 -type f | xargs rm -f + rm -f ./node_modules/.deno/.deno.lock.poll + + # sometimes a .deno dir is slipped into a node_modules package + # it's unclear why. but it can just be deleted + find -L ./node_modules -name ".deno" -type d | sort -r | head -n-1 | xargs rm -rf + fi + + rm -f "$DENO_DIR"/dep_analysis_cache_v2-shm + rm -f "$DENO_DIR"/dep_analysis_cache_v2-wal + rm -f "$DENO_DIR"/dep_analysis_cache_v2 + } + pruneNonReproducibles + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + if [[ -d "$DENO_DIR" ]]; then + mkdir -p $out/$DENO_DIR + cp -r --no-preserve=mode $DENO_DIR $out + fi + if [[ -d "./vendor" ]]; then + mkdir -p $out/vendor + cp -r --no-preserve=mode ./vendor $out + fi + if [[ -d "./node_modules" ]]; then + mkdir -p $out/node_modules + cp -r --no-preserve=mode ./node_modules $out + fi + + cp ./deno.lock $out + + runHook postInstall + ''; + + dontFixup = true; + + outputHashMode = "recursive"; + + impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ denoDepsImpureEnvVars; + + SSL_CERT_FILE = + if + ( + hash_.outputHash == "" + || hash_.outputHash == lib.fakeSha256 + || hash_.outputHash == lib.fakeSha512 + || hash_.outputHash == lib.fakeHash + ) + then + "${cacert}/etc/ssl/certs/ca-bundle.crt" + else + "/no-cert-file.crt"; + + } + // hash_ + ); +} diff --git a/pkgs/build-support/deno/fetch-deno-deps/deno.json b/pkgs/build-support/deno/fetch-deno-deps/deno.json new file mode 100644 index 0000000000000..b658546e4b31f --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/deno.json @@ -0,0 +1,8 @@ +{ + "tasks": { "test": "deno test" }, + "imports": { + "@std/assert": "jsr:@std/assert@1.0.13", + "@std/cli": "jsr:@std/cli@1.0.16", + "@std/fs": "jsr:@std/fs@1.0.16" + } +} diff --git a/pkgs/build-support/deno/fetch-deno-deps/deno.lock b/pkgs/build-support/deno/fetch-deno-deps/deno.lock new file mode 100644 index 0000000000000..7791e31422124 --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/deno.lock @@ -0,0 +1,53 @@ +{ + "version": "5", + "specifiers": { + "jsr:@std/assert@1.0.13": "1.0.13", + "jsr:@std/cli@1.0.16": "1.0.16", + "jsr:@std/fs@1.0.16": "1.0.16", + "jsr:@std/internal@^1.0.6": "1.0.7", + "jsr:@std/path@1.0.9": "1.0.9", + "jsr:@std/path@^1.0.8": "1.0.9", + "npm:@types/node@*": "22.15.15" + }, + "jsr": { + "@std/assert@1.0.13": { + "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/cli@1.0.16": { + "integrity": "02df293099c35b9e97d8ca05f57f54bd1ee08134f25d19a4756b3924695f4b00" + }, + "@std/fs@1.0.16": { + "integrity": "81878f62b6eeda0bf546197fc3daa5327c132fee1273f6113f940784a468b036", + "dependencies": [ + "jsr:@std/path@^1.0.8" + ] + }, + "@std/internal@1.0.7": { + "integrity": "39eeb5265190a7bc5d5591c9ff019490bd1f2c3907c044a11b0d545796158a0f" + }, + "@std/path@1.0.9": { + "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e" + } + }, + "npm": { + "@types/node@22.15.15": { + "integrity": "sha512-R5muMcZob3/Jjchn5LcO8jdKwSCbzqmPB6ruBxMcf9kbxtniZHP327s6C37iOfuw8mbKK3cAQa7sEl7afLrQ8A==", + "dependencies": [ + "undici-types" + ] + }, + "undici-types@6.21.0": { + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + } + }, + "workspace": { + "dependencies": [ + "jsr:@std/assert@1.0.13", + "jsr:@std/cli@1.0.16", + "jsr:@std/fs@1.0.16" + ] + } +} diff --git a/pkgs/build-support/deno/fetch-deno-deps/prune-registries.test.ts b/pkgs/build-support/deno/fetch-deno-deps/prune-registries.test.ts new file mode 100644 index 0000000000000..42f7edac640b1 --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/prune-registries.test.ts @@ -0,0 +1,1054 @@ +import { assertEquals } from "@std/assert"; +import type { + LockJson, + MetaJson, + PackageInfo, + PackagesByRegistry, + PackageSpecifiers, + RegistryJson, +} from "./prune-registries.ts"; +import { + getAllPackageRegistries, + getAllPackagesByPackageRegistry, + getScopedName, + parsePackageSpecifier, + pruneMetaJson, + pruneRegistryJson, +} from "./prune-registries.ts"; + +type Fixture = { + testValue: T; + expectedValue: R; +}; + +type Fixtures = Array>; + +function testFactory( + assertFunction: (actual: R, expected: R, msg?: string) => void, + testFunction: (args: T) => R, + fixtures: Fixtures +): () => void { + return () => { + fixtures.forEach((fixture) => { + assertFunction(testFunction(fixture.testValue), fixture.expectedValue); + }); + }; +} + +Deno.test("parsePackageSpecifier", () => { + type Args = string; + type ReturnValue = PackageInfo; + const fixtures: Array> = [ + { + testValue: "jsr:@std/assert@1.0.13", + expectedValue: { + full: "jsr:@std/assert@1.0.13", + registry: "jsr", + scope: "@std", + name: "assert", + version: "1.0.13", + suffix: undefined, + }, + }, + { + testValue: "npm:ini@5.0.0", + expectedValue: { + full: "npm:ini@5.0.0", + registry: "npm", + scope: undefined, + name: "ini", + version: "5.0.0", + suffix: undefined, + }, + }, + { + testValue: "npm:@amazn/style-dictionary@4.2.4_prettier@3.5.3", + expectedValue: { + full: "npm:@amazn/style-dictionary@4.2.4_prettier@3.5.3", + registry: "npm", + scope: "@amazn", + name: "style-dictionary", + version: "4.2.4", + suffix: "_prettier@3.5.3", + }, + }, + ]; + testFactory(assertEquals, parsePackageSpecifier, fixtures)(); +}); + +Deno.test("getScopedName", () => { + type Args = { name: string; scope?: string }; + type ReturnValue = string; + const fixtures: Array> = [ + { + testValue: { name: "assert", scope: undefined }, + expectedValue: "assert", + }, + { + testValue: { name: "assert", scope: "std" }, + expectedValue: "@std/assert", + }, + { + testValue: { name: "assert", scope: "@std" }, + expectedValue: "@std/assert", + }, + ]; + testFactory( + assertEquals, + (args: Args) => getScopedName(args.name, args.scope), + fixtures + )(); +}); + +Deno.test("getAllPackageRegistries", () => { + type Args = PackageSpecifiers; + type ReturnValue = Set; + const fixtures: Array> = [ + { + testValue: { + "jsr:@std/assert@1.0.13": "1.0.13", + "jsr:@std/cli@1.0.16": "1.0.16", + "jsr:@std/fs@1.0.16": "1.0.16", + "jsr:@std/internal@^1.0.6": "1.0.7", + "jsr:@std/path@1.0.9": "1.0.9", + "jsr:@std/path@^1.0.8": "1.0.9", + "npm:ini@5.0.0": "5.0.0", + }, + expectedValue: new Set(["jsr", "npm"]), + }, + ]; + testFactory(assertEquals, getAllPackageRegistries, fixtures)(); +}); + +Deno.test("getAllPackagesByPackageRegistry", () => { + type Args = { lockJson: LockJson; registries: Set }; + type ReturnValue = PackagesByRegistry; + const fixtures: Array> = [ + { + testValue: { + lockJson: JSON.parse(` +{ + "version": "4", + "specifiers": { + "jsr:@std/assert@1.0.13": "1.0.13", + "jsr:@std/cli@1.0.16": "1.0.16", + "jsr:@std/fs@1.0.16": "1.0.16", + "jsr:@std/internal@^1.0.6": "1.0.7", + "jsr:@std/path@1.0.9": "1.0.9", + "jsr:@std/path@^1.0.8": "1.0.9", + "npm:ini@5.0.0": "5.0.0" + }, + "jsr": { + "@std/assert@1.0.13": { + "integrity": "ae0d31e41919b12c656c742b22522c32fb26ed0cba32975cb0de2a273cb68b29", + "dependencies": [ + "jsr:@std/internal" + ] + }, + "@std/cli@1.0.16": { + "integrity": "02df293099c35b9e97d8ca05f57f54bd1ee08134f25d19a4756b3924695f4b00" + }, + "@std/fs@1.0.16": { + "integrity": "81878f62b6eeda0bf546197fc3daa5327c132fee1273f6113f940784a468b036", + "dependencies": [ + "jsr:@std/path@^1.0.8" + ] + }, + "@std/internal@1.0.7": { + "integrity": "39eeb5265190a7bc5d5591c9ff019490bd1f2c3907c044a11b0d545796158a0f" + }, + "@std/path@1.0.9": { + "integrity": "260a49f11edd3db93dd38350bf9cd1b4d1366afa98e81b86167b4e3dd750129e" + } + }, + "npm": { + "ini@5.0.0": { + "integrity": "sha512-+N0ngpO3e7cRUWOJAS7qw0IZIVc6XPrW4MlFBdD066F2L4k1L6ker3hLqSq7iXxU5tgS4WGkIUElWn5vogAEnw==" + } + }, + "workspace": { + "dependencies": [ + "jsr:@std/assert@1.0.13", + "jsr:@std/cli@1.0.16", + "jsr:@std/fs@1.0.16", + "jsr:@std/path@1.0.9", + "npm:ini@5.0.0" + ] + } +} +`), + registries: new Set(["npm", "jsr"]), + }, + expectedValue: { + jsr: { + "@std/assert": { + "1.0.13": { + full: "@std/assert@1.0.13", + registry: undefined, + scope: "@std", + name: "assert", + version: "1.0.13", + suffix: undefined, + }, + }, + "@std/cli": { + "1.0.16": { + full: "@std/cli@1.0.16", + registry: undefined, + scope: "@std", + name: "cli", + version: "1.0.16", + suffix: undefined, + }, + }, + "@std/fs": { + "1.0.16": { + full: "@std/fs@1.0.16", + registry: undefined, + scope: "@std", + name: "fs", + version: "1.0.16", + suffix: undefined, + }, + }, + "@std/internal": { + "1.0.7": { + full: "@std/internal@1.0.7", + registry: undefined, + scope: "@std", + name: "internal", + version: "1.0.7", + suffix: undefined, + }, + }, + "@std/path": { + "1.0.9": { + full: "@std/path@1.0.9", + registry: undefined, + scope: "@std", + name: "path", + version: "1.0.9", + suffix: undefined, + }, + }, + }, + npm: { + ini: { + "5.0.0": { + full: "ini@5.0.0", + registry: undefined, + scope: undefined, + name: "ini", + version: "5.0.0", + suffix: undefined, + }, + }, + }, + }, + }, + ]; + testFactory( + assertEquals, + (args: Args) => + getAllPackagesByPackageRegistry(args.lockJson, args.registries), + fixtures + )(); +}); + +Deno.test("pruneMetaJson", () => { + type Args = { + metaJson: MetaJson; + jsrPackages: PackagesByRegistry; + registry: string; + }; + type ReturnValue = MetaJson; + const fixtures: Array> = [ + { + testValue: { + metaJson: { + scope: "std", + name: "cli", + latest: "1.0.17", + versions: { + "0.222.0": {}, + "1.0.16": {}, + "0.218.2": {}, + "0.218.0": {}, + "1.0.10": {}, + "0.224.6": {}, + "1.0.4": {}, + "1.0.8": {}, + "1.0.2": {}, + "0.211.0": {}, + "0.213.0": {}, + "1.0.0-rc.2": {}, + "1.0.3": {}, + "1.0.0-rc.5": {}, + "0.210.0": {}, + "0.209.0": {}, + "0.212.0": {}, + "0.208.0": {}, + "1.0.7": {}, + "1.0.0": {}, + "0.220.1": {}, + "0.224.2": {}, + "1.0.17": {}, + "1.0.1": {}, + "0.221.0": {}, + "0.224.5": {}, + "0.216.0": {}, + "0.207.0": {}, + "0.224.4": {}, + "1.0.0-rc.4": {}, + "0.214.0": {}, + "0.223.0": {}, + "1.0.6": {}, + "0.224.1": {}, + "0.224.0": {}, + "1.0.15": {}, + "1.0.0-rc.3": {}, + "0.224.3": {}, + "1.0.14": {}, + "1.0.9": {}, + "0.222.1": {}, + "1.0.13": {}, + "1.0.0-rc.1": {}, + "0.219.0": {}, + "1.0.5": {}, + "1.0.11": {}, + "0.224.7": {}, + "0.215.0": {}, + "1.0.12": {}, + "0.217.0": {}, + "0.213.1": {}, + "0.219.1": {}, + "0.218.1": {}, + }, + }, + jsrPackages: { + jsr: { + "@luca/cases": { + "1.0.0": { + full: "@luca/cases@1.0.0", + registry: undefined, + scope: "@luca", + name: "cases", + version: "1.0.0", + suffix: undefined, + }, + }, + "@std/cli": { + "1.0.17": { + full: "@std/cli@1.0.17", + registry: undefined, + scope: "@std", + name: "cli", + version: "1.0.17", + suffix: undefined, + }, + }, + }, + }, + registry: "jsr", + }, + expectedValue: { + scope: "std", + name: "cli", + latest: "", + versions: { "1.0.17": {} }, + }, + }, + { + testValue: { + metaJson: { + scope: "luca", + name: "cases", + latest: "1.0.0", + versions: { "1.0.0": {} }, + }, + jsrPackages: { + jsr: { + "@luca/cases": { + "1.0.0": { + full: "@luca/cases@1.0.0", + registry: undefined, + scope: "@luca", + name: "cases", + version: "1.0.0", + suffix: undefined, + }, + }, + "@std/cli": { + "1.0.17": { + full: "@std/cli@1.0.17", + registry: undefined, + scope: "@std", + name: "cli", + version: "1.0.17", + suffix: undefined, + }, + }, + }, + }, + registry: "jsr", + }, + expectedValue: { + scope: "luca", + name: "cases", + latest: "", + versions: { "1.0.0": {} }, + }, + }, + ]; + testFactory( + assertEquals, + (args: Args) => + pruneMetaJson(args.metaJson, args.jsrPackages, args.registry), + fixtures + )(); +}); + +Deno.test("pruneRegistryJson", () => { + type Args = { + registryJson: RegistryJson; + nonJsrPackages: PackagesByRegistry; + registry: string; + }; + type ReturnValue = RegistryJson; + const fixtures: Array> = [ + { + testValue: { + registryJson: { + name: "decamelize", + versions: { + "1.1.0": { + version: "1.1.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-1.1.0.tgz", + shasum: "fe90c002a0acec1435120ce83a6945641018d0c8", + integrity: + "sha512-n7ZK2Y9+g6neJhxuH+BejddHBOZXp9vh5KcKbedUHVjl1SCU3nnO8iWTqNxLi7OCYabTpypddtlylvtecwrW1w==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "node test.js" }, + deprecated: null, + }, + "3.1.1": { + version: "3.1.1", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-3.1.1.tgz", + shasum: "ebf473c6f8607bd70fd9ed6d892da27c5eb8539e", + integrity: + "sha512-pSJTQCBDZxv8siK5p/M42ZdhThhTtx3JU/OKli0yQSKebfM9q92op6zF7krYrWVKRtsE/RwTDiZLliMV3ECkXQ==", + }, + bin: null, + dependencies: { xregexp: "^4.2.4" }, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + "3.1.0": { + version: "3.1.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-3.1.0.tgz", + shasum: "81cd3f2e9911b8874e290d249da2c366453641d4", + integrity: + "sha512-fgHaR077tSDdzV2ExQwtJ8Kx8LYOvnf1cm5JaQ1ESeGgO8CTH7wv3202zJEg1YND0Fx7WQDxeuDPdAPMERXBEg==", + }, + bin: null, + dependencies: { xregexp: "^4.2.4" }, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + "1.1.1": { + version: "1.1.1", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-1.1.1.tgz", + shasum: "8871479a6c0487f5653d48a992f1d0381ca6f031", + integrity: + "sha512-l2nWbx7Uy2MCRQjEJQm6lep1GwWzl1DHr9wTcQzLQYOSes2RwALmR87OG91eNjoMbih7xrYhZX9cPWP3U7Kxmw==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "node test.js" }, + deprecated: null, + }, + "1.2.0": { + version: "1.2.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + shasum: "f6534d15148269b20352e7bee26f501f9a191290", + integrity: + "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava" }, + deprecated: null, + }, + "2.0.0": { + version: "2.0.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", + shasum: "656d7bbc8094c4c788ea53c5840908c9c7d063c7", + integrity: + "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", + }, + bin: null, + dependencies: { xregexp: "4.0.0" }, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava" }, + deprecated: null, + }, + "3.0.0": { + version: "3.0.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-3.0.0.tgz", + shasum: "5efdacb0ff1b6e4031ccd0da71257340c1b846b7", + integrity: + "sha512-NUW7GyGP5Al0a4QIr3qj/FVzPNjpixU/HWPMJ7kuFlMpVnLcNeUrKsvOOMlywL2QPr/JG3am40S5a2G9F0REcw==", + }, + bin: null, + dependencies: { xregexp: "^4.2.4" }, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd-check" }, + deprecated: null, + }, + "5.0.0": { + version: "5.0.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-5.0.0.tgz", + shasum: "88358157b010ef133febfd27c18994bd80c6215b", + integrity: + "sha512-U75DcT5hrio3KNtvdULAWnLiAPbFUC4191ldxMmj4FA/mRuBnmDwU0boNfPyFRhnan+Jm+haLeSn3P0afcBn4w==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + "1.1.2": { + version: "1.1.2", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-1.1.2.tgz", + shasum: "dcc93727be209632e98b02718ef4cb79602322f2", + integrity: + "sha512-TzUj+sMdUozL/R01HUZfQNgHBclsYvlLLDoXpoVT//50AAuGNYj1jayRptx0gBgBWaViSim8YHnx0NgLmdx2KQ==", + }, + bin: null, + dependencies: { "escape-string-regexp": "^1.0.4" }, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava" }, + deprecated: null, + }, + "4.0.0": { + version: "4.0.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + shasum: "aa472d7bf660eb15f3494efd531cab7f2a709837", + integrity: + "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + "5.0.1": { + version: "5.0.1", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-5.0.1.tgz", + shasum: "db11a92e58c741ef339fb0a2868d8a06a9a7b1e9", + integrity: + "sha512-VfxadyCECXgQlkoEAjeghAr5gY3Hf+IKjKb+X8tGVDtveCjN+USwprd2q3QXBR9T1+x2DG0XZF5/w+7HAtSaXA==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + "1.0.0": { + version: "1.0.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-1.0.0.tgz", + shasum: "5287122f71691d4505b18ff2258dc400a5b23847", + integrity: + "sha512-6OlbjTSfBWyqM8oFO7TYc6DgCIiT6vgCiZ973GDA98xVf+DOXVZvYLzRyi0HEJy5J31/69lel4AeY78OaasBLQ==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "node test.js" }, + deprecated: null, + }, + "3.2.0": { + version: "3.2.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-3.2.0.tgz", + shasum: "84b8e8f4f8c579f938e35e2cc7024907e0090851", + integrity: + "sha512-4TgkVUsmmu7oCSyGBm5FvfMoACuoh9EOidm7V5/J2X2djAwwt57qb3F2KMP2ITqODTCSwb+YRV+0Zqrv18k/hw==", + }, + bin: null, + dependencies: { xregexp: "^4.2.4" }, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + "6.0.0": { + version: "6.0.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-6.0.0.tgz", + shasum: "8cad4d916fde5c41a264a43d0ecc56fe3d31749e", + integrity: + "sha512-Fv96DCsdOgB6mdGl67MT5JaTNKRzrzill5OH5s8bjYJXVlcXyPYGyPsUkWyGV5p1TXI5esYIYMMeDJL0hEIwaA==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava && tsd" }, + deprecated: null, + }, + }, + "dist-tags": { latest: "6.0.0" }, + }, + nonJsrPackages: { + npm: { + "ansi-regex": { + "3.0.1": { + full: "ansi-regex@3.0.1", + registry: undefined, + scope: undefined, + name: "ansi-regex", + version: "3.0.1", + suffix: undefined, + }, + "5.0.1": { + full: "ansi-regex@5.0.1", + registry: undefined, + scope: undefined, + name: "ansi-regex", + version: "5.0.1", + suffix: undefined, + }, + }, + "ansi-styles": { + "4.3.0": { + full: "ansi-styles@4.3.0", + registry: undefined, + scope: undefined, + name: "ansi-styles", + version: "4.3.0", + suffix: undefined, + }, + }, + camelcase: { + "5.3.1": { + full: "camelcase@5.3.1", + registry: undefined, + scope: undefined, + name: "camelcase", + version: "5.3.1", + suffix: undefined, + }, + }, + cliui: { + "6.0.0": { + full: "cliui@6.0.0", + registry: undefined, + scope: undefined, + name: "cliui", + version: "6.0.0", + suffix: undefined, + }, + }, + "color-convert": { + "2.0.1": { + full: "color-convert@2.0.1", + registry: undefined, + scope: undefined, + name: "color-convert", + version: "2.0.1", + suffix: undefined, + }, + }, + "color-name": { + "1.1.4": { + full: "color-name@1.1.4", + registry: undefined, + scope: undefined, + name: "color-name", + version: "1.1.4", + suffix: undefined, + }, + }, + cowsay: { + "1.6.0": { + full: "cowsay@1.6.0", + registry: undefined, + scope: undefined, + name: "cowsay", + version: "1.6.0", + suffix: undefined, + }, + }, + decamelize: { + "1.2.0": { + full: "decamelize@1.2.0", + registry: undefined, + scope: undefined, + name: "decamelize", + version: "1.2.0", + suffix: undefined, + }, + }, + "emoji-regex": { + "8.0.0": { + full: "emoji-regex@8.0.0", + registry: undefined, + scope: undefined, + name: "emoji-regex", + version: "8.0.0", + suffix: undefined, + }, + }, + "find-up": { + "4.1.0": { + full: "find-up@4.1.0", + registry: undefined, + scope: undefined, + name: "find-up", + version: "4.1.0", + suffix: undefined, + }, + }, + "get-caller-file": { + "2.0.5": { + full: "get-caller-file@2.0.5", + registry: undefined, + scope: undefined, + name: "get-caller-file", + version: "2.0.5", + suffix: undefined, + }, + }, + "get-stdin": { + "8.0.0": { + full: "get-stdin@8.0.0", + registry: undefined, + scope: undefined, + name: "get-stdin", + version: "8.0.0", + suffix: undefined, + }, + }, + "is-fullwidth-code-point": { + "2.0.0": { + full: "is-fullwidth-code-point@2.0.0", + registry: undefined, + scope: undefined, + name: "is-fullwidth-code-point", + version: "2.0.0", + suffix: undefined, + }, + "3.0.0": { + full: "is-fullwidth-code-point@3.0.0", + registry: undefined, + scope: undefined, + name: "is-fullwidth-code-point", + version: "3.0.0", + suffix: undefined, + }, + }, + "locate-path": { + "5.0.0": { + full: "locate-path@5.0.0", + registry: undefined, + scope: undefined, + name: "locate-path", + version: "5.0.0", + suffix: undefined, + }, + }, + "p-limit": { + "2.3.0": { + full: "p-limit@2.3.0", + registry: undefined, + scope: undefined, + name: "p-limit", + version: "2.3.0", + suffix: undefined, + }, + }, + "p-locate": { + "4.1.0": { + full: "p-locate@4.1.0", + registry: undefined, + scope: undefined, + name: "p-locate", + version: "4.1.0", + suffix: undefined, + }, + }, + "p-try": { + "2.2.0": { + full: "p-try@2.2.0", + registry: undefined, + scope: undefined, + name: "p-try", + version: "2.2.0", + suffix: undefined, + }, + }, + "path-exists": { + "4.0.0": { + full: "path-exists@4.0.0", + registry: undefined, + scope: undefined, + name: "path-exists", + version: "4.0.0", + suffix: undefined, + }, + }, + "require-directory": { + "2.1.1": { + full: "require-directory@2.1.1", + registry: undefined, + scope: undefined, + name: "require-directory", + version: "2.1.1", + suffix: undefined, + }, + }, + "require-main-filename": { + "2.0.0": { + full: "require-main-filename@2.0.0", + registry: undefined, + scope: undefined, + name: "require-main-filename", + version: "2.0.0", + suffix: undefined, + }, + }, + "set-blocking": { + "2.0.0": { + full: "set-blocking@2.0.0", + registry: undefined, + scope: undefined, + name: "set-blocking", + version: "2.0.0", + suffix: undefined, + }, + }, + "string-width": { + "2.1.1": { + full: "string-width@2.1.1", + registry: undefined, + scope: undefined, + name: "string-width", + version: "2.1.1", + suffix: undefined, + }, + "4.2.3": { + full: "string-width@4.2.3", + registry: undefined, + scope: undefined, + name: "string-width", + version: "4.2.3", + suffix: undefined, + }, + }, + "strip-ansi": { + "4.0.0": { + full: "strip-ansi@4.0.0", + registry: undefined, + scope: undefined, + name: "strip-ansi", + version: "4.0.0", + suffix: undefined, + }, + "6.0.1": { + full: "strip-ansi@6.0.1", + registry: undefined, + scope: undefined, + name: "strip-ansi", + version: "6.0.1", + suffix: undefined, + }, + }, + "strip-final-newline": { + "2.0.0": { + full: "strip-final-newline@2.0.0", + registry: undefined, + scope: undefined, + name: "strip-final-newline", + version: "2.0.0", + suffix: undefined, + }, + }, + "which-module": { + "2.0.1": { + full: "which-module@2.0.1", + registry: undefined, + scope: undefined, + name: "which-module", + version: "2.0.1", + suffix: undefined, + }, + }, + "wrap-ansi": { + "6.2.0": { + full: "wrap-ansi@6.2.0", + registry: undefined, + scope: undefined, + name: "wrap-ansi", + version: "6.2.0", + suffix: undefined, + }, + }, + y18n: { + "4.0.3": { + full: "y18n@4.0.3", + registry: undefined, + scope: undefined, + name: "y18n", + version: "4.0.3", + suffix: undefined, + }, + }, + "yargs-parser": { + "18.1.3": { + full: "yargs-parser@18.1.3", + registry: undefined, + scope: undefined, + name: "yargs-parser", + version: "18.1.3", + suffix: undefined, + }, + }, + yargs: { + "15.4.1": { + full: "yargs@15.4.1", + registry: undefined, + scope: undefined, + name: "yargs", + version: "15.4.1", + suffix: undefined, + }, + }, + }, + }, + registry: "npm", + }, + expectedValue: { + name: "decamelize", + versions: { + "1.2.0": { + version: "1.2.0", + dist: { + tarball: + "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + shasum: "f6534d15148269b20352e7bee26f501f9a191290", + integrity: + "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + }, + bin: null, + dependencies: {}, + optionalDependencies: {}, + peerDependencies: {}, + peerDependenciesMeta: {}, + os: [], + cpu: [], + scripts: { test: "xo && ava" }, + deprecated: null, + }, + }, + "dist-tags": {}, + }, + }, + ]; + testFactory( + assertEquals, + (args: Args) => + pruneRegistryJson(args.registryJson, args.nonJsrPackages, args.registry), + fixtures + )(); +}); diff --git a/pkgs/build-support/deno/fetch-deno-deps/prune-registries.ts b/pkgs/build-support/deno/fetch-deno-deps/prune-registries.ts new file mode 100644 index 0000000000000..0a8b12d0a4a9c --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/prune-registries.ts @@ -0,0 +1,346 @@ +#!/usr/bin/env deno +import { parseArgs } from "@std/cli/parse-args"; +import { walkSync } from "@std/fs/walk"; + +/** + * NOTE: The problem this script solves, is that in every npm dependency in the deno cache + * is a registry.json file, which serves as a sort of local registry cache for the deno cli. + * Such a file looks like this (with deno v2.1.4): + * ```json + * { + * "name": "@floating-ui/core", + * "versions": { + * "0.7.0": { ... }, + * "1.6.0": { ... }, + * "0.1.2": { ... }, + * ... + * }, + * "dist-tags": { "latest": "1.7.0" } + * } + * ``` + * The deno cli will look into this file when called to look up if the required versions are there. + * The problem is that the available versions for a package change over time. The registry.json files + * need to be part of the fixed output derivation, which will eventually change the hash of the FOD, + * if all those unwanted versions aren't pruned. + * + * On top of that a similar thing happens for jsr packages in the vendor directory + * with `meta.json` files. These also need to be pruned. + * Such a file looks like this (with deno v2.1.4): + * ```json + * { + * "scope": "std", + * "name": "internal", + * "latest": "1.0.6", + * "versions": { + * "0.202.0": {}, + * "1.0.1": {}, + * "0.225.0": { + * "yanked": true + * }, + * } + * ``` + */ + +export type PackageSpecifiers = { + [packageIdent: string]: string; +}; + +export type LockJson = { + specifiers: PackageSpecifiers; + version: string; + workspace: any; + [registry: string]: any; +}; + +export type Config = { + lockJson: LockJson; + cachePath: string; + vendorPath: string; +}; + +export type PackageInfo = { + full: string; + registry: string | undefined; + scope: string | undefined; + name: string; + version: string; + suffix: string | undefined; +}; + +export type PackagesByRegistry = { + [registry: string]: { + [packageName: string]: { + [version: string]: PackageInfo; + }; + }; +}; + +export type PathsByRegistry = { + [packageRegistry: string]: string[]; +}; + +export type RegistryJson = { + "dist-tags": any; + "_deno.etag": string; + versions: { [version: string]: any }; + name: string; +}; + +export type MetaJson = { + scope: string; + name: string; + latest: string; + versions: { + [version: string]: any; + }; +}; + +export function getConfig(): Config { + const flags = parseArgs(Deno.args, { + string: ["lock-json", "cache-path", "vendor-path"], + }); + + if (!flags["lock-json"]) { + throw "--lock-json flag not set but required"; + } + if (!flags["cache-path"]) { + throw "--cache-path flag not set but required"; + } + if (!flags["vendor-path"]) { + throw "--vendor-path flag not set but required"; + } + + const lockJson = JSON.parse( + new TextDecoder("utf-8").decode(Deno.readFileSync(flags["lock-json"])) + ); + if (!lockJson) { + throw `could not parse lockJson at ${flags["lock-json"]}`; + } + + return { + lockJson, + cachePath: flags["cache-path"], + vendorPath: flags["vendor-path"], + }; +} + +export function getAllPackageRegistries( + specifiers: PackageSpecifiers +): Set { + return Object.keys(specifiers).reduce((acc: Set, v: string) => { + const s = v.split(":"); + if (s.length !== 2) { + throw "unexpected registry format"; + } + const registry = s[0]; + acc.add(registry); + return acc; + }, new Set()); +} + +export function parsePackageSpecifier(packageSpecifier: string): PackageInfo { + const match = + /^((?.*):)?((?@.*?)\/)?(?.*?)@(?.*?)(?_.*)?$/.exec( + packageSpecifier + ); + if ( + match !== null && + match.groups?.name !== undefined && + match.groups?.version !== undefined + ) { + return { + // npm:@amazn/style-dictionary@4.2.4_prettier@3.5.3 + full: match[0], + // npm + registry: match.groups?.registry, + // @amazn + scope: match.groups?.scope, + // style-dictionary + name: match.groups?.name, + // 4.2.4 + version: match.groups?.version, + // _prettier@3.5.3 + suffix: match.groups?.suffix, + }; + } + + throw "unexpected package specifier format"; +} + +export function getScopedName(name: string, scope?: string): string { + if (scope !== undefined) { + return `${scope[0] === "@" ? "" : "@"}${scope}/${name}`; + } + return name; +} + +export function getAllPackagesByPackageRegistry( + lockJson: LockJson, + registries: Set +): PackagesByRegistry { + const result: PackagesByRegistry = {}; + for (const registry of Array.from(registries)) { + const packageInfosOfRegistries = Object.keys(lockJson[registry]).map( + parsePackageSpecifier + ); + result[registry] = {}; + for (const packageInfo of packageInfosOfRegistries) { + const scopedName = getScopedName(packageInfo.name, packageInfo.scope); + if (result[registry][scopedName] === undefined) { + result[registry][scopedName] = {}; + } + result[registry][scopedName][packageInfo.version] = packageInfo; + } + } + return result; +} + +export function findRegistryJsonPaths( + cachePath: string, + nonJsrPackages: PackagesByRegistry +): PathsByRegistry { + const result: PathsByRegistry = {}; + for (const registry of Object.keys(nonJsrPackages)) { + const path = `${cachePath}/${registry}`; + const registryJsonPaths = Array.from(walkSync(path)) + .filter((v) => v.name === "registry.json") + .map((v) => v.path); + result[registry] = registryJsonPaths; + } + return result; +} + +export function pruneRegistryJson( + registryJson: RegistryJson, + nonJsrPackages: PackagesByRegistry, + registry: string +) { + const scopedName = registryJson.name; + const packageInfoByVersion = nonJsrPackages[registry][scopedName]; + if (!packageInfoByVersion) { + throw `could not find key "${scopedName}" in\n${Object.keys( + nonJsrPackages[registry] + )}`; + } + + const newRegistryJson: RegistryJson = { + ...registryJson, + "_deno.etag": "", + "dist-tags": {}, + versions: {}, + }; + + for (const version of Object.keys(packageInfoByVersion)) { + newRegistryJson.versions[version] = registryJson.versions[version]; + } + + return newRegistryJson; +} + +export function pruneRegistryJsonFiles( + nonJsrPackages: PackagesByRegistry, + registryJsonPathsByRegistry: PathsByRegistry +): void { + for (const [registry, paths] of Object.entries(registryJsonPathsByRegistry)) { + for (const path of paths) { + const registryJson: RegistryJson = JSON.parse( + new TextDecoder("utf-8").decode(Deno.readFileSync(path)) + ); + + const newRegistryJson = pruneRegistryJson( + registryJson, + nonJsrPackages, + registry + ); + + Deno.writeFileSync( + path, + new TextEncoder().encode(JSON.stringify(newRegistryJson)) + ); + } + } +} + +export function findMetaJsonPaths( + vendorPath: string, + jsrPackages: PackagesByRegistry +): PathsByRegistry { + const result: PathsByRegistry = {}; + for (const registry of Object.keys(jsrPackages)) { + const path = `${vendorPath}`; + const metaJsonPaths = Array.from(walkSync(path)) + .filter((v) => v.name === "meta.json") + .map((v) => v.path); + result[registry] = metaJsonPaths; + } + return result; +} + +export function pruneMetaJson( + metaJson: MetaJson, + jsrPackages: PackagesByRegistry, + registry: string +): MetaJson { + const scopedName = getScopedName(metaJson.name, metaJson.scope); + const packageInfoByVersion = jsrPackages[registry][scopedName]; + if (!packageInfoByVersion) { + throw `could not find key "${scopedName}" in\n${Object.keys( + jsrPackages[registry] + )}`; + } + const newMetaJson: MetaJson = { + ...metaJson, + latest: "", + versions: {}, + }; + + for (const version of Object.keys(packageInfoByVersion)) { + newMetaJson.versions[version] = metaJson.versions[version]; + } + return newMetaJson; +} + +export function pruneMetaJsonFiles( + jsrPackages: PackagesByRegistry, + metaJsonPathsByRegistry: PathsByRegistry +): void { + for (const [registry, paths] of Object.entries(metaJsonPathsByRegistry)) { + for (const path of paths) { + const metaJson: MetaJson = JSON.parse( + new TextDecoder("utf-8").decode(Deno.readFileSync(path)) + ); + + const newMetaJson = pruneMetaJson(metaJson, jsrPackages, registry); + + Deno.writeFileSync( + path, + new TextEncoder().encode(JSON.stringify(newMetaJson)) + ); + } + } +} + +function main() { + const config = getConfig(); + const registries = getAllPackageRegistries(config.lockJson.specifiers); + const packages = getAllPackagesByPackageRegistry(config.lockJson, registries); + + const jsrPackages = { + jsr: structuredClone(packages.jsr), + } satisfies PackagesByRegistry; + delete packages.jsr; + const nonJsrPackages = packages; + + const metaJsonpaths = findMetaJsonPaths(config.vendorPath, jsrPackages); + pruneMetaJsonFiles(jsrPackages, metaJsonpaths); + + const registryJsonPaths = findRegistryJsonPaths( + config.cachePath, + nonJsrPackages + ); + pruneRegistryJsonFiles(nonJsrPackages, registryJsonPaths); +} + +if (import.meta.main) { + main(); +} diff --git a/pkgs/build-support/deno/fetch-deno-deps/shell.nix b/pkgs/build-support/deno/fetch-deno-deps/shell.nix new file mode 100644 index 0000000000000..c81e60e40d1ed --- /dev/null +++ b/pkgs/build-support/deno/fetch-deno-deps/shell.nix @@ -0,0 +1,7 @@ +let + pkgs = import ../../../../default.nix { }; +in +pkgs.mkShell { + buildInputs = [ pkgs.deno ]; + DENO_DIR = "./.deno"; +} diff --git a/pkgs/by-name/de/denort/package.nix b/pkgs/by-name/de/denort/package.nix new file mode 100644 index 0000000000000..45069e059d113 --- /dev/null +++ b/pkgs/by-name/de/denort/package.nix @@ -0,0 +1,30 @@ +{ + deno, + lib, +}: +deno.overrideAttrs ( + final: prev: { + pname = "denort"; + buildAndTestSubdir = "cli/rt"; + postInstall = ""; + installCheckPhase = ""; + passthru = { }; + meta = with lib; { + homepage = "https://deno.land/"; + changelog = "https://github.com/denoland/deno/releases/tag/v${final.version}"; + description = "Slim version of the deno runtime, usually bundled with deno projects into standalone binaries"; + license = licenses.mit; + mainProgram = "denort"; + maintainers = with maintainers; [ + jk + ofalvai + ]; + platforms = [ + "x86_64-linux" + "aarch64-linux" + "x86_64-darwin" + "aarch64-darwin" + ]; + }; + } +) diff --git a/pkgs/test/build-deno-package/.gitignore b/pkgs/test/build-deno-package/.gitignore new file mode 100644 index 0000000000000..cb92b2a7589f0 --- /dev/null +++ b/pkgs/test/build-deno-package/.gitignore @@ -0,0 +1,3 @@ +.deno/ +node_modules/ +vendor/ diff --git a/pkgs/test/build-deno-package/binaries/default.nix b/pkgs/test/build-deno-package/binaries/default.nix new file mode 100644 index 0000000000000..349bf1263dec4 --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/default.nix @@ -0,0 +1,33 @@ +{ nix-gitignore, buildDenoPackage }: +{ + with-npm-linux = buildDenoPackage rec { + pname = "test-deno-build-binaries-with-npm-${targetSystem}"; + version = "0.1.0"; + denoDepsHash = "sha256-k2js/8XsxGVu83rGMJed457orraue8WUZF+JUMMfhVQ="; + src = nix-gitignore.gitignoreSource [ ] ./with-npm; + binaryEntrypointPath = "./main.ts"; + targetSystem = "x86_64-linux"; + }; + without-npm-linux = buildDenoPackage rec { + pname = "test-deno-build-binaries-without-npm-${targetSystem}"; + version = "0.1.0"; + denoDepsHash = "sha256-keshKcgawVcuSGNYAIepUrRl7iqpp0ExRJag4aiV18c="; + src = nix-gitignore.gitignoreSource [ ] ./without-npm; + binaryEntrypointPath = "./main.ts"; + targetSystem = "x86_64-linux"; + }; + # mac = + # let + # targetSystem = "aarch64-darwin"; + # macpkgs = import ../../../../default.nix { crossSystem = { config = "arm64-apple-darwin"; };}; + # in + # buildDenoPackage { + # pname = "test-deno-build-binaries-${targetSystem}"; + # version = "0.1.0"; + # denoDepsHash = ""; + # src = nix-gitignore.gitignoreSource [ ] ./.; + # binaryEntrypointPath = "./main.ts"; + # denortPackage = macpkgs.denort; + # inherit targetSystem; + # }; +} diff --git a/pkgs/test/build-deno-package/binaries/with-npm/.gitignore b/pkgs/test/build-deno-package/binaries/with-npm/.gitignore new file mode 100644 index 0000000000000..cb92b2a7589f0 --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/with-npm/.gitignore @@ -0,0 +1,3 @@ +.deno/ +node_modules/ +vendor/ diff --git a/pkgs/test/build-deno-package/binaries/with-npm/deno.json b/pkgs/test/build-deno-package/binaries/with-npm/deno.json new file mode 100644 index 0000000000000..5e8a1c53d6a20 --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/with-npm/deno.json @@ -0,0 +1,13 @@ +{ + "name": "binary build", + "tasks": { + "build": "deno run --allow-all main.ts" + }, + "imports": { + "@luca/cases": "jsr:@luca/cases@1.0.0", + "@std/cli": "jsr:@std/cli@1.0.17", + "cowsay": "npm:cowsay@1.6.0", + "cases": "https://deno.land/x/case@2.2.0/mod.ts" + }, + "vendor": true +} diff --git a/pkgs/test/build-deno-package/binaries/with-npm/deno.lock b/pkgs/test/build-deno-package/binaries/with-npm/deno.lock new file mode 100644 index 0000000000000..56656abe3767c --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/with-npm/deno.lock @@ -0,0 +1,215 @@ +{ + "version": "5", + "specifiers": { + "jsr:@luca/cases@1.0.0": "1.0.0", + "jsr:@std/cli@1.0.17": "1.0.17", + "npm:cowsay@1.6.0": "1.6.0" + }, + "jsr": { + "@luca/cases@1.0.0": { + "integrity": "b5f9471f1830595e63a2b7d62821ac822a19e16899e6584799be63f17a1fbc30" + }, + "@std/cli@1.0.17": { + "integrity": "e15b9abe629e17be90cc6216327f03a29eae613365f1353837fa749aad29ce7b" + } + }, + "npm": { + "ansi-regex@3.0.1": { + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" + }, + "ansi-regex@5.0.1": { + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles@4.3.0": { + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": [ + "color-convert" + ] + }, + "camelcase@5.3.1": { + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui@6.0.0": { + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": [ + "string-width@4.2.3", + "strip-ansi@6.0.1", + "wrap-ansi" + ] + }, + "color-convert@2.0.1": { + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": [ + "color-name" + ] + }, + "color-name@1.1.4": { + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cowsay@1.6.0": { + "integrity": "sha512-8C4H1jdrgNusTQr3Yu4SCm+ZKsAlDFbpa0KS0Z3im8ueag+9pGOf3CrioruvmeaW/A5oqg9L0ar6qeftAh03jw==", + "dependencies": [ + "get-stdin", + "string-width@2.1.1", + "strip-final-newline", + "yargs" + ], + "bin": true + }, + "decamelize@1.2.0": { + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + }, + "emoji-regex@8.0.0": { + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "find-up@4.1.0": { + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": [ + "locate-path", + "path-exists" + ] + }, + "get-caller-file@2.0.5": { + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stdin@8.0.0": { + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==" + }, + "is-fullwidth-code-point@2.0.0": { + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + }, + "is-fullwidth-code-point@3.0.0": { + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "locate-path@5.0.0": { + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": [ + "p-locate" + ] + }, + "p-limit@2.3.0": { + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": [ + "p-try" + ] + }, + "p-locate@4.1.0": { + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": [ + "p-limit" + ] + }, + "p-try@2.2.0": { + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists@4.0.0": { + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "require-directory@2.1.1": { + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-main-filename@2.0.0": { + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "set-blocking@2.0.0": { + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "string-width@2.1.1": { + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dependencies": [ + "is-fullwidth-code-point@2.0.0", + "strip-ansi@4.0.0" + ] + }, + "string-width@4.2.3": { + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": [ + "emoji-regex", + "is-fullwidth-code-point@3.0.0", + "strip-ansi@6.0.1" + ] + }, + "strip-ansi@4.0.0": { + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dependencies": [ + "ansi-regex@3.0.1" + ] + }, + "strip-ansi@6.0.1": { + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": [ + "ansi-regex@5.0.1" + ] + }, + "strip-final-newline@2.0.0": { + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "which-module@2.0.1": { + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "wrap-ansi@6.2.0": { + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": [ + "ansi-styles", + "string-width@4.2.3", + "strip-ansi@6.0.1" + ] + }, + "y18n@4.0.3": { + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs-parser@18.1.3": { + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": [ + "camelcase", + "decamelize" + ] + }, + "yargs@15.4.1": { + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": [ + "cliui", + "decamelize", + "find-up", + "get-caller-file", + "require-directory", + "require-main-filename", + "set-blocking", + "string-width@4.2.3", + "which-module", + "y18n", + "yargs-parser" + ] + } + }, + "remote": { + "https://deno.land/x/case@2.2.0/camelCase.ts": "b9a4cf361a7c9740ecb75e00b5e2c006bd4e5d40e442d26c5f2760286fa66796", + "https://deno.land/x/case@2.2.0/constantCase.ts": "c698fc32f00cd267c1684b1d413d784260d7e7798f2bf506803e418497d839b5", + "https://deno.land/x/case@2.2.0/dotCase.ts": "03ae55d5635e6a4ca894a003d9297cd9cd283af2e7d761dd3de13663849a9423", + "https://deno.land/x/case@2.2.0/headerCase.ts": "3f6c8ab2ab30a88147326bce28a00d1189ec98ab61c83ab72ce79e852afddc4a", + "https://deno.land/x/case@2.2.0/lowerCase.ts": "d75eb55cadfa589f9f2a973924a8a209054477d9574da669410f4d817ab25b41", + "https://deno.land/x/case@2.2.0/lowerFirstCase.ts": "b001efbf2d715b53d066b22cdbf8eda7f99aa7108e3d12fb02f80d499bae93d9", + "https://deno.land/x/case@2.2.0/mod.ts": "28b0b1329c7b18730799ac05627a433d9547c04b9bfb429116247c60edecd97b", + "https://deno.land/x/case@2.2.0/normalCase.ts": "085c8b6f9d69283c8b86f2e504d43278c2be8b7e56a3ed8d4a5f395e398bdc29", + "https://deno.land/x/case@2.2.0/paramCase.ts": "a234c9c17dfbaddee647b6571c2c90e8f6530123fed26c4546f4063d67c1609f", + "https://deno.land/x/case@2.2.0/pascalCase.ts": "4b3ef0a68173871a821d306d4067e8f72d42aeeef1eea6aeab30af6bfa3d7427", + "https://deno.land/x/case@2.2.0/pathCase.ts": "330a34b4df365b0291d8e36158235340131730aae6f6add66962ed2d0fbead4a", + "https://deno.land/x/case@2.2.0/sentenceCase.ts": "b312cef147a13b58ffdf3c36bf55b33aa8322c91f4aa9b32318f3911bb92327f", + "https://deno.land/x/case@2.2.0/snakeCase.ts": "e5ac1e08532ca397aa3150a0a3255d59f63a186d934e5094a8ffd24cbca7f955", + "https://deno.land/x/case@2.2.0/swapCase.ts": "bb03742fcf613f733890680ceca1b39b65ed290f36a317fcd47edd517c4e0e1e", + "https://deno.land/x/case@2.2.0/titleCase.ts": "c287131ea2c955e67cdd5cf604de96d31a8e2813305759922b9ed27e3be354e7", + "https://deno.land/x/case@2.2.0/types.ts": "8e2bd6edaa27c0d1972c0d5b76698564740f37b4d3787d58d1fb5f48de611e61", + "https://deno.land/x/case@2.2.0/upperCase.ts": "6cca267bb04d098bf4abf21e42e60c3e68ede89b12e525643c6b6eff3e10de34", + "https://deno.land/x/case@2.2.0/upperFirstCase.ts": "b964c2d8d3a85c78cd35f609135cbde99d84b9522a21470336b5af80a37facbd", + "https://deno.land/x/case@2.2.0/vendor/camelCaseRegexp.ts": "7d9ff02aad4ab6429eeab7c7353f7bcdd6cc5909a8bd3dda97918c8bbb7621ae", + "https://deno.land/x/case@2.2.0/vendor/camelCaseUpperRegexp.ts": "292de54a698370f90adcdf95727993d09888b7f33d17f72f8e54ba75f7791787", + "https://deno.land/x/case@2.2.0/vendor/nonWordRegexp.ts": "c1a052629a694144b48c66b0175a22a83f4d61cb40f4e45293fc5d6b123f927e" + }, + "workspace": { + "dependencies": [ + "jsr:@luca/cases@1.0.0", + "jsr:@std/cli@1.0.17", + "npm:cowsay@1.6.0" + ] + } +} diff --git a/pkgs/test/build-deno-package/binaries/with-npm/main.ts b/pkgs/test/build-deno-package/binaries/with-npm/main.ts new file mode 100644 index 0000000000000..0d8b922bac22c --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/with-npm/main.ts @@ -0,0 +1,15 @@ +import { camelCase } from "@luca/cases"; +import { say } from "cowsay"; +import { pascalCase } from "cases"; +import { parseArgs } from "@std/cli"; + +const flags = parseArgs(Deno.args, { + string: ["text"], +}); + +if (!flags.text) { + throw "--text required but not specified"; +} + +console.log(camelCase(say({ text: flags.text }))); +console.log(pascalCase(say({ text: flags.text }))); diff --git a/pkgs/test/build-deno-package/binaries/without-npm/.gitignore b/pkgs/test/build-deno-package/binaries/without-npm/.gitignore new file mode 100644 index 0000000000000..cb92b2a7589f0 --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/without-npm/.gitignore @@ -0,0 +1,3 @@ +.deno/ +node_modules/ +vendor/ diff --git a/pkgs/test/build-deno-package/binaries/without-npm/deno.json b/pkgs/test/build-deno-package/binaries/without-npm/deno.json new file mode 100644 index 0000000000000..c9a829c9c1abf --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/without-npm/deno.json @@ -0,0 +1,12 @@ +{ + "name": "binary build", + "tasks": { + "build": "deno run --allow-all main.ts" + }, + "imports": { + "@luca/cases": "jsr:@luca/cases@1.0.0", + "@std/cli": "jsr:@std/cli@1.0.17", + "cases": "https://deno.land/x/case@2.2.0/mod.ts" + }, + "vendor": true +} diff --git a/pkgs/test/build-deno-package/binaries/without-npm/deno.lock b/pkgs/test/build-deno-package/binaries/without-npm/deno.lock new file mode 100644 index 0000000000000..3f40f2593aa50 --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/without-npm/deno.lock @@ -0,0 +1,44 @@ +{ + "version": "5", + "specifiers": { + "jsr:@luca/cases@1.0.0": "1.0.0", + "jsr:@std/cli@1.0.17": "1.0.17" + }, + "jsr": { + "@luca/cases@1.0.0": { + "integrity": "b5f9471f1830595e63a2b7d62821ac822a19e16899e6584799be63f17a1fbc30" + }, + "@std/cli@1.0.17": { + "integrity": "e15b9abe629e17be90cc6216327f03a29eae613365f1353837fa749aad29ce7b" + } + }, + "remote": { + "https://deno.land/x/case@2.2.0/camelCase.ts": "b9a4cf361a7c9740ecb75e00b5e2c006bd4e5d40e442d26c5f2760286fa66796", + "https://deno.land/x/case@2.2.0/constantCase.ts": "c698fc32f00cd267c1684b1d413d784260d7e7798f2bf506803e418497d839b5", + "https://deno.land/x/case@2.2.0/dotCase.ts": "03ae55d5635e6a4ca894a003d9297cd9cd283af2e7d761dd3de13663849a9423", + "https://deno.land/x/case@2.2.0/headerCase.ts": "3f6c8ab2ab30a88147326bce28a00d1189ec98ab61c83ab72ce79e852afddc4a", + "https://deno.land/x/case@2.2.0/lowerCase.ts": "d75eb55cadfa589f9f2a973924a8a209054477d9574da669410f4d817ab25b41", + "https://deno.land/x/case@2.2.0/lowerFirstCase.ts": "b001efbf2d715b53d066b22cdbf8eda7f99aa7108e3d12fb02f80d499bae93d9", + "https://deno.land/x/case@2.2.0/mod.ts": "28b0b1329c7b18730799ac05627a433d9547c04b9bfb429116247c60edecd97b", + "https://deno.land/x/case@2.2.0/normalCase.ts": "085c8b6f9d69283c8b86f2e504d43278c2be8b7e56a3ed8d4a5f395e398bdc29", + "https://deno.land/x/case@2.2.0/paramCase.ts": "a234c9c17dfbaddee647b6571c2c90e8f6530123fed26c4546f4063d67c1609f", + "https://deno.land/x/case@2.2.0/pascalCase.ts": "4b3ef0a68173871a821d306d4067e8f72d42aeeef1eea6aeab30af6bfa3d7427", + "https://deno.land/x/case@2.2.0/pathCase.ts": "330a34b4df365b0291d8e36158235340131730aae6f6add66962ed2d0fbead4a", + "https://deno.land/x/case@2.2.0/sentenceCase.ts": "b312cef147a13b58ffdf3c36bf55b33aa8322c91f4aa9b32318f3911bb92327f", + "https://deno.land/x/case@2.2.0/snakeCase.ts": "e5ac1e08532ca397aa3150a0a3255d59f63a186d934e5094a8ffd24cbca7f955", + "https://deno.land/x/case@2.2.0/swapCase.ts": "bb03742fcf613f733890680ceca1b39b65ed290f36a317fcd47edd517c4e0e1e", + "https://deno.land/x/case@2.2.0/titleCase.ts": "c287131ea2c955e67cdd5cf604de96d31a8e2813305759922b9ed27e3be354e7", + "https://deno.land/x/case@2.2.0/types.ts": "8e2bd6edaa27c0d1972c0d5b76698564740f37b4d3787d58d1fb5f48de611e61", + "https://deno.land/x/case@2.2.0/upperCase.ts": "6cca267bb04d098bf4abf21e42e60c3e68ede89b12e525643c6b6eff3e10de34", + "https://deno.land/x/case@2.2.0/upperFirstCase.ts": "b964c2d8d3a85c78cd35f609135cbde99d84b9522a21470336b5af80a37facbd", + "https://deno.land/x/case@2.2.0/vendor/camelCaseRegexp.ts": "7d9ff02aad4ab6429eeab7c7353f7bcdd6cc5909a8bd3dda97918c8bbb7621ae", + "https://deno.land/x/case@2.2.0/vendor/camelCaseUpperRegexp.ts": "292de54a698370f90adcdf95727993d09888b7f33d17f72f8e54ba75f7791787", + "https://deno.land/x/case@2.2.0/vendor/nonWordRegexp.ts": "c1a052629a694144b48c66b0175a22a83f4d61cb40f4e45293fc5d6b123f927e" + }, + "workspace": { + "dependencies": [ + "jsr:@luca/cases@1.0.0", + "jsr:@std/cli@1.0.17" + ] + } +} diff --git a/pkgs/test/build-deno-package/binaries/without-npm/main.ts b/pkgs/test/build-deno-package/binaries/without-npm/main.ts new file mode 100644 index 0000000000000..2bfff532685c8 --- /dev/null +++ b/pkgs/test/build-deno-package/binaries/without-npm/main.ts @@ -0,0 +1,14 @@ +import { camelCase } from "@luca/cases"; +import { pascalCase } from "cases"; +import { parseArgs } from "@std/cli"; + +const flags = parseArgs(Deno.args, { + string: ["text"], +}); + +if (!flags.text) { + throw "--text required but not specified"; +} + +console.log(camelCase(flags.text)); +console.log(pascalCase(flags.text)); diff --git a/pkgs/test/build-deno-package/default.nix b/pkgs/test/build-deno-package/default.nix new file mode 100644 index 0000000000000..dd72e45292cef --- /dev/null +++ b/pkgs/test/build-deno-package/default.nix @@ -0,0 +1,4 @@ +{ pkgs }: +(pkgs.callPackage ./workspaces { }) +// (pkgs.callPackage ./binaries { }) +// (pkgs.callPackage ./external { }) diff --git a/pkgs/test/build-deno-package/external/default.nix b/pkgs/test/build-deno-package/external/default.nix new file mode 100644 index 0000000000000..b8691599e784f --- /dev/null +++ b/pkgs/test/build-deno-package/external/default.nix @@ -0,0 +1,67 @@ +{ fetchFromGitHub, buildDenoPackage }: +{ + readma-cli-linux = buildDenoPackage rec { + pname = "readma-cli"; + version = "2.11.0"; + denoDepsHash = "sha256-ixet3k6OEWfxVnN/V7vk4qDvoXjA+6bU/JjXk76aThE="; + src = fetchFromGitHub { + owner = "elcoosp"; + repo = "readma"; + rev = "${version}"; + hash = "sha256-FVQTn+r7Ztj02vNvqFZIRIsokWeo1tPfFYffK2tvxjA="; + }; + denoInstallFlags = [ + "--allow-scripts" + "--frozen" + "--cached-only" + "--entrypoint" + "./cli/mod.ts" + ]; + binaryEntrypointPath = "./cli/mod.ts"; + targetSystem = "x86_64-linux"; + }; + fresh-init-cli-linux = buildDenoPackage { + pname = "fresh-init-cli"; + version = ""; + denoDepsHash = "sha256-WlMv431qTt3gw0w/V7lG8LnLkEt8VW1fNpyclzBwMcw="; + src = fetchFromGitHub { + owner = "denoland"; + repo = "fresh"; + rev = "c7c341b695bad8d0f3e3575e5fa9c82e0fa28bd4"; + hash = "sha256-bC4akr4Wt4sRqGkgjNuXztW8Q6YBLBsbuIOhsXH8NQU="; + }; + denoWorkspacePath = "./init"; + binaryEntrypointPath = "./src/mod.ts"; + targetSystem = "x86_64-linux"; + }; + invidious-companion-cli-linux = buildDenoPackage { + pname = "invidious-companion-cli"; + version = ""; + denoDepsHash = "sha256-sPcvVaVb4VsLI87kiYe3Z3eoXL1uDKwTQMck91cXVnM="; + src = fetchFromGitHub { + owner = "iv-org"; + repo = "invidious-companion"; + rev = "a34c27ff63e51f9e3adc0e8647cd12382f8f1ffe"; + hash = "sha256-/S8F7G8li12k0objsdFuh+mle6p2mk8zNUUCrG9hgns="; + }; + binaryEntrypointPath = "src/main.ts"; + denoCompileFlags = [ + "--include=./src/lib/helpers/youtubePlayerReq.ts" + "--include=./src/lib/helpers/getFetchClient.ts" + "--allow-import=github.com:443,jsr.io:443,cdn.jsdelivr.net:443,esm.sh:443,deno.land:443" + "--allow-net" + "--allow-env" + "--allow-read" + "--allow-sys=hostname" + "--allow-write=/var/tmp/youtubei.js" + ]; + denoInstallFlags = [ + "--allow-scripts" + "--frozen" + "--cached-only" + "--entrypoint" + "src/main.ts" + ]; + targetSystem = "x86_64-linux"; + }; +} diff --git a/pkgs/test/build-deno-package/shell.nix b/pkgs/test/build-deno-package/shell.nix new file mode 100644 index 0000000000000..4f34fa2db6405 --- /dev/null +++ b/pkgs/test/build-deno-package/shell.nix @@ -0,0 +1,9 @@ +let + pkgs = import ../../../default.nix { }; +in +pkgs.mkShell { + buildInputs = [ pkgs.deno ]; + DENO_DIR = "./.deno"; + + shellHook = ''''; +} diff --git a/pkgs/test/build-deno-package/workspaces/.gitignore b/pkgs/test/build-deno-package/workspaces/.gitignore new file mode 100644 index 0000000000000..cb92b2a7589f0 --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/.gitignore @@ -0,0 +1,3 @@ +.deno/ +node_modules/ +vendor/ diff --git a/pkgs/test/build-deno-package/workspaces/default.nix b/pkgs/test/build-deno-package/workspaces/default.nix new file mode 100644 index 0000000000000..01fe1067ae7f9 --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/default.nix @@ -0,0 +1,40 @@ +{ nix-gitignore, buildDenoPackage }: +rec { + sub1 = buildDenoPackage { + pname = "test-deno-build-workspaces-sub1"; + version = "0.1.0"; + denoDepsHash = "sha256-imraVvtIJqi31aaWv7U1ODVRmOuou1ZR++z7QqnTPr0="; + src = nix-gitignore.gitignoreSource [ ] ./.; + denoWorkspacePath = "./sub1"; + extraTaskFlags = [ + "--text" + "sub1" + ]; + denoTaskSuffix = ">out.txt"; + + installPhase = '' + cp out.txt $out + ''; + }; + sub2 = buildDenoPackage { + pname = "test-deno-build-workspaces-sub2"; + version = "0.1.0"; + inherit (sub1) denoDeps src; + denoWorkspacePath = "./sub2"; + extraTaskFlags = [ + "--text" + "sub2" + ]; + denoTaskSuffix = ">out.txt"; + installPhase = '' + cp out.txt $out + ''; + }; + sub1Binary = buildDenoPackage { + pname = "test-deno-build-workspaces-sub1-binary"; + version = "0.1.0"; + inherit (sub1) denoDeps src; + denoWorkspacePath = "./sub1"; + binaryEntrypointPath = "./main.ts"; + }; +} diff --git a/pkgs/test/build-deno-package/workspaces/deno.json b/pkgs/test/build-deno-package/workspaces/deno.json new file mode 100644 index 0000000000000..86437ea041975 --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/deno.json @@ -0,0 +1,7 @@ +{ + "workspace":[ + "./sub1", + "./sub2" + ], + "vendor": true +} diff --git a/pkgs/test/build-deno-package/workspaces/deno.lock b/pkgs/test/build-deno-package/workspaces/deno.lock new file mode 100644 index 0000000000000..e9007eb566702 --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/deno.lock @@ -0,0 +1,225 @@ +{ + "version": "5", + "specifiers": { + "jsr:@luca/cases@1.0.0": "1.0.0", + "jsr:@std/cli@1.0.17": "1.0.17", + "npm:cowsay@1.6.0": "1.6.0" + }, + "jsr": { + "@luca/cases@1.0.0": { + "integrity": "b5f9471f1830595e63a2b7d62821ac822a19e16899e6584799be63f17a1fbc30" + }, + "@std/cli@1.0.17": { + "integrity": "e15b9abe629e17be90cc6216327f03a29eae613365f1353837fa749aad29ce7b" + } + }, + "npm": { + "ansi-regex@3.0.1": { + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==" + }, + "ansi-regex@5.0.1": { + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles@4.3.0": { + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": [ + "color-convert" + ] + }, + "camelcase@5.3.1": { + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui@6.0.0": { + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": [ + "string-width@4.2.3", + "strip-ansi@6.0.1", + "wrap-ansi" + ] + }, + "color-convert@2.0.1": { + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": [ + "color-name" + ] + }, + "color-name@1.1.4": { + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "cowsay@1.6.0": { + "integrity": "sha512-8C4H1jdrgNusTQr3Yu4SCm+ZKsAlDFbpa0KS0Z3im8ueag+9pGOf3CrioruvmeaW/A5oqg9L0ar6qeftAh03jw==", + "dependencies": [ + "get-stdin", + "string-width@2.1.1", + "strip-final-newline", + "yargs" + ], + "bin": true + }, + "decamelize@1.2.0": { + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==" + }, + "emoji-regex@8.0.0": { + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "find-up@4.1.0": { + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": [ + "locate-path", + "path-exists" + ] + }, + "get-caller-file@2.0.5": { + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stdin@8.0.0": { + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==" + }, + "is-fullwidth-code-point@2.0.0": { + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==" + }, + "is-fullwidth-code-point@3.0.0": { + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "locate-path@5.0.0": { + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": [ + "p-locate" + ] + }, + "p-limit@2.3.0": { + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": [ + "p-try" + ] + }, + "p-locate@4.1.0": { + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": [ + "p-limit" + ] + }, + "p-try@2.2.0": { + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "path-exists@4.0.0": { + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "require-directory@2.1.1": { + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-main-filename@2.0.0": { + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "set-blocking@2.0.0": { + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + }, + "string-width@2.1.1": { + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dependencies": [ + "is-fullwidth-code-point@2.0.0", + "strip-ansi@4.0.0" + ] + }, + "string-width@4.2.3": { + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": [ + "emoji-regex", + "is-fullwidth-code-point@3.0.0", + "strip-ansi@6.0.1" + ] + }, + "strip-ansi@4.0.0": { + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dependencies": [ + "ansi-regex@3.0.1" + ] + }, + "strip-ansi@6.0.1": { + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": [ + "ansi-regex@5.0.1" + ] + }, + "strip-final-newline@2.0.0": { + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "which-module@2.0.1": { + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" + }, + "wrap-ansi@6.2.0": { + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": [ + "ansi-styles", + "string-width@4.2.3", + "strip-ansi@6.0.1" + ] + }, + "y18n@4.0.3": { + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yargs-parser@18.1.3": { + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": [ + "camelcase", + "decamelize" + ] + }, + "yargs@15.4.1": { + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": [ + "cliui", + "decamelize", + "find-up", + "get-caller-file", + "require-directory", + "require-main-filename", + "set-blocking", + "string-width@4.2.3", + "which-module", + "y18n", + "yargs-parser" + ] + } + }, + "remote": { + "https://deno.land/x/case@2.2.0/camelCase.ts": "b9a4cf361a7c9740ecb75e00b5e2c006bd4e5d40e442d26c5f2760286fa66796", + "https://deno.land/x/case@2.2.0/constantCase.ts": "c698fc32f00cd267c1684b1d413d784260d7e7798f2bf506803e418497d839b5", + "https://deno.land/x/case@2.2.0/dotCase.ts": "03ae55d5635e6a4ca894a003d9297cd9cd283af2e7d761dd3de13663849a9423", + "https://deno.land/x/case@2.2.0/headerCase.ts": "3f6c8ab2ab30a88147326bce28a00d1189ec98ab61c83ab72ce79e852afddc4a", + "https://deno.land/x/case@2.2.0/lowerCase.ts": "d75eb55cadfa589f9f2a973924a8a209054477d9574da669410f4d817ab25b41", + "https://deno.land/x/case@2.2.0/lowerFirstCase.ts": "b001efbf2d715b53d066b22cdbf8eda7f99aa7108e3d12fb02f80d499bae93d9", + "https://deno.land/x/case@2.2.0/mod.ts": "28b0b1329c7b18730799ac05627a433d9547c04b9bfb429116247c60edecd97b", + "https://deno.land/x/case@2.2.0/normalCase.ts": "085c8b6f9d69283c8b86f2e504d43278c2be8b7e56a3ed8d4a5f395e398bdc29", + "https://deno.land/x/case@2.2.0/paramCase.ts": "a234c9c17dfbaddee647b6571c2c90e8f6530123fed26c4546f4063d67c1609f", + "https://deno.land/x/case@2.2.0/pascalCase.ts": "4b3ef0a68173871a821d306d4067e8f72d42aeeef1eea6aeab30af6bfa3d7427", + "https://deno.land/x/case@2.2.0/pathCase.ts": "330a34b4df365b0291d8e36158235340131730aae6f6add66962ed2d0fbead4a", + "https://deno.land/x/case@2.2.0/sentenceCase.ts": "b312cef147a13b58ffdf3c36bf55b33aa8322c91f4aa9b32318f3911bb92327f", + "https://deno.land/x/case@2.2.0/snakeCase.ts": "e5ac1e08532ca397aa3150a0a3255d59f63a186d934e5094a8ffd24cbca7f955", + "https://deno.land/x/case@2.2.0/swapCase.ts": "bb03742fcf613f733890680ceca1b39b65ed290f36a317fcd47edd517c4e0e1e", + "https://deno.land/x/case@2.2.0/titleCase.ts": "c287131ea2c955e67cdd5cf604de96d31a8e2813305759922b9ed27e3be354e7", + "https://deno.land/x/case@2.2.0/types.ts": "8e2bd6edaa27c0d1972c0d5b76698564740f37b4d3787d58d1fb5f48de611e61", + "https://deno.land/x/case@2.2.0/upperCase.ts": "6cca267bb04d098bf4abf21e42e60c3e68ede89b12e525643c6b6eff3e10de34", + "https://deno.land/x/case@2.2.0/upperFirstCase.ts": "b964c2d8d3a85c78cd35f609135cbde99d84b9522a21470336b5af80a37facbd", + "https://deno.land/x/case@2.2.0/vendor/camelCaseRegexp.ts": "7d9ff02aad4ab6429eeab7c7353f7bcdd6cc5909a8bd3dda97918c8bbb7621ae", + "https://deno.land/x/case@2.2.0/vendor/camelCaseUpperRegexp.ts": "292de54a698370f90adcdf95727993d09888b7f33d17f72f8e54ba75f7791787", + "https://deno.land/x/case@2.2.0/vendor/nonWordRegexp.ts": "c1a052629a694144b48c66b0175a22a83f4d61cb40f4e45293fc5d6b123f927e" + }, + "workspace": { + "members": { + "sub1": { + "dependencies": [ + "jsr:@std/cli@1.0.17", + "npm:cowsay@1.6.0" + ] + }, + "sub2": { + "dependencies": [ + "jsr:@luca/cases@1.0.0", + "jsr:@std/cli@1.0.17", + "npm:cowsay@1.6.0" + ] + } + } + } +} diff --git a/pkgs/test/build-deno-package/workspaces/sub1/deno.json b/pkgs/test/build-deno-package/workspaces/sub1/deno.json new file mode 100644 index 0000000000000..dc00086de60dc --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/sub1/deno.json @@ -0,0 +1,10 @@ +{ + "tasks": { + "build": "deno run --allow-all main.ts" + }, + "imports": { + "@std/cli": "jsr:@std/cli@1.0.17", + "cowsay": "npm:cowsay@1.6.0", + "cases": "https://deno.land/x/case@2.2.0/mod.ts" + } +} diff --git a/pkgs/test/build-deno-package/workspaces/sub1/main.ts b/pkgs/test/build-deno-package/workspaces/sub1/main.ts new file mode 100644 index 0000000000000..7164d1aeecbab --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/sub1/main.ts @@ -0,0 +1,13 @@ +import { say } from "cowsay"; +import { pascalCase } from "cases"; +import { parseArgs } from "@std/cli"; + +const flags = parseArgs(Deno.args, { + string: ["text"], +}); + +if (!flags.text) { + throw "--text required but not specified"; +} + +console.log(pascalCase(say({ text: flags.text }))); diff --git a/pkgs/test/build-deno-package/workspaces/sub2/deno.json b/pkgs/test/build-deno-package/workspaces/sub2/deno.json new file mode 100644 index 0000000000000..a7d350d391fc1 --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/sub2/deno.json @@ -0,0 +1,10 @@ +{ + "tasks": { + "build": "deno run --allow-all main.ts" + }, + "imports": { + "@luca/cases": "jsr:@luca/cases@1.0.0", + "@std/cli": "jsr:@std/cli@1.0.17", + "cowsay": "npm:cowsay@1.6.0" + } +} diff --git a/pkgs/test/build-deno-package/workspaces/sub2/main.ts b/pkgs/test/build-deno-package/workspaces/sub2/main.ts new file mode 100644 index 0000000000000..cb1806f1bcd6e --- /dev/null +++ b/pkgs/test/build-deno-package/workspaces/sub2/main.ts @@ -0,0 +1,13 @@ +import { camelCase } from "@luca/cases"; +import { say } from "cowsay"; +import { parseArgs } from "@std/cli"; + +const flags = parseArgs(Deno.args, { + string: ["text"], +}); + +if (!flags.text) { + throw "--text required but not specified"; +} + +console.log(camelCase(say({ text: flags.text }))); diff --git a/pkgs/test/default.nix b/pkgs/test/default.nix index 7804ea23b06e7..6910141bf659e 100644 --- a/pkgs/test/default.nix +++ b/pkgs/test/default.nix @@ -212,4 +212,6 @@ with pkgs; build-environment-info = callPackage ./build-environment-info { }; rust-hooks = recurseIntoAttrs (callPackages ../build-support/rust/hooks/test { }); + + build-deno-package = callPackage ./build-deno-package { }; } diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 09c32d2f97c23..6453e52fd0fab 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -3642,6 +3642,12 @@ with pkgs; node2nix = nodePackages.node2nix; + buildDenoPackage = callPackage ../build-support/deno/build-deno-package { }; + + inherit (callPackages ../build-support/deno/fetch-deno-deps { }) fetchDenoDeps; + + denoHooks = callPackage ../build-support/deno/build-deno-package/hooks { }; + kcollectd = libsForQt5.callPackage ../tools/misc/kcollectd { }; ktailctl = kdePackages.callPackage ../applications/networking/ktailctl { };