diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..c19f9355b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +/packages/node_modules/** linguist-generated=false diff --git a/.gitignore b/.gitignore index 5415d9f4f..25fca64a5 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,7 @@ node_modules public locales/zz-ZZ nodes/core/locales/zz-ZZ +!packages/node_modules +packages/node_modules/@node-red/editor-client/public +!test/**/node_modules +docs diff --git a/.nodemonignore b/.nodemonignore index 8be3f3845..612a1e15b 100644 --- a/.nodemonignore +++ b/.nodemonignore @@ -1,5 +1,4 @@ /Gruntfile.js /.git/* -/lib/* *.backup /public/* diff --git a/.npmignore b/.npmignore deleted file mode 100644 index b0d89b67e..000000000 --- a/.npmignore +++ /dev/null @@ -1,7 +0,0 @@ -.settings -.jshintignore -.jshintrc -.project -.tern-project -.travis.yml -.git diff --git a/.travis.yml b/.travis.yml index 054edefba..94bf3698c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,5 +8,3 @@ matrix: before_script: - npm install -g istanbul coveralls - node_js: "8" - - node_js: "6" - - node_js: "4" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a73106c4..29b8dabb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,115 @@ +#### 0.19.4: Maintenance Release + + - Fix race condition in non-cache lfs context Fixes #1888 + - LocalFileSystem Context: Remove extra flush code + - Prevent race condition in caching mode of lfs context (#1889) + - Allow context store name to be provided in the key + - Switch node: only use promises when absolutely necessary + - Fix dbl-click handling on webkit-based browsers + - Ensure context.flow/global cannot be deleted or enumerated + - Handle context.get with multiple levels of unknown key Fixes #1883 + - Fix global.get("foo.bar") for functionGlobalContext set values + - Fix node color bug (#1877) + - Merge pull request #1857 from cclauss/patch-1 + - Define raw_input() in Python 3 & fix time.sleep() + +#### 0.19.3: Maintenance Release + + - Split node - fix complete to send msg for k/v object + - Remove unused Join node merged object key typed input + - Set the JavaScript editor to full-screen + - Filter global modules installed locally + - Add svg to permitted icon extension list + - Debug node - indicate status all the time if selected to do so + - pi nodes - increase test coverage slightly + - TCP-request node - only write payload + - JSON schema: perform validation when obj -> obj or str -> str + - JSON schema: add draft-06 support (via $schema keyword) + - Mqtt proxy configuration for websocket connection, #1651. + - Allows MQTT Shared Subscriptions for MQTT-In core node + - Fix use of HTML tag or CSS class specification as icon of typedInput + +#### 0.19.2: Maintenance Release + + - Ensure node default colour is used if palette.theme has no match + - fix lost messages / properties in TCPRequest Node; closes #1863 (#1864) + - Fix typo in template.html + - Improve error reporting from context plugin loading + - Prevent no-op edit of node marking as changed due to icon + - Change node must handle empty rule set + +#### 0.19.1: Maintenance Release + + - Pull in latest twitter node + - Handle windows paths for context storage + - Handle persisting objects with circular refs in context + - Ensure js editor can expand to fill available space + - Add example localfilesystem contextStorage to settings + - Fix template node handling of nested context tags + +#### 0.19: Milestone Release + +Editor + + - Add editorTheme.palette.theme to allow overriding colours + - Index all node properties when searching Fixes #1446 + - Handle NaN and Infinity properly in debug sidebar Fixes #1778 #1779 + - Prevent horizontal scroll when palette name cannot wrap + - Ignore middle-click on node/ports to enable panning + - Better wire layout when looping back + - fix appearence of retry button of remote branch management dialog + - Handle releasing ctrl when using quick-add node dialog + - Add $env function to JSONata expressions + - Widen support for env var to use ${} or $() syntax + - Add env-var support to TypedInput + - Show unknown node properties in info tab + - Add node icon picker widget + - Only edit nodes on dbl click on primary button with no modifiers + - Allow subflows to be put in any palette category + - Add flow navigator widget + - Cache flow library result to improve response time Fixes #1753 + - Add middle-button-drag to pan the workspace + - allow multi-line category name in editor + - Redesign sidebar tabs + - Do not disable the export-clipboard menu option with empty selection + +Nodes + + - Change: Ensure runtime errors in Change node can be caught Fixes #1769 + - File: Add output to File Out node + - Function: add expandable JavaScript editor pane + - Function: allow id and name reference in function node code (#1731) + - HTTP Request: Move to request module + - HTTP: Ensure apiMaxLength applies to HTTP Nodes Fixes #1278 + - Join: accumulate top level properties + - Join: allow environment variable as reduce init value + - JSON: add JSON schema validation via msg.schema + - Pi: Let nrgpio code work with python 3 + - Pi: let Pi nodes be visible/editable on all platforms + - Switch: add isEmpty rule + - TCP: queue messages while connecting; closes #1414 + - TLS: Add servername option to TLS config node for SNI Fixes #1805 + - UDP: Don't accidentally re-use udp port when set to not do so + +Persistent Context + + - Add Context data sidebar + - Add persistable context option + - Add default memory store + - Add file-based context store + - Add async mode to evaluateJSONataExpression + - Update RED.util.evaluateNodeProperty to support context stores + +Runtime + + - Support flow.disabled and .info in /flow API + - Node errors should be Strings not Errors Fixes #1781 + - Add detection of connection timeout in git communication Fixes #1770 + - Handle loading empty nodesDir + - Add 'private' property to userDir generated package.json + - Add RED.require to allow nodes to access other modules + - Ensure add/remove modules are run sequentially + #### 0.18.7: Maintenance Release Editor Fixes diff --git a/Gruntfile.js b/Gruntfile.js index 508fadc58..411b6305f 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -42,7 +42,7 @@ module.exports = function(grunt) { reporter: 'spec' }, all: { src: ['test/**/*_spec.js'] }, - core: { src: ["test/_spec.js","test/red/**/*_spec.js"]}, + core: { src: ["test/_spec.js","test/unit/**/*_spec.js"]}, nodes: { src: ["test/nodes/**/*_spec.js"]} }, webdriver: { @@ -59,8 +59,8 @@ module.exports = function(grunt) { reportFormats: ['lcov','html'], print: 'both' }, - all: { src: ["test/_spec.js","test/red/**/*_spec.js","test/nodes/**/*_spec.js"] }, - core: { src: ["test/_spec.js","test/red/**/*_spec.js"]}, + all: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js","test/nodes/**/*_spec.js"] }, + core: { src: ["test/unit/_spec.js","test/unit/**/*_spec.js"]}, nodes: { src: ["test/nodes/**/*_spec.js"]} }, jshint: { @@ -80,16 +80,14 @@ module.exports = function(grunt) { all: [ 'Gruntfile.js', 'red.js', - 'red/**/*.js', - 'nodes/core/*/*.js', - 'editor/js/**/*.js' + 'packages/**/*.js' ], core: { files: { src: [ 'Gruntfile.js', 'red.js', - 'red/**/*.js' + 'packages/**/*.js', ] } }, @@ -120,80 +118,83 @@ module.exports = function(grunt) { src: [ // Ensure editor source files are concatenated in // the right order - "editor/js/red.js", - "editor/js/events.js", - "editor/js/i18n.js", - "editor/js/settings.js", - "editor/js/user.js", - "editor/js/comms.js", - "editor/js/text/bidi.js", - "editor/js/text/format.js", - "editor/js/ui/state.js", - "editor/js/nodes.js", - "editor/js/history.js", - "editor/js/validators.js", - "editor/js/ui/utils.js", - "editor/js/ui/common/editableList.js", - "editor/js/ui/common/checkboxSet.js", - "editor/js/ui/common/menu.js", - "editor/js/ui/common/panels.js", - "editor/js/ui/common/popover.js", - "editor/js/ui/common/searchBox.js", - "editor/js/ui/common/tabs.js", - "editor/js/ui/common/stack.js", - "editor/js/ui/common/typedInput.js", - "editor/js/ui/actions.js", - "editor/js/ui/deploy.js", - "editor/js/ui/diff.js", - "editor/js/ui/keyboard.js", - "editor/js/ui/workspaces.js", - "editor/js/ui/view.js", - "editor/js/ui/view-navigator.js", - "editor/js/ui/sidebar.js", - "editor/js/ui/palette.js", - "editor/js/ui/tab-info.js", - "editor/js/ui/tab-config.js", - "editor/js/ui/tab-context.js", - "editor/js/ui/palette-editor.js", - "editor/js/ui/editor.js", - "editor/js/ui/tray.js", - "editor/js/ui/clipboard.js", - "editor/js/ui/library.js", - "editor/js/ui/notifications.js", - "editor/js/ui/search.js", - "editor/js/ui/typeSearch.js", - "editor/js/ui/subflow.js", - "editor/js/ui/userSettings.js", - "editor/js/ui/projects/projects.js", - "editor/js/ui/projects/projectSettings.js", - "editor/js/ui/projects/projectUserSettings.js", - "editor/js/ui/projects/tab-versionControl.js", - "editor/js/ui/touch/radialMenu.js" + "packages/node_modules/@node-red/editor-client/src/js/red.js", + "packages/node_modules/@node-red/editor-client/src/js/events.js", + "packages/node_modules/@node-red/editor-client/src/js/i18n.js", + "packages/node_modules/@node-red/editor-client/src/js/settings.js", + "packages/node_modules/@node-red/editor-client/src/js/user.js", + "packages/node_modules/@node-red/editor-client/src/js/comms.js", + "packages/node_modules/@node-red/editor-client/src/js/text/bidi.js", + "packages/node_modules/@node-red/editor-client/src/js/text/format.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/state.js", + "packages/node_modules/@node-red/editor-client/src/js/nodes.js", + "packages/node_modules/@node-red/editor-client/src/js/font-awesome.js", + "packages/node_modules/@node-red/editor-client/src/js/history.js", + "packages/node_modules/@node-red/editor-client/src/js/validators.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/utils.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/editableList.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/checkboxSet.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/menu.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/panels.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/popover.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/searchBox.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/tabs.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/stack.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/common/typedInput.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/actions.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/deploy.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/diff.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/keyboard.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/workspaces.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/view.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/view-navigator.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/sidebar.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/palette.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/tab-info.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/tab-config.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/tab-context.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/palette-editor.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/editor.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/editors/*.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/event-log.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/tray.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/clipboard.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/library.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/notifications.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/search.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/typeSearch.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/userSettings.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projects.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectSettings.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/projects/projectUserSettings.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/projects/tab-versionControl.js", + "packages/node_modules/@node-red/editor-client/src/js/ui/touch/radialMenu.js" ], - dest: "public/red/red.js" + dest: "packages/node_modules/@node-red/editor-client/public/red/red.js" }, vendor: { files: { - "public/vendor/vendor.js": [ - "editor/vendor/jquery/js/jquery-1.11.3.min.js", - "editor/vendor/bootstrap/js/bootstrap.min.js", - "editor/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js", - "editor/vendor/jquery/js/jquery.ui.touch-punch.min.js", - "editor/vendor/marked/marked.min.js", - "editor/vendor/d3/d3.v3.min.js", - "editor/vendor/i18next/i18next.min.js" + "packages/node_modules/@node-red/editor-client/public/vendor/vendor.js": [ + "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-1.11.3.min.js", + "packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/js/bootstrap.min.js", + "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery-ui-1.10.3.custom.min.js", + "packages/node_modules/@node-red/editor-client/src/vendor/jquery/js/jquery.ui.touch-punch.min.js", + "packages/node_modules/@node-red/editor-client/src/vendor/marked/marked.min.js", + "packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js", + "packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js" ], - "public/vendor/vendor.css": [ + "packages/node_modules/@node-red/editor-client/public/vendor/vendor.css": [ // TODO: resolve relative resource paths in // bootstrap/FA/jquery ], - "public/vendor/jsonata/jsonata.min.js": [ + "packages/node_modules/@node-red/editor-client/public/vendor/jsonata/jsonata.min.js": [ "node_modules/jsonata/jsonata-es5.min.js", - "editor/vendor/jsonata/formatter.js" + "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js" ], - "public/vendor/ace/worker-jsonata.js": [ + "packages/node_modules/@node-red/editor-client/public/vendor/ace/worker-jsonata.js": [ "node_modules/jsonata/jsonata-es5.min.js", - "editor/vendor/jsonata/worker-jsonata.js" + "packages/node_modules/@node-red/editor-client/src/vendor/jsonata/worker-jsonata.js" ] } } @@ -201,10 +202,10 @@ module.exports = function(grunt) { uglify: { build: { files: { - 'public/red/red.min.js': 'public/red/red.js', - 'public/red/main.min.js': 'public/red/main.js', - 'public/vendor/ace/mode-jsonata.js': 'editor/vendor/jsonata/mode-jsonata.js', - 'public/vendor/ace/snippets/jsonata.js': 'editor/vendor/jsonata/snippets-jsonata.js' + 'packages/node_modules/@node-red/editor-client/public/red/red.min.js': 'packages/node_modules/@node-red/editor-client/public/red/red.js', + 'packages/node_modules/@node-red/editor-client/public/red/main.min.js': 'packages/node_modules/@node-red/editor-client/public/red/main.js', + 'packages/node_modules/@node-red/editor-client/public/vendor/ace/mode-jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/mode-jsonata.js', + 'packages/node_modules/@node-red/editor-client/public/vendor/ace/snippets/jsonata.js': 'packages/node_modules/@node-red/editor-client/src/vendor/jsonata/snippets-jsonata.js' } } }, @@ -214,50 +215,50 @@ module.exports = function(grunt) { outputStyle: 'compressed' }, files: [{ - dest: 'public/red/style.min.css', - src: 'editor/sass/style.scss' + dest: 'packages/node_modules/@node-red/editor-client/public/red/style.min.css', + src: 'packages/node_modules/@node-red/editor-client/src/sass/style.scss' }, { - dest: 'public/vendor/bootstrap/css/bootstrap.min.css', - src: 'editor/vendor/bootstrap/css/bootstrap.css' + dest: 'packages/node_modules/@node-red/editor-client/public/vendor/bootstrap/css/bootstrap.min.css', + src: 'packages/node_modules/@node-red/editor-client/src/vendor/bootstrap/css/bootstrap.css' }] } }, jsonlint: { messages: { src: [ - 'nodes/core/locales/en-US/messages.json', - 'red/api/locales/en-US/editor.json', - 'red/runtime/locales/en-US/runtime.json' + 'packages/node_modules/@node-red/nodes/locales/**/*.json', + 'packages/node_modules/@node-red/editor-client/locales/**/*.json', + 'packages/node_modules/@node-red/runtime/locales/**/*.json' ] }, keymaps: { src: [ - 'editor/js/keymap.json' + 'packages/node_modules/@node-red/editor-client/src/js/keymap.json' ] } }, attachCopyright: { js: { src: [ - 'public/red/red.min.js', - 'public/red/main.min.js' + 'packages/node_modules/@node-red/editor-client/public/red/red.min.js', + 'packages/node_modules/@node-red/editor-client/public/red/main.min.js' ] }, css: { src: [ - 'public/red/style.min.css' + 'packages/node_modules/@node-red/editor-client/public/red/style.min.css' ] } }, clean: { build: { src: [ - "public/red", - "public/index.html", - "public/favicon.ico", - "public/icons", - "public/vendor" + "packages/node_modules/@node-red/editor-client/public/red", + "packages/node_modules/@node-red/editor-client/public/index.html", + "packages/node_modules/@node-red/editor-client/public/favicon.ico", + "packages/node_modules/@node-red/editor-client/public/icons", + "packages/node_modules/@node-red/editor-client/public/vendor" ] }, release: { @@ -269,27 +270,27 @@ module.exports = function(grunt) { watch: { js: { files: [ - 'editor/js/**/*.js' + 'packages/node_modules/@node-red/editor-client/src/js/**/*.js' ], tasks: ['copy:build','concat','uglify','attachCopyright:js'] }, sass: { files: [ - 'editor/sass/**/*.scss' + 'packages/node_modules/@node-red/editor-client/src/sass/**/*.scss' ], tasks: ['sass','attachCopyright:css'] }, json: { files: [ - 'nodes/core/locales/en-US/messages.json', - 'red/api/locales/en-US/editor.json', - 'red/runtime/locales/en-US/runtime.json' + 'packages/node_modules/@node-red/nodes/locales/**/*.json', + 'packages/node_modules/@node-red/editor-client/locales/**/*.json', + 'packages/node_modules/@node-red/runtime/locales/**/*.json' ], tasks: ['jsonlint:messages'] }, keymaps: { files: [ - 'editor/js/keymap.json' + 'packages/node_modules/@node-red/editor-client/src/js/keymap.json' ], tasks: ['jsonlint:keymaps','copy:build'] }, @@ -304,12 +305,13 @@ module.exports = function(grunt) { nodemon: { /* uses .nodemonignore */ dev: { - script: 'red.js', + script: 'packages/node_modules/node-red/red.js', options: { args: nodemonArgs, ext: 'js,html,json', watch: [ - 'red','nodes' + 'packages/node_modules', + '!packages/node_modules/@node-red/editor-client' ] } } @@ -328,21 +330,21 @@ module.exports = function(grunt) { build: { files:[ { - src: 'editor/js/main.js', - dest: 'public/red/main.js' + src: 'packages/node_modules/@node-red/editor-client/src/js/main.js', + dest: 'packages/node_modules/@node-red/editor-client/public/red/main.js' }, { - src: 'editor/js/keymap.json', - dest: 'public/red/keymap.json' + src: 'packages/node_modules/@node-red/editor-client/src/js/keymap.json', + dest: 'packages/node_modules/@node-red/editor-client/public/red/keymap.json' }, { - cwd: 'editor/images', + cwd: 'packages/node_modules/@node-red/editor-client/src/images', src: '**', expand: true, - dest: 'public/red/images/' + dest: 'packages/node_modules/@node-red/editor-client/public/red/images/' }, { - cwd: 'editor/vendor', + cwd: 'packages/node_modules/@node-red/editor-client/src/vendor', src: [ 'ace/**', //'bootstrap/css/**', @@ -351,46 +353,31 @@ module.exports = function(grunt) { 'font-awesome/**' ], expand: true, - dest: 'public/vendor/' + dest: 'packages/node_modules/@node-red/editor-client/public/vendor/' }, { - cwd: 'editor/icons', + cwd: 'packages/node_modules/@node-red/editor-client/src/icons', src: '**', expand: true, - dest: 'public/icons/' + dest: 'packages/node_modules/@node-red/editor-client/public/icons/' }, { expand: true, - src: ['editor/index.html','editor/favicon.ico'], - dest: 'public/', + src: ['packages/node_modules/@node-red/editor-client/src/index.html','packages/node_modules/@node-red/editor-client/src/favicon.ico'], + dest: 'packages/node_modules/@node-red/editor-client/public/', flatten: true }, { src: 'CHANGELOG.md', - dest: 'public/red/about' + dest: 'packages/node_modules/@node-red/editor-client/public/red/about' + }, + { + cwd: 'packages/node_modules/@node-red/editor-client/src/ace/bin/', + src: '**', + expand: true, + dest: 'packages/node_modules/@node-red/editor-client/public/vendor/ace/' } ] - }, - release: { - files: [{ - mode: true, - expand: true, - src: [ - '*.md', - 'LICENSE', - 'package.json', - 'settings.js', - 'red.js', - 'lib/.gitignore', - 'nodes/*.demo', - 'nodes/core/**', - 'red/**', - 'public/**', - 'editor/templates/**', - 'bin/**' - ], - dest: path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>') - }] } }, chmod: { @@ -399,8 +386,8 @@ module.exports = function(grunt) { }, release: { src: [ - path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/nodes/core/hardware/nrgpio*'), - path.resolve('<%= paths.dist %>/node-red-<%= pkg.version %>/red/runtime/storage/localfilesystem/projects/git/node-red-*sh') + "packages/node_modules/@node-red/nodes/core/hardware/nrgpio", + "packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/node-red-*sh" ] } }, @@ -410,8 +397,43 @@ module.exports = function(grunt) { archive: '<%= paths.dist %>/node-red-<%= pkg.version %>.zip' }, expand: true, - cwd: '<%= paths.dist %>/', - src: ['node-red-<%= pkg.version %>/**'] + cwd: 'packages/node_modules/', + src: [ + '**', + '!@node-red/editor-client/src/**' + ] + } + }, + jsdoc : { + runtimeAPI: { + src: 'packages/node_modules/@node-red/runtime/lib/api/*.js', + options: { + destination: 'docs', + configure: './jsdoc.json' + } + }, + nodeREDUtil: { + src: 'packages/node_modules/@node-red/util/**/*.js', + options: { + destination: 'packages/node_modules/@node-red/util/docs', + configure: './jsdoc.json' + } + } + }, + jsdoc2md: { + runtimeAPI: { + options: { + separators: true + }, + src: 'packages/node_modules/@node-red/runtime/lib/api/*.js', + dest: 'docs/runtime-api.md' + }, + nodeREDUtil: { + options: { + separators: true + }, + src: 'packages/node_modules/@node-red/util/**/*.js', + dest: 'packages/node_modules/@node-red/util/docs/api.md' } } }); @@ -431,6 +453,8 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-jsonlint'); grunt.loadNpmTasks('grunt-mocha-istanbul'); grunt.loadNpmTasks('grunt-webdriver'); + grunt.loadNpmTasks('grunt-jsdoc'); + grunt.loadNpmTasks('grunt-jsdoc-to-markdown'); grunt.registerMultiTask('attachCopyright', function() { var files = this.data.src; @@ -472,6 +496,15 @@ module.exports = function(grunt) { } }); + grunt.registerTask('verifyPackageDependencies', function() { + var verifyDependencies = require("./scripts/verify-package-dependencies.js"); + var failures = verifyDependencies(); + if (failures.length > 0) { + failures.forEach(f => grunt.log.error(f)); + grunt.fail.fatal("Failed to verify package dependencies"); + } + }); + grunt.registerTask('setDevEnv', 'Sets NODE_ENV=development so non-minified assets are used', function () { @@ -480,7 +513,7 @@ module.exports = function(grunt) { grunt.registerTask('default', 'Builds editor content then runs code style checks and unit tests on all components', - ['build','jshint:editor','mocha_istanbul:all']); + ['build','verifyPackageDependencies','jshint:editor','mocha_istanbul:all']); grunt.registerTask('test-core', 'Runs code style check and unit tests on core runtime code', @@ -508,9 +541,13 @@ module.exports = function(grunt) { grunt.registerTask('release', 'Create distribution zip file', - ['build','clean:release','copy:release','chmod:release','compress:release']); + ['build','verifyPackageDependencies','clean:release','chmod:release','compress:release']); grunt.registerTask('coverage', 'Run Istanbul code test coverage task', ['build','mocha_istanbul:all']); + + grunt.registerTask('docs', + 'Generates API documentation', + ['jsdoc','jsdoc2md']); }; diff --git a/README.md b/README.md index c1306a796..3d0acb0e3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ http://nodered.org -[![Build Status](https://travis-ci.org/node-red/node-red.svg)](https://travis-ci.org/node-red/node-red) +[![Build Status](https://travis-ci.org/node-red/node-red.svg?branch=master)](https://travis-ci.org/node-red/node-red) [![Coverage Status](https://coveralls.io/repos/node-red/node-red/badge.svg?branch=master)](https://coveralls.io/r/node-red/node-red?branch=master) A visual tool for wiring the Internet of Things. @@ -44,9 +44,6 @@ If you want to run the latest code from git, here's how to get started: 4. Run npm start - or - - node red.js ## Contributing diff --git a/editor/js/ui/common/panels.js b/editor/js/ui/common/panels.js deleted file mode 100644 index 84e1d4c7e..000000000 --- a/editor/js/ui/common/panels.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Copyright JS Foundation and other contributors, http://js.foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - **/ - - -RED.panels = (function() { - - function createPanel(options) { - var container = options.container || $("#"+options.id); - var children = container.children(); - if (children.length !== 2) { - throw new Error("Container must have exactly two children"); - } - - container.addClass("red-ui-panels"); - var separator = $('
').insertAfter(children[0]); - var startPosition; - var panelHeights = []; - var modifiedHeights = false; - var panelRatio; - - separator.draggable({ - axis: "y", - containment: container, - scroll: false, - start:function(event,ui) { - var height = container.height(); - startPosition = ui.position.top; - panelHeights = [$(children[0]).height(),$(children[1]).height()]; - }, - drag: function(event,ui) { - var height = container.height(); - var delta = ui.position.top-startPosition; - var newHeights = [panelHeights[0]+delta,panelHeights[1]-delta]; - $(children[0]).height(newHeights[0]); - $(children[1]).height(newHeights[1]); - if (options.resize) { - options.resize(newHeights[0],newHeights[1]); - } - ui.position.top -= delta; - panelRatio = newHeights[0]/height; - }, - stop:function(event,ui) { - modifiedHeights = true; - } - }); - - return { - resize: function(height) { - var panelHeights = [$(children[0]).height(),$(children[1]).height()]; - container.height(height); - if (modifiedHeights) { - var topPanelHeight = panelRatio*height; - var bottomPanelHeight = height - topPanelHeight - 48; - panelHeights = [topPanelHeight,bottomPanelHeight]; - $(children[0]).height(panelHeights[0]); - $(children[1]).height(panelHeights[1]); - } - if (options.resize) { - options.resize(panelHeights[0],panelHeights[1]); - } - } - } - } - - return { - create: createPanel - } -})(); diff --git a/editor/sass/ace.scss b/editor/sass/ace.scss deleted file mode 100644 index 9425c356c..000000000 --- a/editor/sass/ace.scss +++ /dev/null @@ -1,8 +0,0 @@ -.ace_gutter { - border-top-left-radius: 4px; - border-bottom-left-radius: 4px; -} -.ace_scroller { - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; -} diff --git a/editor/templates/index.mst b/editor/templates/index.mst deleted file mode 100644 index 846150118..000000000 --- a/editor/templates/index.mst +++ /dev/null @@ -1,229 +0,0 @@ - - - - - - - - - -Flows stopped due to missing node types.
", + "safe-mode":"Flows stopped in safe mode.
You can modify your flows and deploy the changes to restart.
", "restartRequired": "Node-RED must be restarted to enable upgraded modules", "credentials_load_failed": "Flows stopped as the credentials could not be decrypted.
The flow credential file is encrypted, but the project's encryption key is missing or invalid.
", "credentials_load_failed_reset":"Credentials could not be decrypted
The flow credential file is encrypted, but the project's encryption key is missing or invalid.
The flow credential file will be reset on the next deployment. Any existing flow credentials will be cleared.
", @@ -172,7 +183,10 @@ "modifiedFlowsDesc": "Only deploys flows that contain changed nodes", "modifiedNodes": "Modified Nodes", "modifiedNodesDesc": "Only deploys nodes that have changed", + "restartFlows": "Restart Flows", + "restartFlowsDesc": "Restarts the current deployed flows", "successfulDeploy": "Successfully deployed", + "successfulRestart": "Successfully restarted flows", "deployFailed": "Deploy failed: __message__", "unusedConfigNodes":"You have some unused configuration nodes.", "unusedConfigNodesLink":"Click here to see them", @@ -201,6 +215,10 @@ "plusNMore": "+ __count__ more" } }, + "eventLog": { + "title": "Event log", + "view": "View log" + }, "diff": { "unresolvedCount": "__count__ unresolved conflict", "unresolvedCount_plural": "__count__ unresolved conflicts", @@ -265,6 +283,9 @@ "settingIcon": "Icon", "noDefaultLabel": "none", "defaultLabel": "use default label", + "searchIcons": "Search icons", + "useDefault": "use default", + "description": "Description", "errors": { "scopeChange": "Changing the scope will make it unavailable to nodes in other flows that use it" } @@ -306,13 +327,11 @@ "savedNodes": "Saved nodes", "savedType": "Saved __type__", "saveFailed": "Save failed: __message__", - "filename": "Filename", "folder": "Folder", "filenamePlaceholder": "file", "fullFilenamePlaceholder": "a/b/file", "folderPlaceholder": "a/b", - "breadcrumb": "Library" }, "palette": { @@ -330,6 +349,10 @@ "analysis": "analysis", "advanced": "advanced" }, + "actions": { + "collapse-all": "Collapse all categories", + "expand-all": "Expand all categories" + }, "event": { "nodeAdded": "Node added to palette:", "nodeAdded_plural": "Nodes added to palette", @@ -358,7 +381,6 @@ "monthsV_plural": "__count__ months ago", "yearsV": "__count__ year ago", "yearsV_plural": "__count__ years ago", - "yearMonthsV": "__y__ year, __count__ month ago", "yearMonthsV_plural": "__y__ year, __count__ months ago", "yearsMonthsV": "__y__ years, __count__ month ago", @@ -426,6 +448,7 @@ "label": "info", "node": "Node", "type": "Type", + "module": "Module", "id": "ID", "status": "Status", "enabled": "Enabled", @@ -434,6 +457,7 @@ "instances": "Instances", "properties": "Properties", "info": "Information", + "desc": "Description", "blank": "blank", "null": "null", "showMore": "show more", @@ -460,8 +484,14 @@ "filtered": "__count__ hidden" }, "context": { - "name":"Context", - "label":"context" + "name":"Context Data", + "label":"context", + "none": "none selected", + "refresh": "refresh to load", + "empty": "empty", + "node": "Node", + "flow": "Flow", + "global": "Global" }, "palette": { "name": "Palette management", @@ -477,21 +507,22 @@ "editDescription": "Edit project description", "editDependencies": "Edit project dependencies", "editReadme": "Edit README.md", + "showProjectSettings": "Show project settings", "projectSettings": { + "title": "Project Settings", "edit": "edit", "none": "None", "install": "install", "removeFromProject": "remove from project", "addToProject": "add to project", - "none": "None", "files": "Files", "flow": "Flow", "credentials": "Credentials", "invalidEncryptionKey": "Invalid encryption key", "encryptionEnabled": "Encryption enabled", "encryptionDisabled": "Encryption disabled", - "resetTheEncryptionKey": "Reset the encryption key:", "setTheEncryptionKey": "Set the encryption key:", + "resetTheEncryptionKey": "Reset the encryption key:", "changeTheEncryptionKey": "Change the encryption key:", "currentKey": "Current key", "newKey": "New key", @@ -583,6 +614,7 @@ "pullUnrelatedHistory": "The remote has an unrelated history of commits.
Are you sure you want to pull the changes into your local repository?
", "pullChanges": "Pull changes", "history": "history", + "projectHistory": "Project History", "daysAgo": "__count__ day ago", "daysAgo_plural": "__count__ days ago", "hoursAgo": "__count__ hour ago", @@ -614,7 +646,9 @@ "bool": "boolean", "json": "JSON", "bin": "buffer", - "date": "timestamp" + "date": "timestamp", + "jsonata": "expression", + "env": "env variable" } }, "editableList": { @@ -643,6 +677,9 @@ "eval": "Error evaluating expression:\n __message__" } }, + "jsEditor": { + "title": "JavaScript editor" + }, "jsonEditor": { "title": "JSON editor", "format": "format JSON" @@ -705,7 +742,7 @@ "ssh-key-add": "Add an ssh key", "credential-key": "Credentials encryption key", "cant-get-ssh-key": "Error! Can't get selected SSH key path.", - "already-exists": "already exists", + "already-exists2": "already exists", "git-error": "git error", "connection-failed": "Connection failed", "not-git-repo": "Not a git repository", diff --git a/red/api/editor/locales/en-US/infotips.json b/packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json similarity index 100% rename from red/api/editor/locales/en-US/infotips.json rename to packages/node_modules/@node-red/editor-client/locales/en-US/infotips.json diff --git a/red/api/editor/locales/en-US/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json similarity index 99% rename from red/api/editor/locales/en-US/jsonata.json rename to packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json index c839c759e..23917e749 100644 --- a/red/api/editor/locales/en-US/jsonata.json +++ b/packages/node_modules/@node-red/editor-client/locales/en-US/jsonata.json @@ -189,11 +189,11 @@ "desc":"Returns an aggregated value derived from applying the `function` parameter successively to each value in `array` in combination with the result of the previous application of the function.\n\nThe function must accept two arguments, and behaves like an infix operator between each value within the `array`.\n\nThe optional `init` parameter is used as the initial value in the aggregation." }, "$flowContext": { - "args": "string", + "args": "string[, string]", "desc": "Retrieves a flow context property.\n\nThis is a Node-RED defined function." }, "$globalContext": { - "args": "string", + "args": "string[, string]", "desc": "Retrieves a global context property.\n\nThis is a Node-RED defined function." }, "$pad": { diff --git a/red/api/editor/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json similarity index 94% rename from red/api/editor/locales/ja/editor.json rename to packages/node_modules/@node-red/editor-client/locales/ja/editor.json index e884ec842..eb1ae260e 100644 --- a/red/api/editor/locales/ja/editor.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json @@ -78,6 +78,12 @@ "projects-settings": "設定" } }, + "actions": { + "toggle-navigator": "ナビゲータの表示/非表示を切替", + "zoom-out": "縮小", + "zoom-reset": "拡大/縮小を初期化", + "zoom-in": "拡大" + }, "user": { "loggedInAs": "__name__ としてログインしました", "username": "ユーザ名", @@ -97,11 +103,15 @@ "undeployedChanges": "ノードの変更をデプロイしていません", "nodeActionDisabled": "ノードのアクションは、サブフロー内で無効になっています", "missing-types": "不明なノードが存在するため、フローを停止しました。詳細はログを確認してください。", + "safe-mode": "セーフモードでフローを停止しました
フローを変更し、再起動するために変更をデプロイできます
", "restartRequired": "更新されたモジュールを有効化するため、Node-REDを再起動する必要があります", - "credentials_load_failed": "認証情報を復号できないため、フローを停止しました
フローの認証情報は暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です
", + "credentials_load_failed": "認証情報を復号できないため、フローを停止しました
フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です
", + "credentials_load_failed_reset": "認証情報を復号できません
フローの認証情報ファイルは暗号化されています。しかし、プロジェクトの暗号鍵が存在しない、または不正です。
次回のデプロイでフローの認証情報ファイルがリセットされます。既存フローの認証情報は削除されます。
", "missing_flow_file": "プロジェクトのフローファイルが存在しません
本プロジェクトにフローファイルが登録されていません
", + "missing_package_file": "プロジェクトのパッケージファイルが存在しません
本プロジェクトにはpackage.jsonファイルがありません
", "project_empty": "空のプロジェクトです
デフォルトのプロジェクトファイルを作成しますか?
作成しない場合、エディタの外でファイルをプロジェクトへ手動で追加する必要があります
プロジェクト '__project__' が存在しません
" + "project_not_found": "プロジェクト '__project__' が存在しません
", + "git_merge_conflict": "変更の自動マージが失敗しました
マージされていない競合を解決し、コミットしてください
" }, "error": "エラー: __message__", "errors": { @@ -168,7 +178,10 @@ "modifiedFlowsDesc": "変更したノードを含むフローのみデプロイ", "modifiedNodes": "変更したノード", "modifiedNodesDesc": "変更したノードのみデプロイ", + "restartFlows": "フローを再起動", + "restartFlowsDesc": "デプロイされた現在のフローを再起動", "successfulDeploy": "デプロイが成功しました", + "successfulRestart": "フローの再起動が成功しました", "deployFailed": "デプロイが失敗しました: __message__", "unusedConfigNodes": "使われていない「ノードの設定」があります。", "unusedConfigNodesLink": "設定を参照する", @@ -236,6 +249,7 @@ "output": "出力:", "deleteSubflow": "サブフローを削除", "info": "詳細", + "category": "カテゴリ", "format": "マークダウン形式", "errors": { "noNodesSelected": "サブフローを作成できません: ノードが選択されていません", @@ -260,6 +274,9 @@ "settingIcon": "アイコン", "noDefaultLabel": "なし", "defaultLabel": "既定の名前を使用", + "searchIcons": "アイコンを検索", + "useDefault": "デフォルトを使用", + "description": "詳細", "errors": { "scopeChange": "スコープの変更は、他のフローで使われているノードを無効にします" } @@ -312,6 +329,7 @@ "noInfo": "情報がありません", "filter": "ノードを検索", "search": "ノードを検索", + "addCategory": "新規追加...", "label": { "subflows": "サブフロー", "input": "入力", @@ -322,6 +340,10 @@ "analysis": "分析", "advanced": "その他" }, + "actions": { + "collapse-all": "全カテゴリを折畳む", + "expand-all": "全カテゴリを展開" + }, "event": { "nodeAdded": "ノードをパレットへ追加しました:", "nodeAdded_plural": "ノードをパレットへ追加しました", @@ -424,6 +446,7 @@ "instances": "インスタンス", "properties": "プロパティ", "info": "情報", + "desc": "詳細", "blank": "ブランク", "null": "ヌル", "showMore": "さらに表示", @@ -449,6 +472,16 @@ "filterAll": "全て", "filtered": "__count__ 個が無効" }, + "context": { + "name": "コンテキストデータ", + "label": "コンテキストデータ", + "none": "選択されていません", + "refresh": "読み込みのため更新してください", + "empty": "データが存在しません", + "node": "Node", + "flow": "Flow", + "global": "Global" + }, "palette": { "name": "パレットの管理", "label": "パレット" @@ -463,7 +496,9 @@ "editDescription": "プロジェクトの詳細を編集", "editDependencies": "プロジェクトの依存関係を編集", "editReadme": "README.mdを編集", + "showProjectSettings": "プロジェクト設定を表示", "projectSettings": { + "title": "プロジェクト設定", "edit": "編集", "none": "なし", "install": "インストール", @@ -568,7 +603,7 @@ "pullUnrelatedHistory": "リモートに関連のないコミット履歴があります。
本当に変更をプルしてローカルリポジトリに反映しますか?
", "pullChanges": "プル変更", "history": "履歴", - "plural": "", + "projectHistory": "プロジェクト履歴", "daysAgo": "__count__ 日前", "daysAgo_plural": "__count__ 日前", "hoursAgo": "__count__ 時間前", @@ -600,7 +635,9 @@ "bool": "真偽", "json": "JSON", "bin": "バッファ", - "date": "日時" + "date": "日時", + "jsonata": "JSONata式", + "env": "環境変数" } }, "editableList": { @@ -629,6 +666,9 @@ "eval": "表現評価エラー:\n __message__" } }, + "jsEditor": { + "title": "JavaScriptエディタ" + }, "jsonEditor": { "title": "JSONエディタ", "format": "JSONフォーマット" @@ -691,14 +731,14 @@ "ssh-key-add": "SSHキーの追加", "credential-key": "認証情報の暗号化キー", "cant-get-ssh-key": "エラー! 選択したSSHキーのパスを取得できません。", - "already-exists": "既に存在します", + "already-exists2": "既に存在します", "git-error": "Gitエラー", "connection-failed": "接続に失敗しました", "not-git-repo": "Gitリポジトリではありません", "repo-not-found": "リポジトリが見つかりません" }, "default-files": { - "create": "プロジェクト関連ファアイルの作成", + "create": "プロジェクト関連ファイルの作成", "desc0": "プロジェクトはフローファイル、README、package.jsonを含みます。", "desc1": "その他、Gitリポジトリで管理したいファイルを含めても構いません。", "desc2": "既存のフローと認証情報ファイルをプロジェクトにコピーします。", @@ -714,7 +754,7 @@ "desc4": "認証情報を公開Gitリポジトリに保存する際には、秘密キーフレーズによって暗号化します。", "desc5": "フロー認証情報ファイルはsettingsファイルのcredentialSecretプロパティで暗号化されています。", "desc6": "フロー認証情報ファイルはシステムが生成したキーによって暗号化されています。このプロジェクト用に新しい秘密キーを指定してください。", - "desc7": "キーはプロジェクトファイルとば別に保存されます。他のNode-REDでこのプロジェクトを利用するには、このプロジェクトのキーが必要です。", + "desc7": "キーはプロジェクトファイルとは別に保存されます。他のNode-REDでこのプロジェクトを利用するには、このプロジェクトのキーが必要です。", "credentials": "認証情報", "enable": "暗号化を有効にする", "disable": "暗号化を無効にする", @@ -799,7 +839,7 @@ "no-empty": "デフォルトのファイル群を空でないプロジェクトに作成することはできません。", "git-error": "Gitエラー" }, - "errors" : { + "errors": { "no-username-email": "Gitクライアントのユーザ名/emailが設定されていません。", "unexpected": "予期しないエラーが発生しました", "code": "コード" diff --git a/red/api/editor/locales/ja/infotips.json b/packages/node_modules/@node-red/editor-client/locales/ja/infotips.json similarity index 100% rename from red/api/editor/locales/ja/infotips.json rename to packages/node_modules/@node-red/editor-client/locales/ja/infotips.json diff --git a/red/api/editor/locales/ja/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json similarity index 99% rename from red/api/editor/locales/ja/jsonata.json rename to packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json index d4ff2935b..1c1e35168 100644 --- a/red/api/editor/locales/ja/jsonata.json +++ b/packages/node_modules/@node-red/editor-client/locales/ja/jsonata.json @@ -214,5 +214,9 @@ "$toMillis": { "args": "timestamp", "desc": "ISO 8601形式の文字列 `timestamp` を、Unixエポック(1 January, 1970 UTC)からの経過ミリ秒を表す数値へ変換します。 文字列が正しい形式でない場合、エラーとなります。" + }, + "$env": { + "args": "arg", + "desc": "環境変数の値を返します。\n\n本関数はNode-REDの定義関数です。" } } diff --git a/red/api/editor/locales/zh-CN/editor.json b/packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json similarity index 100% rename from red/api/editor/locales/zh-CN/editor.json rename to packages/node_modules/@node-red/editor-client/locales/zh-CN/editor.json diff --git a/red/api/editor/locales/zh-CN/infotips.json b/packages/node_modules/@node-red/editor-client/locales/zh-CN/infotips.json similarity index 100% rename from red/api/editor/locales/zh-CN/infotips.json rename to packages/node_modules/@node-red/editor-client/locales/zh-CN/infotips.json diff --git a/red/api/editor/locales/zh-CN/jsonata.json b/packages/node_modules/@node-red/editor-client/locales/zh-CN/jsonata.json similarity index 100% rename from red/api/editor/locales/zh-CN/jsonata.json rename to packages/node_modules/@node-red/editor-client/locales/zh-CN/jsonata.json diff --git a/packages/node_modules/@node-red/editor-client/package.json b/packages/node_modules/@node-red/editor-client/package.json new file mode 100644 index 000000000..8dad4770a --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/package.json @@ -0,0 +1,14 @@ +{ + "name": "@node-red/editor-client", + "version": "0.20.0-alpha.0", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/node-red/node-red.git" + }, + "contributors": [ + { "name": "Nick O'Leary" }, + { "name": "Dave Conway-Jones"} + ], + "main": "./lib/index.js" +} diff --git a/packages/node_modules/@node-red/editor-client/src/ace/README.md b/packages/node_modules/@node-red/editor-client/src/ace/README.md new file mode 100644 index 000000000..bbcef5713 --- /dev/null +++ b/packages/node_modules/@node-red/editor-client/src/ace/README.md @@ -0,0 +1,50 @@ +How to build the custom ACE modes for Node-RED +---------------------------------------------- + +Node-RED includes custom JSONata and JavaScript modes. + + +## JSONata + +The `ace/mode/jsonata` mode is maintained under `editor-client/src/vendor/jsonata`. +Those files are edited in place and copied into the build by Grunt. + +## JavaScript + +The `ace/mode/nrjavascript` mode is used exclusively by the Function node. It +inherits almost entirely from the normal JavaScript mode. The one key difference +is that it wraps the code with a Function before parsing. This is required to +avoid some false-flagged errors. + +The source of the mode is under `editor-client/src/ace/mode`. If those files are +modified in anyway, they *must* be manually built to generate the files under +`editor-client/src/ace/bin` and checked in. Those files are the ones the Grunt +built copies out in the Node-RED build. + +### Building the mode files + + +#### Setup build environment + + cd /tmp/ + git clone https://github.com/ajaxorg/ace.git + cd ace + npm install + +#### Copy mode src files into build environment + + cd