mirror of
https://github.com/nix-community/dream2nix.git
synced 2024-12-18 20:11:33 +03:00
implement project discoverer for nodejs
This commit is contained in:
parent
afcf7158ae
commit
fb8928ae0a
35
src/discoverers/default.nix
Normal file
35
src/discoverers/default.nix
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
dlib,
|
||||
lib,
|
||||
}:
|
||||
|
||||
let
|
||||
l = lib // builtins;
|
||||
|
||||
subsystems = dlib.dirNames ./.;
|
||||
|
||||
allDiscoverers =
|
||||
l.collect
|
||||
(v: v ? discover)
|
||||
discoverers;
|
||||
|
||||
discoverProjects = source:
|
||||
let
|
||||
tree = dlib.prepareSourceTree { inherit source; };
|
||||
in
|
||||
l.flatten
|
||||
(l.map
|
||||
(discoverer: discoverer.discover { inherit tree; })
|
||||
allDiscoverers);
|
||||
|
||||
discoverers = l.genAttrs subsystems (subsystem:
|
||||
(import (./. + "/${subsystem}") { inherit dlib lib subsystem; })
|
||||
);
|
||||
in
|
||||
|
||||
{
|
||||
inherit
|
||||
discoverProjects
|
||||
discoverers
|
||||
;
|
||||
}
|
141
src/discoverers/nodejs/default.nix
Normal file
141
src/discoverers/nodejs/default.nix
Normal file
@ -0,0 +1,141 @@
|
||||
{
|
||||
dlib,
|
||||
lib,
|
||||
|
||||
subsystem,
|
||||
}:
|
||||
|
||||
let
|
||||
l = lib // builtins;
|
||||
|
||||
discover =
|
||||
{
|
||||
tree,
|
||||
}:
|
||||
discoverInternal {
|
||||
inherit tree;
|
||||
};
|
||||
|
||||
|
||||
getTranslatorNames = path:
|
||||
let
|
||||
nodes = l.readDir path;
|
||||
in
|
||||
l.optionals (nodes ? "package-lock.json") [ "package-lock" ]
|
||||
++ l.optionals (nodes ? "yarn.lock") [ "yarn-lock" ]
|
||||
++ [ "package-json" ];
|
||||
|
||||
# returns the parsed package.json of a given directory
|
||||
getPackageJson = dirPath:
|
||||
l.fromJSON (l.readFile "${dirPath}/package.json");
|
||||
|
||||
# returns all relative paths to workspaces defined by a glob
|
||||
getWorkspacePaths = glob: tree:
|
||||
if l.hasSuffix "*" glob then
|
||||
let
|
||||
prefix = l.removeSuffix "*" glob;
|
||||
dirNames = dlib.listDirs "${tree.fullPath}/${prefix}";
|
||||
in
|
||||
l.map (dname: "${prefix}/${dname}") dirNames
|
||||
else
|
||||
[ glob ];
|
||||
|
||||
# collect project info for workspaces defined by current package.json
|
||||
getWorkspaces = tree: parentInfo:
|
||||
let
|
||||
packageJson = tree.files."package.json".jsonContent;
|
||||
in
|
||||
l.flatten
|
||||
(l.forEach packageJson.workspaces
|
||||
(glob:
|
||||
let
|
||||
workspacePaths = getWorkspacePaths glob tree;
|
||||
in
|
||||
l.forEach workspacePaths
|
||||
(wPath: makeWorkspaceProjectInfo tree wPath parentInfo)));
|
||||
|
||||
makeWorkspaceProjectInfo = tree: wsRelPath: parentInfo:
|
||||
{
|
||||
inherit subsystem;
|
||||
name = (getPackageJson "${tree.fullPath}/${wsRelPath}").name or null;
|
||||
relPath = dlib.sanitizeRelativePath "${tree.relPath}/${wsRelPath}";
|
||||
translators =
|
||||
l.unique
|
||||
(parentInfo.translators
|
||||
++ (getTranslatorNames "${tree.fullPath}/${wsRelPath}"));
|
||||
subsystemInfo = {
|
||||
workspaceParent = tree.relPath;
|
||||
};
|
||||
};
|
||||
|
||||
discoverInternal =
|
||||
{
|
||||
tree,
|
||||
|
||||
# Internal parameter preventing workspace projects from being discovered
|
||||
# twice.
|
||||
alreadyDiscovered ? {},
|
||||
}:
|
||||
# skip if not a nodajs project
|
||||
if alreadyDiscovered ? "${tree.relPath}"
|
||||
|| ! tree ? files."package.json"
|
||||
then
|
||||
# this will be cleaned by `flatten` for sub-directories
|
||||
[]
|
||||
else
|
||||
let
|
||||
|
||||
# project info of current directory
|
||||
currentProjectInfo =
|
||||
{
|
||||
inherit subsystem;
|
||||
inherit (tree) relPath;
|
||||
name = tree.files."package.json".jsonContent.name or null;
|
||||
translators = getTranslatorNames tree.fullPath;
|
||||
subsystemInfo =
|
||||
l.optionalAttrs (workspaces != []) {
|
||||
workspaces = l.map (w: w.relPath) workspaces;
|
||||
};
|
||||
};
|
||||
|
||||
workspaces = getWorkspaces tree currentProjectInfo;
|
||||
|
||||
|
||||
# list of all projects infos found by the current iteration
|
||||
foundProjects =
|
||||
# current directories project info
|
||||
[ currentProjectInfo ]
|
||||
|
||||
# workspaces defined by the current directory
|
||||
++
|
||||
workspaces;
|
||||
|
||||
# index of already found projects
|
||||
# This is needed, because sub-projects also contain a `package.json`,
|
||||
# and would otherwise be discovered again as an independent project.
|
||||
alreadyDiscovered' =
|
||||
alreadyDiscovered
|
||||
//
|
||||
(l.genAttrs
|
||||
(l.map (p: p.relPath) foundProjects)
|
||||
(relPath: null));
|
||||
in
|
||||
# the current directory
|
||||
foundProjects
|
||||
|
||||
# sub-directories
|
||||
# Thanks to `alreadyDiscovered`, workspace projects won't be discovered
|
||||
# a second time.
|
||||
++
|
||||
l.flatten
|
||||
((l.mapAttrsToList
|
||||
(dname: dir: discoverInternal {
|
||||
alreadyDiscovered = alreadyDiscovered';
|
||||
tree = dir;
|
||||
})
|
||||
(tree.directories or {})));
|
||||
in
|
||||
|
||||
{
|
||||
inherit discover;
|
||||
}
|
@ -13,18 +13,98 @@ let
|
||||
calcInvalidationHash
|
||||
containsMatchingFile
|
||||
dirNames
|
||||
discoverers
|
||||
listDirs
|
||||
listFiles
|
||||
prepareSourceTree
|
||||
readTextFile
|
||||
translators
|
||||
sanitizeRelativePath
|
||||
;
|
||||
};
|
||||
|
||||
# other libs
|
||||
translators = import ./translators.nix { inherit dlib lib; };
|
||||
discoverers = import ../discoverers { inherit dlib lib; };
|
||||
|
||||
|
||||
# INTERNAL
|
||||
|
||||
# prepare source tree for executing discovery phase
|
||||
# produces this structure:
|
||||
# {
|
||||
# files = {
|
||||
# "package.json" = {
|
||||
# relPath = "package.json"
|
||||
# fullPath = "${source}/package.json"
|
||||
# content = ;
|
||||
# jsonContent = ;
|
||||
# tomlContent = ;
|
||||
# }
|
||||
# };
|
||||
# directories = {
|
||||
# "packages" = {
|
||||
# relPath = "packages";
|
||||
# fullPath = "${source}/packages";
|
||||
# files = {
|
||||
#
|
||||
# };
|
||||
# directories = {
|
||||
#
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# }
|
||||
prepareSourceTreeInternal = sourceRoot: relPath: name: depth:
|
||||
let
|
||||
relPath' = relPath;
|
||||
fullPath' = "${sourceRoot}/${relPath}";
|
||||
current = l.readDir fullPath';
|
||||
|
||||
fileNames =
|
||||
l.filterAttrs (n: v: v == "regular") current;
|
||||
|
||||
directoryNames =
|
||||
l.filterAttrs (n: v: v == "directory") current;
|
||||
|
||||
makeNewPath = prefix: name:
|
||||
if prefix == "" then
|
||||
name
|
||||
else
|
||||
"${prefix}/name";
|
||||
|
||||
directories =
|
||||
l.mapAttrs
|
||||
(dname: _:
|
||||
prepareSourceTreeInternal
|
||||
sourceRoot
|
||||
(makeNewPath relPath dname)
|
||||
dname
|
||||
(depth - 1))
|
||||
directoryNames;
|
||||
|
||||
files =
|
||||
l.mapAttrs
|
||||
(fname: _: l.trace fname rec {
|
||||
name = fname;
|
||||
fullPath = "${fullPath'}/${fname}";
|
||||
relPath = makeNewPath relPath fname;
|
||||
content = readTextFile fullPath;
|
||||
jsonContent = l.fromJSON content;
|
||||
tomlContent = l.fromTOML content;
|
||||
})
|
||||
fileNames;
|
||||
|
||||
in
|
||||
{
|
||||
inherit name files relPath;
|
||||
|
||||
fullPath = fullPath';
|
||||
}
|
||||
# stop recursion if depth is reached
|
||||
// (l.optionalAttrs (depth > 0) {
|
||||
inherit directories;
|
||||
});
|
||||
|
||||
|
||||
# EXPORTED
|
||||
@ -52,11 +132,24 @@ let
|
||||
patterns;
|
||||
|
||||
# directory names of a given directory
|
||||
dirNames = dir: lib.attrNames (lib.filterAttrs (name: type: type == "directory") (builtins.readDir dir));
|
||||
dirNames = dir: l.attrNames (l.filterAttrs (name: type: type == "directory") (builtins.readDir dir));
|
||||
|
||||
listDirs = path: lib.attrNames (lib.filterAttrs (n: v: v == "directory") (builtins.readDir path));
|
||||
listDirs = path: l.attrNames (l.filterAttrs (n: v: v == "directory") (builtins.readDir path));
|
||||
|
||||
listFiles = path: l.attrNames (l.filterAttrs (n: v: v == "regular") (builtins.readDir path));
|
||||
|
||||
prepareSourceTree =
|
||||
{
|
||||
source,
|
||||
depth ? 3,
|
||||
}:
|
||||
prepareSourceTreeInternal source "" "" depth;
|
||||
|
||||
readTextFile = file: l.replaceStrings [ "\r\n" ] [ "\n" ] (l.readFile file);
|
||||
|
||||
sanitizeRelativePath = path:
|
||||
l.removePrefix "/" (l.toString (l.toPath "/${path}"));
|
||||
|
||||
in
|
||||
|
||||
dlib
|
||||
|
@ -5,9 +5,10 @@
|
||||
|
||||
let
|
||||
b = builtins;
|
||||
l = lib // builtins;
|
||||
in
|
||||
|
||||
{
|
||||
rec {
|
||||
translate =
|
||||
{
|
||||
translatorName,
|
||||
|
@ -52,14 +52,13 @@ rec {
|
||||
dirNames
|
||||
listDirs
|
||||
listFiles
|
||||
readTextFile
|
||||
;
|
||||
|
||||
dreamLock = dreamLockUtils;
|
||||
|
||||
inherit (dreamLockUtils) readDreamLock;
|
||||
|
||||
readTextFile = file: lib.replaceStrings [ "\r\n" ] [ "\n" ] (b.readFile file);
|
||||
|
||||
traceJ = toTrace: eval: b.trace (b.toJSON toTrace) eval;
|
||||
|
||||
isFile = path: (builtins.readDir (b.dirOf path))."${b.baseNameOf path}" == "regular";
|
||||
|
Loading…
Reference in New Issue
Block a user