@bonsae/nrg 0.6.1 → 0.6.3

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 +13 -77
  3. package/{src/core/client → shims}/components.d.ts +2 -0
  4. package/{src/tsconfig → tsconfig}/client.json +3 -3
  5. package/types/client.d.ts +37 -0
  6. package/types/index.d.ts +211 -0
  7. package/types/server.d.ts +2307 -0
  8. package/types/vite.d.ts +12 -0
  9. package/build/vite/utils.js +0 -56
  10. package/src/core/client/app.vue +0 -185
  11. package/src/core/client/components/node-red-config-input.vue +0 -79
  12. package/src/core/client/components/node-red-editor-input.vue +0 -307
  13. package/src/core/client/components/node-red-input-label.vue +0 -53
  14. package/src/core/client/components/node-red-input.vue +0 -93
  15. package/src/core/client/components/node-red-json-schema-form.vue +0 -444
  16. package/src/core/client/components/node-red-select-input.vue +0 -108
  17. package/src/core/client/components/node-red-toggle.vue +0 -115
  18. package/src/core/client/components/node-red-typed-input.vue +0 -158
  19. package/src/core/client/index.ts +0 -500
  20. package/src/core/client/tsconfig.json +0 -18
  21. package/src/core/constants.ts +0 -18
  22. package/src/core/errors.ts +0 -9
  23. package/src/core/server/api/index.ts +0 -1
  24. package/src/core/server/api/serve-nrg-resources.ts +0 -54
  25. package/src/core/server/index.ts +0 -191
  26. package/src/core/server/nodes/config-node.ts +0 -67
  27. package/src/core/server/nodes/factories.ts +0 -136
  28. package/src/core/server/nodes/index.ts +0 -5
  29. package/src/core/server/nodes/io-node.ts +0 -179
  30. package/src/core/server/nodes/node.ts +0 -259
  31. package/src/core/server/nodes/types/config-node.ts +0 -28
  32. package/src/core/server/nodes/types/factories.ts +0 -130
  33. package/src/core/server/nodes/types/index.ts +0 -4
  34. package/src/core/server/nodes/types/io-node.ts +0 -40
  35. package/src/core/server/nodes/types/node.ts +0 -41
  36. package/src/core/server/nodes/utils.ts +0 -106
  37. package/src/core/server/schemas/base.ts +0 -66
  38. package/src/core/server/schemas/index.ts +0 -3
  39. package/src/core/server/schemas/type.ts +0 -95
  40. package/src/core/server/schemas/types/index.ts +0 -82
  41. package/src/core/server/tsconfig.json +0 -17
  42. package/src/core/server/types/index.ts +0 -220
  43. package/src/core/server/utils.ts +0 -56
  44. package/src/core/server/validator.ts +0 -36
  45. package/src/core/validator.ts +0 -222
  46. package/src/index.ts +0 -2
  47. package/src/types.ts +0 -189
  48. package/src/utils.ts +0 -20
  49. package/src/vite/async-utils.ts +0 -61
  50. package/src/vite/client/build.ts +0 -227
  51. package/src/vite/client/index.ts +0 -1
  52. package/src/vite/client/plugins/html-generator.ts +0 -75
  53. package/src/vite/client/plugins/index.ts +0 -5
  54. package/src/vite/client/plugins/locales-generator.ts +0 -126
  55. package/src/vite/client/plugins/minifier.ts +0 -23
  56. package/src/vite/client/plugins/node-definitions-inliner.ts +0 -275
  57. package/src/vite/client/plugins/static-copy.ts +0 -43
  58. package/src/vite/defaults.ts +0 -77
  59. package/src/vite/errors.ts +0 -37
  60. package/src/vite/index.ts +0 -2
  61. package/src/vite/logger.ts +0 -94
  62. package/src/vite/node-red-launcher.ts +0 -344
  63. package/src/vite/plugin.ts +0 -61
  64. package/src/vite/plugins/build.ts +0 -85
  65. package/src/vite/plugins/index.ts +0 -2
  66. package/src/vite/plugins/server.ts +0 -267
  67. package/src/vite/server/build.ts +0 -124
  68. package/src/vite/server/index.ts +0 -1
  69. package/src/vite/server/plugins/index.ts +0 -3
  70. package/src/vite/server/plugins/output-wrapper.ts +0 -109
  71. package/src/vite/server/plugins/package-json-generator.ts +0 -203
  72. package/src/vite/server/plugins/type-generator.ts +0 -442
  73. package/src/vite/types.ts +0 -174
  74. package/src/vite/utils.ts +0 -72
  75. /package/{build/index.js → index.js} +0 -0
  76. /package/{build/server → server}/index.cjs +0 -0
  77. /package/{build/server → server}/resources/nrg-client.js +0 -0
  78. /package/{build/server → server}/resources/vue.esm-browser.js +0 -0
  79. /package/{build/server → server}/resources/vue.esm-browser.prod.js +0 -0
  80. /package/{src/core/client → shims}/globals.d.ts +0 -0
  81. /package/{src/core/client → shims}/shims-vue.d.ts +0 -0
  82. /package/{src/tsconfig → tsconfig}/base.json +0 -0
  83. /package/{src/tsconfig → tsconfig}/server.json +0 -0
  84. /package/{build/vite → vite}/index.js +0 -0
@@ -1,442 +0,0 @@
1
- import type { Plugin } from "vite";
2
- import dts from "vite-plugin-dts";
3
- import fs from "fs";
4
- import path from "path";
5
- import ts from "typescript";
6
-
7
- /**
8
- * Recursively collect all .ts files under a directory, excluding .d.ts files.
9
- */
10
- function collectTsFiles(dir: string): string[] {
11
- if (!fs.existsSync(dir)) return [];
12
- return fs.readdirSync(dir, { withFileTypes: true }).flatMap((dirent) => {
13
- const full = path.join(dir, dirent.name);
14
- if (dirent.isDirectory()) return collectTsFiles(full);
15
- if (
16
- dirent.isFile() &&
17
- dirent.name.endsWith(".ts") &&
18
- !dirent.name.endsWith(".d.ts")
19
- )
20
- return [full];
21
- return [];
22
- });
23
- }
24
-
25
- /**
26
- * Convert a file basename (without extension) to PascalCase.
27
- * E.g. "your-node" → "YourNode", "remote_server" → "RemoteServer"
28
- */
29
- function toPascalCase(name: string): string {
30
- return name
31
- .split(/[-_]/)
32
- .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
33
- .join("");
34
- }
35
-
36
- /**
37
- * Positional semantic names for each framework base class.
38
- * Position i in the generic corresponds to the i-th semantic slot.
39
- * Users can name their types anything — the position determines meaning.
40
- */
41
- const BASE_CLASS_SLOTS: Record<string, string[]> = {
42
- IONode: ["Config", "Credentials", "Input", "Output", "Settings"],
43
- ConfigNode: ["Config", "Credentials", "Settings"],
44
- };
45
-
46
- /**
47
- * Parse a node source file and return `{ localName, semanticName }` pairs for
48
- * types that should be exported from the package.
49
- *
50
- * The semantic name is derived from the generic POSITION in the base class, so
51
- * a user can name their types anything:
52
- *
53
- * export default class MyNode extends IONode<Bananas, MyCreds, …>
54
- * export type Bananas = { … } → exported as {Ns}Config (position 0)
55
- * export type MyCreds = { … } → exported as {Ns}Credentials (position 1)
56
- *
57
- * Only types that appear as generic args AND are exported from the file are
58
- * included, so unrelated helper types are never leaked.
59
- */
60
- function getNodeTypeExports(
61
- filePath: string,
62
- ): Array<{ localName: string; semanticName: string }> {
63
- const content = fs.readFileSync(filePath, "utf-8");
64
- const source = ts.createSourceFile(
65
- filePath,
66
- content,
67
- ts.ScriptTarget.ESNext,
68
- /* setParentNodes */ true,
69
- );
70
-
71
- const hasModifier = (node: ts.HasModifiers, kind: ts.SyntaxKind) =>
72
- (node.modifiers ?? []).some((m) => m.kind === kind);
73
-
74
- // Collect names of exported type aliases and interfaces.
75
- const exportedTypeNames = new Set<string>();
76
- for (const stmt of source.statements) {
77
- if (
78
- ts.isTypeAliasDeclaration(stmt) &&
79
- hasModifier(stmt, ts.SyntaxKind.ExportKeyword)
80
- ) {
81
- exportedTypeNames.add(stmt.name.text);
82
- }
83
- if (
84
- ts.isInterfaceDeclaration(stmt) &&
85
- hasModifier(stmt, ts.SyntaxKind.ExportKeyword)
86
- ) {
87
- exportedTypeNames.add(stmt.name.text);
88
- }
89
- }
90
-
91
- if (exportedTypeNames.size === 0) return [];
92
-
93
- // Find `export default class … extends BaseClass<T0, T1, …>` and extract
94
- // the base class name and its generic type argument names by position.
95
- let baseClassName = "";
96
- const genericArgNames: string[] = [];
97
-
98
- for (const stmt of source.statements) {
99
- if (
100
- !ts.isClassDeclaration(stmt) ||
101
- !hasModifier(stmt, ts.SyntaxKind.DefaultKeyword)
102
- ) {
103
- continue;
104
- }
105
- for (const clause of stmt.heritageClauses ?? []) {
106
- if (clause.token !== ts.SyntaxKind.ExtendsKeyword) continue;
107
- for (const type of clause.types) {
108
- if (ts.isIdentifier(type.expression)) {
109
- baseClassName = type.expression.text;
110
- }
111
- for (const arg of type.typeArguments ?? []) {
112
- if (ts.isTypeReferenceNode(arg) && ts.isIdentifier(arg.typeName)) {
113
- genericArgNames.push(arg.typeName.text);
114
- } else {
115
- // Unknown / complex type arg — push empty string to preserve positions.
116
- genericArgNames.push("");
117
- }
118
- }
119
- }
120
- }
121
- break;
122
- }
123
-
124
- const slots = BASE_CLASS_SLOTS[baseClassName];
125
- if (!slots) return [];
126
-
127
- // Build pairs: for each position, if the arg is exported AND we have a
128
- // semantic name for that slot, include it.
129
- const result: Array<{ localName: string; semanticName: string }> = [];
130
- for (let i = 0; i < genericArgNames.length; i++) {
131
- const localName = genericArgNames[i];
132
- const semanticName = slots[i];
133
- if (localName && semanticName && exportedTypeNames.has(localName)) {
134
- result.push({ localName, semanticName });
135
- }
136
- }
137
- return result;
138
- }
139
-
140
- /**
141
- * Build re-export statements for every file in {srcDir}/nodes/, relative to
142
- * the given entry file path.
143
- *
144
- * Per node file two kinds of statements are generated:
145
- *
146
- * // 1. Class re-export — so api-extractor includes the class declaration
147
- * // in the bundled .d.ts, enabling `import { YourNode }`, `instanceof`,
148
- * // type assertions `as YourNode`, and `resolveTypedInput<YourNode>()`.
149
- * export { default as YourNode } from "./nodes/your-node";
150
- *
151
- * // 2. Type-only exports — one per exported type alias/interface, prefixed
152
- * // with the namespace name to avoid collisions across node files.
153
- * // Enables `import type { YourNodeConfig, YourNodeCredentials }`.
154
- * export type { Config as YourNodeConfig, Credentials as YourNodeCredentials,
155
- * Input as YourNodeInput, Output as YourNodeOutput,
156
- * Settings as YourNodeSettings } from "./nodes/your-node";
157
- *
158
- * These statements are appended in memory to the entry file content served to
159
- * the TypeScript compiler via a `ts.sys.readFile` patch, so api-extractor
160
- * includes them in the final bundled `.d.ts` without touching any source file.
161
- * Runtime class values are exposed by `cjsDefaultExportPlugin` dynamically
162
- * via the `nodes` array on the package function.
163
- */
164
- /**
165
- * Semantic names for schema properties in both class static properties
166
- * and factory definition objects.
167
- */
168
- const SCHEMA_PROP_SEMANTICS: Record<string, string> = {
169
- configSchema: "ConfigSchema",
170
- credentialsSchema: "CredentialsSchema",
171
- inputSchema: "InputSchema",
172
- outputsSchema: "OutputsSchema",
173
- settingsSchema: "SettingsSchema",
174
- };
175
-
176
- /**
177
- * Extract schema references from a node file — works for both class-based
178
- * and factory-based (defineIONode/defineConfigNode) patterns.
179
- *
180
- * Returns an array of { localName, semanticName, importSource } where:
181
- * - localName: the identifier used in the file (e.g., "ConfigsSchema")
182
- * - semanticName: the semantic slot name (e.g., "ConfigSchema")
183
- * - importSource: the relative import path (e.g., "../schemas/my-node")
184
- */
185
- function getSchemaReferences(
186
- filePath: string,
187
- ): Array<{ localName: string; semanticName: string; importSource: string }> {
188
- const content = fs.readFileSync(filePath, "utf-8");
189
- const source = ts.createSourceFile(
190
- filePath,
191
- content,
192
- ts.ScriptTarget.ESNext,
193
- true,
194
- );
195
-
196
- // Build a map of imported identifiers → their source module
197
- const importMap = new Map<string, string>();
198
- for (const stmt of source.statements) {
199
- if (ts.isImportDeclaration(stmt) && stmt.importClause) {
200
- const moduleSpecifier = (stmt.moduleSpecifier as ts.StringLiteral).text;
201
- const namedBindings = stmt.importClause.namedBindings;
202
- if (namedBindings && ts.isNamedImports(namedBindings)) {
203
- for (const el of namedBindings.elements) {
204
- importMap.set(el.name.text, moduleSpecifier);
205
- }
206
- }
207
- }
208
- }
209
-
210
- // Collect schema property assignments: { propName → identifiers[] }
211
- const schemaRefs = new Map<string, string[]>();
212
-
213
- // Extract identifier(s) from an initializer — handles both single identifiers
214
- // and array literals like [Output1Schema, Output2Schema].
215
- function extractIdentifiers(node: ts.Expression): string[] {
216
- if (ts.isIdentifier(node)) return [node.text];
217
- if (ts.isArrayLiteralExpression(node)) {
218
- return node.elements.filter(ts.isIdentifier).map((el) => el.text);
219
- }
220
- return [];
221
- }
222
-
223
- for (const stmt of source.statements) {
224
- // Class-based: static readonly configSchema = ConfigsSchema
225
- // static readonly outputsSchema = [Output1Schema, Output2Schema]
226
- if (ts.isClassDeclaration(stmt)) {
227
- for (const member of stmt.members) {
228
- if (
229
- ts.isPropertyDeclaration(member) &&
230
- ts.isIdentifier(member.name) &&
231
- member.name.text in SCHEMA_PROP_SEMANTICS &&
232
- member.initializer
233
- ) {
234
- const ids = extractIdentifiers(member.initializer);
235
- if (ids.length > 0) {
236
- schemaRefs.set(member.name.text, ids);
237
- }
238
- }
239
- }
240
- }
241
-
242
- // Factory-based: export default defineIONode({ configSchema: X, ... })
243
- if (
244
- ts.isExportAssignment(stmt) &&
245
- stmt.expression &&
246
- ts.isCallExpression(stmt.expression)
247
- ) {
248
- const callee = stmt.expression.expression;
249
- if (
250
- ts.isIdentifier(callee) &&
251
- (callee.text === "defineIONode" || callee.text === "defineConfigNode")
252
- ) {
253
- const arg = stmt.expression.arguments[0];
254
- if (arg && ts.isObjectLiteralExpression(arg)) {
255
- for (const prop of arg.properties) {
256
- if (
257
- ts.isPropertyAssignment(prop) &&
258
- ts.isIdentifier(prop.name) &&
259
- prop.name.text in SCHEMA_PROP_SEMANTICS
260
- ) {
261
- const ids = extractIdentifiers(prop.initializer);
262
- if (ids.length > 0) {
263
- schemaRefs.set(prop.name.text, ids);
264
- }
265
- }
266
- }
267
- }
268
- }
269
- }
270
- }
271
-
272
- // Build result: match schema references to their import sources
273
- const result: Array<{
274
- localName: string;
275
- semanticName: string;
276
- importSource: string;
277
- tupleProp?: string;
278
- }> = [];
279
- for (const [propName, identifiers] of schemaRefs) {
280
- const semanticName = SCHEMA_PROP_SEMANTICS[propName];
281
- const isArray = identifiers.length > 1;
282
- for (const identifier of identifiers) {
283
- const importSource = importMap.get(identifier);
284
- if (importSource) {
285
- result.push({
286
- localName: identifier,
287
- semanticName: isArray ? identifier : semanticName,
288
- importSource,
289
- tupleProp: isArray ? semanticName : undefined,
290
- });
291
- }
292
- }
293
- }
294
- return result;
295
- }
296
-
297
- function buildNodeReexports(srcDir: string, entryFile: string): string {
298
- const nodesDir = path.join(srcDir, "nodes");
299
- const nodeFiles = collectTsFiles(nodesDir);
300
- return nodeFiles
301
- .map((file) => {
302
- const rel = path
303
- .relative(path.dirname(entryFile), file)
304
- .replace(/\\/g, "/");
305
- const relPath = rel.startsWith(".") ? rel : `./${rel}`;
306
- const specifier = relPath.replace(/\.ts$/, "");
307
- const ns = toPascalCase(path.basename(file, ".ts"));
308
-
309
- const lines = [`export { default as ${ns} } from "${specifier}";`];
310
-
311
- // Re-export type aliases from the node file (class-based nodes)
312
- const typePairs = getNodeTypeExports(file);
313
- if (typePairs.length > 0) {
314
- const prefixed = typePairs
315
- .map(
316
- ({ localName, semanticName }) =>
317
- `${localName} as ${ns}${semanticName}`,
318
- )
319
- .join(", ");
320
- lines.push(`export type { ${prefixed} } from "${specifier}";`);
321
- }
322
-
323
- // Re-export schemas referenced by the node definition (class or factory)
324
- const schemaRefs = getSchemaReferences(file);
325
- // Group by import source for cleaner re-exports
326
- const bySource = new Map<string, string[]>();
327
- for (const ref of schemaRefs) {
328
- const resolvedSource = path
329
- .relative(
330
- path.dirname(entryFile),
331
- path.resolve(path.dirname(file), ref.importSource),
332
- )
333
- .replace(/\\/g, "/");
334
- const sourceSpecifier = resolvedSource.startsWith(".")
335
- ? resolvedSource
336
- : `./${resolvedSource}`;
337
- if (!bySource.has(sourceSpecifier)) bySource.set(sourceSpecifier, []);
338
- bySource
339
- .get(sourceSpecifier)!
340
- .push(`${ref.localName} as ${ns}${ref.semanticName}`);
341
- }
342
- for (const [source, names] of bySource) {
343
- lines.push(`export { ${names.join(", ")} } from "${source}";`);
344
- }
345
-
346
- return lines.join("\n");
347
- })
348
- .join("\n");
349
- }
350
-
351
- function typeGenerator(options: {
352
- srcDir: string;
353
- outDir: string;
354
- /** Absolute paths of entry files (values from the entryPoints record). */
355
- entryFiles: string[];
356
- }): Plugin[] {
357
- const { srcDir, outDir, entryFiles } = options;
358
-
359
- // Prefer the server-specific tsconfig (inside srcDir) over the root one.
360
- // The root tsconfig typically only includes vite.config.ts, while the server
361
- // tsconfig includes the actual source files needed for declaration emit.
362
- const serverTsconfig = path.resolve(srcDir, "tsconfig.json");
363
- const rootTsconfig = path.resolve("tsconfig.json");
364
- const userTsconfig = fs.existsSync(serverTsconfig)
365
- ? serverTsconfig
366
- : rootTsconfig;
367
- // Exclude the user's client dir (sibling of srcDir), any nested client dirs,
368
- // and the vite/ build-tooling dir — none of these should appear in the
369
- // published type declarations.
370
- const clientDir = path.relative(
371
- process.cwd(),
372
- path.join(path.dirname(srcDir), "client"),
373
- );
374
-
375
- // Absolute resolved path → augmented source content (in-memory only).
376
- const augmentedContents = new Map<string, string>();
377
- // Original ts.sys.readFile — restored in closeBundle.
378
- let origReadFile: typeof ts.sys.readFile | null = null;
379
-
380
- const nodeTypeExporter: Plugin = {
381
- name: "vite-plugin-node-red:server:type-exporter",
382
- enforce: "pre",
383
- buildStart() {
384
- augmentedContents.clear();
385
- for (const entryFile of entryFiles) {
386
- const reexports = buildNodeReexports(srcDir, entryFile);
387
- if (!reexports) continue;
388
- const original = fs.readFileSync(entryFile, "utf-8");
389
- augmentedContents.set(
390
- path.resolve(entryFile),
391
- `${original}\n${reexports}\n`,
392
- );
393
- }
394
- if (augmentedContents.size === 0) return;
395
- origReadFile = ts.sys.readFile.bind(ts.sys);
396
- ts.sys.readFile = (fileName, encoding) => {
397
- const resolved = path.resolve(fileName);
398
- return (
399
- augmentedContents.get(resolved) ?? origReadFile!(fileName, encoding)
400
- );
401
- };
402
- },
403
- closeBundle() {
404
- if (origReadFile) {
405
- ts.sys.readFile = origReadFile;
406
- origReadFile = null;
407
- }
408
- augmentedContents.clear();
409
- },
410
- };
411
-
412
- return [
413
- nodeTypeExporter,
414
- dts({
415
- rollupTypes: true,
416
- rollupOptions: {
417
- messageCallback(message) {
418
- if (message.messageId === "console-preamble") {
419
- message.logLevel = "none";
420
- }
421
- },
422
- },
423
- outDir,
424
- ...(fs.existsSync(userTsconfig) && { tsconfigPath: userTsconfig }),
425
- compilerOptions: {
426
- noEmit: false,
427
- declaration: true,
428
- emitDeclarationOnly: true,
429
- noCheck: true,
430
- },
431
- exclude: [
432
- `${clientDir}/**`,
433
- "**/client/**",
434
- "vite/**",
435
- "node_modules/**",
436
- "dist/**",
437
- ],
438
- }),
439
- ].flat();
440
- }
441
-
442
- export { typeGenerator };
package/src/vite/types.ts DELETED
@@ -1,174 +0,0 @@
1
- import type { Plugin } from "vite";
2
- import type { NodeRedLauncher } from "./node-red-launcher";
3
-
4
- interface BuildContext {
5
- outDir: string;
6
- packageName: string;
7
- isDev: boolean;
8
- }
9
-
10
- interface BuildPluginOptions {
11
- serverBuildOptions: ServerBuildOptions;
12
- clientBuildOptions: ClientBuildOptions;
13
- extraFilesCopyTargets: CopyTarget[];
14
- buildContext: BuildContext;
15
- }
16
-
17
- interface ClientBuildOptions {
18
- /** Source directory for client code. @default "./src/client" */
19
- srcDir?: string;
20
- /** Entry filename relative to srcDir. @default "index.ts" */
21
- entry?: string;
22
- /** Subdirectory name for node definition files. @default "nodes" */
23
- nodesSubdir?: string;
24
- /** Pattern to match node definition files. */
25
- nodeFilePattern?: RegExp;
26
- /** Global variable name for the UMD/IIFE bundle. @default "NodeRedNodes" */
27
- name?: string;
28
- /** Output format for the client bundle. @default "es" */
29
- format?: "es" | "iife" | "umd";
30
- /** Base public path for serving resources. */
31
- base?: string;
32
- /** Path to LICENSE file to include in the HTML output. @default "./LICENSE" */
33
- licensePath?: string;
34
- /** Internationalization options for labels and docs. */
35
- locales?: LocalesOptions;
36
- /** Directories for static assets (icons, public files). */
37
- staticDirs?: {
38
- /** Directory containing node icons ({type}.png). @default "./src/icons" */
39
- icons?: string;
40
- /** Directory for public static files copied to dist/resources/. @default "./src/client/public" */
41
- public?: string;
42
- };
43
- /** Modules to treat as external (not bundled). @default ["jquery", "node-red", "vue", "@bonsae/nrg/client"] */
44
- external?: string[];
45
- /** Global variable mappings for external modules. */
46
- globals?: Record<string, string>;
47
- /** Custom chunk splitting function for Rollup. */
48
- manualChunks?: (id: string) => string | undefined;
49
- /** Additional Vite plugins for the client build. */
50
- plugins: Plugin[];
51
- }
52
-
53
- interface CopyTarget {
54
- /** Source file or directory path. */
55
- src: string;
56
- /** Destination path relative to the output directory. */
57
- dest: string;
58
- }
59
-
60
- interface LocalesOptions {
61
- /** Directory containing documentation files ({type}/{lang}.md or .html). @default "./src/locales/docs" */
62
- docsDir?: string;
63
- /** Directory containing label files ({type}/{lang}.json). @default "./src/locales/labels" */
64
- labelsDir?: string;
65
- /** Supported languages. @default ["en-US", "de", "es-ES", "fr", "ko", "pt-BR", "ru", "ja", "zh-CN", "zh-TW"] */
66
- languages?: string[];
67
- }
68
-
69
- interface LoggerOptions {
70
- name: string;
71
- prefix?: string;
72
- }
73
-
74
- interface NodeRedLauncherOptions {
75
- runtime?: {
76
- /** Port for Node-RED to listen on. @default 1880 */
77
- port?: number;
78
- /** Path to the Node-RED settings file (TypeScript supported). @default "./node-red.settings.ts" */
79
- settingsFilepath?: string;
80
- /** Node-RED version to install for the dev server. @default "latest" */
81
- version?: string;
82
- };
83
- /** Delay in ms before restarting Node-RED after a file change. @default 1000 */
84
- restartDelay?: number;
85
- /** Additional CLI arguments passed to the Node-RED process. */
86
- args?: string[];
87
- }
88
-
89
- /**
90
- * Options for the `nodeRed()` Vite plugin.
91
- *
92
- * All options are optional — defaults work for the standard `src/` directory layout.
93
- */
94
- interface NodeRedPluginOptions {
95
- /** Output directory for the built Node-RED package. @default "./dist" */
96
- outDir?: string;
97
- /** Options for building the client-side editor UI. */
98
- clientBuildOptions?: ClientBuildOptions;
99
- /** Options for building the server-side node runtime. */
100
- serverBuildOptions?: ServerBuildOptions;
101
- /** Options for the Node-RED dev server launcher. */
102
- nodeRedLauncherOptions?: NodeRedLauncherOptions;
103
- /** Extra files to copy into the output directory (e.g., LICENSE, README). */
104
- extraFilesCopyTargets?: CopyTarget[];
105
- }
106
-
107
- interface PackageJson {
108
- name: string;
109
- version: string;
110
- description?: string;
111
- type?: "commonjs" | "module";
112
- main?: string;
113
- types?: string;
114
- exports?: Record<string, unknown>;
115
- scripts?: Record<string, string>;
116
- dependencies?: Record<string, string>;
117
- devDependencies?: Record<string, string>;
118
- peerDependencies?: Record<string, string>;
119
- optionalDependencies?: Record<string, string>;
120
- keywords?: string[];
121
- author?: string | { name: string; email?: string; url?: string };
122
- license?: string;
123
- repository?: string | { type: string; url: string };
124
- bugs?: string | { url: string; email?: string };
125
- homepage?: string;
126
- engines?: Record<string, string>;
127
- files?: string[];
128
- private?: boolean;
129
- publishConfig?: Record<string, unknown>;
130
- "node-red"?: {
131
- nodes?: Record<string, string>;
132
- version?: string;
133
- };
134
- [key: string]: unknown;
135
- }
136
-
137
- interface ServerBuildOptions {
138
- /** Source directory for server code. @default "./src/server" */
139
- srcDir?: string;
140
- /** Entry filename relative to srcDir. @default "index.ts" */
141
- entry?: string;
142
- /** Output format. "esm" builds to .mjs with a CJS bridge for Node-RED. @default "esm" */
143
- format?: "cjs" | "esm";
144
- /** Dependencies to bundle into the output instead of keeping as external. @default [] */
145
- bundled?: string[];
146
- /** Generate rolled-up .d.ts type declarations (production only). @default true */
147
- types?: boolean;
148
- /** esbuild target for the server bundle. @default "node22" */
149
- nodeTarget?: string;
150
- /** Additional Vite plugins for the server build. */
151
- plugins: Plugin[];
152
- }
153
-
154
- interface ServerPluginOptions {
155
- nodeRedLauncher: NodeRedLauncher;
156
- serverBuildOptions: ServerBuildOptions;
157
- clientBuildOptions: ClientBuildOptions;
158
- extraFilesCopyTargets: CopyTarget[];
159
- buildContext: BuildContext;
160
- }
161
-
162
- export {
163
- BuildContext,
164
- BuildPluginOptions,
165
- ClientBuildOptions,
166
- CopyTarget,
167
- LocalesOptions,
168
- LoggerOptions,
169
- NodeRedLauncherOptions,
170
- NodeRedPluginOptions,
171
- PackageJson,
172
- ServerBuildOptions,
173
- ServerPluginOptions,
174
- };
package/src/vite/utils.ts DELETED
@@ -1,72 +0,0 @@
1
- import fs from "fs";
2
- import path from "path";
3
- import type { PackageJson } from "./types";
4
-
5
- function cleanDir(dir: string) {
6
- if (fs.existsSync(dir)) {
7
- fs.rmSync(dir, { recursive: true });
8
- }
9
- fs.mkdirSync(dir, { recursive: true });
10
- }
11
-
12
- function copyFiles(targets: CopyTarget[], outDir: string): void {
13
- for (const { src, dest } of targets) {
14
- const srcPath = path.resolve(src);
15
- const destPath = path.join(outDir, dest);
16
-
17
- if (!fs.existsSync(srcPath)) {
18
- continue;
19
- }
20
-
21
- const stat = fs.statSync(srcPath);
22
-
23
- if (stat.isDirectory()) {
24
- fs.cpSync(srcPath, destPath, { recursive: true });
25
- } else {
26
- fs.mkdirSync(path.dirname(destPath), { recursive: true });
27
- fs.copyFileSync(srcPath, destPath);
28
- }
29
- }
30
- }
31
-
32
- function getPackageName(): string {
33
- const pkgPath = path.resolve("./package.json");
34
- if (fs.existsSync(pkgPath)) {
35
- const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) as PackageJson;
36
- return pkg.name;
37
- }
38
-
39
- return "node-red-nodes";
40
- }
41
-
42
- function mergeOptions<T extends Record<string, unknown>>(
43
- defaults: T,
44
- overrides?: Partial<T>,
45
- ): T {
46
- if (!overrides) return { ...defaults };
47
-
48
- const result = { ...defaults };
49
- for (const key of Object.keys(overrides) as (keyof T)[]) {
50
- const overrideVal = overrides[key];
51
- const defaultVal = defaults[key];
52
- if (
53
- overrideVal !== undefined &&
54
- !Array.isArray(overrideVal) &&
55
- !Array.isArray(defaultVal) &&
56
- typeof overrideVal === "object" &&
57
- typeof defaultVal === "object" &&
58
- overrideVal !== null &&
59
- defaultVal !== null
60
- ) {
61
- result[key] = mergeOptions(
62
- defaultVal as Record<string, unknown>,
63
- overrideVal as Record<string, unknown>,
64
- ) as T[keyof T];
65
- } else if (overrideVal !== undefined) {
66
- result[key] = overrideVal as T[keyof T];
67
- }
68
- }
69
- return result;
70
- }
71
-
72
- export { cleanDir, copyFiles, getPackageName, mergeOptions };
File without changes
File without changes
File without changes
File without changes