Skip to content

Commit 3ba4c29

Browse files
kazuhitoyokoiHiroyasuNishiyama
authored andcommitted
Support --color and --icon options (#89)
1 parent aabec5a commit 3ba4c29

File tree

6 files changed

+117
-33
lines changed

6 files changed

+117
-33
lines changed

bin/getswagger.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ var fs = require('fs');
2020
var request = require('request');
2121

2222
request("http://petstore.swagger.io/v2/swagger.json", function (error, response, body) {
23+
"use strict";
2324
if (!error) {
2425
try {
2526
var swagger = JSON.parse(body);

bin/node-red-nodegen.js

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ var data = {
3636
version: argv.version,
3737
keywords: argv.keywords || argv.k,
3838
category: argv.category || argv.c,
39+
icon: argv.icon,
40+
color: argv.color,
3941
dst: argv.output || argv.o || '.'
4042
};
4143

4244
function help() {
45+
"use strict";
4346
var helpText = 'Usage:'.bold + '\n' +
4447
' node-red-nodegen <source file or URL>' +
4548
' [-o <path to save>]' +
@@ -49,8 +52,8 @@ function help() {
4952
' [--version <version number>]' +
5053
' [--keywords <keywords list>]' +
5154
' [--category <node category>]' +
52-
//' [--icon <png or gif file>]' +
53-
//' [--color <node color>]' +
55+
' [--icon <png or gif file>]' +
56+
' [--color <node color>]' +
5457
' [--tgz]' +
5558
' [--help]' +
5659
' [-v]\n' +
@@ -71,8 +74,8 @@ function help() {
7174
' --version : Node version (format: "number.number.number" like "4.5.1")\n' +
7275
' --keywords : Additional keywords (format: comma separated string, default: "node-red-nodegen")\n' +
7376
' --category : Node category (default: "function")\n' +
74-
//' --icon : png or gif file for node appearance (image size should be 10x20)\n';
75-
//' --color : color for node appearance (format: color hexadecimal numbers like "#A6BBCF")\n';
77+
' --icon : png or gif file for node appearance (image size should be 10x20)\n' +
78+
' --color : color for node appearance (format: color hexadecimal numbers like "A6BBCF")\n' +
7679
' --tgz : Save node as tgz file\n' +
7780
' --help : Show help\n' +
7881
' -v : Show node generator version\n';

lib/nodegen.js

Lines changed: 96 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,18 @@
1616

1717
var when = require("when");
1818
var fs = require('fs');
19+
var path = require('path');
1920
var child_process = require('child_process');
2021
var request = require('request');
2122
var mustache = require('mustache');
2223
var jsStringEscape = require('js-string-escape');
2324
var obfuscator = require('javascript-obfuscator');
2425
var csv = require('csv-string');
25-
var path = require('path');
2626
var CodeGen = require('swagger-js-codegen').CodeGen;
27+
var jimp = require("jimp");
2728

2829
function createCommonFiles(templateDirectory, data) {
30+
"use strict";
2931
// Make directories
3032
try {
3133
fs.mkdirSync(path.join(data.dst, data.module));
@@ -34,14 +36,38 @@ function createCommonFiles(templateDirectory, data) {
3436
console.error(error);
3537
}
3638
}
37-
try {
38-
fs.mkdirSync(path.join(data.dst, data.module, 'icons'));
39-
} catch (error) {
40-
if (error.code !== 'EEXIST') {
41-
console.error(error);
39+
40+
var isStockIcon = data.icon && data.icon.match(/^(alert|arduino|arrow-in|batch|bluetooth|bridge-dash|bridge|cog|comment|db|debug|envelope|feed|file-in|file-out|file|function|hash|inject|join|leveldb|light|link-out|mongodb|mouse|node-changed|node-error|parser-csv|parser-html|parser-json|parser-xml|parser-yaml|range|redis|rpi|serial|sort|split|subflow|swap|switch|template|timer|trigger|twitter|watch|white-globe)\.png$/);
41+
if (!isStockIcon) {
42+
try {
43+
fs.mkdirSync(path.join(data.dst, data.module, 'icons'));
44+
} catch (error) {
45+
if (error.code !== 'EEXIST') {
46+
console.error(error);
47+
}
4248
}
4349
}
44-
try {
50+
if (data.icon) {
51+
if (!isStockIcon) {
52+
try {
53+
jimp.read(data.icon, function (error2, image) {
54+
if (!error2) {
55+
var outputPath = path.join(data.dst, data.module, 'icons', path.basename(data.icon));
56+
if (image.bitmap.width === 20 && image.bitmap.height === 30) {
57+
var buf = fs.readFileSync(data.icon);
58+
fs.writeFileSync(outputPath, buf);
59+
} else {
60+
image.background(0xFFFFFFFF).resize(20, 30).write(outputPath);
61+
}
62+
} else {
63+
console.log('error occurs while converting icon file.');
64+
}
65+
});
66+
} catch (error) {
67+
console.error(error);
68+
}
69+
}
70+
} else {
4571
var icons = fs.readdirSync(path.join(templateDirectory, 'icons'));
4672
icons.forEach(function (icon) {
4773
try {
@@ -51,11 +77,8 @@ function createCommonFiles(templateDirectory, data) {
5177
console.error(error);
5278
}
5379
});
54-
} catch (error) {
55-
if (error.code !== 'ENOENT') {
56-
console.error(error);
57-
}
5880
}
81+
5982
try {
6083
fs.mkdirSync(path.join(data.dst, data.module, 'locales'));
6184
} catch (error) {
@@ -89,6 +112,7 @@ function createCommonFiles(templateDirectory, data) {
89112
}
90113

91114
function runNpmPack(data) {
115+
"use strict";
92116
var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
93117
try {
94118
child_process.execFileSync(npmCommand, ['pack', './' + data.module], { cwd: data.dst });
@@ -98,6 +122,7 @@ function runNpmPack(data) {
98122
}
99123

100124
function extractKeywords(keywordsStr) {
125+
"use strict";
101126
var keywords = ["node-red-nodegen"];
102127
keywords = keywordsStr ? keywords.concat(csv.parse(keywordsStr)[0]) : keywords;
103128
keywords = keywords.map(k => ({ name: k }));
@@ -106,6 +131,7 @@ function extractKeywords(keywordsStr) {
106131
}
107132

108133
function function2node(data, options) {
134+
"use strict";
109135
return when.promise(function (resolve, reject) {
110136
// Read meta data in js file
111137
var meta = {};
@@ -142,6 +168,25 @@ function function2node(data, options) {
142168
data.version = '0.0.1';
143169
}
144170

171+
if (data.icon) {
172+
if (!data.icon.match(/\.(png|gif)$/)) {
173+
data.icon = data.icon + '.png';
174+
}
175+
if (!data.icon.match(/^[a-zA-Z0-9\-\./]+$/)) {
176+
reject('invalid icon file name');
177+
return;
178+
}
179+
}
180+
181+
if (data.color) {
182+
if (data.color.match(/^[a-zA-Z0-9]{6}$/)) {
183+
data.color = '#' + data.color;
184+
} else {
185+
reject('invalid color');
186+
return;
187+
}
188+
}
189+
145190
if (data.name === 'function') {
146191
reject('\'function\' is duplicated node name. Use another name.');
147192
return;
@@ -155,10 +200,18 @@ function function2node(data, options) {
155200
projectVersion: data.version,
156201
keywords: extractKeywords(data.keywords),
157202
category: data.category || 'function',
203+
icon: function () {
204+
if (data.icon) {
205+
return path.basename(data.icon);
206+
} else {
207+
return 'icon.png';
208+
}
209+
},
210+
color: data.color || '#C0DEED',
158211
func: jsStringEscape(data.src),
159212
outputs: meta.outputs
160213
};
161-
214+
162215
createCommonFiles(__dirname + '/../templates/function', data);
163216

164217
// Create package.json
@@ -205,6 +258,7 @@ function function2node(data, options) {
205258
}
206259

207260
function swagger2node(data, options) {
261+
"use strict";
208262
return when.promise(function (resolve, reject) {
209263
// Modify swagger data
210264
var swagger = JSON.parse(JSON.stringify(data.src), function (key, value) {
@@ -272,6 +326,25 @@ function swagger2node(data, options) {
272326
}
273327
}
274328

329+
if (data.icon) {
330+
if (!data.icon.match(/\.(png|gif)$/)) {
331+
data.icon = data.icon + '.png';
332+
}
333+
if (!data.icon.match(/^[a-zA-Z0-9\-\./]+$/)) {
334+
reject('invalid icon file name');
335+
return;
336+
}
337+
}
338+
339+
if (data.color) {
340+
if (data.color.match(/^[a-zA-Z0-9]{6}$/)) {
341+
data.color = '#' + data.color;
342+
} else {
343+
reject('invalid color');
344+
return;
345+
}
346+
}
347+
275348
createCommonFiles(path.join(__dirname, '../templates/swagger'), data);
276349

277350
// Create Node.js SDK
@@ -318,18 +391,18 @@ function swagger2node(data, options) {
318391
var isNotBodyParam = function () {
319392
return function (content, render) {
320393
return render('{{camelCaseName}}') !== 'body' ? render(content) : '';
321-
}
394+
};
322395
};
323396
var isBodyParam = function () {
324397
return function (content, render) {
325398
return render('{{camelCaseName}}') === 'body' ? render(content) : '';
326-
}
399+
};
327400
};
328401
var hasOptionalParams = function () {
329402
return function (content, render) {
330403
var params = render('{{#parameters}}{{^required}}{{camelCaseName}},{{/required}}{{/parameters}}');
331404
return params.split(',').filter(p => p).some(p => p !== 'body') ? render(content) : '';
332-
}
405+
};
333406
};
334407
var hasServiceParams = swagger.host === undefined || swagger.security !== undefined;
335408

@@ -368,6 +441,14 @@ function swagger2node(data, options) {
368441
mustache: {
369442
nodeName: data.name,
370443
category: data.category || 'function',
444+
icon: function () {
445+
if (data.icon) {
446+
return path.basename(data.icon);
447+
} else {
448+
return 'icon.png';
449+
}
450+
},
451+
color: data.color || '#89bf04',
371452
isNotBodyParam: isNotBodyParam,
372453
hasOptionalParams: hasOptionalParams,
373454
hasServiceParams: hasServiceParams

package.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"colors": "1.1.2",
8080
"csv-string": "3.1.2",
8181
"javascript-obfuscator": "0.16.0",
82+
"jimp": "0.2.28",
8283
"js-string-escape": "1.0.1",
8384
"minimist": "1.2.0",
8485
"mustache": "2.3.0",
@@ -88,18 +89,18 @@
8889
"yamljs": "0.3.0"
8990
},
9091
"devDependencies": {
92+
"del": "3.0.0",
9193
"grunt": "1.0.1",
94+
"grunt-mocha-istanbul": "5.0.2",
9295
"grunt-shell": "2.1.0",
9396
"grunt-simple-mocha": "0.4.1",
94-
"grunt-mocha-istanbul": "5.0.2",
9597
"istanbul": "0.4.5",
96-
"should": "13.1.3",
97-
"node-red": "0.18.7",
98+
"node-red": "0.18.4",
9899
"node-red-node-test-helper": "0.1.8",
100+
"q": "1.5.1",
101+
"should": "13.1.3",
99102
"sinon": "4.1.3",
100-
"supertest": "3.0.0",
101-
"del": "3.0.0",
102-
"q": "1.5.1"
103+
"supertest": "3.0.0"
103104
},
104105
"bin": {
105106
"node-red-nodegen": "./bin/node-red-nodegen.js"

templates/function/node.html.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828

2929
<script type="text/javascript">
3030
RED.nodes.registerType('{{&nodeName}}',{
31-
color:"#C0DEED",
31+
color: '{{&color}}',
3232
category: '{{&category}}',
3333
defaults: {
34-
name: {value:""},
34+
name: { value: '' },
3535
},
3636
inputs:1,
3737
outputs: {{&outputs}},
38-
icon: "icon.png",
38+
icon: '{{&icon}}',
3939
label: function() {
4040
return this.name || '{{&nodeName}}';
4141
}

templates/swagger/node.html.mustache

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,23 @@
11
<script type="text/javascript">
22
RED.nodes.registerType('{{&nodeName}}', {
33
category: '{{&category}}',
4-
color: '#89bf04',
4+
color: '{{&color}}',
55
defaults: {
66
{{#hasServiceParams}}
77
service: { value: "", type: "{{&nodeName}}-service", required: true },
88
{{/hasServiceParams}}
9-
method: { value: "" },
10-
9+
method: { value: "", required: true },
1110
{{#methods}}
1211
{{#parameters}}
1312
{{&methodName}}_{{&camelCaseName}}: { value: "" },
1413
{{&methodName}}_{{&camelCaseName}}Type: { value: "str" },
1514
{{/parameters}}
1615
{{/methods}}
17-
1816
name: { value: "" }
1917
},
2018
inputs: 1,
2119
outputs: 1,
22-
icon: "icon.png",
20+
icon: '{{&icon}}',
2321
label: function () {
2422
return this.name || "{{&nodeName}}";
2523
},

0 commit comments

Comments
 (0)