diff --git a/examples/_d2n-flake-parts/flake.nix b/examples/_d2n-flake-parts/flake.nix index c612fb1ec8..8313ea2224 100644 --- a/examples/_d2n-flake-parts/flake.nix +++ b/examples/_d2n-flake-parts/flake.nix @@ -3,7 +3,7 @@ dream2nix.url = "github:nix-community/dream2nix"; nixpkgs.follows = "dream2nix/nixpkgs"; flake-parts.url = "github:hercules-ci/flake-parts"; - src.url = "github:prettier/prettier/2.4.1"; + src.url = "github:DavHau/prettier/master"; src.flake = false; }; @@ -26,7 +26,10 @@ prettier = { name = "prettier"; subsystem = "nodejs"; - translator = "yarn-lock"; + translator = "package-lock"; + translatorArgs.package-lock = { + nodejs = "18"; + }; }; }; }; diff --git a/src/modules/flake-parts/callMakeOutputs.nix b/src/modules/flake-parts/callMakeOutputs.nix new file mode 100644 index 0000000000..776de23e63 --- /dev/null +++ b/src/modules/flake-parts/callMakeOutputs.nix @@ -0,0 +1,34 @@ +/* +This adapter is needed because our interface diverges from what `makeOutputs` +accepts. +# TODO: remove this adapter and change makeOutputs to acceppt the new style + of arguments directly. +*/ +{ + lib, + makeOutputs, +}: input: let + l = lib // builtins; + + mkProject = project: + (l.removeAttrs project ["translatorArgs"]) + // { + subsystemInfo = project.translatorArgs.${project.translator}; + }; + + finalProjects = l.mapAttrs (_: mkProject) input.projects; + + makeOutputsArgs = { + inherit + (input) + source + pname + settings + packageOverrides + sourceOverrides + inject + ; + projects = finalProjects; + }; +in + makeOutputs makeOutputsArgs diff --git a/src/modules/flake-parts/implementation.nix b/src/modules/flake-parts/implementation.nix index ed9441e3c1..479bc9611b 100644 --- a/src/modules/flake-parts/implementation.nix +++ b/src/modules/flake-parts/implementation.nix @@ -25,9 +25,14 @@ in { inherit (d2n) config; }; + callMakeOutputs = import ./callMakeOutputs.nix { + inherit lib; + inherit (instance.dream2nix-interface) makeOutputs; + }; + outputs = l.mapAttrs - (_: args: instance.dream2nix-interface.makeOutputs args) + (_: input: callMakeOutputs input) config.dream2nix.inputs; getAttrFromOutputs = attrName: diff --git a/src/modules/flake-parts/makeOutputsArgs.nix b/src/modules/flake-parts/inputs.nix similarity index 92% rename from src/modules/flake-parts/makeOutputsArgs.nix rename to src/modules/flake-parts/inputs.nix index 5774143059..09a56f9221 100644 --- a/src/modules/flake-parts/makeOutputsArgs.nix +++ b/src/modules/flake-parts/inputs.nix @@ -1,4 +1,8 @@ -{lib, ...}: let +{ + lib, + framework, + ... +}: let l = lib // builtins; t = l.types; mkOption = l.options.mkOption; @@ -15,13 +19,18 @@ type = t.str; }; - # TODO(antotocar34) make a smart enum of all available translators conditional on the given the subsystem? Is this possible? translator = mkOption { description = "Translators to use"; - example = ["yarn-lock" "package-json"]; - type = t.str; + example = "package-json"; + type = t.enum (l.attrNames framework.translators); }; + # this generates options like: translatorArgs.package-lock.nodejs = ...; + translatorArgs = + l.mapAttrs + (name: translator: translator.translatorOptions) + framework.translators; + # TODO(antotocar34) make an enum of all available subsystems? subsystem = mkOption { description = ''Name of subsystem to use. Examples: rust, python, nodejs''; diff --git a/src/modules/flake-parts/interface.nix b/src/modules/flake-parts/interface.nix index 451b1dd0cb..7d08a569f0 100644 --- a/src/modules/flake-parts/interface.nix +++ b/src/modules/flake-parts/interface.nix @@ -36,7 +36,7 @@ in { }; perSystem = flake-parts-lib.mkPerSystemOption - ({...}: { + ({config, ...}: { options = { dream2nix = { instance = l.mkOption { @@ -47,7 +47,12 @@ in { ''; }; inputs = l.mkOption { - type = t.attrsOf (t.submodule ./makeOutputsArgs.nix); + type = t.attrsOf (t.submoduleWith { + modules = [./inputs.nix]; + specialArgs = { + framework = config.dream2nix.instance; + }; + }); default = {}; description = '' A list of inputs to generate outputs from. diff --git a/src/modules/functions.translators.nodejs/default.nix b/src/modules/functions.translators.nodejs/default.nix new file mode 100644 index 0000000000..e0a7730f9a --- /dev/null +++ b/src/modules/functions.translators.nodejs/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./implementation.nix + ./interface.nix + ]; +} diff --git a/src/modules/functions.translators.nodejs/implementation.nix b/src/modules/functions.translators.nodejs/implementation.nix new file mode 100644 index 0000000000..e0d4945da0 --- /dev/null +++ b/src/modules/functions.translators.nodejs/implementation.nix @@ -0,0 +1,65 @@ +/* +migrated from src/subsystems/nodejs/translators/utils.nix +TODO: get rid of the original and remove this comment +*/ +{config, ...}: let + l = config.lib // builtins; + dlib = config.dlib; + getMetaFromPackageJson = packageJson: + {license = dlib.parseSpdxId (packageJson.license or "");} + // ( + l.filterAttrs + (n: v: l.any (on: n == on) ["description" "homepage"]) + packageJson + ); + + getPackageJsonDeps = packageJson: noDev: + (packageJson.dependencies or {}) + // (l.optionalAttrs (! noDev) (packageJson.devDependencies or {})); + + getWorkspaceParent = project: + if project ? subsystemInfo.workspaceParent + then "${project.subsystemInfo.workspaceParent}" + else "${project.relPath}"; + + getWorkspaceLockFile = tree: project: fname: let + # returns the parsed package-lock.json for a given project + dirRelPath = getWorkspaceParent project; + + packageJson = + (tree.getNodeFromPath "${dirRelPath}/package.json").jsonContent; + + hasNoDependencies = + ((packageJson.dependencies or {}) == {}) + && ((packageJson.devDependencies or {}) == {}) + && (! packageJson ? workspaces); + in + if hasNoDependencies + then null + else tree.getNodeFromPath "${dirRelPath}/${fname}"; + + getWorkspacePackageJson = tree: workspaces: + l.genAttrs + workspaces + (wsRelPath: + (tree.getNodeFromPath "${wsRelPath}/package.json").jsonContent); + + getWorkspacePackages = tree: workspaces: + l.mapAttrs' + (wsRelPath: json: + l.nameValuePair + json.name + json.version) + (getWorkspacePackageJson tree workspaces); +in { + config.functions.translators.nodejs = { + inherit + getMetaFromPackageJson + getPackageJsonDeps + getWorkspaceLockFile + getWorkspacePackageJson + getWorkspacePackages + getWorkspaceParent + ; + }; +} diff --git a/src/modules/functions.translators.nodejs/interface.nix b/src/modules/functions.translators.nodejs/interface.nix new file mode 100644 index 0000000000..dde93a102b --- /dev/null +++ b/src/modules/functions.translators.nodejs/interface.nix @@ -0,0 +1,16 @@ +{config, ...}: let + lib = config.lib; + t = lib.types; + functionOption = lib.mkOption { + type = t.uniq (t.functionTo t.attrs); + }; +in { + options.functions.translators.nodejs = { + getMetaFromPackageJson = functionOption; + getPackageJsonDeps = functionOption; + getWorkspaceLockFile = functionOption; + getWorkspacePackageJson = functionOption; + getWorkspacePackages = functionOption; + getWorkspaceParent = functionOption; + }; +} diff --git a/src/modules/interfaces.translator/interface.nix b/src/modules/interfaces.translator/interface.nix index 3d3af146e5..388cd9108a 100644 --- a/src/modules/interfaces.translator/interface.nix +++ b/src/modules/interfaces.translator/interface.nix @@ -75,5 +75,11 @@ in { type = t.int; default = 2; }; + translatorOptions = lib.mkOption { + type = t.attrs; + # TODO: remove the default once the `extraArgs` field of translators is + # deprecated. + default = {}; + }; }; } diff --git a/src/modules/top-level.nix b/src/modules/top-level.nix index 886a045036..ab90a16a85 100644 --- a/src/modules/top-level.nix +++ b/src/modules/top-level.nix @@ -45,12 +45,14 @@ in { ./functions.default-fetcher ./functions.combined-fetcher ./functions.translators + ./functions.translators.nodejs ./functions.updaters ./apps ./builders ./discoverers ./discoverers.default-discoverer ./fetchers + ./translators.package-lock ./translators ./indexers ./utils diff --git a/src/modules/translators.package-lock/default.nix b/src/modules/translators.package-lock/default.nix new file mode 100644 index 0000000000..2a2977247d --- /dev/null +++ b/src/modules/translators.package-lock/default.nix @@ -0,0 +1,5 @@ +{ + imports = [ + ./implementation.nix + ]; +} diff --git a/src/subsystems/nodejs/translators/package-lock/default.nix b/src/modules/translators.package-lock/implementation.nix similarity index 82% rename from src/subsystems/nodejs/translators/package-lock/default.nix rename to src/modules/translators.package-lock/implementation.nix index b3ac1c516c..02a718b166 100644 --- a/src/subsystems/nodejs/translators/package-lock/default.nix +++ b/src/modules/translators.package-lock/implementation.nix @@ -1,12 +1,13 @@ { - dlib, lib, - utils, - name, + config, ... }: let - l = lib // builtins; - nodejsUtils = import ../utils.nix {inherit dlib lib;}; + l = config.lib // builtins; + t = l.types; + dlib = config.dlib; + + nodejsUtils = config.functions.translators.nodejs; getPackageLockPath = tree: project: let parent = nodejsUtils.getWorkspaceParent project; @@ -145,7 +146,7 @@ url = "https://registry.npmjs.org/${name}/-/${name}-${version}.tgz"; }; in - utils.simpleTranslate + config.utils.simpleTranslate ({ getDepByNameVer, dependenciesByOriginalID, @@ -272,39 +273,68 @@ getDependencies = dependencyObject: dependencyObject.depsExact; }); -in rec { - version = 2; - - type = "pure"; - - inherit translate; - - extraArgs = { - name = { - description = "The name of the main package"; - examples = [ - "react" - "@babel/code-frame" - ]; - default = "{automatic}"; - type = "argument"; +in { + translators.package-lock = { + version = 2; + name = "package-lock"; + type = "pure"; + subsystem = "nodejs"; + inherit translate; + + /* + Currently this duplicates the information declared in extraArgs. + `extraArgs` is currently still needed by some internals but could probably + be factored out. + + TODO: remove `extraArgs` + */ + translatorOptions = { + name = l.mkOption { + description = "The name of the main package"; + example = "@babel/code-frame"; + default = "{automatic}"; + type = t.str; + }; + noDev = l.mkOption { + description = "Exclude development dependencies"; + type = t.bool; + default = false; + }; + nodejs = l.mkOption { + description = "nodejs version to use for building"; + default = "14"; + example = "16"; + type = t.str; + }; }; - noDev = { - description = "Exclude development dependencies"; - type = "flag"; - }; + extraArgs = { + name = { + description = "The name of the main package"; + examples = [ + "react" + "@babel/code-frame" + ]; + default = "{automatic}"; + type = "argument"; + }; + + noDev = { + description = "Exclude development dependencies"; + type = "flag"; + }; - # TODO: this should either be removed or only used to select - # the nodejs version for translating, not for building. - nodejs = { - description = "nodejs version to use for building"; - default = "14"; - examples = [ - "14" - "16" - ]; - type = "argument"; + # TODO: this should either be removed or only used to select + # the nodejs version for translating, not for building. + nodejs = { + description = "nodejs version to use for building"; + default = "14"; + examples = [ + "14" + "16" + ]; + type = "argument"; + }; }; }; }