Skip to content

Commit 865f47f

Browse files
committed
feat: add type property to input schema for better type representation
1 parent 5ffb52d commit 865f47f

2 files changed

Lines changed: 27 additions & 12 deletions

File tree

src/util/schema.util.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ import {getSubFlows} from "./subflows.util";
1919
export interface Input {
2020
/** The type of input (string representation) */
2121
input?: string;
22+
/**
23+
* The underlying TypeScript type rendered as a string
24+
* (e.g. "NUMBER", "LIST<TEXT>", "string | undefined"), as produced by the
25+
* type checker for the type this schema node was generated from.
26+
*/
27+
type?: string;
2228
/** Array of suggested values (functions, references, or literals) */
2329
suggestions?: (NodeFunction | ReferenceValue | LiteralValue | SubFlowValue)[];
2430
}
@@ -148,6 +154,10 @@ export const getSchema = (
148154
}
149155
}
150156

157+
// The raw TypeScript type as a string, carried on every schema node so the
158+
// consumer knows the concrete type each input was derived from.
159+
const type = checker.typeToString(parameterType);
160+
151161
// Suggestions are filtered by what the surrounding function accepts, not by
152162
// the narrower type a current value happens to narrow the node-side to.
153163
// Example: `<T>(value: T)` with a current boolean literal must still surface
@@ -188,33 +198,33 @@ export const getSchema = (
188198
)
189199
if (nonNullish.length === 1) {
190200
const baseSchema = getSchema(checker, node, nonNullish[0], functionDeclarations, functions, false, undefined, visited, recursionCache)
191-
return {...baseSchema, ...combinedSuggestions}
201+
return {...baseSchema, type, ...combinedSuggestions}
192202
}
193203
}
194204

195205
// Boolean is internally represented by TypeScript as the union `true | false`,
196206
// so it must be detected before the primitive-literal-union check below; otherwise
197207
// `boolean` (and `true | false`) would incorrectly surface as a select.
198208
if (isBoolean(parameterType)) {
199-
return {input: "boolean", ...combinedSuggestions};
209+
return {input: "boolean", type, ...combinedSuggestions};
200210
}
201211

202212
// Check primitive literal union first (e.g., "a" | "b" | "c") or a single
203213
// string/number literal (e.g., "GET"). A bare literal has only one allowed
204214
// value, so it should still surface as a select rather than a free-form text/number input.
205215
if (isPrimitiveLiteralUnion(parameterType) || isStringOrNumberLiteral(parameterType)) {
206-
return {input: "select", ...combinedSuggestions};
216+
return {input: "select", type, ...combinedSuggestions};
207217
}
208218
if (isNumber(parameterType)) {
209-
return {input: "number", ...combinedSuggestions};
219+
return {input: "number", type, ...combinedSuggestions};
210220
}
211221
if (isString(parameterType)) {
212-
return {input: "text", ...combinedSuggestions};
222+
return {input: "text", type, ...combinedSuggestions};
213223
}
214224

215225
// Check if type has call signatures (is callable/sub-flow)
216226
if (isSubFlow(parameterType)) {
217-
return {input: "sub-flow", ...combinedSuggestions};
227+
return {input: "sub-flow", type, ...combinedSuggestions};
218228
}
219229

220230
// Handle array and tuple types
@@ -233,6 +243,7 @@ export const getSchema = (
233243

234244
return {
235245
input: "list",
246+
type,
236247
items: itemSchemas,
237248
...combinedSuggestions,
238249
};
@@ -252,7 +263,7 @@ export const getSchema = (
252263
(visited.size >= MAX_SCHEMA_DEPTH &&
253264
isRecursiveType(parameterType, checker, recursionCache))
254265
) {
255-
return {input: "data", ...combinedSuggestions};
266+
return {input: "data", type, ...combinedSuggestions};
256267
}
257268
visited.add(parameterType);
258269

@@ -304,6 +315,7 @@ export const getSchema = (
304315

305316
return {
306317
input: "data",
318+
type,
307319
properties,
308320
required,
309321
...combinedSuggestions,
@@ -314,6 +326,7 @@ export const getSchema = (
314326
// suggestions (e.g. references in scope) so the UI is never silently empty.
315327
return {
316328
input: "generic",
329+
type,
317330
...combinedSuggestions,
318331
};
319332
};
@@ -435,6 +448,7 @@ const liftGenericIfValued = (schema: Schema, valueProvided: boolean): Schema =>
435448
if (!valueProvided || schema.input !== "generic") return schema;
436449
return {
437450
input: "data",
451+
...(schema.type ? {type: schema.type} : {}),
438452
properties: {},
439453
required: [],
440454
...(schema.suggestions ? {suggestions: schema.suggestions} : {}),
@@ -464,6 +478,7 @@ const demoteSelect = (schema: Schema): Schema => {
464478
: "text";
465479
return {
466480
input: target,
481+
...(schema.type ? {type: schema.type} : {}),
467482
...(suggestions.length > 0 ? {suggestions} : {}),
468483
};
469484
};

test/schema/schema.test.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1100,23 +1100,23 @@ describe("Schema", () => {
11001100
const ret = returnOf("std::boolean::as_number", [
11011101
{value: {__typename: "LiteralValue", value: true}},
11021102
]);
1103-
expect(ret).toEqual({input: "number"});
1103+
expect(ret).toEqual({input: "number", type: "number"});
11041104
});
11051105

11061106
it("resolves a TEXT return to a text input", () => {
11071107
// std::boolean::as_text → (value: BOOLEAN): TEXT
11081108
const ret = returnOf("std::boolean::as_text", [
11091109
{value: {__typename: "LiteralValue", value: true}},
11101110
]);
1111-
expect(ret).toEqual({input: "text"});
1111+
expect(ret).toEqual({input: "text", type: "string"});
11121112
});
11131113

11141114
it("resolves a BOOLEAN return to a boolean input", () => {
11151115
// std::boolean::from_number → (value: NUMBER): BOOLEAN
11161116
const ret = returnOf("std::boolean::from_number", [
11171117
{value: {__typename: "LiteralValue", value: 1}},
11181118
]);
1119-
expect(ret).toEqual({input: "boolean"});
1119+
expect(ret).toEqual({input: "boolean", type: "boolean"});
11201120
});
11211121

11221122
it("resolves an object return (HTTP_RESPONSE) to a data input with its properties", () => {
@@ -1151,7 +1151,7 @@ describe("Schema", () => {
11511151
{value: {__typename: "LiteralValue", value: [10, 20, 30]}},
11521152
{value: {__typename: "LiteralValue", value: 0}},
11531153
]);
1154-
expect(ret).toEqual({input: "number"});
1154+
expect(ret).toEqual({input: "number", type: "number"});
11551155
});
11561156

11571157
it("returns a generic input for a void signature and no nodeId at the flow level", () => {
@@ -1164,7 +1164,7 @@ describe("Schema", () => {
11641164
);
11651165
// Flow-level probe: no target node, flow signature is `(): void`.
11661166
expect(result.nodeId).toBeUndefined();
1167-
expect(result.return).toEqual({input: "generic"});
1167+
expect(result.return).toEqual({input: "generic", type: "void"});
11681168
});
11691169

11701170
it("never carries suggestions, whatever the return type", () => {

0 commit comments

Comments
 (0)