diff --git a/bin/getswagger.js b/bin/getswagger.js index 097cbc5..d7d5de9 100644 --- a/bin/getswagger.js +++ b/bin/getswagger.js @@ -20,6 +20,7 @@ var fs = require('fs'); var request = require('request'); request("http://petstore.swagger.io/v2/swagger.json", function (error, response, body) { + "use strict"; if (!error) { try { var swagger = JSON.parse(body); diff --git a/bin/node-red-nodegen.js b/bin/node-red-nodegen.js index d94b208..3a4ea27 100644 --- a/bin/node-red-nodegen.js +++ b/bin/node-red-nodegen.js @@ -36,10 +36,13 @@ var data = { version: argv.version, keywords: argv.keywords || argv.k, category: argv.category || argv.c, + icon: argv.icon, + color: argv.color, dst: argv.output || argv.o || '.' }; function help() { + "use strict"; var helpText = 'Usage:'.bold + '\n' + ' node-red-nodegen ' + ' [-o ]' + @@ -49,8 +52,8 @@ function help() { ' [--version ]' + ' [--keywords ]' + ' [--category ]' + - //' [--icon ]' + - //' [--color ]' + + ' [--icon ]' + + ' [--color ]' + ' [--tgz]' + ' [--help]' + ' [-v]\n' + @@ -71,8 +74,8 @@ function help() { ' --version : Node version (format: "number.number.number" like "4.5.1")\n' + ' --keywords : Additional keywords (format: comma separated string, default: "node-red-nodegen")\n' + ' --category : Node category (default: "function")\n' + - //' --icon : png or gif file for node appearance (image size should be 10x20)\n'; - //' --color : color for node appearance (format: color hexadecimal numbers like "#A6BBCF")\n'; + ' --icon : png or gif file for node appearance (image size should be 10x20)\n' + + ' --color : color for node appearance (format: color hexadecimal numbers like "A6BBCF")\n' + ' --tgz : Save node as tgz file\n' + ' --help : Show help\n' + ' -v : Show node generator version\n'; diff --git a/lib/nodegen.js b/lib/nodegen.js index 4d8fb80..2c630d0 100644 --- a/lib/nodegen.js +++ b/lib/nodegen.js @@ -16,16 +16,18 @@ var when = require("when"); var fs = require('fs'); +var path = require('path'); var child_process = require('child_process'); var request = require('request'); var mustache = require('mustache'); var jsStringEscape = require('js-string-escape'); var obfuscator = require('javascript-obfuscator'); var csv = require('csv-string'); -var path = require('path'); var CodeGen = require('swagger-js-codegen').CodeGen; +var jimp = require("jimp"); function createCommonFiles(templateDirectory, data) { + "use strict"; // Make directories try { fs.mkdirSync(path.join(data.dst, data.module)); @@ -34,14 +36,38 @@ function createCommonFiles(templateDirectory, data) { console.error(error); } } - try { - fs.mkdirSync(path.join(data.dst, data.module, 'icons')); - } catch (error) { - if (error.code !== 'EEXIST') { - console.error(error); + + 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$/); + if (!isStockIcon) { + try { + fs.mkdirSync(path.join(data.dst, data.module, 'icons')); + } catch (error) { + if (error.code !== 'EEXIST') { + console.error(error); + } } } - try { + if (data.icon) { + if (!isStockIcon) { + try { + jimp.read(data.icon, function (error2, image) { + if (!error2) { + var outputPath = path.join(data.dst, data.module, 'icons', path.basename(data.icon)); + if (image.bitmap.width === 20 && image.bitmap.height === 30) { + var buf = fs.readFileSync(data.icon); + fs.writeFileSync(outputPath, buf); + } else { + image.background(0xFFFFFFFF).resize(20, 30).write(outputPath); + } + } else { + console.log('error occurs while converting icon file.'); + } + }); + } catch (error) { + console.error(error); + } + } + } else { var icons = fs.readdirSync(path.join(templateDirectory, 'icons')); icons.forEach(function (icon) { try { @@ -51,11 +77,8 @@ function createCommonFiles(templateDirectory, data) { console.error(error); } }); - } catch (error) { - if (error.code !== 'ENOENT') { - console.error(error); - } } + try { fs.mkdirSync(path.join(data.dst, data.module, 'locales')); } catch (error) { @@ -89,6 +112,7 @@ function createCommonFiles(templateDirectory, data) { } function runNpmPack(data) { + "use strict"; var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; try { child_process.execFileSync(npmCommand, ['pack', './' + data.module], { cwd: data.dst }); @@ -98,6 +122,7 @@ function runNpmPack(data) { } function extractKeywords(keywordsStr) { + "use strict"; var keywords = ["node-red-nodegen"]; keywords = keywordsStr ? keywords.concat(csv.parse(keywordsStr)[0]) : keywords; keywords = keywords.map(k => ({ name: k })); @@ -106,6 +131,7 @@ function extractKeywords(keywordsStr) { } function function2node(data, options) { + "use strict"; return when.promise(function (resolve, reject) { // Read meta data in js file var meta = {}; @@ -142,6 +168,25 @@ function function2node(data, options) { data.version = '0.0.1'; } + if (data.icon) { + if (!data.icon.match(/\.(png|gif)$/)) { + data.icon = data.icon + '.png'; + } + if (!data.icon.match(/^[a-zA-Z0-9\-\./]+$/)) { + reject('invalid icon file name'); + return; + } + } + + if (data.color) { + if (data.color.match(/^[a-zA-Z0-9]{6}$/)) { + data.color = '#' + data.color; + } else { + reject('invalid color'); + return; + } + } + if (data.name === 'function') { reject('\'function\' is duplicated node name. Use another name.'); return; @@ -155,10 +200,18 @@ function function2node(data, options) { projectVersion: data.version, keywords: extractKeywords(data.keywords), category: data.category || 'function', + icon: function () { + if (data.icon) { + return path.basename(data.icon); + } else { + return 'icon.png'; + } + }, + color: data.color || '#C0DEED', func: jsStringEscape(data.src), outputs: meta.outputs }; - + createCommonFiles(__dirname + '/../templates/function', data); // Create package.json @@ -205,6 +258,7 @@ function function2node(data, options) { } function swagger2node(data, options) { + "use strict"; return when.promise(function (resolve, reject) { // Modify swagger data var swagger = JSON.parse(JSON.stringify(data.src), function (key, value) { @@ -272,6 +326,25 @@ function swagger2node(data, options) { } } + if (data.icon) { + if (!data.icon.match(/\.(png|gif)$/)) { + data.icon = data.icon + '.png'; + } + if (!data.icon.match(/^[a-zA-Z0-9\-\./]+$/)) { + reject('invalid icon file name'); + return; + } + } + + if (data.color) { + if (data.color.match(/^[a-zA-Z0-9]{6}$/)) { + data.color = '#' + data.color; + } else { + reject('invalid color'); + return; + } + } + createCommonFiles(path.join(__dirname, '../templates/swagger'), data); // Create Node.js SDK @@ -318,18 +391,18 @@ function swagger2node(data, options) { var isNotBodyParam = function () { return function (content, render) { return render('{{camelCaseName}}') !== 'body' ? render(content) : ''; - } + }; }; var isBodyParam = function () { return function (content, render) { return render('{{camelCaseName}}') === 'body' ? render(content) : ''; - } + }; }; var hasOptionalParams = function () { return function (content, render) { var params = render('{{#parameters}}{{^required}}{{camelCaseName}},{{/required}}{{/parameters}}'); return params.split(',').filter(p => p).some(p => p !== 'body') ? render(content) : ''; - } + }; }; var hasServiceParams = swagger.host === undefined || swagger.security !== undefined; @@ -368,6 +441,14 @@ function swagger2node(data, options) { mustache: { nodeName: data.name, category: data.category || 'function', + icon: function () { + if (data.icon) { + return path.basename(data.icon); + } else { + return 'icon.png'; + } + }, + color: data.color || '#89bf04', isNotBodyParam: isNotBodyParam, hasOptionalParams: hasOptionalParams, hasServiceParams: hasServiceParams diff --git a/package.json b/package.json index 2b8b891..90df6d8 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "colors": "1.1.2", "csv-string": "3.1.2", "javascript-obfuscator": "0.16.0", + "jimp": "0.2.28", "js-string-escape": "1.0.1", "minimist": "1.2.0", "mustache": "2.3.0", @@ -85,18 +86,18 @@ "yamljs": "0.3.0" }, "devDependencies": { + "del": "3.0.0", "grunt": "1.0.1", + "grunt-mocha-istanbul": "5.0.2", "grunt-shell": "2.1.0", "grunt-simple-mocha": "0.4.1", - "grunt-mocha-istanbul": "5.0.2", "istanbul": "0.4.5", - "should": "13.1.3", - "node-red": "0.18.7", + "node-red": "0.18.4", "node-red-node-test-helper": "0.1.8", + "q": "1.5.1", + "should": "13.1.3", "sinon": "4.1.3", - "supertest": "3.0.0", - "del": "3.0.0", - "q": "1.5.1" + "supertest": "3.0.0" }, "bin": { "node-red-nodegen": "./bin/node-red-nodegen.js" diff --git a/templates/function/node.html.mustache b/templates/function/node.html.mustache index 481013e..9b6ee28 100644 --- a/templates/function/node.html.mustache +++ b/templates/function/node.html.mustache @@ -28,14 +28,14 @@