Skip to content

Commit c71f38e

Browse files
committed
nodejs: add package-lock v2 translator
- discovers peer dependencies correctly - adds metadata like os, dev and hasInstallScripts to sources
1 parent 98e0a1a commit c71f38e

File tree

6 files changed

+313
-21
lines changed

6 files changed

+313
-21
lines changed

flake.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@
226226

227227
# a dev shell for working on dream2nix
228228
# use via 'nix develop . -c $SHELL'
229+
# TODO only for the current system?
229230
devShells = forAllSystems (system: pkgs: let
230231
makeDevshell = import "${inp.devshell}/modules" pkgs;
231232
mkShell = config:

src/subsystems/nodejs/discoverers/default/default.nix

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@
3535
in
3636
childrenRemoved;
3737

38-
getTranslatorNames = path: let
39-
nodes = l.readDir path;
40-
packageJson = l.fromJSON (l.readFile "${path}/package.json");
38+
getTranslatorNames = subTree: let
39+
# TODO use nodejsUtils.getWorkspaceLockFile
40+
packageJson = subTree.files."package.json".jsonContent;
41+
lockJson = subTree.files."package-lock.json".jsonContent or null;
4142
translators =
4243
# if the package has no dependencies we use the
4344
# package-lock translator with `packageLock = null`
@@ -46,17 +47,21 @@
4647
&& (packageJson.devDependencies or {} == {})
4748
&& (packageJson.workspaces or [] == [])
4849
then ["package-lock"]
50+
else if lockJson != null
51+
then let
52+
lockVersion = lockJson.lockfileVersion or 0;
53+
in
54+
if lockVersion == 1
55+
then ["package-lock"]
56+
else if lockVersion == 2 || lockVersion == 3
57+
then ["package-lock-v2"]
58+
else ["package-json"]
4959
else
50-
l.optionals (nodes ? "package-lock.json") ["package-lock"]
51-
++ l.optionals (nodes ? "yarn.lock") ["yarn-lock"]
60+
l.optionals (subTree.files ? "yarn.lock") ["yarn-lock"]
5261
++ ["package-json"];
5362
in
5463
translators;
5564

56-
# returns the parsed package.json of a given directory
57-
getPackageJson = dirPath:
58-
l.fromJSON (l.readFile "${dirPath}/package.json");
59-
6065
# returns all relative paths to workspaces defined by a glob
6166
getWorkspacePaths = glob: tree:
6267
if l.hasSuffix "*" glob
@@ -121,15 +126,13 @@
121126
makeWorkspaceProjectInfo = tree: wsRelPath: parentInfo:
122127
dlib.construct.discoveredProject {
123128
inherit subsystem;
124-
name =
125-
(getPackageJson "${tree.fullPath}/${wsRelPath}").name
126-
or "${parentInfo.name}/${wsRelPath}";
129+
name = (tree.getNodeFromPath wsRelPath).files."package.json".jsonContent.name or "${parentInfo.name}/${wsRelPath}";
127130
relPath = dlib.sanitizeRelativePath "${tree.relPath}/${wsRelPath}";
128131
translators =
129132
l.unique
130133
(
131-
(lib.filter (trans: l.elem trans ["package-lock" "yarn-lock"]) parentInfo.translators)
132-
++ (getTranslatorNames "${tree.fullPath}/${wsRelPath}")
134+
(lib.filter (trans: l.elem trans ["package-lock" "package-lock-v2" "yarn-lock"]) parentInfo.translators)
135+
++ (getTranslatorNames (tree.getNodeFromPath wsRelPath))
133136
);
134137
subsystemInfo = {
135138
workspaceParent = tree.relPath;
@@ -152,7 +155,7 @@
152155
})
153156
(tree.directories or {}));
154157
in
155-
# skip if not a nodajs project
158+
# skip if not a nodejs project
156159
if
157160
alreadyDiscovered
158161
? "${tree.relPath}"
@@ -165,8 +168,14 @@
165168
currentProjectInfo = dlib.construct.discoveredProject {
166169
inherit subsystem;
167170
inherit (tree) relPath;
168-
name = tree.files."package.json".jsonContent.name or tree.relPath;
169-
translators = getTranslatorNames tree.fullPath;
171+
name =
172+
tree.files."package.json".jsonContent.name
173+
or (
174+
if tree.relPath == ""
175+
then "noname"
176+
else tree.relPath
177+
);
178+
translators = getTranslatorNames tree;
170179
subsystemInfo = l.optionalAttrs (workspaces != []) {
171180
workspaces =
172181
l.map

src/subsystems/nodejs/translators/package-json/default.nix

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
openssh
3232
]
3333
''
34-
# accroding to the spec, the translator reads the input from a json file
34+
# according to the spec, the translator reads the input from a json file
3535
jsonInput=$1
3636
3737
# read the json input
@@ -40,14 +40,17 @@
4040
relPath=$(jq '.project.relPath' -c -r $jsonInput)
4141
npmArgs=$(jq '.project.subsystemInfo.npmArgs' -c -r $jsonInput)
4242
43+
# TODO: Do we really need to copy everything? Just package.json + .npmrc
44+
# is enough, no? And then pass the lock file to translate separately?
4345
cp -r $source/* ./
4446
chmod -R +w ./
4547
newSource=$(pwd)
4648
4749
cd ./$relPath
4850
rm -rf package-lock.json yarn.lock
4951
50-
echo "translating in temp dir: $(pwd)"
52+
echo "Translating with npm in temp dir: $(pwd)"
53+
echo "You can avoid this by adding your own package-lock.json file"
5154
5255
if [ "$(jq '.project.subsystemInfo.noDev' -c -r $jsonInput)" == "true" ]; then
5356
echo "excluding dev dependencies"
@@ -61,7 +64,7 @@
6164
jq ".source = \"$newSource\"" -c -r $jsonInput > $TMPDIR/newJsonInput
6265
6366
cd $WORKDIR
64-
${subsystems.nodejs.translators.package-lock.translateBin} $TMPDIR/newJsonInput
67+
${subsystems.nodejs.translators.package-lock-v2.translateBin} $TMPDIR/newJsonInput
6568
'';
6669

6770
# inherit options from package-lock translator
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
# TODO use translate2
2+
# TODO use package.json for v1 lock files
3+
{
4+
dlib,
5+
lib,
6+
...
7+
}: let
8+
b = builtins;
9+
l = lib // builtins;
10+
nodejsUtils = import ../utils.nix {inherit lib;};
11+
12+
translate = {
13+
translatorName,
14+
utils,
15+
pkgs,
16+
...
17+
}: {
18+
project,
19+
source,
20+
tree,
21+
# translator args
22+
# name
23+
# nodejs
24+
...
25+
} @ args: let
26+
b = builtins;
27+
28+
name =
29+
if (args.name or "{automatic}") != "{automatic}"
30+
then args.name
31+
else project.name;
32+
tree = args.tree.getNodeFromPath project.relPath;
33+
relPath = project.relPath;
34+
source = "${args.source}/${relPath}";
35+
workspaces = project.subsystemInfo.workspaces or [];
36+
37+
getResolved = tree: project: let
38+
lock =
39+
(nodejsUtils.getWorkspaceLockFile tree project "package-lock.json").jsonContent;
40+
resolved = import ./v2-parse.nix {inherit lib lock source;};
41+
in
42+
resolved;
43+
44+
resolved = getResolved args.tree project;
45+
46+
packageVersion = resolved.self.version or "unknown";
47+
48+
rootDependencies = resolved.self.deps;
49+
50+
identifyGitSource = dep:
51+
# TODO: when integrity is there, and git url is github then use tarball instead
52+
# ! (dep ? integrity) &&
53+
dlib.identifyGitUrl dep.url;
54+
55+
getVersion = dep: dep.version;
56+
57+
getPath = dep:
58+
lib.removePrefix "file:" dep.url;
59+
60+
getSource = {
61+
url,
62+
hash,
63+
...
64+
}: {inherit url hash;};
65+
66+
# TODO check that this works with workspaces
67+
extraInfo = b.foldl' (acc: dep:
68+
if dep.extra != {}
69+
then l.recursiveUpdate acc {${dep.pname}.${dep.version} = dep.extra;}
70+
else acc) {}
71+
resolved.allDeps;
72+
73+
# TODO workspaces
74+
hasBuildScript = let
75+
pkgJson =
76+
(nodejsUtils.getWorkspaceLockFile tree project "package.json").jsonContent;
77+
in
78+
(pkgJson.scripts or {}) ? build;
79+
in
80+
utils.simpleTranslate
81+
({
82+
getDepByNameVer,
83+
dependenciesByOriginalID,
84+
...
85+
}: rec {
86+
inherit translatorName;
87+
location = relPath;
88+
89+
# values
90+
inputData = resolved.allDeps;
91+
92+
defaultPackage = name;
93+
94+
packages =
95+
{"${defaultPackage}" = packageVersion;}
96+
// (nodejsUtils.getWorkspacePackages tree workspaces);
97+
98+
mainPackageDependencies = resolved.self.deps;
99+
100+
subsystemName = "nodejs";
101+
102+
subsystemAttrs = {
103+
inherit extraInfo hasBuildScript;
104+
nodejsVersion = args.nodejs;
105+
};
106+
107+
# functions
108+
serializePackages = inputData: inputData;
109+
110+
getName = dep: dep.pname;
111+
112+
inherit getVersion;
113+
114+
# TODO handle npm link maybe? not sure what it looks like in lock
115+
getSourceType = dep:
116+
if lib.hasPrefix "file:" dep.url
117+
then "path"
118+
else if identifyGitSource dep
119+
then "git"
120+
else "http";
121+
122+
sourceConstructors = {
123+
git = dep:
124+
(getSource dep)
125+
// (dlib.parseGitUrl dep.url);
126+
127+
http = dep: (getSource dep);
128+
129+
path = dep: (dlib.construct.pathSource {
130+
path = getPath dep;
131+
rootName = project.name;
132+
rootVersion = packageVersion;
133+
});
134+
};
135+
136+
getDependencies = dep: dep.deps;
137+
});
138+
in rec {
139+
version = 2;
140+
141+
type = "pure";
142+
143+
inherit translate;
144+
145+
extraArgs = {
146+
name = {
147+
description = "The name of the main package";
148+
examples = [
149+
"react"
150+
"@babel/code-frame"
151+
];
152+
default = "{automatic}";
153+
type = "argument";
154+
};
155+
156+
transitiveBinaries = {
157+
description = "Should all the binaries from all modules be available, or only those from dependencies";
158+
default = false;
159+
type = "boolean";
160+
};
161+
162+
# TODO: this should either be removed or only used to select
163+
# the nodejs version for translating, not for building.
164+
nodejs = {
165+
description = "nodejs version to use for building";
166+
default = "16";
167+
examples = [
168+
"14"
169+
"16"
170+
];
171+
type = "argument";
172+
};
173+
};
174+
}

0 commit comments

Comments
 (0)