├── .gitignore
├── index.js
├── setup.js
├── generate-themes.js
├── webpack.config.js
├── nls-replace.js
├── package.json
├── common.js
├── update-types.js
├── README.md
├── generate-extraLibs.js
├── theme-extra
├── ace.json
├── forge-light.json
└── forge-dark.json
├── demo.html
├── node-red-types
├── util.d.ts
└── func.d.ts
├── LICENSE
└── generate-monaco-esm-i18n.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | output
3 | temp
4 | .cache
5 | .vscode
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | // import * as monaco from 'monaco-editor-esm-i18n';
2 | // window.monaco = monaco;
3 | // window.MonacoEnvironment = window.MonacoEnvironment || {};
4 | // if(!window.MonacoEnvironment.Locale) {
5 | // window.MonacoEnvironment.Locale = window.MonacoLocale
6 | // }
7 |
8 | import * as monaco from 'monaco-editor-esm-i18n';
9 | const parent = typeof globalThis === "object" ? globalThis : typeof window === "object" ? window : typeof self === "object" ? self : global;
10 | parent.monaco = monaco;
11 | monaco.parent = parent;
12 | parent.MonacoEnvironment = parent.MonacoEnvironment || {};
13 | if(!parent.MonacoEnvironment.Locale) {
14 | parent.MonacoEnvironment.Locale = parent.MonacoLocale
15 | }
--------------------------------------------------------------------------------
/setup.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 |
3 | exports.projectDir = __dirname;
4 | exports.srcDir = path.join(exports.projectDir);
5 | exports.targetDir = path.join(exports.projectDir, "output");
6 | exports.tempDir = path.join(exports.projectDir, "temp");
7 | exports.npmDir = path.join(exports.srcDir);
8 |
9 | exports.nodeModulesDir= path.join(exports.npmDir, "node_modules");
10 | exports.monacoDir = path.join(exports.nodeModulesDir, "monaco-editor");
11 |
12 | exports.monacoModDir = path.join(exports.nodeModulesDir, "monaco-editor-esm-i18n");
13 | exports.monacoModEsmDir= path.join(exports.monacoModDir, "esm");
14 | exports.monacoThemesDir= path.join(exports.npmDir, "monaco-themes/themes");
15 |
16 | exports.gitDir = path.join(exports.tempDir, "git");
17 | exports.vsCodeLocDir = path.join(exports.gitDir, "vscode-loc");
18 | exports.vsCodeLocI18nDir = path.join(exports.vsCodeLocDir, "i18n");
19 | exports.generatedSourceLocaleDir = path.join(exports.targetDir, "monaco/dist/locale");
20 |
21 | exports.MINIFY_DTS = false;
22 | exports.NODE_VERSION_TO_INCLUDE = "v20.14.8";
23 | exports.NODE_LIB_SOURCE = path.join(exports.projectDir, 'node_modules/@types/node');
24 | exports.NODE_LIB_DESTINATION = path.join(exports.projectDir, 'output/types/node');
25 |
26 | exports.NODE_RED_LIB_SOURCE = path.join(exports.projectDir, 'node-red-types');
27 | exports.NODE_RED_LIB_DESTINATION = path.join(exports.projectDir, 'output/types/node-red');
--------------------------------------------------------------------------------
/generate-themes.js:
--------------------------------------------------------------------------------
1 | /*
2 | Generates monaco compatible themes from tm themes and renames the file to that of
3 | */
4 | const path = require('path');
5 | const parseTmTheme = require('monaco-themes').parseTmTheme;
6 | const fs = require('fs');
7 |
8 | const exclude = ["themelist.json"];
9 | const SOURCE1 = path.join(__dirname, 'node_modules/monaco-themes/themes');
10 | const SOURCE2 = path.join(__dirname, 'theme-extra');
11 | const DESTINATION = path.join(__dirname, 'output/monaco/dist/theme');
12 |
13 |
14 |
15 | (function () {
16 | try {
17 | fs.statSync(DESTINATION);
18 | } catch (err) {
19 | fs.mkdirSync(DESTINATION, { recursive: true });
20 | }
21 | importThemes(SOURCE1, DESTINATION);
22 | importThemes(SOURCE2, DESTINATION);
23 | })();
24 |
25 |
26 | function importThemes(source, destination) {
27 | function readFile(name, dir) {
28 | const srcPath = path.join(dir, name);
29 | return fs.readFileSync(srcPath).toString();
30 | }
31 |
32 | function getNewFileName(src) {
33 | let newName = src.toLowerCase();
34 | if (newName.endsWith(".tmtheme")) {
35 | newName = newName.replace(".tmtheme", ".json")
36 | }
37 | newName = newName.split(" ").join("-");
38 | newName = newName.split("[").join("");
39 | newName = newName.split("]").join("");
40 | newName = newName.split("(").join("");
41 | newName = newName.split(")").join("");
42 | return newName
43 | }
44 |
45 | const themeFiles = fs.readdirSync(source);
46 | while (themeFiles.length > 0) {
47 | const srcFileName = themeFiles.shift();
48 | let skip = exclude.includes(srcFileName);
49 | if (skip) continue;
50 |
51 | let tmThemeString = readFile(srcFileName, source);
52 | var themeData = tmThemeString;
53 | let dstFileName = srcFileName;
54 | if (dstFileName.toLowerCase().endsWith(".json")) {
55 | dstFileName = getNewFileName(srcFileName);
56 | } else if (dstFileName.toLowerCase().endsWith(".tmtheme")) {
57 | dstFileName = getNewFileName(srcFileName);
58 | let monacoTheme = parseTmTheme(tmThemeString);
59 | themeData = JSON.stringify(monacoTheme, null, 2);
60 | }
61 | console.log(`Adding ${srcFileName} as ${dstFileName}`)
62 | fs.writeFileSync(path.join(destination, dstFileName), themeData);
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const { monacoModDir } = require("./setup");
3 | const monacoModPath = path.resolve(__dirname, "node_modules", monacoModDir);
4 | const nls = require.resolve("./nls-replace.js");
5 | const LimitChunkCountPlugin = require("webpack/lib/optimize/LimitChunkCountPlugin");
6 | const NormalModuleWebpackReplacementPlugin = require("webpack/lib/NormalModuleReplacementPlugin");
7 | const CopyWebpackPlugin = require('copy-webpack-plugin');
8 | const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
9 |
10 | module.exports = (env, argv) => {
11 | const devMode = ["development", "dev"].includes(argv?.mode || "production");
12 | env = env || {};
13 | env.production = env.production === true || env.production === "true" || !devMode
14 | // env.production = false; // force dev mode build
15 | if (env.production) {
16 | console.log("Running webpack in production mode");
17 | } else {
18 | console.log("Running webpack in development mode");
19 | }
20 | return {
21 | mode: env.production ? "production" : "development",
22 | devtool: env.production ? undefined : "inline-source-map",
23 | entry: { editor: "./index.js" },
24 | output: {
25 | path: path.resolve(__dirname, "output", "monaco", "dist"),
26 | filename: 'editor.js'
27 | },
28 | stats: {
29 | assets: true,
30 | children: true,
31 | chunks: false,
32 | errors: true,
33 | errorDetails: true,
34 | modules: false,
35 | timings: true,
36 | colors: true
37 | },
38 | target: ['web', 'es6'],
39 | module: {
40 | rules: [{
41 | test: /\.css$/,
42 | use: ["style-loader", "css-loader"],
43 | }, {
44 | test: /\.ttf$/,
45 | type: 'asset/resource'
46 | }
47 | ]
48 | },
49 | plugins: [
50 | new NormalModuleWebpackReplacementPlugin(/\/(vscode\-)?nls\.js/, function (resource) {
51 | resource.request = nls;
52 | resource.resource = nls;
53 | }),
54 | new MonacoWebpackPlugin({ globalAPI: true, monacoEditorPath: monacoModPath }),
55 | new LimitChunkCountPlugin({
56 | maxChunks: 1,
57 | }),
58 | new CopyWebpackPlugin({
59 | patterns: [
60 | { from: 'node_modules/monaco-themes/LICENSE', to: "theme" },
61 | { from: 'node_modules/monaco-editor-esm-i18n/ThirdPartyNotices.txt', to: "ThirdPartyNotices.txt" },
62 | { from: 'node_modules/monaco-editor-esm-i18n/LICENSE', to: "LICENSE", toType: "file" }
63 | ]
64 | }),
65 | ],
66 |
67 | optimization: {
68 | minimize: env.production ? true : false,
69 | splitChunks: {
70 | minSize: 9999999999999999,
71 | }
72 | }
73 | };
74 | };
75 |
--------------------------------------------------------------------------------
/nls-replace.js:
--------------------------------------------------------------------------------
1 | // Modified to support localization.
2 | /*---------------------------------------------------------------------------------------------
3 | * Copyright (c) Microsoft Corporation. All rights reserved.
4 | * Licensed under the MIT License. See License.txt in the project root for license information.
5 | *--------------------------------------------------------------------------------------------*/
6 | const globalScope = typeof globalThis === "object" ? globalThis : typeof window === "object" ? window : typeof self === "object" ? self : global;
7 | let isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0);
8 |
9 | function _format(message, args) {
10 | let result;
11 | if (args.length === 0) {
12 | result = message;
13 | }
14 | else {
15 | result = message.replace(/\{(\d+)\}/g, function (match, rest) {
16 | const index = rest[0];
17 | return typeof args[index] !== 'undefined' ? args[index] : match;
18 | });
19 | }
20 | if (isPseudo) {
21 | // FF3B and FF3D is the Unicode zenkaku representation for [ and ]
22 | result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D';
23 | }
24 | return result;
25 | }
26 |
27 | /**
28 | * @skipMangle
29 | */
30 | export function localize(path, data, defaultMessage, ...args) {
31 | const key = typeof data=== "object" ? data.key : data;
32 | // data = ((globalScope.MonacoEnvironment||{}).Locale||{}).data||{};
33 | // data = ((globalScope.MonacoLocale || {}) || {}).data || {};
34 | // let message = (data[path]||{})[key];
35 | const localeData = ((globalScope.MonacoLocale || {}) || {}).data || {};
36 | let message = (localeData[path] || {})[key];
37 | if (!message) {
38 | message = defaultMessage;
39 | }
40 | args = [];
41 | for (let _i = 3; _i < arguments.length; _i++) {
42 | args[_i - 3] = arguments[_i];
43 | }
44 | return _format(message, args);
45 | }
46 | /**
47 | * @skipMangle
48 | */
49 | export function localize2(path, data, defaultMessage, ...args) {
50 | const key = typeof data=== "object" ? data.key : data;
51 | // data = ((globalScope.MonacoEnvironment||{}).Locale||{}).data||{};
52 | // data = ((globalScope.MonacoLocale || {}) || {}).data || {};
53 | // let message = (data[path]||{})[key];
54 | const localeData = ((globalScope.MonacoLocale || {}) || {}).data || {};
55 | let message = (localeData[path] || {})[key];
56 | if (!message) {
57 | message = defaultMessage;
58 | }
59 | args = [];
60 | for (let _i = 3; _i < arguments.length; _i++) {
61 | args[_i - 3] = arguments[_i];
62 | }
63 | const original = _format(message, args);
64 | return {
65 | value: original,
66 | original
67 | };
68 | }
69 |
70 | export function loadMessageBundle(file) {
71 | return localize;
72 | }
73 |
74 | export function config(opt) {
75 | return loadMessageBundle;
76 | }
77 |
78 | /**
79 | * @skipMangle
80 | */
81 | export function getConfiguredDefaultLocale() {
82 | return (self.MonacoLocale || {}).language;
83 | }
84 | /**
85 | * @skipMangle
86 | */
87 | export function getNLSLanguage() {
88 | return (self.MonacoLocale || {}).language;
89 | }
90 | export function getNLSMessages() {
91 | return ((self.MonacoLocale || {}) || {}).data || {};
92 | }
93 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "nr-monaco-build",
3 | "version": "0.52.2",
4 | "description": "A wrapper to generate an es6 monaco editor with i18n, specifically developed for node-red",
5 | "private": true,
6 | "main": "index.js",
7 | "scripts": {
8 | "build": "npm run update-types && npm run generate && npm run generate-themes && npm run pack",
9 | "build-dev": "npm run update-types && npm run generate && npm run generate-themes && npm run pack-dev",
10 | "copy": "npm run copyCheck1 && npm run copyCheck1 && npm run copyPrep1 && npm run copyPrep2 && npm run copyPrep3 && npm run copyAct1 && npm run copyAct2",
11 | "all": "npm run clean && npm run build && npm run copy",
12 | "all-dev": "npm run clean && npm run build-dev && npm run copy",
13 | "clean": "rm -r -f output && rm -r -f temp",
14 | "generate": "node generate-monaco-esm-i18n.js",
15 | "generate-themes": "node generate-themes.js",
16 | "update-types": "node update-types.js",
17 | "pack": "npx webpack",
18 | "pack-dev": "npx webpack --mode development",
19 | "demo": "npx http-server -p 8080 -c-1 -o demo.html",
20 | "generate-extraLibs": "node generate-extraLibs.js",
21 | "copyCheck1": "test -d output/monaco/dist",
22 | "copyCheck2": "test -d ../node-red/packages/node_modules/@node-red/editor-client/src",
23 | "copyPrep1": "rm -rf ../node-red/packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/*",
24 | "copyPrep2": "rm -rf ../node-red/packages/node_modules/@node-red/editor-client/src/types/node/*",
25 | "copyPrep3": "rm -rf ../node-red/packages/node_modules/@node-red/editor-client/src/types/node-red/*",
26 | "copyAct1": "cp -r output/monaco/dist ../node-red/packages/node_modules/@node-red/editor-client/src/vendor/monaco/",
27 | "copyAct2": "cp -r output/types ../node-red/packages/node_modules/@node-red/editor-client/src"
28 | },
29 | "keywords": [
30 | "monaco",
31 | "node-red"
32 | ],
33 | "author": "steve-mcl",
34 | "license": "Apache-2.0",
35 | "devDependencies": {
36 | "@types/node": "^20.14.8",
37 | "copy-webpack-plugin": "^13.0.1",
38 | "css-loader": "^7.1.2",
39 | "degit": "^2.8.4",
40 | "dts-minify": "^0.3.3",
41 | "glob": "^10.2.6",
42 | "mkdirp": "^3.0.1",
43 | "monaco-editor": "0.52.2",
44 | "monaco-editor-webpack-plugin": "^7.1.0",
45 | "monaco-themes": "^0.4.7",
46 | "ncp": "^2.0.0",
47 | "read-package-json": "^7.0.1",
48 | "recursive-readdir": "^2.2.3",
49 | "replace-in-file": "^6.3.2",
50 | "rimraf": "^5.0.5",
51 | "style-loader": "^3.3.3",
52 | "typedoc": "^0.28.11",
53 | "typescript": "^5.9.2",
54 | "url-loader": "^4.1.1",
55 | "webpack": "^5.101.3",
56 | "webpack-cli": "^5.1.4"
57 | },
58 | "browserslist": [
59 | "> 1%",
60 | "last 2 versions"
61 | ],
62 | "staticFiles": {
63 | "staticPath": [
64 | {
65 | "outDirPattern": "**/dist",
66 | "staticPath": "theme",
67 | "staticOutDir": "theme"
68 | },
69 | {
70 | "outDirPattern": "**/dist-legacy",
71 | "staticPath": "theme",
72 | "staticOutDir": "theme"
73 | }
74 | ]
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/common.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const _semver = require("semver");
4 |
5 | function findClosestSemverMatch(semverString, semverStringArray) {
6 | if (!semverStringArray.length) {
7 | return null
8 | }
9 | let semversArray = semverStringArray.map(e => semver(e));
10 | const semverB = semver(semverString);
11 | const semversSameMajor = semversArray.filter(e => e.major == semverB.major);
12 | if(semversSameMajor && semversSameMajor.length) {
13 | semversArray = semversSameMajor;
14 | }
15 | semversArray.sort(function(a, b){
16 | if(a.major < b.major) return -1;
17 | else if(a.major > b.major) return 1;
18 | else {
19 | if(a.minor < b.minor) return -1;
20 | else if(a.minor > b.minor) return 1;
21 | else {
22 | if(a.revision < b.revision) return -1;
23 | else if(a.revision > b.revision) return 1;
24 | }
25 | }
26 | });
27 |
28 | let below, above, best;
29 | for (let index = 0; index < semversArray.length; index++) {
30 | const element = semversArray[index];
31 | if(element.major == semverB.major && element.minor == semverB.minor && element.patch == semverB.patch) {
32 | best = element;
33 | break;
34 | }
35 | if(element.major <= semverB.major && element.minor <= semverB.minor && element.patch < semverB.patch) {
36 | below = element;
37 | }
38 | if(element.major >= semverB.major && element.minor >= semverB.minor && element.patch > semverB.patch) {
39 | above = element;
40 | break;
41 | }
42 | }
43 | if(!best) {
44 | best = above ? above : below;
45 | }
46 | if(!best) {
47 | return null;
48 | }
49 |
50 | return best.toString();
51 | }
52 |
53 | function semver(/** @type {string} */ ver) {
54 | let verClean = (ver+"");
55 | verClean = verClean.replace(">","").replace("<","").replace("^","").replace("~","").replace("=","");
56 | const parts = verClean.split('.');
57 | if(parts.length === 1) parts.push("0");
58 | if(parts.length === 2) parts.push("0");
59 | if(parts.length > 3) {
60 | parts[2] = parts.slice(2).join(".");
61 | }
62 |
63 | const p1 = ((parts[0] + "") || "0").trim();
64 | const p2 = ((parts[1] + "") || "0").trim();
65 | const p3 = ((parts[2] + "") || "0").trim();
66 | const version = _semver.parse(`${p1}.${p2}.${p3}`);
67 |
68 | return version;
69 | }
70 |
71 | function mkDirSafe(dst) {
72 | try {
73 | fs.statSync(dst);
74 | } catch (err) {
75 | fs.mkdirSync(dst, { recursive: true });
76 | }
77 | }
78 |
79 |
80 | //this is deliberately long hand since rmdirSync did not support .recursive {option} until v12.10.0
81 | function deleteFileOrDir(_path){
82 | if (fs.existsSync(_path)) {
83 | if (fs.lstatSync(_path).isDirectory()) {
84 | var files = fs.readdirSync(_path);
85 | if (!files.length) return fs.rmdirSync(_path);
86 | for (var file in files) {
87 | var currentPath = path.join(_path, files[file]);
88 | if (!fs.existsSync(currentPath)) continue;
89 | if (fs.lstatSync(currentPath).isFile()) {
90 | fs.unlinkSync(currentPath);
91 | continue;
92 | }
93 | if (fs.lstatSync(currentPath).isDirectory() && !fs.readdirSync(currentPath).length) {
94 | fs.rmdirSync(currentPath);
95 | } else {
96 | deleteFileOrDir(currentPath, _path);
97 | }
98 | }
99 | deleteFileOrDir(_path);
100 | } else {
101 | fs.unlinkSync(_path);
102 | }
103 | }
104 | }
105 |
106 | exports.findClosestSemverMatch = findClosestSemverMatch;
107 | exports.semver = semver;
108 | exports.deleteFileOrDir = deleteFileOrDir;
109 | exports.mkDirSafe = mkDirSafe;
--------------------------------------------------------------------------------
/update-types.js:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | const path = require('path');
5 | const fs = require('fs');
6 | const { execSync } = require('child_process');
7 | const note = `\n/* NOTE: Do not edit directly! This file is generated using \`npm run update-types\` in https://github.com/node-red/nr-monaco-build */\n\n`;
8 | const excludeLibs = ["base.d.ts", "constants.d.ts", "index.d.ts", "inspector.d.ts", "punycode.d.ts", "globals.global.d.ts", "repl.d.ts"];
9 |
10 | const { findClosestSemverMatch, deleteFileOrDir, mkDirSafe } = require("./common");
11 |
12 | const {
13 | MINIFY_DTS,
14 | NODE_LIB_SOURCE,
15 | NODE_LIB_DESTINATION,
16 | NODE_RED_LIB_SOURCE,
17 | NODE_RED_LIB_DESTINATION,
18 | NODE_VERSION_TO_INCLUDE
19 | } = require("./setup");
20 |
21 | let ts, minifier;
22 | if (MINIFY_DTS) {
23 | const { createMinifier } = require("dts-minify");
24 | ts = require("typescript");
25 | minifier = createMinifier(ts);// setup (provide a TS Compiler API object)
26 | }
27 |
28 | (function () {
29 | let nodeVer = NODE_VERSION_TO_INCLUDE || process.version
30 | if (nodeVer[0] === "v") { nodeVer = nodeVer.substring(1) }
31 |
32 | //get available nodejs types from npm
33 | const cmd1 = `npm view @types/node versions --json`
34 | const r1 = execSync(cmd1)
35 |
36 | //determine closes version
37 | const versions = JSON.parse(r1);
38 | const closestVersion = findClosestSemverMatch(nodeVer, versions);
39 |
40 | //install @types/node@closestVersion
41 | const cmd2 = `npm i -s @types/node@${closestVersion} --save-dev`;
42 | execSync(cmd2)
43 | //import the libs from NODE_LIB_SOURCE to NODE_LIB_DESTINATION
44 | deleteFileOrDir(NODE_LIB_DESTINATION);
45 | deleteFileOrDir(NODE_RED_LIB_DESTINATION);
46 | copyFiles(NODE_LIB_SOURCE, NODE_LIB_DESTINATION);
47 | copyFiles(NODE_RED_LIB_SOURCE, NODE_RED_LIB_DESTINATION);
48 | })();
49 |
50 |
51 | function copyFiles(src, dst) {
52 | function readLibFile(name, dir) {
53 | const srcPath = path.join(dir, name);
54 | return fs.readFileSync(srcPath).toString();
55 | }
56 | function getDirectories(_path) {
57 | return fs.readdirSync(_path).filter(function (file) {
58 | return fs.statSync(path.join(_path, file)).isDirectory();
59 | });
60 | }
61 | const nodeDtsFiles = fs.readdirSync(src).filter((f) => f.includes('.ts'));
62 | if (nodeDtsFiles && nodeDtsFiles.length) {
63 | var files = nodeDtsFiles.filter(e => excludeLibs.includes(e) == false);//remove excluded files
64 | if (files.length) {
65 | console.log(`Copy '${files.length}' file(s) from '${src}' to '${dst}'...`)
66 | mkDirSafe(dst);
67 | while (files.length > 0) {
68 | const name = files.shift();
69 | console.log(`Copying '${name}'`)
70 | const output = note + readLibFile(name, src).replace(/\r\n/g, '\n');
71 | if (minifier) {
72 | const minifiedText = minifier.minify(output, {
73 | keepJsDocs: true, // false by default
74 | });
75 | fs.writeFileSync(path.join(dst, name), minifiedText);
76 | } else {
77 | fs.writeFileSync(path.join(dst, name), output);
78 | }
79 |
80 | }
81 | }
82 | }
83 | const dirs = getDirectories(src);
84 | if (dirs && dirs.length) {
85 | for (let index = 0; index < dirs.length; index++) {
86 | const p = dirs[index];
87 | const srcDir = path.join(src, p);
88 | const dstDir = path.join(dst, p);
89 | copyFiles(srcDir, dstDir);
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ***IMPORTANT NOTE: This project is specifically for building monaco for node-red and will likely not be of much use to any other projects***
4 |
5 |
6 |
7 | ## About
8 | This project makes an ESM bundle of monaco-editor with 50 themes and localization support. It was built specifically for use in node-red.
9 |
10 | ## Credits
11 | * Huge credit to [primefaces-monaco](https://github.com/blutorange/primefaces-monaco). Without their work, I would never have gotten i18n working.
12 | * All credits to https://www.npmjs.com/package/monaco-themes for the themes
13 |
14 |
15 | ## Notes
16 | * A bug / issue I had to handle is: when changing mode, html worker would attempt to get links from document, but occasionally `document` would be `null` and an exception would be thrown. This has been handled by adding `if(!document) return []` at the top of `function findDocumentLinks(...)` in file `htmlLinks.js`
17 |
18 | ## Instructions
19 |
20 | ### Clone repo
21 | ```bash
22 | git clone https://github.com/node-red/nr-monaco-build
23 | cd nr-monaco-build
24 | ```
25 |
26 | ### Prepare
27 |
28 | #### Step 1
29 |
30 | Prepare the build:
31 |
32 | 1. Check & update `package.json` for latest version of `monaco-editor` (check [here](https://www.npmjs.com/package/monaco-editor)) and other dev dependencies
33 | 2. Update the `package.json` `version` field to match the version of `monaco-editor` you are using.
34 | 3. Check + update `setup.js` in particular the node version set in `env.NODE_VERSION_TO_INCLUDE` This should match a version found in [@types/node](https://www.npmjs.com/package/@types/node?activeTab=versions) on NPM e.g. `v20.14.8`
35 |
36 | #### Step 2
37 |
38 | Check + update node-red (function node/server-side) type defs
39 | * `./node-red-types/func.d.ts`
40 | * `./node-red-types/util.d.ts`
41 |
42 | ### Step 3
43 |
44 | Install dependencies, clean and build
45 |
46 | ```bash
47 | npm install --include=dev
48 | npm run clean
49 | npm run build
50 | ```
51 |
52 | This will bundle the monaco editor with localization support and themes:
53 |
54 | ```bash
55 | cd output/monaco/dist/
56 | ```
57 |
58 | ### Check it works
59 |
60 | Check editor works in browser...
61 |
62 | ```bash
63 | npm run demo
64 | ```
65 |
66 | Now go to
67 |
68 | ```
69 | http://localhost:8080/demo.html
70 | ```
71 |
72 | and you should see monaco editor with a theme set and foreign menus (try opening the context menu with a right click)
73 |
74 | ### Add to node-red src
75 |
76 | #### Automatically
77 |
78 | If your Node-RED source is relative to this repo, you can run the following helper script:
79 |
80 | ```bash
81 | npm run copy
82 | ```
83 |
84 | #### Manually
85 |
86 | When your Node-RED source is not relative to this repo, you can copy the files manually:
87 |
88 | ```bash
89 | # Set the path to your node-red source e.g.
90 | export nr_src=~/repos/github/node-red-org/node-red
91 | # clean up
92 | rm -rf $nr_src/packages/node_modules/@node-red/editor-client/src/vendor/monaco/dist/*
93 | rm -rf $nr_src/packages/node_modules/@node-red/editor-client/src/types/node/*
94 | rm -rf $nr_src/packages/node_modules/@node-red/editor-client/src/types/node-red/*
95 |
96 | # copy
97 | cp -r output/monaco/dist \
98 | $nr_src/packages/node_modules/@node-red/editor-client/src/vendor/monaco/
99 | cp -r output/types \
100 | $nr_src/packages/node_modules/@node-red/editor-client/src/
101 |
102 | ```
103 |
104 | ### Additional helper scripts
105 |
106 | #### Build monaco in development mode
107 |
108 | ```bash
109 | npm run build-dev
110 | ```
111 |
112 |
113 | #### All in one (production mode)
114 |
115 | This will run `npm run clean`, `npm run build`, `npm run copy` in sequence
116 |
117 | ```bash
118 | npm run all
119 | ```
120 |
121 | #### All in one (development mode)
122 |
123 | This will run `npm run clean`, `npm run build-dev`, `npm run copy` in sequence
124 |
125 | ```bash
126 | npm run all-dev
127 | ```
128 |
--------------------------------------------------------------------------------
/generate-extraLibs.js:
--------------------------------------------------------------------------------
1 | /*
2 | Generates a single file containing monacoExtraLibs with an index lookup and the types as strings in a lookup
3 | This version IS NOt USED - but could be utilised at a later date.
4 | Worth keeping this code for "just in case"
5 | */
6 | const path = require('path');
7 | const fs = require('fs');
8 | const child_process = require('child_process');
9 | const note = `\n/* NOTE: Do not edit directly! This file is generated using \`npm run generate-extraLibs\` */\n`;
10 | const enableDefault = ["console.d.ts", "globals.d.ts", "buffer.d.ts", "red-util.d.ts", "red-func.d.ts"];
11 | const excludeLibs = ["base.d.ts","constants.d.ts","index.d.ts","inspector.d.ts","punycode.d.ts", "globals.global.d.ts", "repl.d.ts"];
12 | const NODE_LIB_SOURCE = path.join(__dirname, 'node_modules/@types/node');
13 | const NODE_RED_LIB_SOURCE = path.join(__dirname, 'node-red-types');
14 | const LIB_DESTINATION = path.join(__dirname, 'output/types/extraLibs');
15 |
16 | (function () {
17 | try {
18 | fs.statSync(LIB_DESTINATION);
19 | } catch (err) {
20 | fs.mkdirSync(LIB_DESTINATION, { recursive: true });
21 | }
22 | importLibs();
23 |
24 | })();
25 |
26 |
27 | function importLibs() {
28 | function readLibFile(name, dir) {
29 | const srcPath = path.join(dir, name);
30 | return fs.readFileSync(srcPath).toString();
31 | }
32 |
33 | let strLib = `${note}
34 | /** default export */
35 | export const monacoExtraLibs = {}
36 | `;
37 |
38 | let strLibResult = `${note}
39 | /** lib files */
40 | monacoExtraLibs.typeMap = {}
41 | `;
42 |
43 | let strIndexResult = `${note}
44 | /** lib index */
45 | monacoExtraLibs.typeSet = {}
46 | `;
47 | const nodeDtsFiles = fs.readdirSync(NODE_LIB_SOURCE).filter((f) => f.includes('.ts'));
48 | while (nodeDtsFiles.length > 0) {
49 | const name = nodeDtsFiles.shift();
50 | let skip = excludeLibs.includes(name);
51 | if(skip) continue;
52 | console.log(`Adding ${name}`)
53 | const output = readLibFile(name, NODE_LIB_SOURCE).replace(/\r\n/g, '\n');
54 | strLibResult += `monacoExtraLibs.typeMap['node/${name}'] = "${escapeText(output)}";\n`;
55 | let en = enableDefault.includes(name);
56 | strIndexResult += `monacoExtraLibs.typeSet['node/${name}'] = ${en};\n`;
57 | }
58 | const noderedDtsFiles = fs.readdirSync(NODE_RED_LIB_SOURCE).filter((f) => f.includes('.ts'));
59 | while (noderedDtsFiles.length > 0) {
60 | const name = noderedDtsFiles.shift();
61 | let skip = excludeLibs.includes(name);
62 | if(skip) continue;
63 | console.log(`Adding ${name}`)
64 | const output = readLibFile(name, NODE_RED_LIB_SOURCE).replace(/\r\n/g, '\n');
65 | strLibResult += `monacoExtraLibs.typeMap['red/${name}'] = "${escapeText(output)}";\n`;
66 | strIndexResult += `monacoExtraLibs.typeSet['red/${name}'] = true;\n`;
67 | }
68 |
69 | fs.writeFileSync(path.join(LIB_DESTINATION, 'extraLibs.js'), strLib + strIndexResult + strLibResult );
70 | }
71 |
72 | /**
73 | * Escape text such that it can be used in a javascript string enclosed by double quotes (")
74 | */
75 | function escapeText(text) {
76 | // See http://www.javascriptkit.com/jsref/escapesequence.shtml
77 | const _backspace = '\b'.charCodeAt(0);
78 | const _formFeed = '\f'.charCodeAt(0);
79 | const _newLine = '\n'.charCodeAt(0);
80 | const _nullChar = 0;
81 | const _carriageReturn = '\r'.charCodeAt(0);
82 | const _tab = '\t'.charCodeAt(0);
83 | const _verticalTab = '\v'.charCodeAt(0);
84 | const _backslash = '\\'.charCodeAt(0);
85 | const _doubleQuote = '"'.charCodeAt(0);
86 |
87 | const len = text.length;
88 | let startPos = 0;
89 | let chrCode;
90 | let replaceWith = null;
91 | let resultPieces = [];
92 |
93 | for (let i = 0; i < len; i++) {
94 | chrCode = text.charCodeAt(i);
95 | switch (chrCode) {
96 | case _backspace:
97 | replaceWith = '\\b';
98 | break;
99 | case _formFeed:
100 | replaceWith = '\\f';
101 | break;
102 | case _newLine:
103 | replaceWith = '\\n';
104 | break;
105 | case _nullChar:
106 | replaceWith = '\\0';
107 | break;
108 | case _carriageReturn:
109 | replaceWith = '\\r';
110 | break;
111 | case _tab:
112 | replaceWith = '\\t';
113 | break;
114 | case _verticalTab:
115 | replaceWith = '\\v';
116 | break;
117 | case _backslash:
118 | replaceWith = '\\\\';
119 | break;
120 | case _doubleQuote:
121 | replaceWith = '\\"';
122 | break;
123 | }
124 | if (replaceWith !== null) {
125 | resultPieces.push(text.substring(startPos, i));
126 | resultPieces.push(replaceWith);
127 | startPos = i + 1;
128 | replaceWith = null;
129 | }
130 | }
131 | resultPieces.push(text.substring(startPos, len));
132 | return resultPieces.join('');
133 | }
134 |
135 | function stripSourceMaps(str) {
136 | return str.replace(/\/\/# sourceMappingURL[^\n]+/gm, '');
137 | }
138 |
--------------------------------------------------------------------------------
/theme-extra/ace.json:
--------------------------------------------------------------------------------
1 | {
2 | "base": "vs",
3 | "inherit": true,
4 | "rules": [
5 | {
6 | "token": "",
7 | "foreground": "5c6773"
8 | },
9 | {
10 | "token": "invalid",
11 | "foreground": "ff3333"
12 | },
13 | {
14 | "token": "emphasis",
15 | "fontStyle": "italic"
16 | },
17 | {
18 | "token": "strong",
19 | "fontStyle": "bold"
20 | },
21 | {
22 | "token": "variable",
23 | "foreground": "5c6773"
24 | },
25 | {
26 | "token": "variable.predefined",
27 | "foreground": "5c6773"
28 | },
29 | {
30 | "token": "constant",
31 | "foreground": "f08c36"
32 | },
33 | {
34 | "token": "comment",
35 | "foreground": "abb0b6",
36 | "fontStyle": "italic"
37 | },
38 | {
39 | "token": "number",
40 | "foreground": "f08c36"
41 | },
42 | {
43 | "token": "number.hex",
44 | "foreground": "f08c36"
45 | },
46 | {
47 | "token": "regexp",
48 | "foreground": "4dbf99"
49 | },
50 | {
51 | "token": "annotation",
52 | "foreground": "41a6d9"
53 | },
54 | {
55 | "token": "type",
56 | "foreground": "41a6d9"
57 | },
58 | {
59 | "token": "delimiter",
60 | "foreground": "5c6773"
61 | },
62 | {
63 | "token": "delimiter.html",
64 | "foreground": "5c6773"
65 | },
66 | {
67 | "token": "delimiter.xml",
68 | "foreground": "5c6773"
69 | },
70 | {
71 | "token": "tag",
72 | "foreground": "e7c547"
73 | },
74 | {
75 | "token": "tag.id.jade",
76 | "foreground": "e7c547"
77 | },
78 | {
79 | "token": "tag.class.jade",
80 | "foreground": "e7c547"
81 | },
82 | {
83 | "token": "meta.scss",
84 | "foreground": "e7c547"
85 | },
86 | {
87 | "token": "metatag",
88 | "foreground": "e7c547"
89 | },
90 | {
91 | "token": "metatag.content.html",
92 | "foreground": "86b300"
93 | },
94 | {
95 | "token": "metatag.html",
96 | "foreground": "e7c547"
97 | },
98 | {
99 | "token": "metatag.xml",
100 | "foreground": "e7c547"
101 | },
102 | {
103 | "token": "metatag.php",
104 | "fontStyle": "bold"
105 | },
106 | {
107 | "token": "key",
108 | "foreground": "41a6d9"
109 | },
110 | {
111 | "token": "string.key.json",
112 | "foreground": "41a6d9"
113 | },
114 | {
115 | "token": "string.value.json",
116 | "foreground": "86b300"
117 | },
118 | {
119 | "token": "attribute.name",
120 | "foreground": "f08c36"
121 | },
122 | {
123 | "token": "attribute.value",
124 | "foreground": "0451A5"
125 | },
126 | {
127 | "token": "attribute.value.number",
128 | "foreground": "abb0b6"
129 | },
130 | {
131 | "token": "attribute.value.unit",
132 | "foreground": "86b300"
133 | },
134 | {
135 | "token": "attribute.value.html",
136 | "foreground": "86b300"
137 | },
138 | {
139 | "token": "attribute.value.xml",
140 | "foreground": "86b300"
141 | },
142 | {
143 | "token": "string",
144 | "foreground": "86b300"
145 | },
146 | {
147 | "token": "string.html",
148 | "foreground": "86b300"
149 | },
150 | {
151 | "token": "string.sql",
152 | "foreground": "86b300"
153 | },
154 | {
155 | "token": "string.yaml",
156 | "foreground": "86b300"
157 | },
158 | {
159 | "token": "keyword",
160 | "foreground": "f2590c"
161 | },
162 | {
163 | "token": "keyword.json",
164 | "foreground": "f2590c"
165 | },
166 | {
167 | "token": "keyword.flow",
168 | "foreground": "f2590c"
169 | },
170 | {
171 | "token": "keyword.flow.scss",
172 | "foreground": "f2590c"
173 | },
174 | {
175 | "token": "operator.scss",
176 | "foreground": "666666"
177 | },
178 | {
179 | "token": "operator.sql",
180 | "foreground": "778899"
181 | },
182 | {
183 | "token": "operator.swift",
184 | "foreground": "666666"
185 | },
186 | {
187 | "token": "predefined.sql",
188 | "foreground": "FF00FF"
189 | }
190 | ],
191 | "colors": {
192 | "editor.background": "#fafafa",
193 | "editor.foreground": "#5c6773",
194 | "editorIndentGuide.background": "#ecebec",
195 | "editorIndentGuide.activeBackground": "#e0e0e0"
196 | }
197 | }
--------------------------------------------------------------------------------
/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | Demonstrating monaco editor esm with i18n
15 | Things to check...
16 |
17 | - Theme should be set to
forge-dark
18 | - Intellisense for node globals, node-red utility functions should be present
19 | - Monaco lang should be german (right click inside the editor, check palette menu F1 or CTRL-SHIFT-P)
20 |
21 |
22 | MONACO
23 |
24 |
25 |
26 |
27 |
117 |
118 |
119 |
120 |
--------------------------------------------------------------------------------
/theme-extra/forge-light.json:
--------------------------------------------------------------------------------
1 | {
2 | "base": "vs",
3 | "inherit": true,
4 | "rules": [
5 | {
6 | "background": "f2f3fb",
7 | "token": ""
8 | },
9 | {
10 | "foreground": "8e908c",
11 | "token": "comment"
12 | },
13 | {
14 | "foreground": "31959A",
15 | "token": "keyword.operator.class"
16 | },
17 | {
18 | "foreground": "31959A",
19 | "token": "constant.other"
20 | },
21 | {
22 | "foreground": "c82829",
23 | "token": "variable"
24 | },
25 | {
26 | "foreground": "c82829",
27 | "token": "support.other.variable"
28 | },
29 | {
30 | "foreground": "c82829",
31 | "token": "string.other.link"
32 | },
33 | {
34 | "foreground": "c82829",
35 | "token": "string.regexp"
36 | },
37 | {
38 | "foreground": "c82829",
39 | "token": "entity.name.tag"
40 | },
41 | {
42 | "foreground": "c82829",
43 | "token": "entity.other.attribute-name"
44 | },
45 | {
46 | "foreground": "c82829",
47 | "token": "meta.tag"
48 | },
49 | {
50 | "foreground": "c82829",
51 | "token": "declaration.tag"
52 | },
53 | {
54 | "foreground": "c82829",
55 | "token": "markup.deleted.git_gutter"
56 | },
57 | {
58 | "foreground": "f5871f",
59 | "token": "constant.numeric"
60 | },
61 | {
62 | "foreground": "f5871f",
63 | "token": "constant.language"
64 | },
65 | {
66 | "foreground": "f5871f",
67 | "token": "support.constant"
68 | },
69 | {
70 | "foreground": "f5871f",
71 | "token": "constant.character"
72 | },
73 | {
74 | "foreground": "f5871f",
75 | "token": "variable.parameter"
76 | },
77 | {
78 | "foreground": "f5871f",
79 | "token": "punctuation.section.embedded"
80 | },
81 | {
82 | "foreground": "f5871f",
83 | "token": "keyword.other.unit"
84 | },
85 | {
86 | "foreground": "c99e00",
87 | "token": "entity.name.class"
88 | },
89 | {
90 | "foreground": "c99e00",
91 | "token": "entity.name.type.class"
92 | },
93 | {
94 | "foreground": "c99e00",
95 | "token": "support.type"
96 | },
97 | {
98 | "foreground": "c99e00",
99 | "token": "support.class"
100 | },
101 | {
102 | "foreground": "ED4E4E",
103 | "token": "string"
104 | },
105 | {
106 | "foreground": "ED4E4E",
107 | "token": "constant.other.symbol"
108 | },
109 | {
110 | "foreground": "ED4E4E",
111 | "token": "entity.other.inherited-class"
112 | },
113 | {
114 | "foreground": "ED4E4E",
115 | "token": "markup.heading"
116 | },
117 | {
118 | "foreground": "718c00",
119 | "token": "markup.inserted.git_gutter"
120 | },
121 | {
122 | "foreground": "31959A",
123 | "token": "keyword.operator"
124 | },
125 | {
126 | "foreground": "31959A",
127 | "token": "constant.other.color"
128 | },
129 | {
130 | "foreground": "4271ae",
131 | "token": "entity.name.function"
132 | },
133 | {
134 | "foreground": "4271ae",
135 | "token": "meta.function-call"
136 | },
137 | {
138 | "foreground": "4271ae",
139 | "token": "support.function"
140 | },
141 | {
142 | "foreground": "4271ae",
143 | "token": "keyword.other.special-method"
144 | },
145 | {
146 | "foreground": "4271ae",
147 | "token": "meta.block-level"
148 | },
149 | {
150 | "foreground": "4271ae",
151 | "token": "markup.changed.git_gutter"
152 | },
153 | {
154 | "foreground": "31959A",
155 | "token": "keyword"
156 | },
157 | {
158 | "foreground": "8959a8",
159 | "token": "storage"
160 | },
161 | {
162 | "foreground": "8959a8",
163 | "token": "storage.type"
164 | },
165 | {
166 | "foreground": "f12229",
167 | "token": "invalid"
168 | },
169 | {
170 | "foreground": "ffffff",
171 | "background": "4271ae",
172 | "token": "meta.separator"
173 | },
174 | {
175 | "foreground": "f12229",
176 | "background": "8959a8",
177 | "token": "invalid.deprecated"
178 | },
179 | {
180 | "background": "718c00",
181 | "token": "markup.inserted.diff"
182 | },
183 | {
184 | "background": "718c00",
185 | "token": "meta.diff.header.to-file"
186 | },
187 | {
188 | "background": "c82829",
189 | "token": "markup.deleted.diff"
190 | },
191 | {
192 | "background": "c82829",
193 | "token": "meta.diff.header.from-file"
194 | },
195 | {
196 | "foreground": "ffffff",
197 | "background": "4271ae",
198 | "token": "meta.diff.header.from-file"
199 | },
200 | {
201 | "foreground": "ffffff",
202 | "background": "4271ae",
203 | "token": "meta.diff.header.to-file"
204 | },
205 | {
206 | "foreground": "31959A",
207 | "fontStyle": "italic",
208 | "token": "meta.diff.range"
209 | }
210 | ],
211 | "colors": {
212 | "editor.foreground": "#1f2937",
213 | "editor.background": "#ffffff",
214 | "editorCursor.foreground": "#4E4F5D",
215 | "editorLineNumber.foreground": "#1f2937",
216 | "dropdown.background": "#F7F8FC",
217 | "editor.selectionBackground": "#65718370",
218 | "editor.inactiveSelectionBackground": "#65718330",
219 | "editorWidget.background":"#F7F8FC",
220 | "list.hoverForeground": "#F7F8FC",
221 | "list.hoverBackground": "#657183",
222 | "list.focusForeground": "#F7F8FC",
223 | "list.focusBackground": "#657183",
224 | "list.activeSelectionForeground": "#F7F8FC",
225 | "list.activeSelectionBackground": "#657183"
226 | }
227 | }
--------------------------------------------------------------------------------
/theme-extra/forge-dark.json:
--------------------------------------------------------------------------------
1 | {
2 | "base": "vs-dark",
3 | "inherit": true,
4 | "rules": [
5 | {
6 | "background": "1f2937",
7 | "token": ""
8 | },
9 | {
10 | "foreground": "6272a4",
11 | "token": "comment"
12 | },
13 | {
14 | "foreground": "f1fa8c",
15 | "token": "string"
16 | },
17 | {
18 | "foreground": "bd93f9",
19 | "token": "constant.numeric"
20 | },
21 | {
22 | "foreground": "bd93f9",
23 | "token": "constant.language"
24 | },
25 | {
26 | "foreground": "bd93f9",
27 | "token": "constant.character"
28 | },
29 | {
30 | "foreground": "bd93f9",
31 | "token": "constant.other"
32 | },
33 | {
34 | "foreground": "ffb86c",
35 | "token": "variable.other.readwrite.instance"
36 | },
37 | {
38 | "foreground": "ff79c6",
39 | "token": "constant.character.escaped"
40 | },
41 | {
42 | "foreground": "ff79c6",
43 | "token": "constant.character.escape"
44 | },
45 | {
46 | "foreground": "ff79c6",
47 | "token": "string source"
48 | },
49 | {
50 | "foreground": "ff79c6",
51 | "token": "string source.ruby"
52 | },
53 | {
54 | "foreground": "ff79c6",
55 | "token": "keyword"
56 | },
57 | {
58 | "foreground": "ff79c6",
59 | "token": "storage"
60 | },
61 | {
62 | "foreground": "8be9fd",
63 | "fontStyle": "italic",
64 | "token": "storage.type"
65 | },
66 | {
67 | "foreground": "50fa7b",
68 | "fontStyle": "underline",
69 | "token": "entity.name.class"
70 | },
71 | {
72 | "foreground": "50fa7b",
73 | "fontStyle": "italic underline",
74 | "token": "entity.other.inherited-class"
75 | },
76 | {
77 | "foreground": "50fa7b",
78 | "token": "entity.name.function"
79 | },
80 | {
81 | "foreground": "ffb86c",
82 | "fontStyle": "italic",
83 | "token": "variable.parameter"
84 | },
85 | {
86 | "foreground": "ff79c6",
87 | "token": "entity.name.tag"
88 | },
89 | {
90 | "foreground": "50fa7b",
91 | "token": "entity.other.attribute-name"
92 | },
93 | {
94 | "foreground": "8be9fd",
95 | "token": "support.function"
96 | },
97 | {
98 | "foreground": "6be5fd",
99 | "token": "support.constant"
100 | },
101 | {
102 | "foreground": "66d9ef",
103 | "fontStyle": " italic",
104 | "token": "support.type"
105 | },
106 | {
107 | "foreground": "66d9ef",
108 | "fontStyle": " italic",
109 | "token": "support.class"
110 | },
111 | {
112 | "foreground": "f8f8f0",
113 | "background": "ff79c6",
114 | "token": "invalid"
115 | },
116 | {
117 | "foreground": "f8f8f0",
118 | "background": "bd93f9",
119 | "token": "invalid.deprecated"
120 | },
121 | {
122 | "foreground": "cfcfc2",
123 | "token": "meta.structure.dictionary.json string.quoted.double.json"
124 | },
125 | {
126 | "foreground": "6272a4",
127 | "token": "meta.diff"
128 | },
129 | {
130 | "foreground": "6272a4",
131 | "token": "meta.diff.header"
132 | },
133 | {
134 | "foreground": "ff79c6",
135 | "token": "markup.deleted"
136 | },
137 | {
138 | "foreground": "50fa7b",
139 | "token": "markup.inserted"
140 | },
141 | {
142 | "foreground": "e6db74",
143 | "token": "markup.changed"
144 | },
145 | {
146 | "foreground": "bd93f9",
147 | "token": "constant.numeric.line-number.find-in-files - match"
148 | },
149 | {
150 | "foreground": "e6db74",
151 | "token": "entity.name.filename"
152 | },
153 | {
154 | "foreground": "f83333",
155 | "token": "message.error"
156 | },
157 | {
158 | "foreground": "eeeeee",
159 | "token": "punctuation.definition.string.begin.json - meta.structure.dictionary.value.json"
160 | },
161 | {
162 | "foreground": "eeeeee",
163 | "token": "punctuation.definition.string.end.json - meta.structure.dictionary.value.json"
164 | },
165 | {
166 | "foreground": "8be9fd",
167 | "token": "meta.structure.dictionary.json string.quoted.double.json"
168 | },
169 | {
170 | "foreground": "f1fa8c",
171 | "token": "meta.structure.dictionary.value.json string.quoted.double.json"
172 | },
173 | {
174 | "foreground": "50fa7b",
175 | "token": "meta meta meta meta meta meta meta.structure.dictionary.value string"
176 | },
177 | {
178 | "foreground": "ffb86c",
179 | "token": "meta meta meta meta meta meta.structure.dictionary.value string"
180 | },
181 | {
182 | "foreground": "ff79c6",
183 | "token": "meta meta meta meta meta.structure.dictionary.value string"
184 | },
185 | {
186 | "foreground": "bd93f9",
187 | "token": "meta meta meta meta.structure.dictionary.value string"
188 | },
189 | {
190 | "foreground": "50fa7b",
191 | "token": "meta meta meta.structure.dictionary.value string"
192 | },
193 | {
194 | "foreground": "ffb86c",
195 | "token": "meta meta.structure.dictionary.value string"
196 | }
197 | ],
198 | "colors": {
199 | "editor.foreground": "#f8f8f2",
200 | "editor.background": "#1f2937",
201 | "editorCursor.foreground": "#f8f8f0",
202 | "dropdown.background": "#44475a",
203 | "editor.selectionBackground": "#44475a70",
204 | "editor.inactiveSelectionBackground": "#44475a30",
205 | "editorWidget.background": "#44475a",
206 | "list.hoverForeground": "#44475a",
207 | "list.hoverBackground": "#F7F8FC",
208 | "list.focusForeground": "#44475a",
209 | "list.focusBackground": "#F7F8FC",
210 | "list.activeSelectionForeground": "#44475a",
211 | "list.activeSelectionBackground": "#F7F8FC"
212 | }
213 | }
--------------------------------------------------------------------------------
/node-red-types/util.d.ts:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | How to generate...
4 | 1. Generate from packages\node_modules\@node-red\util\lib\util.js using `npx typescript` and a tsconfig.json of...
5 | {
6 | "files": ["packages/node_modules/@node-red/util/lib/util.js"],
7 | "compilerOptions": {
8 | "allowJs": true,
9 | "declaration": true,
10 | "emitDeclarationOnly": true,
11 | "outDir": "types",
12 | "strict": false,
13 | "moduleResolution": "node"
14 | }
15 | }
16 | 2. remove all the `export ` statements
17 | 3. Wrap the remaining code in declare namespace RED { declare namespace util { ... } }
18 | 4. check . adjust types like String --> string, Object --> object etc (where appropriate)
19 | */
20 |
21 | declare namespace RED {
22 | /**
23 | * Utility functions for the node-red function sandbox
24 | */
25 | namespace util {
26 |
27 | /**
28 | * Encode an object to JSON without losing information about non-JSON types
29 | * such as Buffer and Function.
30 | *
31 | * *This function is closely tied to its reverse within the editor*
32 | *
33 | * @param {Object} msg
34 | * @param {Object} opts
35 | * @return {Object} the encoded object
36 | * @memberof @node-red/util_util
37 | */
38 | function encodeObject(msg: any, opts: any): any;
39 | /**
40 | * Converts the provided argument to a String, using type-dependent
41 | * methods.
42 | *
43 | * @param {any} o - the property to convert to a String
44 | * @return {string} the stringified version
45 | * @memberof @node-red/util_util
46 | */
47 | function ensureString(o: any): string;
48 | /**
49 | * Converts the provided argument to a Buffer, using type-dependent
50 | * methods.
51 | *
52 | * @param {any} o - the property to convert to a Buffer
53 | * @return {string} the Buffer version
54 | * @memberof @node-red/util_util
55 | */
56 | function ensureBuffer(o: any): string;
57 | /**
58 | * Safely clones a message object. This handles msg.req/msg.res objects that must
59 | * not be cloned.
60 | *
61 | * @param {object} msg - the message object to clone
62 | * @return {object} the cloned message
63 | * @memberof @node-red/util_util
64 | */
65 | function cloneMessage(msg: object): object;
66 | /**
67 | * Compares two objects, handling various JavaScript types.
68 | *
69 | * @param {any} obj1
70 | * @param {any} obj2
71 | * @return {boolean} whether the two objects are the same
72 | * @memberof @node-red/util_util
73 | */
74 | function compareObjects(obj1: any, obj2: any): boolean;
75 | /**
76 | * Generates a psuedo-unique-random id.
77 | * @return {string} a random-ish id
78 | * @memberof @node-red/util_util
79 | */
80 | function generateId(): string;
81 | /**
82 | * Gets a property of a message object.
83 | *
84 | * Unlike {@link @node-red/util-util.getObjectProperty}, this function will strip `msg.` from the
85 | * front of the property expression if present.
86 | *
87 | * @param {object} msg - the message object
88 | * @param {string} expr - the property expression
89 | * @return {any} the message property, or undefined if it does not exist
90 | * @throws Will throw an error if the *parent* of the property does not exist
91 | * @memberof @node-red/util_util
92 | */
93 | function getMessageProperty(msg: object, expr: string): any;
94 | /**
95 | * Sets a property of a message object.
96 | *
97 | * Unlike {@link @node-red/util-util.setObjectProperty}, this function will strip `msg.` from the
98 | * front of the property expression if present.
99 | *
100 | * @param {object} msg - the message object
101 | * @param {string} prop - the property expression
102 | * @param {any} [value] - the value to set
103 | * @param {boolean} [createMissing] - whether to create missing parent properties
104 | * @memberof @node-red/util_util
105 | */
106 | function setMessageProperty(msg: object, prop: string, value?: any, createMissing?: boolean): boolean;
107 | /**
108 | * Gets a property of an object.
109 | *
110 | * Given the object:
111 | *
112 | * {
113 | * "pet": {
114 | * "type": "cat"
115 | * }
116 | * }
117 | *
118 | * - `pet.type` will return `"cat"`.
119 | * - `pet.name` will return `undefined`
120 | * - `car` will return `undefined`
121 | * - `car.type` will throw an Error (as `car` does not exist)
122 | *
123 | * @param {object} msg - the object
124 | * @param {string} expr - the property expression
125 | * @return {any} the object property, or undefined if it does not exist
126 | * @throws Will throw an error if the *parent* of the property does not exist
127 | * @memberof @node-red/util_util
128 | */
129 | function getObjectProperty(msg: object, expr: string): any;
130 | /**
131 | * Sets a property of an object.
132 | *
133 | * @param {object} msg - the object
134 | * @param {string} prop - the property expression
135 | * @param {any} [value] - the value to set
136 | * @param {boolean} [createMissing] - whether to create missing parent properties
137 | * @memberof @node-red/util_util
138 | */
139 | function setObjectProperty(msg: object, prop: string, value?: any, createMissing?: boolean): boolean;
140 | /**
141 | * Evaluates a property value according to its type.
142 | *
143 | * @param {string} value - the raw value
144 | * @param {string} type - the type of the value
145 | * @param {Node} node - the node evaluating the property
146 | * @param {Object} msg - the message object to evaluate against
147 | * @param {Function} callback - (optional) called when the property is evaluated
148 | * @return {any} The evaluated property, if no `callback` is provided
149 | * @memberof @node-red/util_util
150 | */
151 | function evaluateNodeProperty(value: string, type: string, node: Node, msg: any, callback: Function): any;
152 | /**
153 | * Parses a property expression, such as `msg.foo.bar[3]` to validate it
154 | * and convert it to a canonical version expressed as an Array of property
155 | * names.
156 | *
157 | * For example, `a["b"].c` returns `['a','b','c']`
158 | *
159 | * @param {string} str - the property expression
160 | * @return {any[]} the normalised expression
161 | * @memberof @node-red/util_util
162 | */
163 | function normalisePropertyExpression(str: string): any[];
164 | /**
165 | * Normalise a node type name to camel case.
166 | *
167 | * For example: `a-random node type` will normalise to `aRandomNodeType`
168 | *
169 | * @param {string} name - the node type
170 | * @return {string} The normalised name
171 | * @memberof @node-red/util_util
172 | */
173 | function normaliseNodeTypeName(name: string): string;
174 | /**
175 | * Prepares a JSONata expression for evaluation.
176 | * This attaches Node-RED specific functions to the expression.
177 | *
178 | * @param {string} value - the JSONata expression
179 | * @param {Node} node - the node evaluating the property
180 | * @return {any} The JSONata expression that can be evaluated
181 | * @memberof @node-red/util_util
182 | */
183 | function prepareJSONataExpression(value: string, node: Node): any;
184 | /**
185 | * Evaluates a JSONata expression.
186 | * The expression must have been prepared with {@link @node-red/util-util.prepareJSONataExpression}
187 | * before passing to this function.
188 | *
189 | * @param {Object} expr - the prepared JSONata expression
190 | * @param {Object} msg - the message object to evaluate against
191 | * @param {Function} callback - (optional) called when the expression is evaluated
192 | * @return {any} If no callback was provided, the result of the expression
193 | * @memberof @node-red/util_util
194 | */
195 | function evaluateJSONataExpression(expr: any, msg: any, callback: Function): any;
196 | /**
197 | * Parses a context property string, as generated by the TypedInput, to extract
198 | * the store name if present.
199 | *
200 | * For example, `#:(file)::foo` results in ` { store: "file", key: "foo" }`.
201 | *
202 | * @param {string} key - the context property string to parse
203 | * @return {any} The parsed property
204 | * @memberof @node-red/util_util
205 | */
206 | function parseContextStore(key: string): any;
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/
2 |
3 | Apache License
4 | Version 2.0, January 2004
5 | http://www.apache.org/licenses/
6 |
7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
8 |
9 | 1. Definitions.
10 |
11 | "License" shall mean the terms and conditions for use, reproduction,
12 | and distribution as defined by Sections 1 through 9 of this document.
13 |
14 | "Licensor" shall mean the copyright owner or entity authorized by
15 | the copyright owner that is granting the License.
16 |
17 | "Legal Entity" shall mean the union of the acting entity and all
18 | other entities that control, are controlled by, or are under common
19 | control with that entity. For the purposes of this definition,
20 | "control" means (i) the power, direct or indirect, to cause the
21 | direction or management of such entity, whether by contract or
22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
23 | outstanding shares, or (iii) beneficial ownership of such entity.
24 |
25 | "You" (or "Your") shall mean an individual or Legal Entity
26 | exercising permissions granted by this License.
27 |
28 | "Source" form shall mean the preferred form for making modifications,
29 | including but not limited to software source code, documentation
30 | source, and configuration files.
31 |
32 | "Object" form shall mean any form resulting from mechanical
33 | transformation or translation of a Source form, including but
34 | not limited to compiled object code, generated documentation,
35 | and conversions to other media types.
36 |
37 | "Work" shall mean the work of authorship, whether in Source or
38 | Object form, made available under the License, as indicated by a
39 | copyright notice that is included in or attached to the work
40 | (an example is provided in the Appendix below).
41 |
42 | "Derivative Works" shall mean any work, whether in Source or Object
43 | form, that is based on (or derived from) the Work and for which the
44 | editorial revisions, annotations, elaborations, or other modifications
45 | represent, as a whole, an original work of authorship. For the purposes
46 | of this License, Derivative Works shall not include works that remain
47 | separable from, or merely link (or bind by name) to the interfaces of,
48 | the Work and Derivative Works thereof.
49 |
50 | "Contribution" shall mean any work of authorship, including
51 | the original version of the Work and any modifications or additions
52 | to that Work or Derivative Works thereof, that is intentionally
53 | submitted to Licensor for inclusion in the Work by the copyright owner
54 | or by an individual or Legal Entity authorized to submit on behalf of
55 | the copyright owner. For the purposes of this definition, "submitted"
56 | means any form of electronic, verbal, or written communication sent
57 | to the Licensor or its representatives, including but not limited to
58 | communication on electronic mailing lists, source code control systems,
59 | and issue tracking systems that are managed by, or on behalf of, the
60 | Licensor for the purpose of discussing and improving the Work, but
61 | excluding communication that is conspicuously marked or otherwise
62 | designated in writing by the copyright owner as "Not a Contribution."
63 |
64 | "Contributor" shall mean Licensor and any individual or Legal Entity
65 | on behalf of whom a Contribution has been received by Licensor and
66 | subsequently incorporated within the Work.
67 |
68 | 2. Grant of Copyright License. Subject to the terms and conditions of
69 | this License, each Contributor hereby grants to You a perpetual,
70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
71 | copyright license to reproduce, prepare Derivative Works of,
72 | publicly display, publicly perform, sublicense, and distribute the
73 | Work and such Derivative Works in Source or Object form.
74 |
75 | 3. Grant of Patent License. Subject to the terms and conditions of
76 | this License, each Contributor hereby grants to You a perpetual,
77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
78 | (except as stated in this section) patent license to make, have made,
79 | use, offer to sell, sell, import, and otherwise transfer the Work,
80 | where such license applies only to those patent claims licensable
81 | by such Contributor that are necessarily infringed by their
82 | Contribution(s) alone or by combination of their Contribution(s)
83 | with the Work to which such Contribution(s) was submitted. If You
84 | institute patent litigation against any entity (including a
85 | cross-claim or counterclaim in a lawsuit) alleging that the Work
86 | or a Contribution incorporated within the Work constitutes direct
87 | or contributory patent infringement, then any patent licenses
88 | granted to You under this License for that Work shall terminate
89 | as of the date such litigation is filed.
90 |
91 | 4. Redistribution. You may reproduce and distribute copies of the
92 | Work or Derivative Works thereof in any medium, with or without
93 | modifications, and in Source or Object form, provided that You
94 | meet the following conditions:
95 |
96 | (a) You must give any other recipients of the Work or
97 | Derivative Works a copy of this License; and
98 |
99 | (b) You must cause any modified files to carry prominent notices
100 | stating that You changed the files; and
101 |
102 | (c) You must retain, in the Source form of any Derivative Works
103 | that You distribute, all copyright, patent, trademark, and
104 | attribution notices from the Source form of the Work,
105 | excluding those notices that do not pertain to any part of
106 | the Derivative Works; and
107 |
108 | (d) If the Work includes a "NOTICE" text file as part of its
109 | distribution, then any Derivative Works that You distribute must
110 | include a readable copy of the attribution notices contained
111 | within such NOTICE file, excluding those notices that do not
112 | pertain to any part of the Derivative Works, in at least one
113 | of the following places: within a NOTICE text file distributed
114 | as part of the Derivative Works; within the Source form or
115 | documentation, if provided along with the Derivative Works; or,
116 | within a display generated by the Derivative Works, if and
117 | wherever such third-party notices normally appear. The contents
118 | of the NOTICE file are for informational purposes only and
119 | do not modify the License. You may add Your own attribution
120 | notices within Derivative Works that You distribute, alongside
121 | or as an addendum to the NOTICE text from the Work, provided
122 | that such additional attribution notices cannot be construed
123 | as modifying the License.
124 |
125 | You may add Your own copyright statement to Your modifications and
126 | may provide additional or different license terms and conditions
127 | for use, reproduction, or distribution of Your modifications, or
128 | for any such Derivative Works as a whole, provided Your use,
129 | reproduction, and distribution of the Work otherwise complies with
130 | the conditions stated in this License.
131 |
132 | 5. Submission of Contributions. Unless You explicitly state otherwise,
133 | any Contribution intentionally submitted for inclusion in the Work
134 | by You to the Licensor shall be under the terms and conditions of
135 | this License, without any additional terms or conditions.
136 | Notwithstanding the above, nothing herein shall supersede or modify
137 | the terms of any separate license agreement you may have executed
138 | with Licensor regarding such Contributions.
139 |
140 | 6. Trademarks. This License does not grant permission to use the trade
141 | names, trademarks, service marks, or product names of the Licensor,
142 | except as required for reasonable and customary use in describing the
143 | origin of the Work and reproducing the content of the NOTICE file.
144 |
145 | 7. Disclaimer of Warranty. Unless required by applicable law or
146 | agreed to in writing, Licensor provides the Work (and each
147 | Contributor provides its Contributions) on an "AS IS" BASIS,
148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
149 | implied, including, without limitation, any warranties or conditions
150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
151 | PARTICULAR PURPOSE. You are solely responsible for determining the
152 | appropriateness of using or redistributing the Work and assume any
153 | risks associated with Your exercise of permissions under this License.
154 |
155 | 8. Limitation of Liability. In no event and under no legal theory,
156 | whether in tort (including negligence), contract, or otherwise,
157 | unless required by applicable law (such as deliberate and grossly
158 | negligent acts) or agreed to in writing, shall any Contributor be
159 | liable to You for damages, including any direct, indirect, special,
160 | incidental, or consequential damages of any character arising as a
161 | result of this License or out of the use or inability to use the
162 | Work (including but not limited to damages for loss of goodwill,
163 | work stoppage, computer failure or malfunction, or any and all
164 | other commercial damages or losses), even if such Contributor
165 | has been advised of the possibility of such damages.
166 |
167 | 9. Accepting Warranty or Additional Liability. While redistributing
168 | the Work or Derivative Works thereof, You may choose to offer,
169 | and charge a fee for, acceptance of support, warranty, indemnity,
170 | or other liability obligations and/or rights consistent with this
171 | License. However, in accepting such obligations, You may act only
172 | on Your own behalf and on Your sole responsibility, not on behalf
173 | of any other Contributor, and only if You agree to indemnify,
174 | defend, and hold each Contributor harmless for any liability
175 | incurred by, or claims asserted against, such Contributor by reason
176 | of your accepting any such warranty or additional liability.
177 |
178 | END OF TERMS AND CONDITIONS
179 |
--------------------------------------------------------------------------------
/generate-monaco-esm-i18n.js:
--------------------------------------------------------------------------------
1 | const degit = require('degit');
2 | const fs = require("fs");
3 | const path = require("path");
4 | const recursive = require("recursive-readdir");
5 | const mkdirp = require("mkdirp");
6 | const { replaceInFileSync } = require("replace-in-file");
7 | const ncp = require("ncp").ncp;
8 | const { rimraf } = require("rimraf");
9 | const readJson = require('read-package-json')
10 | const { semver } = require("./common");
11 |
12 | const {
13 | monacoDir,
14 | monacoModDir,
15 | monacoModEsmDir,
16 | gitDir,
17 | vsCodeLocDir,
18 | vsCodeLocI18nDir,
19 | generatedSourceLocaleDir,
20 | } = require("./setup");
21 |
22 | const langDirPrefix = "vscode-language-pack-";
23 | const vsCodeRepository = "https://github.com/Microsoft/vscode-loc.git";
24 | const fileExistsCache = new Map();
25 |
26 | function readPackage(packageFile) {
27 | return new Promise(function (resolve, reject) {
28 | readJson(packageFile, console.error, false, (err, data) => {
29 | if (err) {
30 | reject(err);
31 | } else {
32 | resolve(data)
33 | }
34 | });
35 | });
36 | }
37 |
38 | /**
39 | * The microsoft/vscode-loc contains many more i18n keys that are used by monaco editor.
40 | * Keys are grouped by source files, so we include only those keys whose source files
41 | * exists in the monaco editor repository.
42 | * @param {string} key
43 | * @return {boolean}
44 | */
45 | function sourceFileExists(key) {
46 | if (fileExistsCache.has(key)) {
47 | return fileExistsCache.get(key);
48 | }
49 | const filePath = path.join(monacoModEsmDir, key + ".js");
50 | const exists = fs.existsSync(filePath);
51 | fileExistsCache.set(key, exists);
52 | return exists;
53 | }
54 |
55 | /**
56 | * The call to the `localize` function only include the i18 key, but translations
57 | * in the microsoft/vscode-loc repository are first grouped by source file name,
58 | * then i18n key. So we modify the each call to `localize` so that it includes
59 | * the source file name.
60 | *
61 | * > nls.localize(key, args)
62 | *
63 | * becomes
64 | *
65 | * > nls.localize("source/file.js", key, args)
66 | * @param callback
67 | */
68 | function injectSourcePath(monacoVersion, callback) {
69 | rimraf(monacoModDir).then(() => {
70 | ncp(monacoDir, monacoModDir, function (err) {
71 | if (err) {
72 | callback(err);
73 | return;
74 | }
75 | recursive(monacoModEsmDir, (err, files) => {
76 | if (err) {
77 | callback(err);
78 | return;
79 | }
80 | files.forEach(file => {
81 | if (file.endsWith(".js")) {
82 | const vsPath = path.relative(monacoModEsmDir, path.dirname(file)).replace(/\\/g, "/");
83 | const transPath = vsPath + "/" + path.basename(file, ".js");
84 | //1a. Find localize( : localize( localize2( .localize2( etc (but NOT function localize() )
85 | //1b. Change to localize("path/to/translation/item", xxxx
86 | //2a. Find localize.apply(
87 | //2b. Change to localize.apply("path/to/translation/item", xxxxx
88 | replaceInFileSync({
89 | files: file,
90 | from: [
91 | /(? -1) {
143 | //insert version:
144 | //1. Find const api = createMonacoBaseAPI();
145 | //2. Insert Object.defineProperty(api, 'version', {get: function() { return 'x.y.z' }});
146 | // export const version = api.version;
147 | replaceInFileSync({
148 | files: file,
149 | from: [
150 | /(const\s+?)(\w*?)(\s+?=\s+?createMonacoBaseAPI\(\).*$)/gm
151 | ],
152 | to: [
153 | `$1$2$3` +
154 | `\nObject.defineProperty($2, 'version', {get: function() { return '${monacoVersion}' }});` +
155 | `\nexport const version = $2.version;`
156 | ],
157 | });
158 | }
159 | }
160 | });
161 | callback();
162 | });
163 | });
164 | }).catch(err => {
165 | callback(err);
166 | })
167 | }
168 |
169 | /**
170 | * Reads all files from the microsoft/vscode-loc repository for the given language
171 | * and creates one object with all i18n keys.
172 | * @param lang Language, eg. `en` or `de`.
173 | * @param langPath Full path to the directory with the language files.
174 | * @param callback Called on completion with error and the created locale object.
175 | */
176 | function createLocale(lang, langPath, callback) {
177 | const locale = {};
178 | const allTranslations = {};
179 | recursive(langPath, function (err, files) {
180 | if (err) {
181 | callback(err);
182 | return;
183 | }
184 | files.forEach(file => {
185 | if (file.endsWith(".i18n.json")) {
186 | const data = fs.readFileSync(file, { encoding: "UTF-8" });
187 | let json;
188 | try {
189 | json = JSON.parse(data);
190 | }
191 | catch (e1) {
192 | try {
193 | json = eval("(" + data + ")");
194 | }
195 | catch (e2) {
196 | const newErr = new Error("Error while parsing i18n file " + file);
197 | newErr.stack += "\n\ncaused by: " + e2.stack;
198 | callback(newErr);
199 | return;
200 | }
201 | }
202 | if (typeof json.contents !== "object") {
203 | console.warn("no translations found", file);
204 | return;
205 | }
206 | delete json.contents["package"];
207 | for (const key of Object.keys(json.contents)) {
208 | if (key) {
209 | if (sourceFileExists(key)) {
210 | locale[key] = json.contents[key];
211 | }
212 | allTranslations[key] = json.contents[key];
213 | }
214 | }
215 | }
216 | });
217 | callback(undefined, locale);
218 | });
219 | }
220 |
221 | function createScript(lang, locale) {
222 | const sortedKeys = Object.keys(locale).sort((lhs, rhs) => {
223 | const l = lhs.toLowerCase();
224 | const r = rhs.toLowerCase();
225 | return l < r ? -1 : l > r ? 1 : 0;
226 | });
227 | const sortedLocale = {};
228 | for (const key of sortedKeys) {
229 | sortedLocale[key] = locale[key];
230 | // sortedLocale[safeKey(key)] = locale[key];
231 | }
232 | return `window.MonacoEnvironment = window.MonacoEnvironment || {};
233 | window.MonacoEnvironment.Locale = window.MonacoLocale = {
234 | language: '${lang}',
235 | data: ${JSON.stringify(sortedLocale, null, 2)}
236 | };`;
237 | }
238 |
239 | async function main() {
240 | const pkg = await readPackage("package.json");
241 | const monacoDep = pkg.devDependencies["monaco-editor"];
242 | const monacoSemver = semver(monacoDep);
243 | const monacoVersion = monacoSemver.toString();
244 |
245 | mkdirp.sync(gitDir);
246 | injectSourcePath(monacoVersion, err => {
247 | if (err) throw err;
248 | const emitter = degit('Microsoft/vscode-loc', { force: true });
249 | emitter.clone(vsCodeLocDir).then(() => {
250 | fs.readdir(vsCodeLocI18nDir, (err, langDirs) => {
251 | if (err) throw err;
252 | langDirs.forEach(langDir => {
253 | if (!langDir.startsWith(langDirPrefix)) {
254 | return;
255 | }
256 | const lang = langDir.substring(langDirPrefix.length).toLowerCase();
257 | const transPath = path.join(vsCodeLocI18nDir, langDir, "translations");
258 | if (fs.existsSync(transPath) && fs.lstatSync(transPath).isDirectory()) {
259 | createLocale(lang, transPath, (err, locale) => {
260 | if (err) throw err;
261 | mkdirp.sync(generatedSourceLocaleDir)
262 | const mappedLang = lang;
263 | fs.writeFile(path.join(generatedSourceLocaleDir, mappedLang + ".js"), createScript(mappedLang, locale), { encoding: "UTF-8" }, err => {
264 | if (err) throw err;
265 | console.log("generated locale " + mappedLang + ".js");
266 | });
267 | });
268 | }
269 | })
270 | });
271 | }).catch(err => {
272 | throw err;
273 | });
274 | });
275 | }
276 |
277 | main();
278 |
--------------------------------------------------------------------------------
/node-red-types/func.d.ts:
--------------------------------------------------------------------------------
1 | interface NodeMessage {
2 | topic?: string;
3 | payload?: any;
4 | /** `_msgid` is generated internally. It not something you typically need to set or modify. */ _msgid?: string;
5 | [other: string]: any; //permit other properties
6 | }
7 |
8 | /** @type {NodeMessage} the `msg` object */
9 | declare var msg: NodeMessage;
10 | /** @type {string} the id of the incoming `msg` (alias of msg._msgid) */
11 | declare const __msgid__:string;
12 |
13 | declare const util:typeof import('util')
14 | declare const promisify:typeof import('util').promisify
15 |
16 | /**
17 | * @typedef NodeStatus
18 | * @type {object}
19 | * @property {'red'|'green'|'yellow'|'blue'|'grey'|string} [fill] - The fill property can be: red, green, yellow, blue or grey.
20 | * @property {'ring'|'dot'|string} [shape] The shape property can be: ring or dot.
21 | * @property {string|boolean|number} [text] The text to display
22 | */
23 | interface NodeStatus {
24 | /** The fill property can be: red, green, yellow, blue or grey */
25 | fill?: 'red'|'green'|'yellow'|'blue'|'grey'|string,
26 | /** The shape property can be: ring or dot */
27 | shape?: 'ring'|'dot'|string,
28 | /** The text to display */
29 | text?: string|boolean|number
30 | }
31 |
32 | declare class node {
33 | /**
34 | * Send 1 or more messages asynchronously
35 | * @param {object | object[]} msg The msg object
36 | * @param {Boolean} [clone=true] Flag to indicate the `msg` should be cloned. Default = `true`
37 | * @see Node-RED documentation [writing-functions: sending messages asynchronously](https://nodered.org/docs/user-guide/writing-functions#sending-messages-asynchronously)
38 | */
39 | static send(msg:NodeMessage|NodeMessage[], clone?:Boolean): void;
40 | /** Inform runtime this instance has completed its operation */
41 | static done();
42 | /** Send an error to the console and debug side bar. Include `msg` in the 2nd parameter to trigger the catch node. */
43 | static error(err:string|Error, msg?:NodeMessage);
44 | /** Log a warn message to the console and debug sidebar */
45 | static warn(warning:string|object);
46 | /** Log an info message to the console (not sent to sidebar)' */
47 | static log(info:string|object);
48 | /** Sets the status icon and text underneath the node.
49 | * @param {NodeStatus} status - The status object `{fill, shape, text}`
50 | * @see Node-RED documentation [writing-functions: adding-status](https://nodered.org/docs/user-guide/writing-functions#adding-status)
51 | */
52 | static status(status:NodeStatus);
53 | /** Sets the status text underneath the node.
54 | * @see Node-RED documentation [writing-functions: adding-status](https://nodered.org/docs/user-guide/writing-functions#adding-status)
55 | */
56 | static status(status:string|boolean|number);
57 | /** the id of this node */
58 | public static readonly id:string;
59 | /** the name of this node */
60 | public static readonly name:string;
61 | /** the path identifier for this node */
62 | public static readonly path:string;
63 | /** the number of outputs of this node */
64 | public static readonly outputCount:number;
65 | }
66 | declare class context {
67 | /**
68 | * Get one or multiple values from context (synchronous).
69 | * @param name - Name of context variable
70 | */
71 | static get(name: string | string[]);
72 | /**
73 | * Get one or multiple values from context (asynchronous).
74 | * @param name - Name (or array of names) to get from context
75 | * @param {function} callback - (optional) Callback function (`(err,value) => {}`)
76 | */
77 | static get(name: string | string[], callback: Function);
78 | /**
79 | * Get one or multiple values from context (synchronous).
80 | * @param name - Name (or array of names) to get from context
81 | * @param store - Name of context store
82 | */
83 | static get(name: string | string[], store: string);
84 | /**
85 | * Get one or multiple values from context (asynchronous).
86 | * @param name - Name (or array of names) to get from context
87 | * @param store - Name of context store
88 | * @param {function} callback - (optional) Callback function (`(err,value) => {}`)
89 | */
90 | static get(name: string | string[], store: string, callback: Function);
91 |
92 |
93 | /**
94 | * Set one or multiple values in context (synchronous).
95 | * @param name - Name (or array of names) to set in context
96 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
97 | */
98 | static set(name: string | string[], value?: any | any[]);
99 | /**
100 | * Set one or multiple values in context (asynchronous).
101 | * @param name - Name (or array of names) to set in context
102 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
103 | * @param callback - (optional) Callback function (`(err) => {}`)
104 | */
105 | static set(name: string | string[], value?: any | any[], callback?: Function);
106 | /**
107 | * Set one or multiple values in context (synchronous).
108 | * @param name - Name (or array of names) to set in context
109 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
110 | * @param store - (optional) Name of context store
111 | */
112 | static set(name: string | string[], value?: any | any[], store?: string);
113 | /**
114 | * Set one or multiple values in context (asynchronous).
115 | * @param name - Name (or array of names) to set in context
116 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
117 | * @param store - (optional) Name of context store
118 | * @param callback - (optional) Callback function (`(err) => {}`)
119 | */
120 | static set(name: string | string[], value?: any | any[], store?: string, callback?: Function);
121 |
122 | /** Get an array of the keys in the context store */
123 | static keys(): Array;
124 | /** Get an array of the keys in the context store */
125 | static keys(store: string): Array;
126 | /** Get an array of the keys in the context store */
127 | static keys(callback: Function);
128 | /** Get an array of the keys in the context store */
129 | static keys(store: string, callback: Function);
130 | }
131 | declare class flow {
132 | /**
133 | * Get one or multiple values from context (synchronous).
134 | * @param name - Name of context variable
135 | */
136 | static get(name: string | string[]);
137 | /**
138 | * Get one or multiple values from context (asynchronous).
139 | * @param name - Name (or array of names) to get from context
140 | * @param {function} callback - (optional) Callback function (`(err,value) => {}`)
141 | */
142 | static get(name: string | string[], callback: Function);
143 | /**
144 | * Get one or multiple values from context (synchronous).
145 | * @param name - Name (or array of names) to get from context
146 | * @param store - Name of context store
147 | */
148 | static get(name: string | string[], store: string);
149 | /**
150 | * Get one or multiple values from context (asynchronous).
151 | * @param name - Name (or array of names) to get from context
152 | * @param store - Name of context store
153 | * @param {function} callback - (optional) Callback function (`(err,value) => {}`)
154 | */
155 | static get(name: string | string[], store: string, callback: Function);
156 |
157 |
158 | /**
159 | * Set one or multiple values in context (synchronous).
160 | * @param name - Name (or array of names) to set in context
161 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
162 | */
163 | static set(name: string | string[], value?: any | any[]);
164 | /**
165 | * Set one or multiple values in context (asynchronous).
166 | * @param name - Name (or array of names) to set in context
167 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
168 | * @param callback - (optional) Callback function (`(err) => {}`)
169 | */
170 | static set(name: string | string[], value?: any | any[], callback?: Function);
171 | /**
172 | * Set one or multiple values in context (synchronous).
173 | * @param name - Name (or array of names) to set in context
174 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
175 | * @param store - (optional) Name of context store
176 | */
177 | static set(name: string | string[], value?: any | any[], store?: string);
178 | /**
179 | * Set one or multiple values in context (asynchronous).
180 | * @param name - Name (or array of names) to set in context
181 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
182 | * @param store - (optional) Name of context store
183 | * @param callback - (optional) Callback function (`(err) => {}`)
184 | */
185 | static set(name: string | string[], value?: any | any[], store?: string, callback?: Function);
186 |
187 | /** Get an array of the keys in the context store */
188 | static keys(): Array;
189 | /** Get an array of the keys in the context store */
190 | static keys(store: string): Array;
191 | /** Get an array of the keys in the context store */
192 | static keys(callback: Function);
193 | /** Get an array of the keys in the context store */
194 | static keys(store: string, callback: Function);
195 | }
196 |
197 | // @ts-ignore
198 | declare class global {
199 | /**
200 | * Get one or multiple values from context (synchronous).
201 | * @param name - Name of context variable
202 | */
203 | static get(name: string | string[]);
204 | /**
205 | * Get one or multiple values from context (asynchronous).
206 | * @param name - Name (or array of names) to get from context
207 | * @param {function} callback - (optional) Callback function (`(err,value) => {}`)
208 | */
209 | static get(name: string | string[], callback: Function);
210 | /**
211 | * Get one or multiple values from context (synchronous).
212 | * @param name - Name (or array of names) to get from context
213 | * @param store - Name of context store
214 | */
215 | static get(name: string | string[], store: string);
216 | /**
217 | * Get one or multiple values from context (asynchronous).
218 | * @param name - Name (or array of names) to get from context
219 | * @param store - Name of context store
220 | * @param {function} callback - (optional) Callback function (`(err,value) => {}`)
221 | */
222 | static get(name: string | string[], store: string, callback: Function);
223 |
224 |
225 | /**
226 | * Set one or multiple values in context (synchronous).
227 | * @param name - Name (or array of names) to set in context
228 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
229 | */
230 | static set(name: string | string[], value?: any | any[]);
231 | /**
232 | * Set one or multiple values in context (asynchronous).
233 | * @param name - Name (or array of names) to set in context
234 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
235 | * @param callback - (optional) Callback function (`(err) => {}`)
236 | */
237 | static set(name: string | string[], value?: any | any[], callback?: Function);
238 | /**
239 | * Set one or multiple values in context (synchronous).
240 | * @param name - Name (or array of names) to set in context
241 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
242 | * @param store - (optional) Name of context store
243 | */
244 | static set(name: string | string[], value?: any | any[], store?: string);
245 | /**
246 | * Set one or multiple values in context (asynchronous).
247 | * @param name - Name (or array of names) to set in context
248 | * @param value - The value (or array of values) to store in context. If the value(s) are null/undefined, the context item(s) will be removed.
249 | * @param store - (optional) Name of context store
250 | * @param callback - (optional) Callback function (`(err) => {}`)
251 | */
252 | static set(name: string | string[], value?: any | any[], store?: string, callback?: Function);
253 |
254 | /** Get an array of the keys in the context store */
255 | static keys(): Array;
256 | /** Get an array of the keys in the context store */
257 | static keys(store: string): Array;
258 | /** Get an array of the keys in the context store */
259 | static keys(callback: Function);
260 | /** Get an array of the keys in the context store */
261 | static keys(store: string, callback: Function);
262 | }
263 |
264 | // (string & {}) is a workaround for offering string type completion without enforcing it. See https://github.com/microsoft/TypeScript/issues/29729#issuecomment-567871939
265 | type NR_ENV_NAME_STRING = 'NR_NODE_ID'|'NR_NODE_NAME'|'NR_NODE_PATH'|'NR_GROUP_ID'|'NR_GROUP_NAME'|'NR_FLOW_ID'|'NR_FLOW_NAME'|'NR_SUBFLOW_ID'|'NR_SUBFLOW_NAME'|'NR_SUBFLOW_PATH' | (string & {})
266 | declare class env {
267 | /**
268 | * Get an environment variable value defined in the OS, or in the global/flow/subflow/group environment variables.
269 | *
270 | * Predefined node-red variables...
271 | * * `NR_NODE_ID` - the ID of the node
272 | * * `NR_NODE_NAME` - the Name of the node
273 | * * `NR_NODE_PATH` - the Path of the node
274 | * * `NR_GROUP_ID` - the ID of the containing group
275 | * * `NR_GROUP_NAME` - the Name of the containing group
276 | * * `NR_FLOW_ID` - the ID of the flow the node is on
277 | * * `NR_FLOW_NAME` - the Name of the flow the node is on
278 | * * `NR_SUBFLOW_ID` - the ID of the subflow the node is in
279 | * * `NR_SUBFLOW_NAME` - the Name of the subflow the node is in
280 | * * `NR_SUBFLOW_PATH` - the Path of the subflow the node is in
281 | * @param name - The name of the environment variable
282 | * @example
283 | * ```const flowName = env.get("NR_FLOW_NAME") // get the name of the flow```
284 | * @example
285 | * ```const systemHomeDir = env.get("HOME") // get the user's home directory```
286 | * @example
287 | * ```const systemHomeDir = env.get("LABEL1") // get the value of a global/flow/subflow/group defined variable named "LABEL1"```
288 | */
289 | static get(name:NR_ENV_NAME_STRING) :any;
290 | }
291 |
--------------------------------------------------------------------------------