Compare commits

..

1 Commits

Author SHA1 Message Date
Nick O'Leary
c294532152 Fix undo history of moves and post-deploy handling 2024-04-23 22:29:42 +02:00
31 changed files with 167 additions and 220 deletions

View File

@@ -1,26 +1,3 @@
#### 3.1.10: Maintenance Release
- Include rewired nodes when calculating Modified Flows stop list (#4754) @knolleary
- Fix clone of group env var properties (#4753) @knolleary
- Fix losing links when importing a copy of links into a subflow (#4750) @GogoVega
- Ensure all CSS variables are in the output file (#3743) @bonanitech
- Fix the Sidebar Config is not refreshed after a deploy (#4734) @GogoVega
- Fix checkboxes are not updated when calling `typedInput("value", "")` (#4729) @GogoVega
- Fix panning with middle mouse button on windows 10/11 (#4716) @corentin-sodebo-voile
- Add Japanese translation for sidebar tooltip (#4727) @kazuhitoyokoi
- Translate the number of items selected in the options list (#4730) @GogoVega
- Fix a checkbox should return a Boolean value and not the string `on` (#4715) @GogoVega
- Deleting a grouped node should update the group (#4714) @GogoVega
- Change the Config Node cursor to `pointer` (#4711) @GogoVega
- Add missing tooltips to Sidebar (#4713) @GogoVega
- Allow nodes to return additional history entries in onEditSave (#4710) @knolleary
- Pass full error object in Function node and copy over cause property (#4685) @knolleary
- Replacing vm.createScript in favour of vm.Script (#4534) @patlux
- Avoid login loops when autoLogin enabled but login fails (#4684) @knolleary
- Fix undo of subflow env property edits (#4667) @knolleary
- Fix three error typos in monaco.js (#4660) @JoshuaCWebDeveloper
- docs: Add closing paragraph tag (#4664) @ZJvandeWeg
#### 3.1.9: Maintenance Release
- Prevent subflow being added to itself (#4654) @knolleary

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "3.1.10",
"version": "3.1.9",
"description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org",
"license": "Apache-2.0",

View File

@@ -205,10 +205,9 @@ function genericStrategy(adminApp,strategy) {
passport.use(new strategy.strategy(options, verify));
adminApp.get('/auth/strategy',
passport.authenticate(strategy.name, {
session:false,
passport.authenticate(strategy.name, {session:false,
failureMessage: true,
failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
failureRedirect: settings.httpAdminRoot
}),
completeGenerateStrategyAuth,
handleStrategyError
@@ -222,7 +221,7 @@ function genericStrategy(adminApp,strategy) {
passport.authenticate(strategy.name, {
session:false,
failureMessage: true,
failureRedirect: settings.httpAdminRoot + '?session_message=Login Failed'
failureRedirect: settings.httpAdminRoot
}),
completeGenerateStrategyAuth,
handleStrategyError

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "3.1.10",
"version": "3.1.9",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/util": "3.1.10",
"@node-red/editor-client": "3.1.10",
"@node-red/util": "3.1.9",
"@node-red/editor-client": "3.1.9",
"bcryptjs": "2.4.3",
"body-parser": "1.20.2",
"clone": "2.1.2",

View File

@@ -719,7 +719,6 @@
"nodeHelp": "Node Help",
"showHelp": "Show help",
"showInOutline": "Show in outline",
"hideTopics": "Hide topics",
"showTopics": "Show topics",
"noHelp": "No help topic selected",
"changeLog": "Change Log"
@@ -915,8 +914,6 @@
}
},
"typedInput": {
"selected": "__count__ selected",
"selected_plural": "__count__ selected",
"type": {
"str": "string",
"num": "number",

View File

@@ -719,7 +719,6 @@
"nodeHelp": "Aide sur les noeuds",
"showHelp": "Afficher l'aide",
"showInOutline": "Afficher dans les grandes lignes",
"hideTopics": "Masquer les sujets",
"showTopics": "Afficher les sujets",
"noHelp": "Aucune rubrique d'aide sélectionnée",
"changeLog": "Journal des modifications"
@@ -915,8 +914,6 @@
}
},
"typedInput": {
"selected": "__count__ sélectionnée",
"selected_plural": "__count__ sélectionnées",
"type": {
"str": "chaîne de caractères",
"num": "nombre",

View File

@@ -719,7 +719,6 @@
"nodeHelp": "ノードヘルプ",
"showHelp": "ヘルプを表示",
"showInOutline": "アウトラインに表示",
"hideTopics": "トピックを非表示",
"showTopics": "トピックを表示",
"noHelp": "ヘルプのトピックが未選択",
"changeLog": "更新履歴"

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "3.1.10",
"version": "3.1.9",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -706,11 +706,36 @@ RED.history = (function() {
}
function markEventDirty (evt) {
// This isn't 100% thorough - just covers the main move/edit/delete cases
evt.dirty = true
if (evt.multi) {
for (let i = 0; i < evt.events.length-1; i++) {
markEventDirty(evt.events[i])
}
} else if (evt.t === 'move') {
for (let i=0;i<evt.nodes.length;i++) {
evt.nodes[i].moved = true
}
} else if (evt.t === 'edit') {
evt.changed = true
} else if (evt.t === 'delete') {
if (evt.nodes) {
for (let i=0;i<evt.nodes.length;i++) {
evt.nodes[i].changed = true
}
}
}
}
return {
//TODO: this function is a placeholder until there is a 'save' event that can be listened to
markAllDirty: function() {
for (var i=0;i<undoHistory.length;i++) {
// A deploy has happened meaning any undo into the history will represent
// an undeployed change - regardless of what it was when the event was recorded.
// This goes back through the history any marks them all as being dirty events
// and also ensures individual node states are marked dirty
for (let i=0;i<undoHistory.length;i++) {
undoHistory[i].dirty = true;
markEventDirty(undoHistory[i])
}
},
list: function() {

View File

@@ -2379,13 +2379,6 @@ RED.nodes = (function() {
} else {
delete n.g
}
// If importing into a subflow, ensure an outbound-link doesn't get added
if (activeSubflow && /^link /.test(n.type) && n.links) {
n.links = n.links.filter(function(id) {
const otherNode = node_map[id] || RED.nodes.node(id);
return (otherNode && otherNode.z === activeWorkspace);
});
}
for (var d3 in n._def.defaults) {
if (n._def.defaults.hasOwnProperty(d3)) {
if (n._def.defaults[d3].type) {
@@ -2409,6 +2402,14 @@ RED.nodes = (function() {
}
}
}
// If importing into a subflow, ensure an outbound-link doesn't
// get added
if (activeSubflow && /^link /.test(n.type) && n.links) {
n.links = n.links.filter(function(id) {
const otherNode = node_map[id] || RED.nodes.node(id);
return (otherNode && otherNode.z === activeWorkspace)
});
}
}
for (i=0;i<new_subflows.length;i++) {
n = new_subflows[i];

View File

@@ -734,12 +734,12 @@
}
if (menu.opts.multiple) {
var selected = {};
this.value().split(",").forEach(function(f) {
selected[f] = true;
});
this.value().split(",").forEach(function(f) {
selected[f] = true;
})
menu.find('input[type="checkbox"]').each(function() {
$(this).prop("checked", selected[$(this).data('value')] || false);
});
$(this).prop("checked",selected[$(this).data('value')])
})
}
@@ -830,7 +830,7 @@
this.input.trigger('change',[this.propertyType,this.value()]);
}
} else {
this.optionSelectLabel.text(RED._("typedInput.selected", { count: o.length }));
this.optionSelectLabel.text(o.length+" selected");
}
}
},

View File

@@ -631,7 +631,6 @@ RED.deploy = (function() {
// Once deployed, cannot undo back to a clean state
RED.history.markAllDirty();
RED.view.redraw();
RED.sidebar.config.refresh();
RED.events.emit("deploy");
}).fail(function (xhr, textStatus, err) {
RED.nodes.dirty(true);

View File

@@ -248,8 +248,6 @@ RED.editor = (function() {
var value = input.val();
if (defaults[property].hasOwnProperty("format") && defaults[property].format !== "" && input[0].nodeName === "DIV") {
value = input.text();
} else if (input.attr("type") === "checkbox") {
value = input.prop("checked");
}
var valid = validateNodeProperty(node, defaults, property,value);
if (((typeof valid) === "string") || !valid) {
@@ -743,16 +741,9 @@ RED.editor = (function() {
}
try {
const rc = editing_node._def.oneditsave.call(editing_node);
var rc = editing_node._def.oneditsave.call(editing_node);
if (rc === true) {
editState.changed = true;
} else if (typeof rc === 'object' && rc !== null ) {
if (rc.changed === true) {
editState.changed = true
}
if (Array.isArray(rc.history) && rc.history.length > 0) {
editState.history = rc.history
}
}
} catch(err) {
console.warn("oneditsave",editing_node.id,editing_node.type,err.toString());
@@ -923,17 +914,6 @@ RED.editor = (function() {
dirty: startDirty
}
if (editing_node.g) {
const group = RED.nodes.group(editing_node.g);
// Don't use RED.group.removeFromGroup as that emits
// a change event on the node - but we're deleting it
const index = group?.nodes.indexOf(editing_node) ?? -1;
if (index > -1) {
group.nodes.splice(index, 1);
RED.group.markDirty(group);
}
}
RED.nodes.dirty(true);
RED.view.redraw(true);
RED.history.push(historyEvent);
@@ -1035,7 +1015,7 @@ RED.editor = (function() {
}
});
}
let historyEvent = {
var historyEvent = {
t:'edit',
node:editing_node,
changes:editState.changes,
@@ -1051,15 +1031,6 @@ RED.editor = (function() {
instances:subflowInstances
}
}
if (editState.history) {
historyEvent = {
t: 'multi',
events: [ historyEvent, ...editState.history ],
dirty: wasDirty
}
}
RED.history.push(historyEvent);
}
editing_node.dirty = true;

View File

@@ -514,7 +514,7 @@ RED.editor.codeEditor.monaco = (function() {
_monaco.languages.json.jsonDefaults.setDiagnosticsOptions(diagnosticOptions);
if(modeConfiguration) { _monaco.languages.json.jsonDefaults.setModeConfiguration(modeConfiguration); }
} catch (error) {
console.warn("monaco - Error setting up json options", error)
console.warn("monaco - Error setting up json options", err)
}
}
@@ -526,7 +526,7 @@ RED.editor.codeEditor.monaco = (function() {
if(htmlDefaults) { _monaco.languages.html.htmlDefaults.setOptions(htmlDefaults); }
if(handlebarDefaults) { _monaco.languages.html.handlebarDefaults.setOptions(handlebarDefaults); }
} catch (error) {
console.warn("monaco - Error setting up html options", error)
console.warn("monaco - Error setting up html options", err)
}
}
@@ -546,7 +546,7 @@ RED.editor.codeEditor.monaco = (function() {
if(lessDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(lessDefaults_modeConfiguration); }
if(scssDefaults_modeConfiguration) { _monaco.languages.css.cssDefaults.setDiagnosticsOptions(scssDefaults_modeConfiguration); }
} catch (error) {
console.warn("monaco - Error setting up CSS/SCSS/LESS options", error)
console.warn("monaco - Error setting up CSS/SCSS/LESS options", err)
}
}

View File

@@ -382,11 +382,9 @@ RED.sidebar.config = (function() {
refreshConfigNodeList();
}
});
RED.popover.tooltip($('#red-ui-sidebar-config-filter-all'), RED._("sidebar.config.showAllConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-filter-unused'), RED._("sidebar.config.showAllUnusedConfigNodes"));
RED.popover.tooltip($('#red-ui-sidebar-config-collapse-all'), RED._("palette.actions.collapse-all"));
RED.popover.tooltip($('#red-ui-sidebar-config-expand-all'), RED._("palette.actions.expand-all"));
}
function flashConfigNode(el) {

View File

@@ -36,13 +36,7 @@ RED.sidebar.help = (function() {
toolbar = $("<div>", {class:"red-ui-sidebar-header red-ui-info-toolbar"}).appendTo(content);
$('<span class="button-group"><a id="red-ui-sidebar-help-show-toc" class="red-ui-button red-ui-button-small selected" href="#"><i class="fa fa-list-ul"></i></a></span>').appendTo(toolbar)
var showTOCButton = toolbar.find('#red-ui-sidebar-help-show-toc')
RED.popover.tooltip(showTOCButton, function () {
if ($(showTOCButton).hasClass('selected')) {
return RED._("sidebar.help.hideTopics");
} else {
return RED._("sidebar.help.showTopics");
}
});
RED.popover.tooltip(showTOCButton,RED._("sidebar.help.showTopics"));
showTOCButton.on("click",function(e) {
e.preventDefault();
if ($(this).hasClass('selected')) {

View File

@@ -1190,7 +1190,6 @@ RED.view = (function() {
if (d3.event.button === 1) {
// Middle Click pan
d3.event.preventDefault();
mouse_mode = RED.state.PANNING;
mouse_position = [d3.event.pageX,d3.event.pageY]
scroll_position = [chart.scrollLeft(),chart.scrollTop()];
@@ -2168,9 +2167,9 @@ RED.view = (function() {
if (n.ox !== n.n.x || n.oy !== n.n.y || addedToGroup) {
// This node has moved or added to a group
if (rehomedNodes.has(n)) {
moveAndChangedGroupEvent.nodes.push({...n})
moveAndChangedGroupEvent.nodes.push({...n, moved: n.n.moved})
} else {
moveEvent.nodes.push({...n})
moveEvent.nodes.push({...n, moved: n.n.moved})
}
n.n.dirty = true;
n.n.moved = true;

View File

@@ -37,6 +37,7 @@ ul.red-ui-sidebar-node-config-list {
}
.red-ui-palette-node {
// overflow: hidden;
cursor: default;
&.selected {
border-color: transparent;
box-shadow: 0 0 0 2px var(--red-ui-node-selected-color);

View File

@@ -194,46 +194,27 @@
nodeMap[node.links[i]].new = true;
}
}
let editHistories = []
let n;
for (let id in nodeMap) {
var n;
for (var id in nodeMap) {
if (nodeMap.hasOwnProperty(id)) {
n = RED.nodes.node(id);
if (n) {
editHistories.push({
t:'edit',
node: n,
changes: {
links: [...n.links]
},
changed: n.changed
})
if (nodeMap[id].old && !nodeMap[id].new) {
// Removed id
i = n.links.indexOf(node.id);
if (i > -1) {
n.links.splice(i,1);
n.changed = true
n.dirty = true
}
} else if (!nodeMap[id].old && nodeMap[id].new) {
// Added id
i = n.links.indexOf(id);
if (i === -1) {
n.links.push(node.id);
n.changed = true
n.dirty = true
}
}
}
}
}
if (editHistories.length > 0) {
return {
history: editHistories
}
}
}
function onAdd() {
@@ -273,14 +254,13 @@
onEditPrepare(this,"link out");
},
oneditsave: function() {
const result = onEditSave(this);
onEditSave(this);
// In case the name has changed, ensure any link call nodes on this
// tab are redrawn with the updated name
var localCallNodes = RED.nodes.filterNodes({z:RED.workspaces.active(), type:"link call"});
localCallNodes.forEach(function(node) {
node.dirty = true;
});
return result
},
onadd: onAdd,
oneditresize: resizeNodeList
@@ -349,7 +329,7 @@
onEditPrepare(this,"link in");
},
oneditsave: function() {
return onEditSave(this);
onEditSave(this);
},
oneditresize: resizeNodeList
});
@@ -393,7 +373,7 @@
},
oneditsave: function() {
return onEditSave(this);
onEditSave(this);
},
onadd: onAdd,
oneditresize: resizeNodeList

View File

@@ -374,7 +374,7 @@ module.exports = function(RED) {
iniOpt.breakOnSigint = true;
}
}
node.script = new vm.Script(functionText, createVMOpt(node, ""));
node.script = vm.createScript(functionText, createVMOpt(node, ""));
if (node.fin && (node.fin !== "")) {
var finText = `(function () {
var node = {
@@ -438,9 +438,10 @@ module.exports = function(RED) {
//store the error in msg to be used in flows
msg.error = err;
var line = 0;
var errorMessage;
if (stack.length > 0) {
let line = 0;
let errorMessage;
while (line < stack.length && stack[line].indexOf("ReferenceError") !== 0) {
line++;
}
@@ -454,13 +455,11 @@ module.exports = function(RED) {
errorMessage += " (line "+lineno+", col "+cha+")";
}
}
if (errorMessage) {
err.message = errorMessage
}
}
// Pass the whole error object so any additional properties
// (such as cause) are preserved
done(err);
if (!errorMessage) {
errorMessage = err.toString();
}
done(errorMessage);
}
else if (typeof err === "string") {
done(err);

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "3.1.10",
"version": "3.1.9",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "3.1.10",
"version": "3.1.9",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,7 +16,7 @@
}
],
"dependencies": {
"@node-red/util": "3.1.10",
"@node-red/util": "3.1.9",
"clone": "2.1.2",
"fs-extra": "11.1.1",
"semver": "7.5.4",

View File

@@ -678,9 +678,6 @@ class Flow {
if (logMessage.hasOwnProperty('stack')) {
errorMessage.error.stack = logMessage.stack;
}
if (logMessage.hasOwnProperty('cause')) {
errorMessage.error.cause = logMessage.cause;
}
targetCatchNode.receive(errorMessage);
handled = true;
});

View File

@@ -1,6 +1,5 @@
const flowUtil = require("./util");
const credentials = require("../nodes/credentials");
const clone = require("clone");
/**
* This class represents a group within the runtime.

View File

@@ -462,8 +462,9 @@ function stop(type,diff,muteLog,isDeploy) {
if (type === 'nodes') {
stopList = diff.changed.concat(diff.removed);
} else if (type === 'flows') {
stopList = diff.changed.concat(diff.removed).concat(diff.linked).concat(diff.rewired);
stopList = diff.changed.concat(diff.removed).concat(diff.linked);
}
events.emit("flows:stopping",{config: activeConfig, type: type, diff: diff})
// Stop the global flow object last

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "3.1.10",
"version": "3.1.9",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/registry": "3.1.10",
"@node-red/util": "3.1.10",
"@node-red/registry": "3.1.9",
"@node-red/util": "3.1.9",
"async-mutex": "0.4.0",
"clone": "2.1.2",
"express": "4.19.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/util",
"version": "3.1.10",
"version": "3.1.9",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "3.1.10",
"version": "3.1.9",
"description": "Low-code programming for event-driven applications",
"homepage": "https://nodered.org",
"license": "Apache-2.0",
@@ -31,10 +31,10 @@
"flow"
],
"dependencies": {
"@node-red/editor-api": "3.1.10",
"@node-red/runtime": "3.1.10",
"@node-red/util": "3.1.10",
"@node-red/nodes": "3.1.10",
"@node-red/editor-api": "3.1.9",
"@node-red/runtime": "3.1.9",
"@node-red/util": "3.1.9",
"@node-red/nodes": "3.1.9",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"express": "4.19.2",

View File

@@ -13,7 +13,7 @@
// 4. Edit your settings file to set the theme:
// editorTheme: {
// page: {
// css: '/path/to/file/generated/by/this/script'
// css: "/path/to/file/generated/by/this/script"
// }
// }
//
@@ -22,69 +22,110 @@
const os = require('os');
const nopt = require('nopt');
const path = require('path');
const fs = require('fs-extra');
const sass = require('sass');
const os = require("os");
const nopt = require("nopt");
const path = require("path");
const fs = require("fs-extra");
const sass = require("sass");
const knownOpts = {
'help': Boolean,
'long': Boolean,
'in': [path],
'out': [path]
"help": Boolean,
"long": Boolean,
"in": [path],
"out": [path]
};
const shortHands = {
'?':['--help']
"?":["--help"]
};
nopt.invalidHandler = function(k,v,t) {}
const parsedArgs = nopt(knownOpts,shortHands,process.argv,2)
if (parsedArgs.help) {
showUsageAndExit(0)
console.log("Usage: build-custom-theme [-?] [--in FILE] [--out FILE]");
console.log("");
console.log("Options:");
console.log(" --in FILE Custom colors sass file");
console.log(" --out FILE Where you write the result");
console.log(" --long Do not compress the output");
console.log(" -?, --help Show this help");
console.log("");
process.exit();
}
if (!parsedArgs.in) {
console.warn('Missing argument: in')
showUsageAndExit(1)
const ruleRegex = /(\$.*?) *: *(\S[\S\s]*?);/g;
var match;
const customColors = {};
if (parsedArgs.in && fs.existsSync(parsedArgs.in)) {
let customColorsFile = fs.readFileSync(parsedArgs.in,"utf-8");
while((match = ruleRegex.exec(customColorsFile)) !== null) {
customColors[match[1]] = match[2];
}
}
// Load base colours
let colorsFile = fs.readFileSync(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/colors.scss"),"utf-8")
let updatedColors = [];
while((match = ruleRegex.exec(colorsFile)) !== null) {
updatedColors.push(match[1]+": "+(customColors[match[1]]||match[2])+";")
}
(async function() {
const tmpDir = os.tmpdir();
const workingDir = await fs.mkdtemp(`${tmpDir}${path.sep}`);
await fs.copy(path.join(__dirname,"../packages/node_modules/@node-red/editor-client/src/sass/"),workingDir)
await fs.writeFile(path.join(workingDir,"colors.scss"),updatedColors.join("\n"))
await fs.copy(path.join(__dirname, '../packages/node_modules/@node-red/editor-client/src/sass/'), workingDir);
await fs.copyFile(parsedArgs.in, path.join(workingDir,'colors.scss'));
const result = sass.renderSync({
outputStyle: "expanded",
file: path.join(workingDir,"style-custom-theme.scss"),
});
const output = sass.compile(
path.join(workingDir, 'style-custom-theme.scss'),
{style: parsedArgs.long === true ? 'expanded' : 'compressed'}
);
const css = result.css.toString()
const lines = css.split("\n");
const colorCSS = []
const nonColorCSS = [];
const nrPkg = require('../package.json');
let inKeyFrameBlock = false;
lines.forEach(l => {
if (inKeyFrameBlock) {
nonColorCSS.push(l);
if (/^}/.test(l)) {
inKeyFrameBlock = false;
}
} else if (/^@keyframes/.test(l)) {
nonColorCSS.push(l);
inKeyFrameBlock = true;
} else if (!/^ /.test(l)) {
colorCSS.push(l);
nonColorCSS.push(l);
} else if (/color|border|background|fill|stroke|outline|box-shadow/.test(l)) {
colorCSS.push(l);
} else {
nonColorCSS.push(l);
}
});
const nrPkg = require("../package.json");
const now = new Date().toISOString();
const header = `/*\n* Theme generated with Node-RED ${nrPkg.version} on ${now}\n*/`;
const header = `/*
* Theme generated with Node-RED ${nrPkg.version} on ${now}
*/`;
var output = sass.renderSync({outputStyle: parsedArgs.long?"expanded":"compressed",data:colorCSS.join("\n")});
if (parsedArgs.out) {
await fs.writeFile(parsedArgs.out, header+'\n'+output.css);
await fs.writeFile(parsedArgs.out,header+"\n"+output.css);
} else {
console.log(header);
console.log(output.css.toString());
}
await fs.remove(workingDir);
})()
function showUsageAndExit (exitCode) {
console.log('');
console.log('Usage: build-custom-theme [-?] [--in FILE] [--out FILE]');
console.log('');
console.log('Options:');
console.log(' --in FILE Custom colors sass file');
console.log(' --out FILE Where you write the result');
console.log(' --long Do not compress the output');
console.log(' -?, --help Show this help');
console.log('');
process.exit(exitCode);
}

View File

@@ -390,8 +390,7 @@ describe('function node', function() {
msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', 'n1');
msg.should.have.property('type', 'function');
msg.should.have.property('msg')
msg.msg.message.should.equal('ReferenceError: retunr is not defined (line 2, col 1)');
msg.should.have.property('msg', 'ReferenceError: retunr is not defined (line 2, col 1)');
done();
} catch(err) {
done(err);
@@ -660,8 +659,7 @@ describe('function node', function() {
msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', name);
msg.should.have.property('type', 'function');
msg.should.have.property('msg')
msg.msg.message.should.equal('Callback must be a function');
msg.should.have.property('msg', 'Error: Callback must be a function');
done();
}
catch (e) {

View File

@@ -16,31 +16,6 @@ describe('Group', function () {
group.getSetting("NR_GROUP_NAME").should.equal("g1")
group.getSetting("NR_GROUP_ID").should.equal("group1")
})
it("returns cloned env var property", async function () {
const group = new Group({
getSetting: v => v+v
}, {
name: "g1",
id: "group1",
env: [
{
name: 'jsonEnvVar',
type: 'json',
value: '{"a":1}'
}
]
})
await group.start()
const result = group.getSetting('jsonEnvVar')
result.should.have.property('a', 1)
result.a = 2
result.b = 'hello'
const result2 = group.getSetting('jsonEnvVar')
result2.should.have.property('a', 1)
result2.should.not.have.property('b')
})
it("delegates to parent if not found", async function () {
const group = new Group({
getSetting: v => v+v