@jsenv/core 41.4.22 → 41.4.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -149,6 +149,13 @@ const jsenvCoreDirectoryUrl = new URL("../", import.meta.url);
149
149
  * Only exact declared versions ("1.2.3") are compared: a range ("^1.2.3"), a
150
150
  * file/workspace protocol or a tag cannot be checked without resolving what npm
151
151
  * would pick, which is way beyond what is needed here.
152
+ *
153
+ * A status carries a severity so that every consumer (server log, browser
154
+ * overlay, reload on install) reads the same decision: a missing package or an
155
+ * outdated runtime dependency is a "warning", the page is not running what the
156
+ * project asks for. An outdated devDependency is only "info": the installed
157
+ * version runs, what may differ is tooling, and that is worth a line in the
158
+ * console, not a dialog nor a reload once installed.
152
159
  */
153
160
 
154
161
 
@@ -180,13 +187,14 @@ const readDependencyStatus = (
180
187
  if (!packageJSON) {
181
188
  return null;
182
189
  }
183
- const declaredVersion = readDeclaredVersion(packageJSON, packageName);
184
- if (!declaredVersion) {
190
+ const declaration = readDeclaration(packageJSON, packageName);
191
+ if (!declaration) {
185
192
  return null;
186
193
  }
187
194
  return createStatus(packageDirectory, {
188
195
  packageName,
189
- declaredVersion,
196
+ declaredVersion: declaration.version,
197
+ declaredIn: declaration.field,
190
198
  declaringDirectoryUrl,
191
199
  declaredBy: packageJSON.name,
192
200
  });
@@ -194,17 +202,25 @@ const readDependencyStatus = (
194
202
 
195
203
  const createStatus = (
196
204
  packageDirectory,
197
- { packageName, declaredVersion, declaringDirectoryUrl, declaredBy },
205
+ {
206
+ packageName,
207
+ declaredVersion,
208
+ declaredIn,
209
+ declaringDirectoryUrl,
210
+ declaredBy,
211
+ },
198
212
  ) => {
199
213
  const status = {
200
214
  packageName,
201
215
  declaredVersion,
216
+ declaredIn,
202
217
  declaredBy,
203
218
  installedVersion: null,
204
219
  // the file telling this dependency apart; it is what an install rewrites and
205
220
  // what the dev server looks at to know the dependency became the declared one
206
221
  watchedPath: null,
207
222
  state: "missing",
223
+ severity: "warning",
208
224
  };
209
225
  const installedDirectoryUrl = findInstalledDirectoryUrl(
210
226
  declaringDirectoryUrl,
@@ -226,11 +242,16 @@ const createStatus = (
226
242
  status.installedVersion = installedPackageJSON
227
243
  ? installedPackageJSON.version
228
244
  : null;
229
- status.state =
230
- isExactVersion(declaredVersion) &&
231
- status.installedVersion !== declaredVersion
232
- ? "outdated"
233
- : "installed";
245
+ if (
246
+ !isExactVersion(declaredVersion) ||
247
+ status.installedVersion === declaredVersion
248
+ ) {
249
+ status.state = "installed";
250
+ status.severity = null;
251
+ return status;
252
+ }
253
+ status.state = "outdated";
254
+ status.severity = declaredIn === "devDependencies" ? "info" : "warning";
234
255
  return status;
235
256
  };
236
257
 
@@ -258,11 +279,11 @@ const findInstalledDirectoryUrl = (declaringDirectoryUrl, packageName) => {
258
279
  return null;
259
280
  };
260
281
 
261
- const readDeclaredVersion = (packageJSON, packageName) => {
282
+ const readDeclaration = (packageJSON, packageName) => {
262
283
  for (const field of DEPENDENCY_FIELDS) {
263
284
  const dependencies = packageJSON[field];
264
285
  if (dependencies && dependencies[packageName]) {
265
- return dependencies[packageName];
286
+ return { field, version: dependencies[packageName] };
266
287
  }
267
288
  }
268
289
  return null;
@@ -4,6 +4,11 @@
4
4
  * A missing dependency is not handled here: it makes the import fail, so the
5
5
  * error overlay already says it, with more precision (which import, where).
6
6
  *
7
+ * The overlay is for the problems the server marks as "warning" (see severity
8
+ * in package_dependencies.js). An outdated devDependency is "info": it goes to
9
+ * the console as a line, said once, followed by an other line when it gets
10
+ * installed; no overlay, and the server does not reload the page for it.
11
+ *
7
12
  * The overlay does not only describe the problem, it shows the dev server
8
13
  * watching for the fix: the paths being looked at are named and kept alive on
9
14
  * screen, so waiting for "npm install" feels like waiting for something that is
@@ -16,6 +21,9 @@ let watchInfoFromServer = {};
16
21
  // what leaves this map has been installed while the overlay was open, which is
17
22
  // worth showing as such
18
23
  const outdatedPathMap = new Map();
24
+ // the console is append-only: a problem is said when it appears or changes,
25
+ // and its resolution when it leaves the list
26
+ const consoleLineMap = new Map();
19
27
 
20
28
  const initDependencyStatus = ({ problems, watchInfo }) => {
21
29
  watchInfoFromServer = watchInfo || {};
@@ -32,7 +40,10 @@ const initDependencyStatus = ({ problems, watchInfo }) => {
32
40
  };
33
41
 
34
42
  const render = (problems) => {
35
- const outdatedList = problems.filter(({ state }) => state === "outdated");
43
+ logInfoProblems(problems.filter(({ severity }) => severity === "info"));
44
+ const outdatedList = problems.filter(
45
+ ({ state, severity }) => state === "outdated" && severity === "warning",
46
+ );
36
47
  removeOverlay();
37
48
  removeOverlay = () => {};
38
49
  const installedList = [];
@@ -67,6 +78,28 @@ const render = (problems) => {
67
78
  });
68
79
  };
69
80
 
81
+ const logInfoProblems = (infoList) => {
82
+ for (const problem of infoList) {
83
+ const { packageName, declaredIn, declaredVersion, installedVersion } =
84
+ problem;
85
+ const line = `[jsenv] "${packageName}" is installed in ${
86
+ installedVersion || "an unknown version"
87
+ } but package.json declares ${declaredVersion} in ${declaredIn}, run npm install`;
88
+ if (consoleLineMap.get(packageName) === line) {
89
+ continue;
90
+ }
91
+ consoleLineMap.set(packageName, line);
92
+ console.info(line);
93
+ }
94
+ for (const packageName of consoleLineMap.keys()) {
95
+ if (infoList.some((problem) => problem.packageName === packageName)) {
96
+ continue;
97
+ }
98
+ consoleLineMap.delete(packageName);
99
+ console.info(`[jsenv] "${packageName}" is now installed`);
100
+ }
101
+ };
102
+
70
103
  const describe = ({ packageName, declaredVersion, installedVersion }) => {
71
104
  return `${packageName}
72
105
  package.json declares ${declaredVersion}
@@ -62,6 +62,13 @@ const createEventEmitter = () => {
62
62
  * Only exact declared versions ("1.2.3") are compared: a range ("^1.2.3"), a
63
63
  * file/workspace protocol or a tag cannot be checked without resolving what npm
64
64
  * would pick, which is way beyond what is needed here.
65
+ *
66
+ * A status carries a severity so that every consumer (server log, browser
67
+ * overlay, reload on install) reads the same decision: a missing package or an
68
+ * outdated runtime dependency is a "warning", the page is not running what the
69
+ * project asks for. An outdated devDependency is only "info": the installed
70
+ * version runs, what may differ is tooling, and that is worth a line in the
71
+ * console, not a dialog nor a reload once installed.
65
72
  */
66
73
 
67
74
 
@@ -93,13 +100,14 @@ const readDependencyStatus = (
93
100
  if (!packageJSON) {
94
101
  return null;
95
102
  }
96
- const declaredVersion = readDeclaredVersion(packageJSON, packageName);
97
- if (!declaredVersion) {
103
+ const declaration = readDeclaration(packageJSON, packageName);
104
+ if (!declaration) {
98
105
  return null;
99
106
  }
100
107
  return createStatus(packageDirectory, {
101
108
  packageName,
102
- declaredVersion,
109
+ declaredVersion: declaration.version,
110
+ declaredIn: declaration.field,
103
111
  declaringDirectoryUrl,
104
112
  declaredBy: packageJSON.name,
105
113
  });
@@ -126,6 +134,7 @@ const readDependencyStatuses = (packageDirectory) => {
126
134
  createStatus(packageDirectory, {
127
135
  packageName,
128
136
  declaredVersion: dependencies[packageName],
137
+ declaredIn: field,
129
138
  declaringDirectoryUrl: packageDirectory.url,
130
139
  declaredBy: packageJSON.name,
131
140
  }),
@@ -137,17 +146,25 @@ const readDependencyStatuses = (packageDirectory) => {
137
146
 
138
147
  const createStatus = (
139
148
  packageDirectory,
140
- { packageName, declaredVersion, declaringDirectoryUrl, declaredBy },
149
+ {
150
+ packageName,
151
+ declaredVersion,
152
+ declaredIn,
153
+ declaringDirectoryUrl,
154
+ declaredBy,
155
+ },
141
156
  ) => {
142
157
  const status = {
143
158
  packageName,
144
159
  declaredVersion,
160
+ declaredIn,
145
161
  declaredBy,
146
162
  installedVersion: null,
147
163
  // the file telling this dependency apart; it is what an install rewrites and
148
164
  // what the dev server looks at to know the dependency became the declared one
149
165
  watchedPath: null,
150
166
  state: "missing",
167
+ severity: "warning",
151
168
  };
152
169
  const installedDirectoryUrl = findInstalledDirectoryUrl(
153
170
  declaringDirectoryUrl,
@@ -169,11 +186,16 @@ const createStatus = (
169
186
  status.installedVersion = installedPackageJSON
170
187
  ? installedPackageJSON.version
171
188
  : null;
172
- status.state =
173
- isExactVersion(declaredVersion) &&
174
- status.installedVersion !== declaredVersion
175
- ? "outdated"
176
- : "installed";
189
+ if (
190
+ !isExactVersion(declaredVersion) ||
191
+ status.installedVersion === declaredVersion
192
+ ) {
193
+ status.state = "installed";
194
+ status.severity = null;
195
+ return status;
196
+ }
197
+ status.state = "outdated";
198
+ status.severity = declaredIn === "devDependencies" ? "info" : "warning";
177
199
  return status;
178
200
  };
179
201
 
@@ -201,11 +223,11 @@ const findInstalledDirectoryUrl = (declaringDirectoryUrl, packageName) => {
201
223
  return null;
202
224
  };
203
225
 
204
- const readDeclaredVersion = (packageJSON, packageName) => {
226
+ const readDeclaration = (packageJSON, packageName) => {
205
227
  for (const field of DEPENDENCY_FIELDS) {
206
228
  const dependencies = packageJSON[field];
207
229
  if (dependencies && dependencies[packageName]) {
208
- return dependencies[packageName];
230
+ return { field, version: dependencies[packageName] };
209
231
  }
210
232
  }
211
233
  return null;
@@ -12152,15 +12174,29 @@ const startDevServer = async ({
12152
12174
  onChange: (problems) => {
12153
12175
  dependencyProblemEventEmitter.emit(problems);
12154
12176
  },
12155
- onProblem: ({ packageName, declaredVersion, installedVersion, state }) => {
12156
- logger.warn(
12177
+ onProblem: ({
12178
+ packageName,
12179
+ declaredVersion,
12180
+ installedVersion,
12181
+ declaredIn,
12182
+ state,
12183
+ severity,
12184
+ }) => {
12185
+ const message =
12157
12186
  state === "missing"
12158
12187
  ? `"${packageName}@${declaredVersion}" is declared in package.json but not installed, run npm install`
12159
- : `"${packageName}" is installed in ${installedVersion} but package.json declares ${declaredVersion}, run npm install`,
12160
- );
12188
+ : `"${packageName}" is installed in ${installedVersion} but package.json declares ${declaredVersion} in ${declaredIn}, run npm install`;
12189
+ if (severity === "warning") {
12190
+ logger.warn(message);
12191
+ } else {
12192
+ logger.info(message);
12193
+ }
12161
12194
  },
12162
- onInstalled: ({ packageName, declaredVersion }) => {
12195
+ onInstalled: ({ packageName, declaredVersion, severity }) => {
12163
12196
  logger.info(`"${packageName}@${declaredVersion}" is now installed`);
12197
+ if (severity !== "warning") {
12198
+ return;
12199
+ }
12164
12200
  reloadRequestEventEmitter.emit({
12165
12201
  cause: `${packageName}@${declaredVersion} installed`,
12166
12202
  reason: `a dependency became available in node_modules`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/core",
3
- "version": "41.4.22",
3
+ "version": "41.4.24",
4
4
  "type": "module",
5
5
  "description": "Tool to develop, test and build js projects",
6
6
  "repository": {
@@ -220,15 +220,29 @@ export const startDevServer = async ({
220
220
  onChange: (problems) => {
221
221
  dependencyProblemEventEmitter.emit(problems);
222
222
  },
223
- onProblem: ({ packageName, declaredVersion, installedVersion, state }) => {
224
- logger.warn(
223
+ onProblem: ({
224
+ packageName,
225
+ declaredVersion,
226
+ installedVersion,
227
+ declaredIn,
228
+ state,
229
+ severity,
230
+ }) => {
231
+ const message =
225
232
  state === "missing"
226
233
  ? `"${packageName}@${declaredVersion}" is declared in package.json but not installed, run npm install`
227
- : `"${packageName}" is installed in ${installedVersion} but package.json declares ${declaredVersion}, run npm install`,
228
- );
234
+ : `"${packageName}" is installed in ${installedVersion} but package.json declares ${declaredVersion} in ${declaredIn}, run npm install`;
235
+ if (severity === "warning") {
236
+ logger.warn(message);
237
+ } else {
238
+ logger.info(message);
239
+ }
229
240
  },
230
- onInstalled: ({ packageName, declaredVersion }) => {
241
+ onInstalled: ({ packageName, declaredVersion, severity }) => {
231
242
  logger.info(`"${packageName}@${declaredVersion}" is now installed`);
243
+ if (severity !== "warning") {
244
+ return;
245
+ }
232
246
  reloadRequestEventEmitter.emit({
233
247
  cause: `${packageName}@${declaredVersion} installed`,
234
248
  reason: `a dependency became available in node_modules`,
@@ -10,6 +10,13 @@
10
10
  * Only exact declared versions ("1.2.3") are compared: a range ("^1.2.3"), a
11
11
  * file/workspace protocol or a tag cannot be checked without resolving what npm
12
12
  * would pick, which is way beyond what is needed here.
13
+ *
14
+ * A status carries a severity so that every consumer (server log, browser
15
+ * overlay, reload on install) reads the same decision: a missing package or an
16
+ * outdated runtime dependency is a "warning", the page is not running what the
17
+ * project asks for. An outdated devDependency is only "info": the installed
18
+ * version runs, what may differ is tooling, and that is worth a line in the
19
+ * console, not a dialog nor a reload once installed.
13
20
  */
14
21
 
15
22
  import { urlToRelativeUrl } from "@jsenv/urls";
@@ -43,13 +50,14 @@ export const readDependencyStatus = (
43
50
  if (!packageJSON) {
44
51
  return null;
45
52
  }
46
- const declaredVersion = readDeclaredVersion(packageJSON, packageName);
47
- if (!declaredVersion) {
53
+ const declaration = readDeclaration(packageJSON, packageName);
54
+ if (!declaration) {
48
55
  return null;
49
56
  }
50
57
  return createStatus(packageDirectory, {
51
58
  packageName,
52
- declaredVersion,
59
+ declaredVersion: declaration.version,
60
+ declaredIn: declaration.field,
53
61
  declaringDirectoryUrl,
54
62
  declaredBy: packageJSON.name,
55
63
  });
@@ -76,6 +84,7 @@ export const readDependencyStatuses = (packageDirectory) => {
76
84
  createStatus(packageDirectory, {
77
85
  packageName,
78
86
  declaredVersion: dependencies[packageName],
87
+ declaredIn: field,
79
88
  declaringDirectoryUrl: packageDirectory.url,
80
89
  declaredBy: packageJSON.name,
81
90
  }),
@@ -87,17 +96,25 @@ export const readDependencyStatuses = (packageDirectory) => {
87
96
 
88
97
  const createStatus = (
89
98
  packageDirectory,
90
- { packageName, declaredVersion, declaringDirectoryUrl, declaredBy },
99
+ {
100
+ packageName,
101
+ declaredVersion,
102
+ declaredIn,
103
+ declaringDirectoryUrl,
104
+ declaredBy,
105
+ },
91
106
  ) => {
92
107
  const status = {
93
108
  packageName,
94
109
  declaredVersion,
110
+ declaredIn,
95
111
  declaredBy,
96
112
  installedVersion: null,
97
113
  // the file telling this dependency apart; it is what an install rewrites and
98
114
  // what the dev server looks at to know the dependency became the declared one
99
115
  watchedPath: null,
100
116
  state: "missing",
117
+ severity: "warning",
101
118
  };
102
119
  const installedDirectoryUrl = findInstalledDirectoryUrl(
103
120
  declaringDirectoryUrl,
@@ -119,11 +136,16 @@ const createStatus = (
119
136
  status.installedVersion = installedPackageJSON
120
137
  ? installedPackageJSON.version
121
138
  : null;
122
- status.state =
123
- isExactVersion(declaredVersion) &&
124
- status.installedVersion !== declaredVersion
125
- ? "outdated"
126
- : "installed";
139
+ if (
140
+ !isExactVersion(declaredVersion) ||
141
+ status.installedVersion === declaredVersion
142
+ ) {
143
+ status.state = "installed";
144
+ status.severity = null;
145
+ return status;
146
+ }
147
+ status.state = "outdated";
148
+ status.severity = declaredIn === "devDependencies" ? "info" : "warning";
127
149
  return status;
128
150
  };
129
151
 
@@ -151,11 +173,11 @@ const findInstalledDirectoryUrl = (declaringDirectoryUrl, packageName) => {
151
173
  return null;
152
174
  };
153
175
 
154
- const readDeclaredVersion = (packageJSON, packageName) => {
176
+ const readDeclaration = (packageJSON, packageName) => {
155
177
  for (const field of DEPENDENCY_FIELDS) {
156
178
  const dependencies = packageJSON[field];
157
179
  if (dependencies && dependencies[packageName]) {
158
- return dependencies[packageName];
180
+ return { field, version: dependencies[packageName] };
159
181
  }
160
182
  }
161
183
  return null;
@@ -4,6 +4,11 @@
4
4
  * A missing dependency is not handled here: it makes the import fail, so the
5
5
  * error overlay already says it, with more precision (which import, where).
6
6
  *
7
+ * The overlay is for the problems the server marks as "warning" (see severity
8
+ * in package_dependencies.js). An outdated devDependency is "info": it goes to
9
+ * the console as a line, said once, followed by an other line when it gets
10
+ * installed; no overlay, and the server does not reload the page for it.
11
+ *
7
12
  * The overlay does not only describe the problem, it shows the dev server
8
13
  * watching for the fix: the paths being looked at are named and kept alive on
9
14
  * screen, so waiting for "npm install" feels like waiting for something that is
@@ -16,6 +21,9 @@ let watchInfoFromServer = {};
16
21
  // what leaves this map has been installed while the overlay was open, which is
17
22
  // worth showing as such
18
23
  const outdatedPathMap = new Map();
24
+ // the console is append-only: a problem is said when it appears or changes,
25
+ // and its resolution when it leaves the list
26
+ const consoleLineMap = new Map();
19
27
 
20
28
  export const initDependencyStatus = ({ problems, watchInfo }) => {
21
29
  watchInfoFromServer = watchInfo || {};
@@ -32,7 +40,10 @@ export const initDependencyStatus = ({ problems, watchInfo }) => {
32
40
  };
33
41
 
34
42
  const render = (problems) => {
35
- const outdatedList = problems.filter(({ state }) => state === "outdated");
43
+ logInfoProblems(problems.filter(({ severity }) => severity === "info"));
44
+ const outdatedList = problems.filter(
45
+ ({ state, severity }) => state === "outdated" && severity === "warning",
46
+ );
36
47
  removeOverlay();
37
48
  removeOverlay = () => {};
38
49
  const installedList = [];
@@ -67,6 +78,28 @@ const render = (problems) => {
67
78
  });
68
79
  };
69
80
 
81
+ const logInfoProblems = (infoList) => {
82
+ for (const problem of infoList) {
83
+ const { packageName, declaredIn, declaredVersion, installedVersion } =
84
+ problem;
85
+ const line = `[jsenv] "${packageName}" is installed in ${
86
+ installedVersion || "an unknown version"
87
+ } but package.json declares ${declaredVersion} in ${declaredIn}, run npm install`;
88
+ if (consoleLineMap.get(packageName) === line) {
89
+ continue;
90
+ }
91
+ consoleLineMap.set(packageName, line);
92
+ console.info(line);
93
+ }
94
+ for (const packageName of consoleLineMap.keys()) {
95
+ if (infoList.some((problem) => problem.packageName === packageName)) {
96
+ continue;
97
+ }
98
+ consoleLineMap.delete(packageName);
99
+ console.info(`[jsenv] "${packageName}" is now installed`);
100
+ }
101
+ };
102
+
70
103
  const describe = ({ packageName, declaredVersion, installedVersion }) => {
71
104
  return `${packageName}
72
105
  package.json declares ${declaredVersion}