mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
Merge pull request #3676 from Steve-Mcl/nodesdir-feature-parity
Scanning of `nodesdir` to be more aligned (feature wise) with `coreNodeDir` and `userDir`
This commit is contained in:
commit
77c4423059
@ -88,9 +88,10 @@ function getLocalFile(file) {
|
||||
/**
|
||||
* Synchronously walks the directory looking for node files.
|
||||
* @param dir the directory to search
|
||||
* @param skipValidNodeRedModules a flag to skip lading icons & files if the directory a valid node-red module
|
||||
* @return an array of fully-qualified paths to .js files
|
||||
*/
|
||||
function getLocalNodeFiles(dir) {
|
||||
function getLocalNodeFiles(dir, skipValidNodeRedModules) {
|
||||
dir = path.resolve(dir);
|
||||
|
||||
var result = [];
|
||||
@ -102,6 +103,14 @@ function getLocalNodeFiles(dir) {
|
||||
return {files: [], icons: []};
|
||||
}
|
||||
files.sort();
|
||||
// when loading local files, if the path is a valid node-red module
|
||||
// dont include it (will be picked up in scanTreeForNodesModules)
|
||||
if(skipValidNodeRedModules && files.indexOf("package.json") >= 0) {
|
||||
const package = getPackageDetails(dir)
|
||||
if(package.isNodeRedModule) {
|
||||
return {files: [], icons: []};
|
||||
}
|
||||
}
|
||||
files.forEach(function(fn) {
|
||||
var stats = fs.statSync(path.join(dir,fn));
|
||||
if (stats.isFile()) {
|
||||
@ -114,7 +123,7 @@ function getLocalNodeFiles(dir) {
|
||||
} else if (stats.isDirectory()) {
|
||||
// Ignore /.dirs/, /lib/ /node_modules/
|
||||
if (!/^(\..*|lib|icons|node_modules|test|locales)$/.test(fn)) {
|
||||
var subDirResults = getLocalNodeFiles(path.join(dir,fn));
|
||||
var subDirResults = getLocalNodeFiles(path.join(dir,fn), skipValidNodeRedModules);
|
||||
result = result.concat(subDirResults.files);
|
||||
icons = icons.concat(subDirResults.icons);
|
||||
} else if (fn === "icons") {
|
||||
@ -126,21 +135,30 @@ function getLocalNodeFiles(dir) {
|
||||
return {files: result, icons: icons}
|
||||
}
|
||||
|
||||
function scanDirForNodesModules(dir,moduleName) {
|
||||
var results = [];
|
||||
var scopeName;
|
||||
function scanDirForNodesModules(dir,moduleName,package) {
|
||||
let results = [];
|
||||
let scopeName;
|
||||
let files
|
||||
try {
|
||||
var files = fs.readdirSync(dir);
|
||||
if (moduleName) {
|
||||
var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
|
||||
if (m) {
|
||||
scopeName = m[1];
|
||||
moduleName = m[2];
|
||||
let isNodeRedModule = false
|
||||
if(package) {
|
||||
dir = path.join(package.moduleDir,'..')
|
||||
files = [path.basename(package.moduleDir)]
|
||||
moduleName = (package.package ? package.package.name : null) || moduleName
|
||||
isNodeRedModule = package.isNodeRedModule
|
||||
} else {
|
||||
files = fs.readdirSync(dir);
|
||||
if (moduleName) {
|
||||
var m = /^(?:(@[^/]+)[/])?([^@/]+)/.exec(moduleName);
|
||||
if (m) {
|
||||
scopeName = m[1];
|
||||
moduleName = m[2];
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var i=0;i<files.length;i++) {
|
||||
var fn = files[i];
|
||||
if (/^@/.test(fn)) {
|
||||
for (let i=0;i<files.length;i++) {
|
||||
let fn = files[i];
|
||||
if (!isNodeRedModule && /^@/.test(fn)) {
|
||||
if (scopeName && scopeName === fn) {
|
||||
// Looking for a specific scope/module
|
||||
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
||||
@ -149,16 +167,18 @@ function scanDirForNodesModules(dir,moduleName) {
|
||||
results = results.concat(scanDirForNodesModules(path.join(dir,fn),moduleName));
|
||||
}
|
||||
} else {
|
||||
if (isIncluded(fn) && !isExcluded(fn) && (!moduleName || fn == moduleName)) {
|
||||
var pkgfn = path.join(dir,fn,"package.json");
|
||||
if ((isNodeRedModule || (!moduleName || fn == moduleName)) && (isIncluded(fn) && !isExcluded(fn))) {
|
||||
try {
|
||||
var pkg = require(pkgfn);
|
||||
if (pkg['node-red']) {
|
||||
if (!registryUtil.checkModuleAllowed(pkg.name,pkg.version,loadAllowList,loadDenyList)) {
|
||||
log.debug("! Module: "+pkg.name+" "+pkg.version+ " *ignored due to denyList*");
|
||||
const moduleDir = isNodeRedModule ? package.moduleDir : path.join(dir,fn);
|
||||
const pkg = package || getPackageDetails(moduleDir)
|
||||
if(pkg.error) {
|
||||
throw pkg.error
|
||||
}
|
||||
if (pkg.isNodeRedModule) {
|
||||
if (!pkg.allowed) {
|
||||
log.debug("! Module: "+pkg.package.name+" "+pkg.package.version+ " *ignored due to denyList*");
|
||||
} else {
|
||||
var moduleDir = path.join(dir,fn);
|
||||
results.push({dir:moduleDir,package:pkg});
|
||||
results.push({dir:moduleDir,package:pkg.package});
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
@ -182,11 +202,14 @@ function scanDirForNodesModules(dir,moduleName) {
|
||||
* @param moduleName the name of the module to be found
|
||||
* @return a list of node modules: {dir,package}
|
||||
*/
|
||||
function scanTreeForNodesModules(moduleName) {
|
||||
var dir = settings.coreNodesDir;
|
||||
var results = [];
|
||||
var userDir;
|
||||
|
||||
function scanTreeForNodesModules(moduleName) {
|
||||
let coreNodesDir = settings.coreNodesDir;
|
||||
let results = [];
|
||||
let userDir;
|
||||
let nodesDir;
|
||||
if(settings.nodesDir) {
|
||||
nodesDir = Array.isArray(settings.nodesDir) ? settings.nodesDir : [settings.nodesDir]
|
||||
}
|
||||
if (settings.userDir) {
|
||||
packageList = getPackageList();
|
||||
userDir = path.join(settings.userDir,"node_modules");
|
||||
@ -201,15 +224,46 @@ function scanTreeForNodesModules(moduleName) {
|
||||
});
|
||||
}
|
||||
|
||||
if (dir) {
|
||||
var up = path.resolve(path.join(dir,".."));
|
||||
while (up !== dir) {
|
||||
var pm = path.join(dir,"node_modules");
|
||||
if (coreNodesDir) {
|
||||
var up = path.resolve(path.join(coreNodesDir,".."));
|
||||
while (up !== coreNodesDir) {
|
||||
var pm = path.join(coreNodesDir,"node_modules");
|
||||
if (pm != userDir) {
|
||||
results = results.concat(scanDirForNodesModules(pm,moduleName));
|
||||
}
|
||||
dir = up;
|
||||
up = path.resolve(path.join(dir,".."));
|
||||
coreNodesDir = up;
|
||||
up = path.resolve(path.join(coreNodesDir,".."));
|
||||
}
|
||||
}
|
||||
|
||||
// scan nodesDir for any node-red modules
|
||||
/*
|
||||
1. if !exist(package.json) || !package.json.has(node-red) => look for node_modules
|
||||
2. exist(package.json) && package.json.has(node-red) => load this only
|
||||
3. in original scan of nodesDir, ignore if:(exist(package.json) && package.json.has(node-red))
|
||||
*/
|
||||
if (nodesDir) {
|
||||
for (let dirIndex = 0; dirIndex < nodesDir.length; dirIndex++) {
|
||||
const nodeDir = nodesDir[dirIndex];
|
||||
const packageDetails = getPackageDetails(nodeDir)
|
||||
if(packageDetails.isNodeRedModule) {
|
||||
//we have found a node-red module, scan it
|
||||
const nrModules = scanDirForNodesModules(nodeDir, packageDetails.package.name, packageDetails);
|
||||
results = results.concat(nrModules);
|
||||
|
||||
} else if (packageDetails.has_node_modules) {
|
||||
//If this dir has a `node_modues` dir, scan it
|
||||
const nodeModulesDir = path.join(nodeDir, 'node_modules')
|
||||
const nrModules = scanDirForNodesModules(nodeModulesDir, moduleName );
|
||||
results = results.concat(nrModules);
|
||||
|
||||
} else {
|
||||
//If this is not a node-red module AND it does NOT have a node_modules dir,
|
||||
//it may be a directory of project directories or a node_modules dir?
|
||||
//scan this instead
|
||||
const nrModules = scanDirForNodesModules(nodeDir, moduleName);
|
||||
results = results.concat(nrModules);
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
@ -274,24 +328,26 @@ function getModuleNodeFiles(module) {
|
||||
}
|
||||
|
||||
function getNodeFiles(disableNodePathScan) {
|
||||
var dir;
|
||||
// Find all of the nodes to load
|
||||
var nodeFiles = [];
|
||||
var results;
|
||||
|
||||
var dir;
|
||||
var iconList = [];
|
||||
let results;
|
||||
let nodesDir;
|
||||
if(settings.nodesDir) {
|
||||
nodesDir = Array.isArray(settings.nodesDir) ? settings.nodesDir : [settings.nodesDir]
|
||||
}
|
||||
let dir;
|
||||
let nodeFiles = [];
|
||||
let iconList = [];
|
||||
if (settings.coreNodesDir) {
|
||||
results = getLocalNodeFiles(path.resolve(settings.coreNodesDir));
|
||||
nodeFiles = nodeFiles.concat(results.files);
|
||||
iconList = iconList.concat(results.icons);
|
||||
var defaultLocalesPath = path.join(settings.coreNodesDir,"locales");
|
||||
let defaultLocalesPath = path.join(settings.coreNodesDir,"locales");
|
||||
i18n.registerMessageCatalog("node-red",defaultLocalesPath,"messages.json");
|
||||
}
|
||||
|
||||
if (settings.userDir) {
|
||||
dir = path.join(settings.userDir,"lib","icons");
|
||||
var icons = scanIconDir(dir);
|
||||
let icons = scanIconDir(dir);
|
||||
if (icons.length > 0) {
|
||||
iconList.push({path:dir,icons:icons});
|
||||
}
|
||||
@ -301,13 +357,9 @@ function getNodeFiles(disableNodePathScan) {
|
||||
nodeFiles = nodeFiles.concat(results.files);
|
||||
iconList = iconList.concat(results.icons);
|
||||
}
|
||||
if (settings.nodesDir) {
|
||||
dir = settings.nodesDir;
|
||||
if (typeof settings.nodesDir == "string") {
|
||||
dir = [dir];
|
||||
}
|
||||
for (var i=0;i<dir.length;i++) {
|
||||
results = getLocalNodeFiles(dir[i]);
|
||||
if (nodesDir) {
|
||||
for (let i = 0; i < nodesDir.length; i++) {
|
||||
results = getLocalNodeFiles(nodesDir[i], true);
|
||||
nodeFiles = nodeFiles.concat(results.files);
|
||||
iconList = iconList.concat(results.icons);
|
||||
}
|
||||
@ -479,7 +531,52 @@ function getPackageList() {
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the package json object for the supplied `dir`.
|
||||
* If there is no package.json or the `node-red` section is missing, `result.isNodeRedModule` will be `false`.
|
||||
* If there is no package.json `isPackage` will be `false`.
|
||||
* If an error occurs, `result.error` will contain the error.
|
||||
* @param {string} dir The directory to inspect
|
||||
*/
|
||||
function getPackageDetails(dir) {
|
||||
const result = {
|
||||
/** @type {string} The package directory */
|
||||
moduleDir: dir,
|
||||
/** @type {string} The full file path of package.json for this package */
|
||||
packageFile: null,
|
||||
/** @type {boolean} True if this is a valid node-red module */
|
||||
isNodeRedModule: false,
|
||||
/** @type {boolean} True if a package.json file is present */
|
||||
isPackage: false,
|
||||
/** @type {boolean} True if this a node-red module and passes the checks */
|
||||
allowed: false,
|
||||
/** @type {object} The contents of package.json */
|
||||
package: null,
|
||||
}
|
||||
if (!dir) { return result }
|
||||
try {
|
||||
const packagefile = path.join(dir,'package.json')
|
||||
result.has_node_modules = fs.existsSync(path.join(dir,'node_modules'))
|
||||
if(!fs.existsSync(packagefile)) {
|
||||
return result
|
||||
}
|
||||
result.packageFile = packagefile
|
||||
const pkg = require(packagefile)
|
||||
result.package = pkg
|
||||
if(result.package) {
|
||||
result.allowed = true
|
||||
result.isPackage = true
|
||||
result.isNodeRedModule = typeof result.package['node-red'] === 'object'
|
||||
if(result.isNodeRedModule) {
|
||||
result.isNodeRedModule = true;
|
||||
result.allowed = registryUtil.checkModuleAllowed(pkg.name,pkg.version,loadAllowList,loadDenyList)
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
result.error = err; // this is not a package we are interested in!
|
||||
}
|
||||
return result || result;
|
||||
}
|
||||
module.exports = {
|
||||
init: init,
|
||||
getNodeFiles: getNodeFiles,
|
||||
|
@ -14,26 +14,41 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var sinon = require("sinon");
|
||||
var path = require("path");
|
||||
const should = require("should");
|
||||
const sinon = require("sinon");
|
||||
const path = require("path");
|
||||
|
||||
var NR_TEST_UTILS = require("nr-test-utils");
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
|
||||
var localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");
|
||||
const localfilesystem = NR_TEST_UTILS.require("@node-red/registry/lib/localfilesystem");
|
||||
|
||||
var resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
|
||||
var userDir = path.resolve(path.join(__dirname,"resources","userDir"));
|
||||
var moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));
|
||||
const resourcesDir = path.resolve(path.join(__dirname,"resources","local"));
|
||||
const userDir = path.resolve(path.join(__dirname,"resources","userDir"));
|
||||
|
||||
var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
|
||||
const nodesDir1 = path.resolve(path.join(__dirname,"resources","nodesDir1"))
|
||||
const nodesDir2 = path.resolve(path.join(__dirname,"resources","nodesDir2"))
|
||||
const nodesDir3 =path.resolve(path.join(__dirname,"resources","nodesDir3"))
|
||||
|
||||
const moduleDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule"));
|
||||
|
||||
const i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
|
||||
|
||||
describe("red/nodes/registry/localfilesystem",function() {
|
||||
var stubs = [];
|
||||
function stubPathJoin() {
|
||||
var _join = path.join;
|
||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
||||
if (arguments[0] == resourcesDir) {
|
||||
// This stops the module tree scan from going any higher
|
||||
// up the tree than resourcesDir.
|
||||
return arguments[0];
|
||||
}
|
||||
return _join.apply(null,arguments);
|
||||
}));
|
||||
}
|
||||
beforeEach(function() {
|
||||
stubs.push(sinon.stub(i18n,"registerMessageCatalog").callsFake(function() { return Promise.resolve(); }));
|
||||
})
|
||||
|
||||
var stubs = [];
|
||||
afterEach(function() {
|
||||
while(stubs.length) {
|
||||
stubs.pop().restore();
|
||||
@ -129,16 +144,76 @@ describe("red/nodes/registry/localfilesystem",function() {
|
||||
checkNodes(nm.nodes,['TestNode5'],['TestNode1']);
|
||||
done();
|
||||
});
|
||||
it("Finds nodes and icons only in nodesDir with files, icons and valid node-red packages",function(done) {
|
||||
localfilesystem.init({nodesDir:nodesDir1});
|
||||
const nodeList = localfilesystem.getNodeFiles(true);
|
||||
nodeList.should.have.a.property("node-red");
|
||||
const nm = nodeList['node-red'];
|
||||
nm.should.have.a.property('name','node-red');
|
||||
nm.should.have.a.property("nodes");
|
||||
nm.should.have.a.property("icons");
|
||||
checkNodes(nm.nodes,['loose1', 'loose2'], []);
|
||||
//1 icon in nodesDir1/icons/ - should be found
|
||||
//2 icons in nodesDir1/loose2/icons/ - should be found
|
||||
//1 icons in nodesDir1/node-red-node-testnode/icons/ - should be found
|
||||
//1 icons in nodesDir1/regular_module/icons/ - should NOT be found
|
||||
//total icon sets 3, total icons 4
|
||||
nm.icons.should.have.a.property("length", 3);
|
||||
nm.icons[0].should.have.a.property("path")
|
||||
nm.icons[0].should.have.a.property("icons", ['loose1.svg'])
|
||||
nm.icons[1].should.have.a.property("path")
|
||||
nm.icons[1].should.have.a.property("icons", ['loose2.svg', 'loose2b.svg'])
|
||||
nm.icons[2].should.have.a.property("path")
|
||||
nm.icons[2].should.have.a.property("icons", ['test.svg'])
|
||||
done();
|
||||
});
|
||||
it("Should not find node-red node in nodesDir with files, icons and valid node-red packages",function(done) {
|
||||
// path contains a regular node module and a node-red node module
|
||||
localfilesystem.init({nodesDir:path.join(nodesDir1)});
|
||||
const nodeList = localfilesystem.getNodeFiles(true);
|
||||
nodeList.should.have.a.property("node-red");
|
||||
const nm = nodeList['node-red'];
|
||||
nm.should.have.a.property('name','node-red');
|
||||
nm.should.have.a.property("nodes");
|
||||
nm.nodes.should.have.a.property("loose1");
|
||||
nm.nodes.should.have.a.property("loose2");
|
||||
nm.nodes.should.not.have.a.property("regular_module");
|
||||
nm.nodes.should.not.have.a.property("node-red-node-testnode");
|
||||
for (let key of Object.keys(nm.nodes)) {
|
||||
const n = nm.nodes[key];
|
||||
n.file.indexOf("regular_module").should.eql(-1, `found icons in a node-red module`)
|
||||
n.file.indexOf("node-red-node-testnode").should.eql(-1, `found icons in a node-red module`)
|
||||
}
|
||||
//1 icon in nodesDir1/icons/ - should be found
|
||||
//2 icons in nodesDir1/loose2/icons/ - should be found
|
||||
//1 icons in nodesDir1/node-red-node-testnode/icons/ - should be found
|
||||
//1 icons in nodesDir1/regular_module/icons/ - should NOT be found
|
||||
//total icon sets 3, total icons 4
|
||||
nm.should.have.a.property("icons");
|
||||
nm.icons.should.have.a.property("length", 3);
|
||||
let iconCount = 0;
|
||||
for (let index = 0; index < nm.icons.length; index++) {
|
||||
const iconDir = nm.icons[index];
|
||||
iconCount += iconDir.icons.length
|
||||
iconDir.path.indexOf("node-red-node-testnode").should.eql(-1, `should not find icons in a node-red module`)
|
||||
}
|
||||
should(iconCount).eql(4, "Should find only 4 icons")
|
||||
done();
|
||||
});
|
||||
it("Should not find node-red node in nodesDir when regular package and valid node-red packages",function(done) {
|
||||
localfilesystem.init({nodesDir:path.join(nodesDir1,"regular_module")});
|
||||
const nodeList = localfilesystem.getNodeFiles(true);
|
||||
nodeList.should.have.a.property("node-red");
|
||||
const nm = nodeList['node-red'];
|
||||
nm.should.have.a.property('name','node-red');
|
||||
nm.should.have.a.property("nodes", {});
|
||||
nm.should.have.a.property("icons");
|
||||
nm.icons.should.have.a.property("length", 1); //should find 1 icons folder
|
||||
nm.icons[0].should.have.a.property("icons", [ 'test.svg' ]); //should find 1 icon in regular package
|
||||
done();
|
||||
});
|
||||
it("Finds nodes module path",function(done) {
|
||||
var _join = path.join;
|
||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
||||
if (arguments[0] == resourcesDir) {
|
||||
// This stops the module tree scan from going any higher
|
||||
// up the tree than resourcesDir.
|
||||
return arguments[0];
|
||||
}
|
||||
return _join.apply(null,arguments);
|
||||
}));
|
||||
stubPathJoin()
|
||||
localfilesystem.init({coreNodesDir:moduleDir});
|
||||
var nodeList = localfilesystem.getNodeFiles();
|
||||
nodeList.should.have.a.property("node-red");
|
||||
@ -166,8 +241,6 @@ describe("red/nodes/registry/localfilesystem",function() {
|
||||
i18n.registerMessageCatalog.lastCall.args[1].should.eql(path.resolve(path.join(moduleDir,"locales")));
|
||||
i18n.registerMessageCatalog.lastCall.args[2].should.eql('messages.json');
|
||||
|
||||
|
||||
|
||||
done();
|
||||
});
|
||||
it.skip("finds locales directory");
|
||||
@ -205,15 +278,7 @@ describe("red/nodes/registry/localfilesystem",function() {
|
||||
});
|
||||
describe("#getModuleFiles",function() {
|
||||
it("gets a nodes module files",function(done) {
|
||||
var _join = path.join;
|
||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
||||
if (arguments[0] == resourcesDir) {
|
||||
// This stops the module tree scan from going any higher
|
||||
// up the tree than resourcesDir.
|
||||
return arguments[0];
|
||||
}
|
||||
return _join.apply(null,arguments);
|
||||
}));
|
||||
stubPathJoin()
|
||||
localfilesystem.init({coreNodesDir:moduleDir});
|
||||
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
|
||||
nodeModule.should.have.a.property('TestNodeModule');
|
||||
@ -230,16 +295,87 @@ describe("red/nodes/registry/localfilesystem",function() {
|
||||
|
||||
done();
|
||||
});
|
||||
it("Finds only 1 node-red node in nodesDir amongst legacy nodes and regular nodes",function(done) {
|
||||
stubPathJoin()
|
||||
localfilesystem.init({nodesDir:[path.join(nodesDir1,"node-red-node-testnode")]});
|
||||
const nodeModule = localfilesystem.getModuleFiles();
|
||||
const loaded = Object.keys(nodeModule)
|
||||
loaded.should.have.a.property("length", 1)
|
||||
loaded.indexOf('node-red-node-testnode').should.greaterThan(-1, "Should load node-red-node-testnode")
|
||||
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('name','node-red-node-testnode');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('version','1.0.0');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('nodes');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('path');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('user', false);
|
||||
checkNodes(nodeModule['node-red-node-testnode'].nodes,['testnode'],[],'node-red-node-testnode');
|
||||
done();
|
||||
});
|
||||
it("Finds a node-red node in nodesDir with a sub dir containing valid node-red package",function(done) {
|
||||
stubPathJoin()
|
||||
localfilesystem.init({nodesDir:[path.join(nodesDir1,"node-red-node-testnode")]});
|
||||
const nodeModule = localfilesystem.getModuleFiles();
|
||||
const loaded = Object.keys(nodeModule)
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('name','node-red-node-testnode');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('version','1.0.0');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('nodes');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('path');
|
||||
nodeModule['node-red-node-testnode'].should.have.a.property('user', false);
|
||||
checkNodes(nodeModule['node-red-node-testnode'].nodes,['testnode'],[],'node-red-node-testnode');
|
||||
done();
|
||||
});
|
||||
it("Finds 2 node-red modules and 1 plugin in nodesDir (in root of dir)",function(done) {
|
||||
stubPathJoin()
|
||||
localfilesystem.init({nodesDir:[nodesDir2]});
|
||||
const nodeModule = localfilesystem.getModuleFiles();
|
||||
const loaded = Object.keys(nodeModule)
|
||||
loaded.should.have.a.property("length", 3)
|
||||
loaded.indexOf('@test/testnode').should.greaterThan(-1, "Should load @test/testnode")
|
||||
loaded.indexOf('testnode2').should.greaterThan(-1, "Should load testnode2")
|
||||
loaded.indexOf('test-theme2').should.greaterThan(-1, "Should load test-theme2")
|
||||
|
||||
nodeModule['@test/testnode'].should.have.a.property('name','@test/testnode');
|
||||
nodeModule['@test/testnode'].should.have.a.property('version','1.0.0');
|
||||
nodeModule['@test/testnode'].should.have.a.property('nodes');
|
||||
nodeModule['@test/testnode'].should.have.a.property('path');
|
||||
nodeModule['@test/testnode'].should.have.a.property('user', false);
|
||||
|
||||
nodeModule['testnode2'].should.have.a.property('name','testnode2');
|
||||
nodeModule['testnode2'].should.have.a.property('version','1.0.0');
|
||||
nodeModule['testnode2'].should.have.a.property('nodes');
|
||||
nodeModule['testnode2'].should.have.a.property('path');
|
||||
nodeModule['testnode2'].should.have.a.property('user', false);
|
||||
|
||||
nodeModule['test-theme2'].should.have.a.property('name','test-theme2');
|
||||
|
||||
nodeModule['test-theme2'].should.have.a.property('version','0.0.1');
|
||||
nodeModule['test-theme2'].should.have.a.property('nodes', {});
|
||||
nodeModule['test-theme2'].should.have.a.property('path');
|
||||
nodeModule['test-theme2'].should.have.a.property('user', false);
|
||||
nodeModule['test-theme2'].should.have.a.property('plugins');
|
||||
nodeModule['test-theme2'].plugins.should.have.a.property('test-theme2');
|
||||
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('name','test-theme2');
|
||||
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('module','test-theme2');
|
||||
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('version', '0.0.1');
|
||||
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('file');
|
||||
nodeModule['test-theme2'].plugins['test-theme2'].should.have.a.property('local', false);
|
||||
|
||||
done();
|
||||
});
|
||||
it("Finds 2 node-red modules and 1 plugin in nodesDir pointing to a node_modules dir",function(done) {
|
||||
stubPathJoin()
|
||||
localfilesystem.init({nodesDir:[path.join(nodesDir3, "node_modules")]});
|
||||
const nodeModule = localfilesystem.getModuleFiles();
|
||||
const loaded = Object.keys(nodeModule)
|
||||
loaded.should.have.a.property("length", 3)
|
||||
|
||||
loaded.indexOf('@test/testnode').should.greaterThan(-1, "Should load @test/testnode")
|
||||
loaded.indexOf('@test/test-theme3').should.greaterThan(-1, "Should load test-theme3")
|
||||
loaded.indexOf('testnode3').should.greaterThan(-1, "Should load testnode3")
|
||||
done();
|
||||
});
|
||||
it("throws an error if a node isn't found",function(done) {
|
||||
var _join = path.join;
|
||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
||||
if (arguments[0] == resourcesDir) {
|
||||
// This stops the module tree scan from going any higher
|
||||
// up the tree than resourcesDir.
|
||||
return arguments[0];
|
||||
}
|
||||
return _join.apply(null,arguments);
|
||||
}));
|
||||
stubPathJoin()
|
||||
localfilesystem.init({coreNodesDir:moduleDir});
|
||||
/*jshint immed: false */
|
||||
(function(){
|
||||
@ -250,15 +386,7 @@ describe("red/nodes/registry/localfilesystem",function() {
|
||||
it.skip("finds locales directory");
|
||||
it.skip("finds icon path directory");
|
||||
it("scans icon files with a module file",function(done) {
|
||||
var _join = path.join;
|
||||
stubs.push(sinon.stub(path,"join").callsFake(function() {
|
||||
if (arguments[0] == resourcesDir) {
|
||||
// This stops the module tree scan from going any higher
|
||||
// up the tree than resourcesDir.
|
||||
return arguments[0];
|
||||
}
|
||||
return _join.apply(null,arguments);
|
||||
}));
|
||||
stubPathJoin()
|
||||
localfilesystem.init({
|
||||
coreNodesDir: moduleDir
|
||||
});
|
||||
|
@ -0,0 +1 @@
|
||||
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M10.004 14.499h20M10.004 46.503h20M10.004 22.5h20M10.004 30.501h20M10.004 38.502h20" stroke="#fff" stroke-width="2.9997000000000003"/></svg>
|
After Width: | Height: | Size: 236 B |
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
(function() {
|
||||
console.log("hello from loose1.html")
|
||||
})()
|
||||
</script>
|
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from loose1.js")
|
||||
})()
|
@ -0,0 +1 @@
|
||||
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M30.999 31.005v-3h-6.762s.812-12.397 1.162-14 .597-3.35 2.628-3.103 1.971 3.103 1.971 3.103l4.862-.016s-.783-3.984-2.783-5.984-7.946-1.7-9.633.03c-1.687 1.73-2.302 5.065-2.597 6.422-.588 4.5-.854 9.027-1.248 13.547h-8.6v3H18.1s-.812 12.398-1.162 14-.597 3.35-2.628 3.103-1.972-3.102-1.972-3.102l-4.862.015s.783 3.985 2.783 5.985c2 2 7.946 1.699 9.634-.031 1.687-1.73 2.302-5.065 2.597-6.422.587-4.5.854-9.027 1.248-13.547z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1 @@
|
||||
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M7 38.98v3.983h11v12l13-23H19l-.463.017c-1.28 4.048-5.066 6.983-9.537 6.983zm12-11.017h12l-13-23v12H7V20.9l2 .064c4.467 0 8.25 2.93 9.534 6.972zM6.95 24.22a6 6 0 1 1-.083 11.456" fill="#fff" style="isolation:auto;mix-blend-mode:normal"/></svg>
|
After Width: | Height: | Size: 339 B |
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
(function() {
|
||||
console.log("hello from loose2.html")
|
||||
})()
|
||||
</script>
|
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from loose2.js")
|
||||
})()
|
@ -0,0 +1 @@
|
||||
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M30.999 31.005v-3h-6.762s.812-12.397 1.162-14 .597-3.35 2.628-3.103 1.971 3.103 1.971 3.103l4.862-.016s-.783-3.984-2.783-5.984-7.946-1.7-9.633.03c-1.687 1.73-2.302 5.065-2.597 6.422-.588 4.5-.854 9.027-1.248 13.547h-8.6v3H18.1s-.812 12.398-1.162 14-.597 3.35-2.628 3.103-1.972-3.102-1.972-3.102l-4.862.015s.783 3.985 2.783 5.985c2 2 7.946 1.699 9.634-.031 1.687-1.73 2.302-5.065 2.597-6.422.587-4.5.854-9.027 1.248-13.547z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from regular module main.js")
|
||||
})()
|
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "node-red-node-testnode",
|
||||
"version": "1.0.0",
|
||||
"description": "A node-red node that does nothing other than exist",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"node-red"
|
||||
],
|
||||
"node-red": {
|
||||
"nodes": {
|
||||
"testnode": "index.js"
|
||||
}
|
||||
},
|
||||
"author": "@testyMcTersterson",
|
||||
"license": "MIT"
|
||||
}
|
@ -0,0 +1 @@
|
||||
<svg width="40" height="60" viewBox="0, 0, 40, 60" xmlns="http://www.w3.org/2000/svg"><path d="M30.999 31.005v-3h-6.762s.812-12.397 1.162-14 .597-3.35 2.628-3.103 1.971 3.103 1.971 3.103l4.862-.016s-.783-3.984-2.783-5.984-7.946-1.7-9.633.03c-1.687 1.73-2.302 5.065-2.597 6.422-.588 4.5-.854 9.027-1.248 13.547h-8.6v3H18.1s-.812 12.398-1.162 14-.597 3.35-2.628 3.103-1.972-3.102-1.972-3.102l-4.862.015s.783 3.985 2.783 5.985c2 2 7.946 1.699 9.634-.031 1.687-1.73 2.302-5.065 2.597-6.422.587-4.5.854-9.027 1.248-13.547z" fill="#fff"/></svg>
|
After Width: | Height: | Size: 539 B |
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from regular module main.js")
|
||||
})()
|
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "regular_node",
|
||||
"version": "1.0.0",
|
||||
"description": "A regular node that does nothing other than exist",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"test"
|
||||
],
|
||||
"author": "@testyMcTersterson",
|
||||
"license": "MIT"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
(function() {
|
||||
console.log("hello from @test/testnode index.html")
|
||||
})()
|
||||
</script>
|
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from @test/testnode index.js")
|
||||
})()
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@test/testnode",
|
||||
"version": "1.0.0",
|
||||
"description": "A test node that does nothing other than exist",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"node-red",
|
||||
"test"
|
||||
],
|
||||
"node-red": {
|
||||
"nodes": {
|
||||
"testnode": "index.js"
|
||||
}
|
||||
},
|
||||
"author": "@testyMcTersterson",
|
||||
"license": "MIT"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
(function() {
|
||||
console.log("hello from testnode2 index.js")
|
||||
})()
|
||||
</script>
|
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from testnode2 index.js")
|
||||
})()
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "testnode2",
|
||||
"version": "1.0.0",
|
||||
"description": "A test node that does nothing other than exist",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"node-red",
|
||||
"test"
|
||||
],
|
||||
"node-red": {
|
||||
"nodes": {
|
||||
"testnode2": "index.js"
|
||||
}
|
||||
},
|
||||
"author": "@testyMcTersterson",
|
||||
"license": "MIT"
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
(function() {
|
||||
console.log("Hi from test plugin client side")
|
||||
})()
|
@ -0,0 +1,14 @@
|
||||
module.exports = function (RED) {
|
||||
RED.plugins.registerPlugin('test-theme', {
|
||||
type: 'node-red-theme',
|
||||
scripts: [
|
||||
'files/clientside.js'
|
||||
],
|
||||
css: [
|
||||
'files/theme.css',
|
||||
],
|
||||
monacoOptions: {
|
||||
theme: "vs"
|
||||
}
|
||||
})
|
||||
}
|
@ -0,0 +1 @@
|
||||
:root{--red-ui-primary-background: #f2f3fb;}
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "test-theme2",
|
||||
"version": "0.0.1",
|
||||
"description": "test theme for Node-RED",
|
||||
|
||||
"keywords": [
|
||||
"node-red",
|
||||
"plugin",
|
||||
"theme"
|
||||
],
|
||||
"author": {
|
||||
"name": "testy-McTesterson"
|
||||
},
|
||||
"license": "MIT",
|
||||
"node-red": {
|
||||
"version": ">=2.2.0",
|
||||
"plugins": {
|
||||
"test-theme2": "files/plugin.js"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.x"
|
||||
}
|
||||
}
|
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.html
generated
vendored
Normal file
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.html
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
(function() {
|
||||
console.log("hello from @test/testnode index.html")
|
||||
})()
|
||||
</script>
|
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.js
generated
vendored
Normal file
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/index.js
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from @test/testnode index.js")
|
||||
})()
|
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/package.json
generated
vendored
Normal file
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/testnode/package.json
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "@test/testnode",
|
||||
"version": "1.0.0",
|
||||
"description": "A test node that does nothing other than exist",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"node-red",
|
||||
"test"
|
||||
],
|
||||
"node-red": {
|
||||
"nodes": {
|
||||
"testnode": "index.js"
|
||||
}
|
||||
},
|
||||
"author": "@testyMcTersterson",
|
||||
"license": "MIT"
|
||||
}
|
3
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/clientside.js
generated
vendored
Normal file
3
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/clientside.js
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
(function() {
|
||||
console.log("Hi from test plugin client side")
|
||||
})()
|
14
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/plugin.js
generated
vendored
Normal file
14
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/plugin.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
module.exports = function (RED) {
|
||||
RED.plugins.registerPlugin('test-theme', {
|
||||
type: 'node-red-theme',
|
||||
scripts: [
|
||||
'files/clientside.js'
|
||||
],
|
||||
css: [
|
||||
'files/theme.css',
|
||||
],
|
||||
monacoOptions: {
|
||||
theme: "vs"
|
||||
}
|
||||
})
|
||||
}
|
1
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/theme.css
generated
vendored
Normal file
1
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/files/theme.css
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
:root{--red-ui-primary-background: #f2f3fb;}
|
24
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/package.json
generated
vendored
Normal file
24
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/@test/theme-plugin3/package.json
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@test/test-theme3",
|
||||
"version": "0.0.1",
|
||||
"description": "test theme for Node-RED",
|
||||
|
||||
"keywords": [
|
||||
"node-red",
|
||||
"plugin",
|
||||
"theme"
|
||||
],
|
||||
"author": {
|
||||
"name": "testy-McTesterson"
|
||||
},
|
||||
"license": "MIT",
|
||||
"node-red": {
|
||||
"version": ">=2.2.0",
|
||||
"plugins": {
|
||||
"test-theme3": "files/plugin.js"
|
||||
}
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.x"
|
||||
}
|
||||
}
|
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.html
generated
vendored
Normal file
5
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.html
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<script>
|
||||
(function() {
|
||||
console.log("hello from testnode3 index.js")
|
||||
})()
|
||||
</script>
|
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.js
generated
vendored
Normal file
4
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/index.js
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
(function() {
|
||||
console.log("hello from testnode3 index.js")
|
||||
})()
|
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/package.json
generated
vendored
Normal file
20
test/unit/@node-red/registry/lib/resources/nodesDir3/node_modules/testnode3/package.json
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "testnode3",
|
||||
"version": "1.0.0",
|
||||
"description": "A test node that does nothing other than exist",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"node-red",
|
||||
"test"
|
||||
],
|
||||
"node-red": {
|
||||
"nodes": {
|
||||
"testnode3": "index.js"
|
||||
}
|
||||
},
|
||||
"author": "@testyMcTersterson",
|
||||
"license": "MIT"
|
||||
}
|
Loading…
Reference in New Issue
Block a user