@bonsae/nrg 0.4.0 → 0.5.1

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.
@@ -1,5 +1,13 @@
1
1
  <template>
2
2
  <div style="display: flex; flex-direction: column; width: 100%">
3
+ <slot name="label">
4
+ <NodeRedInputLabel
5
+ v-if="label"
6
+ :label="label"
7
+ :icon="icon"
8
+ :required="required"
9
+ />
10
+ </slot>
3
11
  <input
4
12
  ref="typedInput"
5
13
  type="text"
@@ -14,9 +22,11 @@
14
22
 
15
23
  <script lang="ts">
16
24
  import { defineComponent } from "vue";
25
+ import NodeRedInputLabel from "./node-red-input-label.vue";
17
26
  import { TYPED_INPUT_TYPES } from "../../constants";
18
27
 
19
28
  export default defineComponent({
29
+ components: { NodeRedInputLabel },
20
30
  props: {
21
31
  value: {
22
32
  type: Object,
@@ -43,6 +53,18 @@ export default defineComponent({
43
53
  type: Array,
44
54
  default: () => TYPED_INPUT_TYPES,
45
55
  },
56
+ label: {
57
+ type: String,
58
+ default: "",
59
+ },
60
+ icon: {
61
+ type: String,
62
+ default: "",
63
+ },
64
+ required: {
65
+ type: Boolean,
66
+ default: false,
67
+ },
46
68
  error: {
47
69
  type: String,
48
70
  default: "",
@@ -8,6 +8,7 @@ import NodeRedTypedInput from "./components/node-red-typed-input.vue";
8
8
  import NodeRedConfigInput from "./components/node-red-config-input.vue";
9
9
  import NodeRedSelectInput from "./components/node-red-select-input.vue";
10
10
  import NodeRedEditorInput from "./components/node-red-editor-input.vue";
11
+ import NodeRedInputLabel from "./components/node-red-input-label.vue";
11
12
  import NodeRedJsonSchemaForm from "./components/node-red-json-schema-form.vue";
12
13
 
13
14
  const _schemas: Record<string, any> = {};
@@ -163,6 +164,7 @@ function createNodeRedVueApp(
163
164
  features,
164
165
  });
165
166
 
167
+ app.component("NodeRedInputLabel", NodeRedInputLabel);
166
168
  app.component("NodeRedInput", NodeRedInput);
167
169
  app.component("NodeRedTypedInput", NodeRedTypedInput);
168
170
  app.component("NodeRedConfigInput", NodeRedConfigInput);
@@ -15,40 +15,26 @@ function NodeRef<T extends new (...args: any[]) => any>(
15
15
  options?: SchemaOptions,
16
16
  ): TNodeRef<InstanceType<T>> {
17
17
  return {
18
- ...SchemaType.String({
18
+ ...BaseType.String({
19
19
  description:
20
20
  options?.description || `Reference to ${(nodeClass as any).type}`,
21
21
  format: "node-id",
22
22
  }),
23
- "node-type": (nodeClass as any).type,
23
+ "x-nrg-node-type": (nodeClass as any).type,
24
24
  ...options,
25
25
  [Kind]: "NodeRef",
26
26
  } as unknown as TNodeRef<InstanceType<T>>;
27
27
  }
28
28
 
29
- function TypedInput(
30
- options?: SchemaOptions & { types?: string[] },
31
- ): TTypedInput {
32
- const { types, ...rest } = options ?? {};
29
+ function TypedInput(options?: SchemaOptions): TTypedInput {
33
30
  return {
34
31
  ...TypedInputSchema,
35
- ...rest,
36
- ...(types ? { "x-typed-types": types } : {}),
32
+ ...options,
37
33
  [Kind]: "TypedInput",
38
34
  } as unknown as TTypedInput;
39
35
  }
40
36
 
41
- const _OriginalString = BaseType.String.bind(BaseType);
42
- function StringWithLang(options?: SchemaOptions & { lang?: string }) {
43
- const { lang, ...rest } = options ?? {};
44
- return _OriginalString({
45
- ...rest,
46
- ...(lang ? { "x-editor-language": lang } : {}),
47
- });
48
- }
49
-
50
37
  const SchemaType = Object.assign({}, BaseType, {
51
- String: StringWithLang,
52
38
  NodeRef,
53
39
  TypedInput,
54
40
  });
@@ -62,7 +48,7 @@ function markNonValidatable<T extends TSchema>(schema: T): T {
62
48
 
63
49
  // NOTE: if the type is non serializable, like Functions or Constructor, we must skip validation and avoid applying defaults
64
50
  if (hasInvalidType) {
65
- (schema as any)["skip-validation"] = true;
51
+ (schema as any)["x-nrg-skip-validation"] = true;
66
52
 
67
53
  if ((schema as any).default !== undefined) {
68
54
  (schema as any)._default = (schema as any).default;
@@ -11,7 +11,7 @@ interface TNodeRef<T = any> extends TSchema {
11
11
  [Kind]: "NodeRef";
12
12
  static: T;
13
13
  type: "string";
14
- "node-type"?: string;
14
+ "x-nrg-node-type"?: string;
15
15
  }
16
16
 
17
17
  type ResolveNodeRefs<T> =
@@ -37,9 +37,17 @@ interface TTypedInput extends TSchema {
37
37
  };
38
38
  }
39
39
 
40
+ interface NrgFormOptions {
41
+ icon?: string;
42
+ typedInputTypes?: string[];
43
+ editorLanguage?: string;
44
+ }
45
+
40
46
  declare module "@sinclair/typebox" {
41
47
  interface SchemaOptions {
42
48
  exportable?: boolean;
49
+ "x-nrg-node-type"?: string;
50
+ "x-nrg-form"?: NrgFormOptions;
43
51
  }
44
52
  }
45
53
 
@@ -1,7 +1,7 @@
1
1
  import type { TObject, SchemaOptions } from "@sinclair/typebox";
2
2
 
3
3
  interface NodeSchemaOptions extends SchemaOptions {
4
- "node-type"?: string;
4
+ "x-nrg-node-type"?: string;
5
5
  default?: any;
6
6
  format?: string;
7
7
  }
@@ -25,7 +25,7 @@ function getDefaultsFromSchema(
25
25
  required: false,
26
26
  value: property.default ?? undefined,
27
27
  // NOTE: I'm using a custom json schema keyword to determine the node type
28
- type: property["node-type"],
28
+ type: property["x-nrg-node-type"],
29
29
  };
30
30
  }
31
31
 
@@ -5,9 +5,13 @@ class NodeRedValidator extends Validator {
5
5
  constructor(RED: RED) {
6
6
  super({
7
7
  customKeywords: [
8
- { keyword: "skip-validation", schemaType: "boolean", valid: true },
9
8
  {
10
- keyword: "node-type",
9
+ keyword: "x-nrg-skip-validation",
10
+ schemaType: "boolean",
11
+ valid: true,
12
+ },
13
+ {
14
+ keyword: "x-nrg-node-type",
11
15
  type: "string",
12
16
  validate: (schemaValue: string, dataValue: string) => {
13
17
  if (!dataValue) return true;
@@ -39,13 +39,15 @@ async function build(
39
39
  if (fs.existsSync(physicalEntryPath)) {
40
40
  entryPath = physicalEntryPath;
41
41
  } else {
42
- // No physical entry — create a minimal empty file that the inliner
43
- // will prepend auto-registration code into.
44
- if (!fs.existsSync(path.dirname(physicalEntryPath))) {
45
- fs.mkdirSync(path.dirname(physicalEntryPath), { recursive: true });
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 });
46
48
  }
47
- fs.writeFileSync(physicalEntryPath, "// auto-generated entry\n");
48
- entryPath = physicalEntryPath;
49
+ fs.writeFileSync(cachedEntryPath, "// auto-generated entry\n");
50
+ entryPath = cachedEntryPath;
49
51
  generatedEntry = true;
50
52
  }
51
53
 
@@ -215,7 +217,7 @@ async function build(
215
217
  throw new BuildError("client", error as Error);
216
218
  } finally {
217
219
  if (generatedEntry) {
218
- fs.unlinkSync(physicalEntryPath);
220
+ fs.unlinkSync(entryPath);
219
221
  }
220
222
  }
221
223
  }
@@ -28,7 +28,7 @@ function getDefaultsFromSchema(
28
28
  result[key] = {
29
29
  required: false,
30
30
  value: prop.default ?? undefined,
31
- type: prop["node-type"],
31
+ type: prop["x-nrg-node-type"],
32
32
  };
33
33
  }
34
34
  return result;
@@ -37,10 +37,22 @@ function buildPlugin(options: BuildPluginOptions): Plugin {
37
37
  const tsconfigsToCheck = [serverTsconfig, clientTsconfig].filter((p) =>
38
38
  fs.existsSync(p),
39
39
  );
40
- for (const tsconfig of tsconfigsToCheck) {
41
- execSync(`npx tsc -p ${tsconfig} --noEmit`, { stdio: "inherit" });
40
+ try {
41
+ for (const tsconfig of tsconfigsToCheck) {
42
+ execSync(`npx tsc -p ${tsconfig} --noEmit`, {
43
+ stdio: ["inherit", "pipe", "pipe"],
44
+ encoding: "utf-8",
45
+ });
46
+ }
47
+ logger.stopSpinner("Type checked");
48
+ } catch (e: any) {
49
+ logger.stopSpinner("Type check failed");
50
+ const output = (e.stdout || "") + (e.stderr || "");
51
+ if (output) {
52
+ console.error(output);
53
+ }
54
+ throw new BuildError("type-check", e);
42
55
  }
43
- logger.stopSpinner("Type checked");
44
56
 
45
57
  logger.startSpinner("Cleaning");
46
58
  cleanDir(buildContext.outDir);