@mawaru/sdk 0.31.0 → 0.32.0
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.
- package/_schemas/graph.test.ts +8 -0
- package/_schemas/port-spec.test.ts +49 -1
- package/_schemas/port-spec.ts +15 -3
- package/dist/_schemas/port-spec.js +13 -3
- package/package.json +1 -1
package/_schemas/graph.test.ts
CHANGED
|
@@ -548,6 +548,14 @@ const outByKey = (node: TestNode, key: string): GraphPort => {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
describe("saveGraphBodySchema(kind 別ポート構成)", () => {
|
|
551
|
+
it("human の追加出口を保存できる", () => {
|
|
552
|
+
const human = humanNode()
|
|
553
|
+
human.ports.push(port("out", "notion_task"))
|
|
554
|
+
expect(() =>
|
|
555
|
+
saveGraphBodySchema.parse({ nodes: [human], connections: [] }),
|
|
556
|
+
).not.toThrow()
|
|
557
|
+
})
|
|
558
|
+
|
|
551
559
|
it("human の担当なし(human 設定の省略)を拒否する", () => {
|
|
552
560
|
const { human: _human, ...noAssign } = humanNode()
|
|
553
561
|
expect(() =>
|
|
@@ -90,7 +90,26 @@ describe("kindPortsViolation(kind 別ポート構成)", () => {
|
|
|
90
90
|
).toBeNull()
|
|
91
91
|
})
|
|
92
92
|
|
|
93
|
-
it("human
|
|
93
|
+
it("human は追加の出口を持てるが基本ポートは必須", () => {
|
|
94
|
+
const ports = [
|
|
95
|
+
port("in", "in"),
|
|
96
|
+
port("out", "approve"),
|
|
97
|
+
port("out", "reject"),
|
|
98
|
+
port("out", "notion_task"),
|
|
99
|
+
]
|
|
100
|
+
expect(kindPortsViolation("human", ports)).toBeNull()
|
|
101
|
+
expect(
|
|
102
|
+
kindPortsViolation(
|
|
103
|
+
"human",
|
|
104
|
+
ports.filter((p) => p.key !== "reject"),
|
|
105
|
+
),
|
|
106
|
+
).toMatch(/human/)
|
|
107
|
+
expect(
|
|
108
|
+
kindPortsViolation("human", [...ports, port("in", "extra")]),
|
|
109
|
+
).toMatch(/human/)
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
it("human は in / approve / reject を持つ", () => {
|
|
94
113
|
expect(
|
|
95
114
|
kindPortsViolation("human", [
|
|
96
115
|
port("in", "in"),
|
|
@@ -132,6 +151,35 @@ describe("kindPortsViolation(kind 別ポート構成)", () => {
|
|
|
132
151
|
})
|
|
133
152
|
|
|
134
153
|
describe("型伝播(導出ポートの解決)", () => {
|
|
154
|
+
it.each([
|
|
155
|
+
"notion_task",
|
|
156
|
+
"main",
|
|
157
|
+
])("Humanの追加出口 %s の宣言型は承認ビューの型で上書きしない", (key) => {
|
|
158
|
+
const extra = port("out", key, {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: { title: { type: "string" } },
|
|
161
|
+
required: ["title"],
|
|
162
|
+
})
|
|
163
|
+
const human = {
|
|
164
|
+
id: uuid(),
|
|
165
|
+
kind: "human",
|
|
166
|
+
ports: [
|
|
167
|
+
port("in", "in"),
|
|
168
|
+
port("out", "approve"),
|
|
169
|
+
port("out", "reject"),
|
|
170
|
+
extra,
|
|
171
|
+
],
|
|
172
|
+
}
|
|
173
|
+
const resolved = resolvePortSchemas([human], [], {
|
|
174
|
+
viewPortSchemasOf: () => ({
|
|
175
|
+
in: { type: "string" },
|
|
176
|
+
approve: { type: "string" },
|
|
177
|
+
reject: { type: "string" },
|
|
178
|
+
}),
|
|
179
|
+
})
|
|
180
|
+
expect(resolved.get(extra.id)).toEqual(extra.schema)
|
|
181
|
+
})
|
|
182
|
+
|
|
135
183
|
// 伝播テスト用の任意の宣言型(中身の形に意味はない)
|
|
136
184
|
const declaredOut = {
|
|
137
185
|
type: "object",
|
package/_schemas/port-spec.ts
CHANGED
|
@@ -139,11 +139,10 @@ export const dataFormatOf = (schema: JsonSchema): DataFormat | null => {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// ---- kind 別ポート構成 ----
|
|
142
|
-
// human
|
|
142
|
+
// wait は構成が固定。human は基本ポートを保ち追加 out を持てる。program / ai は out 自由
|
|
143
143
|
// (key 自由。複数 out=分岐。AIノードの複数出口(分岐).md)
|
|
144
144
|
|
|
145
145
|
const FIXED_PORT_KEYS: Record<string, { in: string[]; out: string[] }> = {
|
|
146
|
-
human: { in: ["in"], out: ["approve", "reject"] },
|
|
147
146
|
wait: { in: ["in"], out: ["main"] },
|
|
148
147
|
// start は in 1つ(run 入力契約)+ out main 1つの恒等パススルー
|
|
149
148
|
start: { in: ["in"], out: ["main"] },
|
|
@@ -199,6 +198,19 @@ export const kindPortsViolation = (
|
|
|
199
198
|
}
|
|
200
199
|
return null
|
|
201
200
|
}
|
|
201
|
+
if (kind === "human") {
|
|
202
|
+
const inKeys = ports.filter((p) => p.io === "in").map((p) => p.key)
|
|
203
|
+
const outKeys = ports.filter((p) => p.io === "out").map((p) => p.key)
|
|
204
|
+
if (
|
|
205
|
+
inKeys.length !== 1 ||
|
|
206
|
+
inKeys[0] !== "in" ||
|
|
207
|
+
!outKeys.includes("approve") ||
|
|
208
|
+
!outKeys.includes("reject")
|
|
209
|
+
) {
|
|
210
|
+
return "human のポート構成は in(in) と out(approve / reject) が必須です(out は追加できます)"
|
|
211
|
+
}
|
|
212
|
+
return null
|
|
213
|
+
}
|
|
202
214
|
const fixed = FIXED_PORT_KEYS[kind]
|
|
203
215
|
if (!fixed) {
|
|
204
216
|
// program / ai(自由 out):in の構成だけ固定
|
|
@@ -334,7 +346,7 @@ const MIRROR_KINDS = new Set(["program", "ai"])
|
|
|
334
346
|
const isDerivedPort = (kind: string, port: Pick<GraphPort, "io" | "key">) =>
|
|
335
347
|
DERIVED_KINDS.has(kind) &&
|
|
336
348
|
(port.io === "in" ||
|
|
337
|
-
port.key === "main" ||
|
|
349
|
+
(kind !== "human" && port.key === "main") ||
|
|
338
350
|
port.key === "approve" ||
|
|
339
351
|
port.key === "reject")
|
|
340
352
|
|
|
@@ -118,10 +118,9 @@ export const dataFormatOf = (schema) => {
|
|
|
118
118
|
return { format: "list", columns };
|
|
119
119
|
};
|
|
120
120
|
// ---- kind 別ポート構成 ----
|
|
121
|
-
// human
|
|
121
|
+
// wait は構成が固定。human は基本ポートを保ち追加 out を持てる。program / ai は out 自由
|
|
122
122
|
// (key 自由。複数 out=分岐。AIノードの複数出口(分岐).md)
|
|
123
123
|
const FIXED_PORT_KEYS = {
|
|
124
|
-
human: { in: ["in"], out: ["approve", "reject"] },
|
|
125
124
|
wait: { in: ["in"], out: ["main"] },
|
|
126
125
|
// start は in 1つ(run 入力契約)+ out main 1つの恒等パススルー
|
|
127
126
|
start: { in: ["in"], out: ["main"] },
|
|
@@ -166,6 +165,17 @@ export const kindPortsViolation = (kind, ports) => {
|
|
|
166
165
|
}
|
|
167
166
|
return null;
|
|
168
167
|
}
|
|
168
|
+
if (kind === "human") {
|
|
169
|
+
const inKeys = ports.filter((p) => p.io === "in").map((p) => p.key);
|
|
170
|
+
const outKeys = ports.filter((p) => p.io === "out").map((p) => p.key);
|
|
171
|
+
if (inKeys.length !== 1 ||
|
|
172
|
+
inKeys[0] !== "in" ||
|
|
173
|
+
!outKeys.includes("approve") ||
|
|
174
|
+
!outKeys.includes("reject")) {
|
|
175
|
+
return "human のポート構成は in(in) と out(approve / reject) が必須です(out は追加できます)";
|
|
176
|
+
}
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
169
179
|
const fixed = FIXED_PORT_KEYS[kind];
|
|
170
180
|
if (!fixed) {
|
|
171
181
|
// program / ai(自由 out):in の構成だけ固定
|
|
@@ -258,7 +268,7 @@ const DERIVED_KINDS = new Set(["wait", "human", "end", "start"]);
|
|
|
258
268
|
const MIRROR_KINDS = new Set(["program", "ai"]);
|
|
259
269
|
const isDerivedPort = (kind, port) => DERIVED_KINDS.has(kind) &&
|
|
260
270
|
(port.io === "in" ||
|
|
261
|
-
port.key === "main" ||
|
|
271
|
+
(kind !== "human" && port.key === "main") ||
|
|
262
272
|
port.key === "approve" ||
|
|
263
273
|
port.key === "reject");
|
|
264
274
|
// port_id → 解決済みスキーマ。導出は接続を遡って固定点まで反復し、
|