@node-red/registry 3.0.0-beta.2 → 3.0.0
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.
- package/lib/externalModules.js +8 -2
- package/lib/loader.js +1 -0
- package/lib/localfilesystem.js +146 -49
- package/package.json +3 -3
package/lib/externalModules.js
CHANGED
|
@@ -11,6 +11,7 @@ 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
15
|
|
|
15
16
|
const BUILTIN_MODULES = require('module').builtinModules;
|
|
16
17
|
|
|
@@ -139,10 +140,15 @@ function importModule(module) {
|
|
|
139
140
|
}
|
|
140
141
|
const externalModuleDir = getInstallDir();
|
|
141
142
|
const moduleDir = path.join(externalModuleDir,"node_modules",module);
|
|
143
|
+
// To handle both CJS and ESM we need to resolve the module to the
|
|
144
|
+
// specific file that is loaded when the module is required/imported
|
|
145
|
+
// As this won't be on the natural module search path, we use createRequire
|
|
146
|
+
// to access the module
|
|
147
|
+
const modulePath = createRequire(moduleDir).resolve(module)
|
|
142
148
|
// Import needs the full path to the module's main .js file
|
|
143
149
|
// It also needs to be a file:// url for Windows
|
|
144
|
-
const
|
|
145
|
-
return import(
|
|
150
|
+
const moduleUrl = url.pathToFileURL(modulePath);
|
|
151
|
+
return import(moduleUrl);
|
|
146
152
|
}
|
|
147
153
|
|
|
148
154
|
function parseModuleName(module) {
|
package/lib/loader.js
CHANGED
package/lib/localfilesystem.js
CHANGED
|
@@ -88,9 +88,10 @@ function getLocalFile(file) {
|
|
|
88
88
|
/**
|
|
89
89
|
* Synchronously walks the directory looking for node files.
|
|
90
90
|
* @param dir the directory to search
|
|
91
|
+
* @param skipValidNodeRedModules a flag to skip lading icons & files if the directory a valid node-red module
|
|
91
92
|
* @return an array of fully-qualified paths to .js files
|
|
92
93
|
*/
|
|
93
|
-
function getLocalNodeFiles(dir) {
|
|
94
|
+
function getLocalNodeFiles(dir, skipValidNodeRedModules) {
|
|
94
95
|
dir = path.resolve(dir);
|
|
95
96
|
|
|
96
97
|
var result = [];
|
|
@@ -102,6 +103,14 @@ function getLocalNodeFiles(dir) {
|
|
|
102
103
|
return {files: [], icons: []};
|
|
103
104
|
}
|
|
104
105
|
files.sort();
|
|
106
|
+
// when loading local files, if the path is a valid node-red module
|
|
107
|
+
// dont include it (will be picked up in scanTreeForNodesModules)
|
|
108
|
+
if(skipValidNodeRedModules && files.indexOf("package.json") >= 0) {
|
|
109
|
+
const package = getPackageDetails(dir)
|
|
110
|
+
if(package.isNodeRedModule) {
|
|
111
|
+
return {files: [], icons: []};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
105
114
|
files.forEach(function(fn) {
|
|
106
115
|
var stats = fs.statSync(path.join(dir,fn));
|
|
107
116
|
if (stats.isFile()) {
|
|
@@ -114,7 +123,7 @@ function getLocalNodeFiles(dir) {
|
|
|
114
123
|
} else if (stats.isDirectory()) {
|
|
115
124
|
// Ignore /.dirs/, /lib/ /node_modules/
|
|
116
125
|
if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
|
|
117
|
-
var subDirResults = getLocalNodeFiles(path.join(dir,fn));
|
|
126
|
+
var subDirResults = getLocalNodeFiles(path.join(dir,fn), skipValidNodeRedModules);
|
|
118
127
|
result = result.concat(subDirResults.files);
|
|
119
128
|
icons = icons.concat(subDirResults.icons);
|
|
120
129
|
} else if (fn === "icons") {
|
|
@@ -126,21 +135,30 @@ function getLocalNodeFiles(dir) {
|
|
|
126
135
|
return {files: result, icons: icons}
|
|
127
136
|
}
|
|
128
137
|
|
|
129
|
-
function scanDirForNodesModules(dir,moduleName) {
|
|
130
|
-
|
|
131
|
-
|
|
138
|
+
function scanDirForNodesModules(dir,moduleName,package) {
|
|
139
|
+
let results = [];
|
|
140
|
+
let scopeName;
|
|
141
|
+
let files
|
|
132
142
|
try {
|
|
133
|
-
|
|
134
|
-
if
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
let isNodeRedModule = false
|
|
144
|
+
if(package) {
|
|
145
|
+
dir = path.join(package.moduleDir,'..')
|
|
146
|
+
files = [path.basename(package.moduleDir)]
|
|
147
|
+
moduleName = (package.package ? package.package.name : null) || moduleName
|
|
148
|
+
isNodeRedModule = package.isNodeRedModule
|
|
149
|
+
} else {
|
|
150
|
+
files = fs.readdirSync(dir);
|
|
151
|
+
if (moduleName) {
|
|
152
|
+
var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
|
|
153
|
+
if (m) {
|
|
154
|
+
scopeName = m[1];
|
|
155
|
+
moduleName = m[2];
|
|
156
|
+
}
|
|
139
157
|
}
|
|
140
158
|
}
|
|
141
|
-
for (
|
|
142
|
-
|
|
143
|
-
if (/^@/.test(fn)) {
|
|
159
|
+
for (let i=0;i<files.length;i++) {
|
|
160
|
+
let fn = files[i];
|
|
161
|
+
if (!isNodeRedModule && /^@/.test(fn)) {
|
|
144
162
|
if (scopeName && scopeName === fn) {
|
|
145
163
|
// Looking for a specific scope/module
|
|
146
164
|
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
|
@@ -149,16 +167,18 @@ function scanDirForNodesModules(dir,moduleName) {
|
|
|
149
167
|
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
|
150
168
|
}
|
|
151
169
|
} else {
|
|
152
|
-
if (
|
|
153
|
-
var pkgfn = path.join(dir,fn,"package.json");
|
|
170
|
+
if ((isNodeRedModule || (!moduleName || fn == moduleName)) && (isIncluded(fn) && !isExcluded(fn))) {
|
|
154
171
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
172
|
+
const moduleDir = isNodeRedModule ? package.moduleDir : path.join(dir,fn);
|
|
173
|
+
const pkg = package || getPackageDetails(moduleDir)
|
|
174
|
+
if(pkg.error) {
|
|
175
|
+
throw pkg.error
|
|
176
|
+
}
|
|
177
|
+
if (pkg.isNodeRedModule) {
|
|
178
|
+
if (!pkg.allowed) {
|
|
179
|
+
log.debug("! Module: "+pkg.package.name+" "+pkg.package.version+ " *ignored due to denyList*");
|
|
159
180
|
} else {
|
|
160
|
-
|
|
161
|
-
results.push({dir:moduleDir,package:pkg});
|
|
181
|
+
results.push({dir:moduleDir,package:pkg.package});
|
|
162
182
|
}
|
|
163
183
|
}
|
|
164
184
|
} catch(err) {
|
|
@@ -182,11 +202,14 @@ function scanDirForNodesModules(dir,moduleName) {
|
|
|
182
202
|
* @param moduleName the name of the module to be found
|
|
183
203
|
* @return a list of node modules: {dir,package}
|
|
184
204
|
*/
|
|
185
|
-
function scanTreeForNodesModules(moduleName) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
function scanTreeForNodesModules(moduleName) {
|
|
206
|
+
let coreNodesDir = settings.coreNodesDir;
|
|
207
|
+
let results = [];
|
|
208
|
+
let userDir;
|
|
209
|
+
let nodesDir;
|
|
210
|
+
if(settings.nodesDir) {
|
|
211
|
+
nodesDir = Array.isArray(settings.nodesDir) ? settings.nodesDir : [settings.nodesDir]
|
|
212
|
+
}
|
|
190
213
|
if (settings.userDir) {
|
|
191
214
|
packageList = getPackageList();
|
|
192
215
|
userDir = path.join(settings.userDir,"node_modules");
|
|
@@ -201,15 +224,46 @@ function scanTreeForNodesModules(moduleName) {
|
|
|
201
224
|
});
|
|
202
225
|
}
|
|
203
226
|
|
|
204
|
-
if (
|
|
205
|
-
var up = path.resolve(path.join(
|
|
206
|
-
while (up !==
|
|
207
|
-
var pm = path.join(
|
|
227
|
+
if (coreNodesDir) {
|
|
228
|
+
var up = path.resolve(path.join(coreNodesDir,".."));
|
|
229
|
+
while (up !== coreNodesDir) {
|
|
230
|
+
var pm = path.join(coreNodesDir,"node_modules");
|
|
208
231
|
if (pm != userDir) {
|
|
209
232
|
results = results.concat(scanDirForNodesModules(pm,moduleName));
|
|
210
233
|
}
|
|
211
|
-
|
|
212
|
-
up = path.resolve(path.join(
|
|
234
|
+
coreNodesDir = up;
|
|
235
|
+
up = path.resolve(path.join(coreNodesDir,".."));
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// scan nodesDir for any node-red modules
|
|
240
|
+
/*
|
|
241
|
+
1. if !exist(package.json) || !package.json.has(node-red) => look for node_modules
|
|
242
|
+
2. exist(package.json) && package.json.has(node-red) => load this only
|
|
243
|
+
3. in original scan of nodesDir, ignore if:(exist(package.json) && package.json.has(node-red))
|
|
244
|
+
*/
|
|
245
|
+
if (nodesDir) {
|
|
246
|
+
for (let dirIndex = 0; dirIndex < nodesDir.length; dirIndex++) {
|
|
247
|
+
const nodeDir = nodesDir[dirIndex];
|
|
248
|
+
const packageDetails = getPackageDetails(nodeDir)
|
|
249
|
+
if(packageDetails.isNodeRedModule) {
|
|
250
|
+
//we have found a node-red module, scan it
|
|
251
|
+
const nrModules = scanDirForNodesModules(nodeDir, packageDetails.package.name, packageDetails);
|
|
252
|
+
results = results.concat(nrModules);
|
|
253
|
+
|
|
254
|
+
} else if (packageDetails.has_node_modules) {
|
|
255
|
+
//If this dir has a `node_modues` dir, scan it
|
|
256
|
+
const nodeModulesDir = path.join(nodeDir, 'node_modules')
|
|
257
|
+
const nrModules = scanDirForNodesModules(nodeModulesDir, moduleName );
|
|
258
|
+
results = results.concat(nrModules);
|
|
259
|
+
|
|
260
|
+
} else {
|
|
261
|
+
//If this is not a node-red module AND it does NOT have a node_modules dir,
|
|
262
|
+
//it may be a directory of project directories or a node_modules dir?
|
|
263
|
+
//scan this instead
|
|
264
|
+
const nrModules = scanDirForNodesModules(nodeDir, moduleName);
|
|
265
|
+
results = results.concat(nrModules);
|
|
266
|
+
}
|
|
213
267
|
}
|
|
214
268
|
}
|
|
215
269
|
return results;
|
|
@@ -274,24 +328,26 @@ function getModuleNodeFiles(module) {
|
|
|
274
328
|
}
|
|
275
329
|
|
|
276
330
|
function getNodeFiles(disableNodePathScan) {
|
|
277
|
-
var dir;
|
|
278
331
|
// Find all of the nodes to load
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
332
|
+
let results;
|
|
333
|
+
let nodesDir;
|
|
334
|
+
if(settings.nodesDir) {
|
|
335
|
+
nodesDir = Array.isArray(settings.nodesDir) ? settings.nodesDir : [settings.nodesDir]
|
|
336
|
+
}
|
|
337
|
+
let dir;
|
|
338
|
+
let nodeFiles = [];
|
|
339
|
+
let iconList = [];
|
|
284
340
|
if (settings.coreNodesDir) {
|
|
285
341
|
results = getLocalNodeFiles(path.resolve(settings.coreNodesDir));
|
|
286
342
|
nodeFiles = nodeFiles.concat(results.files);
|
|
287
343
|
iconList = iconList.concat(results.icons);
|
|
288
|
-
|
|
344
|
+
let defaultLocalesPath = path.join(settings.coreNodesDir,"locales");
|
|
289
345
|
i18n.registerMessageCatalog("node-red",defaultLocalesPath,"messages.json");
|
|
290
346
|
}
|
|
291
347
|
|
|
292
348
|
if (settings.userDir) {
|
|
293
349
|
dir = path.join(settings.userDir,"lib","icons");
|
|
294
|
-
|
|
350
|
+
let icons = scanIconDir(dir);
|
|
295
351
|
if (icons.length > 0) {
|
|
296
352
|
iconList.push({path:dir,icons:icons});
|
|
297
353
|
}
|
|
@@ -301,13 +357,9 @@ function getNodeFiles(disableNodePathScan) {
|
|
|
301
357
|
nodeFiles = nodeFiles.concat(results.files);
|
|
302
358
|
iconList = iconList.concat(results.icons);
|
|
303
359
|
}
|
|
304
|
-
if (
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
dir = [dir];
|
|
308
|
-
}
|
|
309
|
-
for (var i=0;i<dir.length;i++) {
|
|
310
|
-
results = getLocalNodeFiles(dir[i]);
|
|
360
|
+
if (nodesDir) {
|
|
361
|
+
for (let i = 0; i < nodesDir.length; i++) {
|
|
362
|
+
results = getLocalNodeFiles(nodesDir[i], true);
|
|
311
363
|
nodeFiles = nodeFiles.concat(results.files);
|
|
312
364
|
iconList = iconList.concat(results.icons);
|
|
313
365
|
}
|
|
@@ -479,7 +531,52 @@ function getPackageList() {
|
|
|
479
531
|
}
|
|
480
532
|
return list;
|
|
481
533
|
}
|
|
482
|
-
|
|
534
|
+
/**
|
|
535
|
+
* Gets the package json object for the supplied `dir`.
|
|
536
|
+
* If there is no package.json or the `node-red` section is missing, `result.isNodeRedModule` will be `false`.
|
|
537
|
+
* If there is no package.json `isPackage` will be `false`.
|
|
538
|
+
* If an error occurs, `result.error` will contain the error.
|
|
539
|
+
* @param {string} dir The directory to inspect
|
|
540
|
+
*/
|
|
541
|
+
function getPackageDetails(dir) {
|
|
542
|
+
const result = {
|
|
543
|
+
/** @type {string} The package directory */
|
|
544
|
+
moduleDir: dir,
|
|
545
|
+
/** @type {string} The full file path of package.json for this package */
|
|
546
|
+
packageFile: null,
|
|
547
|
+
/** @type {boolean} True if this is a valid node-red module */
|
|
548
|
+
isNodeRedModule: false,
|
|
549
|
+
/** @type {boolean} True if a package.json file is present */
|
|
550
|
+
isPackage: false,
|
|
551
|
+
/** @type {boolean} True if this a node-red module and passes the checks */
|
|
552
|
+
allowed: false,
|
|
553
|
+
/** @type {object} The contents of package.json */
|
|
554
|
+
package: null,
|
|
555
|
+
}
|
|
556
|
+
if (!dir) { return result }
|
|
557
|
+
try {
|
|
558
|
+
const packagefile = path.join(dir,'package.json')
|
|
559
|
+
result.has_node_modules = fs.existsSync(path.join(dir,'node_modules'))
|
|
560
|
+
if(!fs.existsSync(packagefile)) {
|
|
561
|
+
return result
|
|
562
|
+
}
|
|
563
|
+
result.packageFile = packagefile
|
|
564
|
+
const pkg = require(packagefile)
|
|
565
|
+
result.package = pkg
|
|
566
|
+
if(result.package) {
|
|
567
|
+
result.allowed = true
|
|
568
|
+
result.isPackage = true
|
|
569
|
+
result.isNodeRedModule = typeof result.package['node-red'] === 'object'
|
|
570
|
+
if(result.isNodeRedModule) {
|
|
571
|
+
result.isNodeRedModule = true;
|
|
572
|
+
result.allowed = registryUtil.checkModuleAllowed(pkg.name,pkg.version,loadAllowList,loadDenyList)
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
} catch(err) {
|
|
576
|
+
result.error = err; // this is not a package we are interested in!
|
|
577
|
+
}
|
|
578
|
+
return result || result;
|
|
579
|
+
}
|
|
483
580
|
module.exports = {
|
|
484
581
|
init: init,
|
|
485
582
|
getNodeFiles: getNodeFiles,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@node-red/registry",
|
|
3
|
-
"version": "3.0.0
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"repository": {
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@node-red/util": "3.0.0
|
|
19
|
+
"@node-red/util": "3.0.0",
|
|
20
20
|
"clone": "2.1.2",
|
|
21
21
|
"fs-extra": "10.1.0",
|
|
22
22
|
"semver": "7.3.7",
|
|
23
23
|
"tar": "6.1.11",
|
|
24
|
-
"uglify-js": "3.
|
|
24
|
+
"uglify-js": "3.16.2"
|
|
25
25
|
}
|
|
26
26
|
}
|