check undefined node on build

This commit is contained in:
codetypes committed 2024-12-07 14:30:45 +08:00
1 parent e308d21837
commit ae59c4b811
4 files changed
+97 -47

No files matched your search

+39 -27
View File
@@ -1,5 +1,15 @@
import { EditNode, EditTree, useWorkspace } from "@/contexts/workspace-context"; import { EditNode, EditTree, useWorkspace } from "@/contexts/workspace-context";
import { NodeModel, TreeGraphData } from "@/misc/b3type"; import {
isBoolType,
isEnumType,
isExprType,
isFloatType,
isIntType,
isJsonType,
isStringType,
NodeModel,
TreeGraphData,
} from "@/misc/b3type";
import { import {
checkNodeArgValue, checkNodeArgValue,
checkOneof, checkOneof,
@@ -132,14 +142,14 @@ const NodeInspector: FC = () => {
form.setFieldValue( form.setFieldValue(
name, name,
(Array.isArray(value) ? value : []).map((item) => { (Array.isArray(value) ? value : []).map((item) => {
if (type === "json") { if (isJsonType(type)) {
return item === null ? "null" : JSON.stringify(item ?? arg.default, null, 2); return item === null ? "null" : JSON.stringify(item ?? arg.default, null, 2);
} else { } else {
return item; return item;
} }
}) })
); );
} else if (type === "json") { } else if (isJsonType(type)) {
form.setFieldValue( form.setFieldValue(
name, name,
value === null ? "null" : JSON.stringify(value ?? arg.default, null, 2) value === null ? "null" : JSON.stringify(value ?? arg.default, null, 2)
@@ -249,7 +259,7 @@ const NodeInspector: FC = () => {
const arr: unknown[] = []; const arr: unknown[] = [];
if (Array.isArray(value)) { if (Array.isArray(value)) {
value.forEach((item) => { value.forEach((item) => {
if (type === "json") { if (isJsonType(type)) {
try { try {
arr.push(item === "null" ? null : JSON.parse(item)); arr.push(item === "null" ? null : JSON.parse(item));
} catch { } catch {
@@ -261,7 +271,7 @@ const NodeInspector: FC = () => {
}); });
} }
data.args[arg.name] = arr; data.args[arg.name] = arr;
} else if (type === "json") { } else if (isJsonType(type)) {
try { try {
data.args[arg.name] = value === "null" ? null : JSON.parse(value); data.args[arg.name] = value === "null" ? null : JSON.parse(value);
} catch { } catch {
@@ -546,9 +556,9 @@ const NodeInspector: FC = () => {
validateTrigger={["onChange", "onBlur"]} validateTrigger={["onChange", "onBlur"]}
style={{ width: "100%", marginBottom: 5 }} style={{ width: "100%", marginBottom: 5 }}
initialValue={ initialValue={
type === "boolean" ? arg.default ?? false : arg.default isBoolType(type) ? arg.default ?? false : arg.default
} }
valuePropName={type === "boolean" ? "checked" : undefined} valuePropName={isBoolType(type) ? "checked" : undefined}
rules={[ rules={[
{ {
required, required,
@@ -556,7 +566,7 @@ const NodeInspector: FC = () => {
}, },
() => ({ () => ({
validator(_, value) { validator(_, value) {
if (type === "json") { if (isJsonType(type)) {
try { try {
if (value !== "null") { if (value !== "null") {
JSON.parse(value); JSON.parse(value);
@@ -576,29 +586,29 @@ const NodeInspector: FC = () => {
}), }),
]} ]}
> >
{type === "string" && ( {isStringType(type) && (
<TextArea autoSize disabled={disabled} onBlur={form.submit} /> <TextArea autoSize disabled={disabled} onBlur={form.submit} />
)} )}
{type === "json" && ( {isJsonType(type) && (
<TextArea autoSize disabled={disabled} onBlur={form.submit} /> <TextArea autoSize disabled={disabled} onBlur={form.submit} />
)} )}
{type === "int" && ( {isIntType(type) && (
<InputNumber <InputNumber
disabled={disabled} disabled={disabled}
onBlur={form.submit} onBlur={form.submit}
precision={0} precision={0}
/> />
)} )}
{type === "float" && ( {isFloatType(type) && (
<InputNumber disabled={disabled} onBlur={form.submit} /> <InputNumber disabled={disabled} onBlur={form.submit} />
)} )}
{type === "boolean" && ( {isBoolType(type) && (
<Switch disabled={disabled} onChange={form.submit} /> <Switch disabled={disabled} onChange={form.submit} />
)} )}
{type === "code" && ( {isExprType(type) && (
<Input disabled={disabled} onBlur={form.submit} /> <Input disabled={disabled} onBlur={form.submit} />
)} )}
{type === "enum" && ( {isEnumType(type) && (
<Select <Select
showSearch showSearch
disabled={disabled} disabled={disabled}
@@ -639,8 +649,8 @@ const NodeInspector: FC = () => {
<Button <Button
type="dashed" type="dashed"
onClick={() => { onClick={() => {
add(arg.default ?? type === "boolean" ? false : ""); add(arg.default ?? isBoolType(type) ? false : "");
if (type === "boolean") { if (isBoolType(type)) {
form.submit(); form.submit();
} }
}} }}
@@ -663,13 +673,13 @@ const NodeInspector: FC = () => {
name={`args.${arg.name}`} name={`args.${arg.name}`}
key={`args.${arg.name}`} key={`args.${arg.name}`}
label={arg.desc} label={arg.desc}
initialValue={type === "boolean" ? arg.default ?? false : arg.default} initialValue={isBoolType(type) ? arg.default ?? false : arg.default}
valuePropName={type === "boolean" ? "checked" : undefined} valuePropName={isBoolType(type) ? "checked" : undefined}
rules={[ rules={[
{ required, message: t("node.fileRequired", { field: arg.desc }) }, { required, message: t("node.fileRequired", { field: arg.desc }) },
({ getFieldValue, setFieldValue, isFieldValidating, validateFields }) => ({ ({ getFieldValue, setFieldValue, isFieldValidating, validateFields }) => ({
validator(_, value) { validator(_, value) {
if (value && type === "json") { if (value && isJsonType(type)) {
try { try {
if (value !== "null") { if (value !== "null") {
JSON.parse(value); JSON.parse(value);
@@ -716,19 +726,21 @@ const NodeInspector: FC = () => {
}), }),
]} ]}
> >
{type === "string" && ( {isStringType(type) && (
<TextArea autoSize disabled={disabled} onBlur={form.submit} /> <TextArea autoSize disabled={disabled} onBlur={form.submit} />
)} )}
{type === "json" && ( {isJsonType(type) && (
<TextArea autoSize disabled={disabled} onBlur={form.submit} /> <TextArea autoSize disabled={disabled} onBlur={form.submit} />
)} )}
{type === "int" && ( {isIntType(type) && (
<InputNumber disabled={disabled} onBlur={form.submit} precision={0} /> <InputNumber disabled={disabled} onBlur={form.submit} precision={0} />
)} )}
{type === "float" && <InputNumber disabled={disabled} onBlur={form.submit} />} {isFloatType(type) && (
{type === "boolean" && <Switch disabled={disabled} onChange={form.submit} />} <InputNumber disabled={disabled} onBlur={form.submit} />
{type === "code" && <Input disabled={disabled} onBlur={form.submit} />} )}
{type === "enum" && ( {isBoolType(type) && <Switch disabled={disabled} onChange={form.submit} />}
{isExprType(type) && <Input disabled={disabled} onBlur={form.submit} />}
{isEnumType(type) && (
<Select <Select
showSearch showSearch
disabled={disabled} disabled={disabled}
+16 -8
View File
@@ -5,10 +5,10 @@ export type NodeType = "Action" | "Composite" | "Decorator" | "Condition" | "Oth
export interface NodeArg { export interface NodeArg {
name: string; name: string;
type: type:
| "boolean" | "bool"
| "boolean?" | "bool?"
| "boolean[]" | "bool[]"
| "boolean[]?" | "bool[]?"
| "int" | "int"
| "int?" | "int?"
| "int[]" | "int[]"
@@ -29,16 +29,24 @@ export interface NodeArg {
| "enum?" | "enum?"
| "enum[]" | "enum[]"
| "enum[]?" | "enum[]?"
| "code" | "expr"
| "code?" | "expr?"
| "code[]" | "expr[]"
| "code[]?"; | "expr[]?";
desc: string; desc: string;
oneof?: string; oneof?: string;
default?: unknown; default?: unknown;
options?: { name: string; value: string | number }[]; options?: { name: string; value: string | number }[];
} }
export const isIntType = (type: string) => type.startsWith("int");
export const isFloatType = (type: string) => type.startsWith("float");
export const isStringType = (type: string) => type.startsWith("string");
export const isBoolType = (type: string) => type.startsWith("bool");
export const isEnumType = (type: string) => type.startsWith("enum");
export const isExprType = (type: string) => type.startsWith("expr") || type.startsWith("code");
export const isJsonType = (type: string) => type.startsWith("json");
export interface NodeDef { export interface NodeDef {
name: string; name: string;
type: NodeType; type: NodeType;
+41 -11
View File
@@ -1,5 +1,19 @@
import { useWorkspace } from "@/contexts/workspace-context"; import { useWorkspace } from "@/contexts/workspace-context";
import { NodeArg, NodeDef, NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type"; import {
isBoolType,
isEnumType,
isExprType,
isFloatType,
isIntType,
isJsonType,
isStringType,
NodeArg,
NodeDef,
NodeModel,
TreeGraphData,
TreeModel,
unknownNodeDef,
} from "@/misc/b3type";
import i18n from "@/misc/i18n"; import i18n from "@/misc/i18n";
import * as fs from "fs"; import * as fs from "fs";
import { message } from "./hooks"; import { message } from "./hooks";
@@ -130,7 +144,7 @@ export const checkNodeArgValue = (
) => { ) => {
let hasError = false; let hasError = false;
const type = getNodeArgRawType(arg); const type = getNodeArgRawType(arg);
if (type === "float") { if (isFloatType(type)) {
const isNumber = typeof value === "number"; const isNumber = typeof value === "number";
const isOptional = value === undefined && isNodeArgOptional(arg); const isOptional = value === undefined && isNodeArgOptional(arg);
if (!(isNumber || isOptional)) { if (!(isNumber || isOptional)) {
@@ -139,7 +153,7 @@ export const checkNodeArgValue = (
} }
hasError = true; hasError = true;
} }
} else if (type === "int") { } else if (isIntType(type)) {
const isInt = typeof value === "number" && value === Math.floor(value); const isInt = typeof value === "number" && value === Math.floor(value);
const isOptional = value === undefined && isNodeArgOptional(arg); const isOptional = value === undefined && isNodeArgOptional(arg);
if (!(isInt || isOptional)) { if (!(isInt || isOptional)) {
@@ -148,7 +162,7 @@ export const checkNodeArgValue = (
} }
hasError = true; hasError = true;
} }
} else if (type === "string") { } else if (isStringType(type)) {
const isString = typeof value === "string" && value; const isString = typeof value === "string" && value;
const isOptional = (value === undefined || value === "") && isNodeArgOptional(arg); const isOptional = (value === undefined || value === "") && isNodeArgOptional(arg);
if (!(isString || isOptional)) { if (!(isString || isOptional)) {
@@ -157,7 +171,7 @@ export const checkNodeArgValue = (
} }
hasError = true; hasError = true;
} }
} else if (type === "enum") { } else if (isEnumType(type)) {
const isEnum = !!arg.options?.find((option) => option.value === value); const isEnum = !!arg.options?.find((option) => option.value === value);
const isOptional = value === undefined && isNodeArgOptional(arg); const isOptional = value === undefined && isNodeArgOptional(arg);
if (!(isEnum || isOptional)) { if (!(isEnum || isOptional)) {
@@ -166,16 +180,16 @@ export const checkNodeArgValue = (
} }
hasError = true; hasError = true;
} }
} else if (type === "code") { } else if (isExprType(type)) {
const isCode = typeof value === "string" && value; const isExpr = typeof value === "string" && value;
const isOptional = (value === undefined || value === "") && isNodeArgOptional(arg); const isOptional = (value === undefined || value === "") && isNodeArgOptional(arg);
if (!(isCode || isOptional)) { if (!(isExpr || isOptional)) {
if (verbose) { if (verbose) {
error(data, `'${arg.name}=${JSON.stringify(value)}' is not a string`); error(data, `'${arg.name}=${JSON.stringify(value)}' is not an expr string`);
} }
hasError = true; hasError = true;
} }
} else if (type === "json") { } else if (isJsonType(type)) {
const isJson = value !== undefined && value !== ""; const isJson = value !== undefined && value !== "";
const isOptional = isNodeArgOptional(arg); const isOptional = isNodeArgOptional(arg);
if (!(isJson || isOptional)) { if (!(isJson || isOptional)) {
@@ -184,6 +198,16 @@ export const checkNodeArgValue = (
} }
hasError = true; hasError = true;
} }
} else if (isBoolType(type)) {
const isBool = typeof value === "boolean" || value === undefined;
if (!isBool) {
if (verbose) {
error(data, `'${arg.name}=${JSON.stringify(value)}' is not a boolean`);
}
hasError = true;
}
} else {
error(data, `unknown arg type '${arg.type}'`);
} }
return !hasError; return !hasError;
@@ -240,8 +264,14 @@ export const checkNodeData = (data: NodeModel | null | undefined) => {
if (!data) { if (!data) {
return false; return false;
} }
let hasError = false;
const conf = useWorkspace.getState().getNodeDef(data.name); const conf = useWorkspace.getState().getNodeDef(data.name);
if (conf.name === unknownNodeDef.name) {
error(data, `undefined node: ${data.name}`);
return false;
}
let hasError = false;
if (conf.children !== undefined && conf.children !== -1) { if (conf.children !== undefined && conf.children !== -1) {
const count = data.children?.length || 0; const count = data.children?.length || 0;
if (conf.children !== count) { if (conf.children !== count) {