@bonsae/nrg 0.6.0 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +5 -5
  2. package/package.json +14 -75
  3. package/{build/server → server}/index.cjs +1 -1
  4. package/{src/core/client → shims}/components.d.ts +2 -0
  5. package/{src/tsconfig → tsconfig}/client.json +3 -3
  6. package/types/client.d.ts +37 -0
  7. package/types/index.d.ts +211 -0
  8. package/types/server.d.ts +2293 -0
  9. package/types/vite.d.ts +12 -0
  10. package/{build/vite → vite}/index.js +95 -0
  11. package/build/vite/utils.js +0 -56
  12. package/src/core/client/app.vue +0 -185
  13. package/src/core/client/components/node-red-config-input.vue +0 -79
  14. package/src/core/client/components/node-red-editor-input.vue +0 -307
  15. package/src/core/client/components/node-red-input-label.vue +0 -53
  16. package/src/core/client/components/node-red-input.vue +0 -93
  17. package/src/core/client/components/node-red-json-schema-form.vue +0 -444
  18. package/src/core/client/components/node-red-select-input.vue +0 -108
  19. package/src/core/client/components/node-red-toggle.vue +0 -115
  20. package/src/core/client/components/node-red-typed-input.vue +0 -158
  21. package/src/core/client/index.ts +0 -500
  22. package/src/core/client/tsconfig.json +0 -18
  23. package/src/core/constants.ts +0 -18
  24. package/src/core/errors.ts +0 -9
  25. package/src/core/server/api/index.ts +0 -1
  26. package/src/core/server/api/serve-nrg-resources.ts +0 -54
  27. package/src/core/server/index.ts +0 -190
  28. package/src/core/server/nodes/config-node.ts +0 -67
  29. package/src/core/server/nodes/factories.ts +0 -133
  30. package/src/core/server/nodes/index.ts +0 -5
  31. package/src/core/server/nodes/io-node.ts +0 -179
  32. package/src/core/server/nodes/node.ts +0 -259
  33. package/src/core/server/nodes/types/config-node.ts +0 -28
  34. package/src/core/server/nodes/types/factories.ts +0 -115
  35. package/src/core/server/nodes/types/index.ts +0 -4
  36. package/src/core/server/nodes/types/io-node.ts +0 -40
  37. package/src/core/server/nodes/types/node.ts +0 -41
  38. package/src/core/server/nodes/utils.ts +0 -106
  39. package/src/core/server/schemas/base.ts +0 -66
  40. package/src/core/server/schemas/index.ts +0 -3
  41. package/src/core/server/schemas/type.ts +0 -95
  42. package/src/core/server/schemas/types/index.ts +0 -82
  43. package/src/core/server/tsconfig.json +0 -17
  44. package/src/core/server/types/index.ts +0 -220
  45. package/src/core/server/utils.ts +0 -56
  46. package/src/core/server/validator.ts +0 -36
  47. package/src/core/validator.ts +0 -222
  48. package/src/index.ts +0 -2
  49. package/src/types.ts +0 -189
  50. package/src/utils.ts +0 -20
  51. package/src/vite/async-utils.ts +0 -61
  52. package/src/vite/client/build.ts +0 -227
  53. package/src/vite/client/index.ts +0 -1
  54. package/src/vite/client/plugins/html-generator.ts +0 -75
  55. package/src/vite/client/plugins/index.ts +0 -5
  56. package/src/vite/client/plugins/locales-generator.ts +0 -126
  57. package/src/vite/client/plugins/minifier.ts +0 -23
  58. package/src/vite/client/plugins/node-definitions-inliner.ts +0 -275
  59. package/src/vite/client/plugins/static-copy.ts +0 -43
  60. package/src/vite/defaults.ts +0 -77
  61. package/src/vite/errors.ts +0 -37
  62. package/src/vite/index.ts +0 -2
  63. package/src/vite/logger.ts +0 -94
  64. package/src/vite/node-red-launcher.ts +0 -344
  65. package/src/vite/plugin.ts +0 -61
  66. package/src/vite/plugins/build.ts +0 -85
  67. package/src/vite/plugins/index.ts +0 -2
  68. package/src/vite/plugins/server.ts +0 -267
  69. package/src/vite/server/build.ts +0 -124
  70. package/src/vite/server/index.ts +0 -1
  71. package/src/vite/server/plugins/index.ts +0 -3
  72. package/src/vite/server/plugins/output-wrapper.ts +0 -109
  73. package/src/vite/server/plugins/package-json-generator.ts +0 -203
  74. package/src/vite/server/plugins/type-generator.ts +0 -285
  75. package/src/vite/types.ts +0 -174
  76. package/src/vite/utils.ts +0 -72
  77. /package/{build/index.js → index.js} +0 -0
  78. /package/{build/server → server}/resources/nrg-client.js +0 -0
  79. /package/{build/server → server}/resources/vue.esm-browser.js +0 -0
  80. /package/{build/server → server}/resources/vue.esm-browser.prod.js +0 -0
  81. /package/{src/core/client → shims}/globals.d.ts +0 -0
  82. /package/{src/core/client → shims}/shims-vue.d.ts +0 -0
  83. /package/{src/tsconfig → tsconfig}/base.json +0 -0
  84. /package/{src/tsconfig → tsconfig}/server.json +0 -0
@@ -1,227 +0,0 @@
1
- import type { Plugin, InlineConfig } from "vite";
2
- import { build as viteBuild } from "vite";
3
- import vue from "@vitejs/plugin-vue";
4
- import fs from "fs";
5
- import path from "path";
6
- import { BuildError } from "../errors";
7
- import { logger } from "../logger";
8
- import type { ClientBuildOptions, BuildContext, CopyTarget } from "../types";
9
- import {
10
- htmlGenerator,
11
- localesGenerator,
12
- minifier,
13
- nodeDefinitionsInliner,
14
- staticCopy,
15
- } from "./plugins";
16
-
17
- async function build(
18
- clientBuildOptions: ClientBuildOptions,
19
- buildContext: BuildContext,
20
- ): Promise<void> {
21
- const {
22
- srcDir = "./client",
23
- entry = "index.ts",
24
- name = "NodeRedNodes",
25
- format = "es",
26
- licensePath = "./LICENSE",
27
- locales,
28
- staticDirs = {},
29
- external = ["jquery", "node-red", "vue"],
30
- globals = { jquery: "$", "node-red": "RED", vue: "Vue" },
31
- manualChunks,
32
- plugins: userPlugins = [],
33
- } = clientBuildOptions;
34
-
35
- const physicalEntryPath = path.resolve(srcDir, entry);
36
- let entryPath: string;
37
- let generatedEntry = false;
38
-
39
- if (fs.existsSync(physicalEntryPath)) {
40
- entryPath = physicalEntryPath;
41
- } else {
42
- // No physical entry — create a minimal empty file in the cache directory
43
- // so the file watcher on srcDir is not triggered by the create/delete cycle.
44
- const cacheDir = path.resolve("node_modules", ".nrg", "client");
45
- const cachedEntryPath = path.resolve(cacheDir, entry);
46
- if (!fs.existsSync(cacheDir)) {
47
- fs.mkdirSync(cacheDir, { recursive: true });
48
- }
49
- fs.writeFileSync(cachedEntryPath, "// auto-generated entry\n");
50
- entryPath = cachedEntryPath;
51
- generatedEntry = true;
52
- }
53
-
54
- const iconsDir = path.resolve(
55
- staticDirs.icons ?? path.join(path.dirname(path.resolve(srcDir)), "icons"),
56
- );
57
-
58
- const plugins: Plugin[] = [
59
- vue(),
60
- nodeDefinitionsInliner(
61
- buildContext.outDir,
62
- entryPath,
63
- fs.existsSync(iconsDir) ? iconsDir : undefined,
64
- path.resolve(srcDir, "components"),
65
- path.resolve(srcDir, "nodes"),
66
- !generatedEntry,
67
- ),
68
- ...userPlugins,
69
- ];
70
-
71
- plugins.push(
72
- htmlGenerator({
73
- packageName: buildContext.packageName,
74
- licensePath: licensePath ? path.resolve(licensePath) : undefined,
75
- }),
76
- );
77
-
78
- if (locales) {
79
- const {
80
- docsDir = "./locales/docs",
81
- labelsDir = "./locales/labels",
82
- languages = [
83
- "en-US",
84
- "de",
85
- "es-ES",
86
- "fr",
87
- "ko",
88
- "pt-BR",
89
- "ru",
90
- "ja",
91
- "zh-CN",
92
- "zh-TW",
93
- ],
94
- } = locales;
95
-
96
- plugins.push(
97
- localesGenerator({
98
- outDir: path.join(buildContext.outDir, "locales"),
99
- docsDir: path.resolve(docsDir),
100
- labelsDir: path.resolve(labelsDir),
101
- languages,
102
- }),
103
- );
104
- }
105
-
106
- const copyTargets: CopyTarget[] = [];
107
-
108
- const publicDir = path.resolve(
109
- staticDirs.public ?? path.join(srcDir, "public"),
110
- );
111
- if (fs.existsSync(publicDir)) {
112
- copyTargets.push({
113
- src: publicDir,
114
- dest: path.join(buildContext.outDir, "resources"),
115
- });
116
- }
117
-
118
- if (fs.existsSync(iconsDir)) {
119
- copyTargets.push({
120
- src: iconsDir,
121
- dest: path.join(buildContext.outDir, "icons"),
122
- });
123
- }
124
-
125
- if (copyTargets.length > 0) {
126
- plugins.push(staticCopy({ targets: copyTargets }));
127
- }
128
-
129
- if (!buildContext.isDev && format === "es") {
130
- plugins.push(minifier());
131
- }
132
-
133
- // Intercept '@bonsae/nrg/client' before Vite's resolver so it stays external.
134
- // Rollup's string-array external check runs against the *resolved* file path,
135
- // which wouldn't match the original specifier. 'vue' is handled by the
136
- // external array directly (Vite keeps the bare specifier for known packages).
137
- plugins.unshift({
138
- name: "nrg-client-external",
139
- enforce: "pre",
140
- resolveId(id) {
141
- if (id === "@bonsae/nrg/client")
142
- return { id: "@bonsae/nrg/client", external: true };
143
- },
144
- } as Plugin);
145
-
146
- const defaultManualChunks = (id: string): string | undefined => {
147
- if (!id.includes("node_modules")) return undefined;
148
-
149
- const parts = id
150
- .substring(id.lastIndexOf("node_modules/") + "node_modules/".length)
151
- .split("/");
152
-
153
- const pkgName = parts[0].startsWith("@")
154
- ? `${parts[0]}/${parts[1]}`
155
- : parts[0];
156
-
157
- if (["jsonpointer", "es-toolkit"].includes(pkgName)) return "vendor-utils";
158
- return "vendor";
159
- };
160
-
161
- const config: InlineConfig = {
162
- configFile: false,
163
- logLevel: "warn",
164
- base: `/${path.join("resources", buildContext.packageName)}`,
165
- publicDir: path.resolve(srcDir, "public"),
166
- resolve: {
167
- alias: {
168
- "@": path.resolve(srcDir),
169
- },
170
- },
171
- plugins,
172
- css: {
173
- devSourcemap: buildContext.isDev,
174
- },
175
- build: {
176
- outDir: buildContext.outDir,
177
- emptyOutDir: false,
178
- sourcemap: buildContext.isDev ? "inline" : false,
179
- minify: !buildContext.isDev && format !== "es",
180
- copyPublicDir: false,
181
- lib: {
182
- entry: entryPath,
183
- name,
184
- fileName: "index",
185
- formats: [format],
186
- },
187
- rollupOptions: {
188
- external,
189
- treeshake: false,
190
- output: {
191
- entryFileNames: path.join("resources", "index.[hash].js"),
192
- chunkFileNames: path.join("resources", "vendor.[hash].js"),
193
- assetFileNames: path.join("resources", "[name].[hash].[ext]"),
194
- globals,
195
- paths: {
196
- vue: "/nrg/assets/vue.esm-browser.prod.js",
197
- "@bonsae/nrg/client": "/nrg/assets/nrg-client.js",
198
- },
199
- sourcemapPathTransform: (relativeSourcePath) => {
200
- return relativeSourcePath.replace(/\/client\//g, "/");
201
- },
202
- manualChunks: manualChunks ?? defaultManualChunks,
203
- },
204
- },
205
- },
206
- define: {
207
- "process.env.NODE_ENV": JSON.stringify(
208
- buildContext.isDev ? "development" : "production",
209
- ),
210
- "process.env": {},
211
- },
212
- };
213
-
214
- try {
215
- await viteBuild(config);
216
- } catch (error) {
217
- throw new BuildError("client", error as Error);
218
- } finally {
219
- if (generatedEntry) {
220
- if (fs.existsSync(entryPath)) {
221
- fs.unlinkSync(entryPath);
222
- }
223
- }
224
- }
225
- }
226
-
227
- export { build };
@@ -1 +0,0 @@
1
- export { build } from "./build";
@@ -1,75 +0,0 @@
1
- import type { Plugin } from "vite";
2
- import mime from "mime-types";
3
- import fs from "fs";
4
- import path from "path";
5
-
6
- function htmlGenerator(options: {
7
- packageName: string;
8
- licensePath?: string;
9
- }): Plugin {
10
- const { packageName, licensePath } = options;
11
-
12
- return {
13
- name: "vite-plugin-node-red:client:html-generator",
14
- apply: "build",
15
- enforce: "post",
16
-
17
- generateBundle(_, bundle) {
18
- const resourcesTags = Object.keys(bundle)
19
- .map((fileName) => {
20
- const asset = bundle[fileName];
21
- const srcPath = path.join(
22
- "resources",
23
- packageName,
24
- fileName.replace(/^resources\/?/, ""),
25
- );
26
-
27
- const content =
28
- asset.type === "asset"
29
- ? asset.source
30
- : asset.type === "chunk"
31
- ? asset.code
32
- : null;
33
-
34
- if (typeof content !== "string" && !(content instanceof Uint8Array))
35
- return null;
36
-
37
- const mimeType = mime.lookup(fileName);
38
-
39
- switch (mimeType) {
40
- case "application/javascript":
41
- case "text/javascript":
42
- return `<script type="module" src="${srcPath}" defer></script>`;
43
- case "text/css":
44
- return `<link rel="stylesheet" href="${srcPath}">`;
45
- case "font/woff":
46
- case "font/woff2":
47
- case "application/font-woff":
48
- case "application/font-woff2":
49
- case "application/x-font-ttf":
50
- case "application/x-font-opentype":
51
- case "font/ttf":
52
- case "font/otf":
53
- return `<link rel="preload" as="font" href="${srcPath}" type="${mimeType}">`;
54
- default:
55
- return null;
56
- }
57
- })
58
- .filter(Boolean)
59
- .join("\n");
60
-
61
- const licenseBanner =
62
- licensePath && fs.existsSync(licensePath)
63
- ? `<!--\n${fs.readFileSync(licensePath, "utf-8")}\n-->`
64
- : "";
65
-
66
- this.emitFile({
67
- type: "asset",
68
- fileName: "index.html",
69
- source: `${licenseBanner}\n${resourcesTags}`,
70
- });
71
- },
72
- };
73
- }
74
-
75
- export { htmlGenerator };
@@ -1,5 +0,0 @@
1
- export { htmlGenerator } from "./html-generator";
2
- export { localesGenerator } from "./locales-generator";
3
- export { minifier } from "./minifier";
4
- export { nodeDefinitionsInliner } from "./node-definitions-inliner";
5
- export { staticCopy } from "./static-copy";
@@ -1,126 +0,0 @@
1
- import type { Plugin } from "vite";
2
- import fs from "fs";
3
- import path from "path";
4
-
5
- function localesGenerator(options: {
6
- outDir: string;
7
- docsDir: string;
8
- labelsDir: string;
9
- languages: string[];
10
- }): Plugin {
11
- const { outDir, docsDir, labelsDir, languages } = options;
12
-
13
- return {
14
- name: "vite-plugin-node-red:client:locales-generator",
15
- apply: "build",
16
- enforce: "post",
17
-
18
- closeBundle() {
19
- function validateLanguage(lang: string, filePath: string) {
20
- if (!languages.includes(lang)) {
21
- throw new Error(
22
- `[locales] Invalid language "${lang}" in "${filePath}".\n` +
23
- `Supported: ${languages.join(", ")}`,
24
- );
25
- }
26
- }
27
-
28
- function forEachFile<T>(
29
- baseDir: string,
30
- fileExtensions: string[],
31
- processFile: (params: {
32
- ext: string;
33
- filePath: string;
34
- nodeType: string;
35
- }) => T | null,
36
- ): Map<string, T extends unknown[] ? T : Record<string, T>> {
37
- const langMap = new Map();
38
-
39
- if (!fs.existsSync(baseDir)) return langMap;
40
-
41
- const nodeDirs = fs
42
- .readdirSync(baseDir, { withFileTypes: true })
43
- .filter((d) => d.isDirectory());
44
-
45
- for (const nodeDir of nodeDirs) {
46
- const nodeType = nodeDir.name;
47
- const nodePath = path.join(baseDir, nodeType);
48
- const files = fs.readdirSync(nodePath);
49
-
50
- for (const file of files) {
51
- const ext = path.extname(file);
52
- if (!fileExtensions.includes(ext)) continue;
53
-
54
- const lang = path.basename(file, ext);
55
- const filePath = path.join(nodePath, file);
56
- validateLanguage(lang, filePath);
57
-
58
- const value = processFile({ ext, filePath, nodeType });
59
- if (value == null) continue;
60
-
61
- if (!langMap.has(lang)) {
62
- langMap.set(lang, Array.isArray(value) ? [] : {});
63
- }
64
-
65
- if (Array.isArray(value)) {
66
- langMap.get(lang).push(...value);
67
- } else {
68
- langMap.get(lang)[nodeType] = value;
69
- }
70
- }
71
- }
72
-
73
- return langMap;
74
- }
75
-
76
- function writeOutput<T>(
77
- langMap: Map<string, T>,
78
- fileName: string,
79
- serialize: (value: T) => string,
80
- ) {
81
- for (const [lang, data] of langMap.entries()) {
82
- const langOutDir = path.join(outDir, lang);
83
- fs.mkdirSync(langOutDir, { recursive: true });
84
- fs.writeFileSync(
85
- path.join(langOutDir, fileName),
86
- serialize(data),
87
- "utf-8",
88
- );
89
- }
90
- }
91
-
92
- const docLangs = forEachFile(
93
- docsDir,
94
- [".html", ".md"],
95
- ({ ext, filePath, nodeType }) => {
96
- const type =
97
- ext === ".html"
98
- ? "text/html"
99
- : ext === ".md"
100
- ? "text/markdown"
101
- : null;
102
- if (!type) return null;
103
-
104
- const content = fs.readFileSync(filePath, "utf-8");
105
- return [
106
- `<script type="${type}" data-help-name="${nodeType}">\n${content}\n</script>`,
107
- ];
108
- },
109
- );
110
-
111
- writeOutput(docLangs, "index.html", (value: string[]) =>
112
- value.join("\n"),
113
- );
114
-
115
- const labelLangs = forEachFile(labelsDir, [".json"], ({ filePath }) =>
116
- JSON.parse(fs.readFileSync(filePath, "utf-8")),
117
- );
118
-
119
- writeOutput(labelLangs, "index.json", (value) =>
120
- JSON.stringify(value, null, 2),
121
- );
122
- },
123
- };
124
- }
125
-
126
- export { localesGenerator };
@@ -1,23 +0,0 @@
1
- import type { Plugin } from "vite";
2
- import { transform } from "esbuild";
3
-
4
- function minifier(): Plugin {
5
- return {
6
- name: "vite-plugin-node-red:client:minifier",
7
- apply: "build",
8
-
9
- async generateBundle(_options, bundle) {
10
- for (const [fileName, chunk] of Object.entries(bundle)) {
11
- if (chunk.type === "chunk" && fileName.endsWith(".js")) {
12
- const result = await transform(chunk.code, {
13
- minify: true,
14
- });
15
- chunk.code = result.code;
16
- chunk.map = null as any;
17
- }
18
- }
19
- },
20
- };
21
- }
22
-
23
- export { minifier };