@node-red/registry 5.0.7 → 5.0.9

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.
@@ -11,11 +11,9 @@ const exec = require("@node-red/util").exec;
11
11
  const log = require("@node-red/util").log;
12
12
  const hooks = require("@node-red/util").hooks;
13
13
  const url = require("url");
14
- const { createRequire } = require("module");
14
+ const { createRequire, isBuiltin } = require("module");
15
15
  const validateNpmPackageName = require("validate-npm-package-name");
16
16
 
17
- const BUILTIN_MODULES = require('module').builtinModules;
18
-
19
17
  const npmPackageJson = require.resolve('npm/package.json')
20
18
  const npmRoot = path.dirname(npmPackageJson);
21
19
  const npmCli = path.join(npmRoot, 'bin', 'npm-cli.js');
@@ -129,23 +127,122 @@ function importModule(module) {
129
127
  // specific file that is loaded when the module is required/imported
130
128
  // As this won't be on the natural module search path, we use createRequire
131
129
  // to access the module
132
- const modulePath = createRequire(moduleDir).resolve(module)
130
+ let modulePath;
131
+ try {
132
+ modulePath = createRequire(moduleDir).resolve(module)
133
+ } catch (err) {
134
+ if (err.code !== 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
135
+ throw err;
136
+ }
137
+ // require.resolve only matches the 'require' export condition. ESM-only
138
+ // packages may only provide an 'import' condition, so resolve it ourselves.
139
+ modulePath = resolveImportExport(moduleDir, parsedModule.subpath);
140
+ if (!modulePath) {
141
+ throw err;
142
+ }
143
+ }
133
144
  // Import needs the full path to the module's main .js file
134
145
  // It also needs to be a file:// url for Windows
135
146
  const moduleUrl = url.pathToFileURL(modulePath);
136
147
  return import(moduleUrl);
137
148
  }
138
149
 
150
+ const IMPORT_CONDITIONS = ['import', 'node', 'default'];
151
+
152
+ /**
153
+ * Resolve a package subpath using the 'import' conditions of its package.json exports
154
+ * @param {string} moduleDir - the directory of the package
155
+ * @param {string} subpath - the subpath being imported, eg '' or '/foo'
156
+ * @return {string|null} the absolute path to the file, or null if it cannot be resolved
157
+ */
158
+ function resolveImportExport(moduleDir, subpath) {
159
+ let pkg;
160
+ try {
161
+ pkg = fs.readJsonSync(path.join(moduleDir, 'package.json'));
162
+ } catch (err) {
163
+ return null;
164
+ }
165
+ const exportsField = pkg.exports;
166
+ if (exportsField === undefined || exportsField === null) {
167
+ return null;
168
+ }
169
+ const request = '.' + (subpath || '');
170
+ let target;
171
+ let patternMatch;
172
+ const isSubpathMap = typeof exportsField === 'object' && !Array.isArray(exportsField) &&
173
+ Object.keys(exportsField).some(k => k.startsWith('.'));
174
+ if (!isSubpathMap) {
175
+ if (request === '.') {
176
+ target = exportsField;
177
+ }
178
+ } else if (Object.prototype.hasOwnProperty.call(exportsField, request)) {
179
+ target = exportsField[request];
180
+ } else {
181
+ // Find the most specific matching pattern, eg "./features/*.js"
182
+ let bestKey;
183
+ for (const key of Object.keys(exportsField)) {
184
+ const star = key.indexOf('*');
185
+ if (star === -1) {
186
+ continue;
187
+ }
188
+ const prefix = key.substring(0, star);
189
+ const suffix = key.substring(star + 1);
190
+ if (request.length >= key.length && request.startsWith(prefix) && request.endsWith(suffix) &&
191
+ (!bestKey || prefix.length > bestKey.indexOf('*'))) {
192
+ bestKey = key;
193
+ patternMatch = request.substring(prefix.length, request.length - suffix.length);
194
+ }
195
+ }
196
+ if (bestKey) {
197
+ target = exportsField[bestKey];
198
+ }
199
+ }
200
+ const resolved = resolveExportTarget(target, patternMatch);
201
+ if (!resolved) {
202
+ return null;
203
+ }
204
+ const resolvedPath = path.resolve(moduleDir, resolved);
205
+ // Do not allow the target to escape the package directory
206
+ if (path.relative(moduleDir, resolvedPath).startsWith('..')) {
207
+ return null;
208
+ }
209
+ return resolvedPath;
210
+ }
211
+
212
+ function resolveExportTarget(target, patternMatch) {
213
+ if (typeof target === 'string') {
214
+ if (!target.startsWith('./')) {
215
+ return null;
216
+ }
217
+ return patternMatch !== undefined ? target.replace(/\*/g, patternMatch) : target;
218
+ }
219
+ if (Array.isArray(target)) {
220
+ for (const t of target) {
221
+ const resolved = resolveExportTarget(t, patternMatch);
222
+ if (resolved) {
223
+ return resolved;
224
+ }
225
+ }
226
+ return null;
227
+ }
228
+ if (target && typeof target === 'object') {
229
+ for (const condition of Object.keys(target)) {
230
+ if (IMPORT_CONDITIONS.includes(condition)) {
231
+ const resolved = resolveExportTarget(target[condition], patternMatch);
232
+ if (resolved) {
233
+ return resolved;
234
+ }
235
+ }
236
+ }
237
+ }
238
+ return null;
239
+ }
240
+
139
241
  function parseModuleName(module) {
140
242
  const match = /((?:@[^/]+\/)?[^/@]+)(\/[^/@]+)?(?:@([\s\S]+))?/.exec(module);
141
243
  if (match) {
142
244
  const moduleName = match[1]
143
- let isBuiltIn = false
144
- if (/^node:/.test(moduleName)) {
145
- isBuiltIn = BUILTIN_MODULES.includes(moduleName.substring(5))
146
- } else {
147
- isBuiltIn = BUILTIN_MODULES.includes(moduleName)
148
- }
245
+ const isBuiltIn = isBuiltin(moduleName)
149
246
  return {
150
247
  spec: module,
151
248
  module: moduleName,
package/lib/loader.js CHANGED
@@ -272,7 +272,7 @@ async function loadNodeConfig(fileInfo) {
272
272
  module: module,
273
273
  name: name,
274
274
  file: file,
275
- template: file.replace(/\.c?js$/,".html"),
275
+ template: file.replace(/\.[cm]?js$/,".html"),
276
276
  enabled: isEnabled,
277
277
  loaded:false,
278
278
  version: version,
@@ -72,11 +72,11 @@ function getLocalFile(file) {
72
72
  return null;
73
73
  }
74
74
  try {
75
- fs.statSync(file.replace(/\.c?js$/,".html"));
75
+ fs.statSync(file.replace(/\.[cm]?js$/,".html"));
76
76
  return {
77
77
  file: file,
78
78
  module: "node-red",
79
- name: path.basename(file).replace(/^\d+-/,"").replace(/\.c?js$/,""),
79
+ name: path.basename(file).replace(/^\d+-/,"").replace(/\.[cm]?js$/,""),
80
80
  version: settings.version
81
81
  };
82
82
  } catch(err) {
@@ -114,7 +114,7 @@ function getLocalNodeFiles(dir, skipValidNodeRedModules) {
114
114
  files.forEach(function(fn) {
115
115
  var stats = fs.statSync(path.join(dir,fn));
116
116
  if (stats.isFile()) {
117
- if (/\.c?js$/.test(fn)) {
117
+ if (/\.[cm]?js$/.test(fn)) {
118
118
  var info = getLocalFile(path.join(dir,fn));
119
119
  if (info) {
120
120
  result.push(info);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/registry",
3
- "version": "5.0.7",
3
+ "version": "5.0.9",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./lib/index.js",
6
6
  "repository": {
@@ -16,10 +16,10 @@
16
16
  }
17
17
  ],
18
18
  "dependencies": {
19
- "@node-red/util": "5.0.7",
19
+ "@node-red/util": "5.0.9",
20
20
  "clone": "2.1.2",
21
- "fs-extra": "11.4.0",
22
- "npm": "11.19.1",
21
+ "fs-extra": "11.4.1",
22
+ "npm": "11.21.1",
23
23
  "semver": "7.8.5",
24
24
  "tar": "7.5.22",
25
25
  "uglify-js": "3.19.3",