@vedangiitb/qwintly-core 1.4.6 → 1.4.8
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/dist/ai/prompts/codegen.prompt.js +2 -2
- package/dist/ai/prompts/codegen.prompt.js.map +1 -1
- package/dist/ai/prompts/examples/codegen.examples.d.ts.map +1 -1
- package/dist/ai/prompts/examples/codegen.examples.js +40 -22
- package/dist/ai/prompts/examples/codegen.examples.js.map +1 -1
- package/dist/ai/tools/implementations/factories.d.ts +40 -2
- package/dist/ai/tools/implementations/factories.d.ts.map +1 -1
- package/dist/ai/tools/implementations/insertElement.impl.d.ts +40 -2
- package/dist/ai/tools/implementations/insertElement.impl.d.ts.map +1 -1
- package/dist/ai/tools/implementations/insertElement.impl.js +67 -8
- package/dist/ai/tools/implementations/insertElement.impl.js.map +1 -1
- package/dist/ai/tools/schemas/insertElement.schema.d.ts +107 -2
- package/dist/ai/tools/schemas/insertElement.schema.d.ts.map +1 -1
- package/dist/ai/tools/schemas/insertElement.schema.js +35 -42
- package/dist/ai/tools/schemas/insertElement.schema.js.map +1 -1
- package/dist/ai/tools/validators/builderElement.zod.d.ts +89 -1
- package/dist/ai/tools/validators/builderElement.zod.d.ts.map +1 -1
- package/dist/ai/tools/validators/builderElement.zod.js +34 -20
- package/dist/ai/tools/validators/builderElement.zod.js.map +1 -1
- package/dist/image/unsplash.service.js +1 -1
- package/dist/image/unsplash.service.js.map +1 -1
- package/dist/tests/insertUpdate.impl.test.js +113 -0
- package/dist/tests/insertUpdate.impl.test.js.map +1 -1
- package/dist/tests/unsplash.service.test.js +2 -0
- package/dist/tests/unsplash.service.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -82,44 +82,9 @@ const BuilderElementPropsSchema = {
|
|
|
82
82
|
},
|
|
83
83
|
},
|
|
84
84
|
};
|
|
85
|
-
// NOTE: Gemini tool `parameters` schemas reject `$ref`, so true recursion isn't available here.
|
|
86
|
-
// We unroll nesting to a reasonable max depth; for deeper trees, insert in multiple steps.
|
|
87
|
-
const buildBuilderElementSchema = (depth) => {
|
|
88
|
-
return {
|
|
89
|
-
type: Type.OBJECT,
|
|
90
|
-
properties: {
|
|
91
|
-
type: {
|
|
92
|
-
type: Type.STRING,
|
|
93
|
-
enum: ELEMENT_TYPES,
|
|
94
|
-
description: "Element type to render. Use 'text' for <p>, 'image' forn <img>, 'link' for <a>, 'icon' for Lucide icon, 'fragment' renders children only",
|
|
95
|
-
},
|
|
96
|
-
className: {
|
|
97
|
-
type: Type.STRING,
|
|
98
|
-
description: "Tailwind CSS className (Tailwind only)",
|
|
99
|
-
},
|
|
100
|
-
visible: {
|
|
101
|
-
type: Type.BOOLEAN,
|
|
102
|
-
description: "Visibility flag",
|
|
103
|
-
},
|
|
104
|
-
props: BuilderElementPropsSchema,
|
|
105
|
-
children: {
|
|
106
|
-
type: Type.ARRAY,
|
|
107
|
-
description: "Child elements. Each child can itself have children (children[].children[]...)",
|
|
108
|
-
items: depth > 0
|
|
109
|
-
? buildBuilderElementSchema(depth - 1)
|
|
110
|
-
: {
|
|
111
|
-
type: Type.OBJECT,
|
|
112
|
-
description: "Max depth reached. Insert deeper children separately using the returned inserted_id as parent_id",
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
required: ["type"],
|
|
117
|
-
};
|
|
118
|
-
};
|
|
119
|
-
export const BuilderElementSchema = buildBuilderElementSchema(4);
|
|
120
85
|
export const InsertElementSchema = {
|
|
121
86
|
name: "insert_element",
|
|
122
|
-
description: "Inserts
|
|
87
|
+
description: "Inserts a tree of UI elements represented as a flat array of elements. One or more elements can have parentId set to 'parent' to be the roots (siblings inserted at the same level). Subsequent children point to their parent using temporary ID references (e.g., parentId set to parent's temporary id).",
|
|
123
88
|
parameters: {
|
|
124
89
|
type: Type.OBJECT,
|
|
125
90
|
properties: {
|
|
@@ -131,18 +96,46 @@ export const InsertElementSchema = {
|
|
|
131
96
|
},
|
|
132
97
|
parent_id: {
|
|
133
98
|
type: Type.STRING,
|
|
134
|
-
description: "The parent
|
|
99
|
+
description: "The parent ID to insert the element tree under.",
|
|
135
100
|
},
|
|
136
101
|
before_id: {
|
|
137
102
|
type: Type.STRING,
|
|
138
|
-
description: "Optional. If provided, inserts the new
|
|
103
|
+
description: "Optional. If provided, inserts the new root elements before the existing child element with this id (within parent_id's children list). If not found, appends at the end.",
|
|
139
104
|
},
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
description: "
|
|
105
|
+
elements: {
|
|
106
|
+
type: Type.ARRAY,
|
|
107
|
+
description: "Flat array of elements that form a tree. One or more elements can have parentId set to 'parent' to attach directly under the parent_id as siblings. Subsequent child elements should have parentId matching the temporary id of their parent in this array.",
|
|
108
|
+
items: {
|
|
109
|
+
type: Type.OBJECT,
|
|
110
|
+
properties: {
|
|
111
|
+
id: {
|
|
112
|
+
type: Type.STRING,
|
|
113
|
+
description: "A unique temporary ID for this element (e.g. 'root_sec', 'card_bg', 'btn_cta') to refer to it in parentId.",
|
|
114
|
+
},
|
|
115
|
+
parentId: {
|
|
116
|
+
type: Type.STRING,
|
|
117
|
+
description: "The temporary ID of the parent element in this list, or 'parent' to insert directly under the page's parent_id.",
|
|
118
|
+
},
|
|
119
|
+
type: {
|
|
120
|
+
type: Type.STRING,
|
|
121
|
+
enum: ELEMENT_TYPES,
|
|
122
|
+
description: "Element type to render. Use 'text' for <p>, 'image' for <img>, 'link' for <a>, 'icon' for Lucide icon, 'fragment' renders children only",
|
|
123
|
+
},
|
|
124
|
+
className: {
|
|
125
|
+
type: Type.STRING,
|
|
126
|
+
description: "Tailwind CSS className (Tailwind only)",
|
|
127
|
+
},
|
|
128
|
+
visible: {
|
|
129
|
+
type: Type.BOOLEAN,
|
|
130
|
+
description: "Visibility flag",
|
|
131
|
+
},
|
|
132
|
+
props: BuilderElementPropsSchema,
|
|
133
|
+
},
|
|
134
|
+
required: ["id", "parentId", "type"],
|
|
135
|
+
},
|
|
143
136
|
},
|
|
144
137
|
},
|
|
145
|
-
required: ["route", "parent_id", "
|
|
138
|
+
required: ["route", "parent_id", "elements"],
|
|
146
139
|
},
|
|
147
140
|
};
|
|
148
141
|
//# sourceMappingURL=insertElement.schema.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insertElement.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/insertElement.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAErC,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,UAAU;IACV,KAAK;IACL,MAAM;IACN,OAAO;IACP,QAAQ;IACR,OAAO;IACP,UAAU;IACV,MAAM;IACN,MAAM;CACE,CAAC;AAEX,MAAM,mBAAmB,GAAG;IAC1B,IAAI,EAAE,IAAI,CAAC,MAAM;IACjB,UAAU,EAAE;QACV,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC;YAC7C,WAAW,EACT,2IAA2I;SAC9I;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,iEAAiE;SACpE;QACD,OAAO,EAAE;YACP,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,WAAW,EAAE,uDAAuD;SACrE;QACD,MAAM,EAAE;YACN,IAAI,EAAE,IAAI,CAAC,OAAO;YAClB,WAAW,EAAE,8CAA8C;SAC5D;KACF;IACD,QAAQ,EAAE,CAAC,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,yBAAyB,GAAG;IAChC,IAAI,EAAE,IAAI,CAAC,MAAM;IACjB,UAAU,EAAE;QACV,OAAO,EAAE,mBAAmB;QAC5B,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,4GAA4G;SAC/G;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,mDAAmD;SACjE;QACD,WAAW,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,2DAA2D;SACzE;QACD,GAAG,EAAE;YACH,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,gIAAgI;SACnI;QACD,MAAM,EAAE;YACN,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,+CAA+C;SAC7D;QACD,GAAG,EAAE;YACH,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,gDAAgD;SAC9D;QACD,KAAK,EAAE;YACL,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,mEAAmE;SACtE;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EACT,iFAAiF;SACpF;QAED,OAAO;QACP,IAAI,EAAE;YACJ,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,2DAA2D;SACzE;QACD,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,yBAAyB,EAAE;QACnE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,2BAA2B,EAAE;QACtE,WAAW,EAAE;YACX,IAAI,EAAE,IAAI,CAAC,MAAM;YACjB,WAAW,EAAE,2BAA2B;SACzC;KACF;CACF,CAAC;AAEF,
|
|
1
|
+
{"version":3,"file":"insertElement.schema.js","sourceRoot":"","sources":["../../../../src/ai/tools/schemas/insertElement.schema.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type } from \"@google/genai\";\n\nexport const ELEMENT_TYPES = [\n \"fragment\",\n \"div\",\n \"text\",\n \"image\",\n \"button\",\n \"input\",\n \"textarea\",\n \"link\",\n \"icon\",\n] as const;\n\nconst OnClickActionSchema = {\n type: Type.OBJECT,\n properties: {\n kind: {\n type: Type.STRING,\n enum: [\"route\", \"back\", \"reload\", \"external\"],\n description:\n \"What happens when the element is clicked. 'route' navigates within the app, 'external' opens a URL, 'back' goes back, 'reload' refreshes.\",\n },\n href: {\n type: Type.STRING,\n description:\n \"URL to navigate to (used for kind='route' and kind='external').\",\n },\n replace: {\n type: Type.BOOLEAN,\n description: \"For kind='route': replace history instead of pushing.\",\n },\n newTab: {\n type: Type.BOOLEAN,\n description: \"For kind='external': open link in a new tab.\",\n },\n },\n required: [\"kind\"],\n};\n\nconst BuilderElementPropsSchema = {\n type: Type.OBJECT,\n properties: {\n onClick: OnClickActionSchema,\n text: {\n type: Type.STRING,\n description:\n \"Text content used by 'text' (<p>), 'button' (label), and as a fallback for 'link' when it has no children.\",\n },\n href: {\n type: Type.STRING,\n description: \"For 'link': the href attribute (defaults to '#').\",\n },\n placeholder: {\n type: Type.STRING,\n description: \"For 'input' and 'textarea': placeholder shown when empty.\",\n },\n alt: {\n type: Type.STRING,\n description:\n \"For 'image': alt text for accessibility AND the query used to fetch a suitable Unsplash image (src is auto-resolved from alt).\",\n },\n target: {\n type: Type.STRING,\n description: \"For 'link': target attribute (e.g. '_blank').\",\n },\n rel: {\n type: Type.STRING,\n description: \"For 'link': rel attribute (e.g. 'noreferrer').\",\n },\n value: {\n type: Type.STRING,\n description:\n \"For 'input' and 'textarea': default value (maps to defaultValue).\",\n },\n type: {\n type: Type.STRING,\n description:\n \"For 'input': input type (e.g. 'text', 'email', 'password'). Defaults to 'text'.\",\n },\n\n // icon\n name: {\n type: Type.STRING,\n description: \"For 'icon': Lucide icon name (e.g. 'ArrowRight', 'Menu').\",\n },\n size: { type: Type.NUMBER, description: \"For 'icon': size in px.\" },\n color: { type: Type.STRING, description: \"For 'icon': stroke color.\" },\n strokeWidth: {\n type: Type.NUMBER,\n description: \"For 'icon': stroke width.\",\n },\n },\n};\n\nexport const InsertElementSchema = {\n name: \"insert_element\",\n description:\n \"Inserts a tree of UI elements represented as a flat array of elements. One or more elements can have parentId set to 'parent' to be the roots (siblings inserted at the same level). Subsequent children point to their parent using temporary ID references (e.g., parentId set to parent's temporary id).\",\n parameters: {\n type: Type.OBJECT,\n properties: {\n route: {\n type: Type.STRING,\n // Accept both \"/about\" and \"about\" (caller might omit the leading slash).\n pattern:\n \"^(?:/(?:[A-Za-z0-9_.[\\\\\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\\\\\]-]+)*)?|[A-Za-z0-9_.[\\\\\\\\\\]-]+(?:/[A-Za-z0-9_.[\\\\\\\\\\]-]+)*)$\",\n description:\n \"The route to insert the element at. Use URL paths with forward slashes only. Examples: '/', '/about', '/pricing'. If you forget the leading '/', it will be assumed (e.g. 'about' -> '/about'). Never send Windows-style backslashes (e.g. '\\\\\\\\') or filesystem paths like 'app/pricing'. Never send empty string.\",\n },\n parent_id: {\n type: Type.STRING,\n description: \"The parent ID to insert the element tree under.\",\n },\n before_id: {\n type: Type.STRING,\n description:\n \"Optional. If provided, inserts the new root elements before the existing child element with this id (within parent_id's children list). If not found, appends at the end.\",\n },\n elements: {\n type: Type.ARRAY,\n description:\n \"Flat array of elements that form a tree. One or more elements can have parentId set to 'parent' to attach directly under the parent_id as siblings. Subsequent child elements should have parentId matching the temporary id of their parent in this array.\",\n items: {\n type: Type.OBJECT,\n properties: {\n id: {\n type: Type.STRING,\n description: \"A unique temporary ID for this element (e.g. 'root_sec', 'card_bg', 'btn_cta') to refer to it in parentId.\",\n },\n parentId: {\n type: Type.STRING,\n description: \"The temporary ID of the parent element in this list, or 'parent' to insert directly under the page's parent_id.\",\n },\n type: {\n type: Type.STRING,\n enum: ELEMENT_TYPES,\n description:\n \"Element type to render. Use 'text' for <p>, 'image' for <img>, 'link' for <a>, 'icon' for Lucide icon, 'fragment' renders children only\",\n },\n className: {\n type: Type.STRING,\n description: \"Tailwind CSS className (Tailwind only)\",\n },\n visible: {\n type: Type.BOOLEAN,\n description: \"Visibility flag\",\n },\n props: BuilderElementPropsSchema,\n },\n required: [\"id\", \"parentId\", \"type\"],\n },\n },\n },\n required: [\"route\", \"parent_id\", \"elements\"],\n },\n};\n"]}
|
|
@@ -14,10 +14,98 @@ export declare const OnClickActionZod: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
14
14
|
newTab: z.ZodOptional<z.ZodBoolean>;
|
|
15
15
|
}, z.core.$strip>], "kind">;
|
|
16
16
|
export declare const BuilderElementZod: z.ZodType<any>;
|
|
17
|
+
export declare const FlatBuilderElementZod: z.ZodObject<{
|
|
18
|
+
id: z.ZodString;
|
|
19
|
+
parentId: z.ZodString;
|
|
20
|
+
type: z.ZodEnum<{
|
|
21
|
+
input: "input";
|
|
22
|
+
fragment: "fragment";
|
|
23
|
+
div: "div";
|
|
24
|
+
text: "text";
|
|
25
|
+
image: "image";
|
|
26
|
+
button: "button";
|
|
27
|
+
textarea: "textarea";
|
|
28
|
+
link: "link";
|
|
29
|
+
icon: "icon";
|
|
30
|
+
}>;
|
|
31
|
+
className: z.ZodOptional<z.ZodString>;
|
|
32
|
+
visible: z.ZodOptional<z.ZodBoolean>;
|
|
33
|
+
props: z.ZodOptional<z.ZodObject<{
|
|
34
|
+
onClick: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
35
|
+
kind: z.ZodLiteral<"route">;
|
|
36
|
+
href: z.ZodPipe<z.ZodTransform<string, unknown>, z.ZodString>;
|
|
37
|
+
replace: z.ZodOptional<z.ZodBoolean>;
|
|
38
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
39
|
+
kind: z.ZodLiteral<"back">;
|
|
40
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
41
|
+
kind: z.ZodLiteral<"reload">;
|
|
42
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
43
|
+
kind: z.ZodLiteral<"external">;
|
|
44
|
+
href: z.ZodString;
|
|
45
|
+
newTab: z.ZodOptional<z.ZodBoolean>;
|
|
46
|
+
}, z.core.$strip>], "kind">>;
|
|
47
|
+
text: z.ZodOptional<z.ZodString>;
|
|
48
|
+
href: z.ZodOptional<z.ZodString>;
|
|
49
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
50
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
51
|
+
target: z.ZodOptional<z.ZodString>;
|
|
52
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
53
|
+
value: z.ZodOptional<z.ZodString>;
|
|
54
|
+
type: z.ZodOptional<z.ZodString>;
|
|
55
|
+
name: z.ZodOptional<z.ZodString>;
|
|
56
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
57
|
+
color: z.ZodOptional<z.ZodString>;
|
|
58
|
+
strokeWidth: z.ZodOptional<z.ZodNumber>;
|
|
59
|
+
}, z.core.$loose>>;
|
|
60
|
+
}, z.core.$strip>;
|
|
17
61
|
export declare const InsertElementArgsZod: z.ZodObject<{
|
|
18
62
|
route: z.ZodPipe<z.ZodTransform<string, unknown>, z.ZodString>;
|
|
19
63
|
parent_id: z.ZodString;
|
|
20
64
|
before_id: z.ZodOptional<z.ZodString>;
|
|
21
|
-
element: z.ZodType<any, unknown, z.core.$ZodTypeInternals<any, unknown
|
|
65
|
+
element: z.ZodOptional<z.ZodType<any, unknown, z.core.$ZodTypeInternals<any, unknown>>>;
|
|
66
|
+
elements: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
67
|
+
id: z.ZodString;
|
|
68
|
+
parentId: z.ZodString;
|
|
69
|
+
type: z.ZodEnum<{
|
|
70
|
+
input: "input";
|
|
71
|
+
fragment: "fragment";
|
|
72
|
+
div: "div";
|
|
73
|
+
text: "text";
|
|
74
|
+
image: "image";
|
|
75
|
+
button: "button";
|
|
76
|
+
textarea: "textarea";
|
|
77
|
+
link: "link";
|
|
78
|
+
icon: "icon";
|
|
79
|
+
}>;
|
|
80
|
+
className: z.ZodOptional<z.ZodString>;
|
|
81
|
+
visible: z.ZodOptional<z.ZodBoolean>;
|
|
82
|
+
props: z.ZodOptional<z.ZodObject<{
|
|
83
|
+
onClick: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
84
|
+
kind: z.ZodLiteral<"route">;
|
|
85
|
+
href: z.ZodPipe<z.ZodTransform<string, unknown>, z.ZodString>;
|
|
86
|
+
replace: z.ZodOptional<z.ZodBoolean>;
|
|
87
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
88
|
+
kind: z.ZodLiteral<"back">;
|
|
89
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
90
|
+
kind: z.ZodLiteral<"reload">;
|
|
91
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
92
|
+
kind: z.ZodLiteral<"external">;
|
|
93
|
+
href: z.ZodString;
|
|
94
|
+
newTab: z.ZodOptional<z.ZodBoolean>;
|
|
95
|
+
}, z.core.$strip>], "kind">>;
|
|
96
|
+
text: z.ZodOptional<z.ZodString>;
|
|
97
|
+
href: z.ZodOptional<z.ZodString>;
|
|
98
|
+
placeholder: z.ZodOptional<z.ZodString>;
|
|
99
|
+
alt: z.ZodOptional<z.ZodString>;
|
|
100
|
+
target: z.ZodOptional<z.ZodString>;
|
|
101
|
+
rel: z.ZodOptional<z.ZodString>;
|
|
102
|
+
value: z.ZodOptional<z.ZodString>;
|
|
103
|
+
type: z.ZodOptional<z.ZodString>;
|
|
104
|
+
name: z.ZodOptional<z.ZodString>;
|
|
105
|
+
size: z.ZodOptional<z.ZodNumber>;
|
|
106
|
+
color: z.ZodOptional<z.ZodString>;
|
|
107
|
+
strokeWidth: z.ZodOptional<z.ZodNumber>;
|
|
108
|
+
}, z.core.$loose>>;
|
|
109
|
+
}, z.core.$strip>>>;
|
|
22
110
|
}, z.core.$strip>;
|
|
23
111
|
//# sourceMappingURL=builderElement.zod.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builderElement.zod.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/validators/builderElement.zod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,8FAUhB,CAAC;AAoBX,eAAO,MAAM,gBAAgB;;;;;;;;;;;;2BAsB3B,CAAC;
|
|
1
|
+
{"version":3,"file":"builderElement.zod.d.ts","sourceRoot":"","sources":["../../../../src/ai/tools/validators/builderElement.zod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,aAAa,8FAUhB,CAAC;AAoBX,eAAO,MAAM,gBAAgB;;;;;;;;;;;;2BAsB3B,CAAC;AAoBH,eAAO,MAAM,iBAAiB,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAM3C,CAAC;AAEH,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAOhC,CAAC;AAEH,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuB9B,CAAC"}
|
|
@@ -50,31 +50,40 @@ export const OnClickActionZod = z.discriminatedUnion("kind", [
|
|
|
50
50
|
newTab: z.boolean().optional(),
|
|
51
51
|
}),
|
|
52
52
|
]);
|
|
53
|
+
const BuilderElementPropsZod = z
|
|
54
|
+
.object({
|
|
55
|
+
onClick: OnClickActionZod.optional(),
|
|
56
|
+
text: z.string().optional(),
|
|
57
|
+
href: z.string().optional(),
|
|
58
|
+
placeholder: z.string().optional(),
|
|
59
|
+
alt: z.string().optional(),
|
|
60
|
+
target: z.string().optional(),
|
|
61
|
+
rel: z.string().optional(),
|
|
62
|
+
value: z.string().optional(),
|
|
63
|
+
type: z.string().optional(),
|
|
64
|
+
name: z.string().optional(),
|
|
65
|
+
size: z.number().optional(),
|
|
66
|
+
color: z.string().optional(),
|
|
67
|
+
strokeWidth: z.number().optional(),
|
|
68
|
+
})
|
|
69
|
+
.passthrough();
|
|
53
70
|
export const BuilderElementZod = z.object({
|
|
54
71
|
type: z.enum(ELEMENT_TYPES),
|
|
55
72
|
className: z.string().optional(),
|
|
56
73
|
visible: z.boolean().optional(),
|
|
57
|
-
props:
|
|
58
|
-
.object({
|
|
59
|
-
onClick: OnClickActionZod.optional(),
|
|
60
|
-
text: z.string().optional(),
|
|
61
|
-
href: z.string().optional(),
|
|
62
|
-
placeholder: z.string().optional(),
|
|
63
|
-
alt: z.string().optional(),
|
|
64
|
-
target: z.string().optional(),
|
|
65
|
-
rel: z.string().optional(),
|
|
66
|
-
value: z.string().optional(),
|
|
67
|
-
type: z.string().optional(),
|
|
68
|
-
name: z.string().optional(),
|
|
69
|
-
size: z.number().optional(),
|
|
70
|
-
color: z.string().optional(),
|
|
71
|
-
strokeWidth: z.number().optional(),
|
|
72
|
-
})
|
|
73
|
-
.passthrough()
|
|
74
|
-
.optional(),
|
|
74
|
+
props: BuilderElementPropsZod.optional(),
|
|
75
75
|
children: z.array(z.lazy(() => BuilderElementZod)).optional(),
|
|
76
76
|
});
|
|
77
|
-
export const
|
|
77
|
+
export const FlatBuilderElementZod = z.object({
|
|
78
|
+
id: z.string().min(1),
|
|
79
|
+
parentId: z.string().min(1),
|
|
80
|
+
type: z.enum(ELEMENT_TYPES),
|
|
81
|
+
className: z.string().optional(),
|
|
82
|
+
visible: z.boolean().optional(),
|
|
83
|
+
props: BuilderElementPropsZod.optional(),
|
|
84
|
+
});
|
|
85
|
+
export const InsertElementArgsZod = z
|
|
86
|
+
.object({
|
|
78
87
|
route: z.preprocess(normalizeInternalRoutePath, z
|
|
79
88
|
.string()
|
|
80
89
|
.min(1)
|
|
@@ -83,6 +92,11 @@ export const InsertElementArgsZod = z.object({
|
|
|
83
92
|
})),
|
|
84
93
|
parent_id: z.string().min(1),
|
|
85
94
|
before_id: z.string().min(1).optional(),
|
|
86
|
-
element: BuilderElementZod,
|
|
95
|
+
element: BuilderElementZod.optional(),
|
|
96
|
+
elements: z.array(FlatBuilderElementZod).min(1).optional(),
|
|
97
|
+
})
|
|
98
|
+
.refine((data) => data.element !== undefined || data.elements !== undefined, {
|
|
99
|
+
message: "Either 'element' or 'elements' must be provided",
|
|
100
|
+
path: ["element"],
|
|
87
101
|
});
|
|
88
102
|
//# sourceMappingURL=builderElement.zod.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builderElement.zod.js","sourceRoot":"","sources":["../../../../src/ai/tools/validators/builderElement.zod.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,UAAU;IACV,KAAK;IACL,MAAM;IACN,OAAO;IACP,QAAQ;IACR,OAAO;IACP,UAAU;IACV,MAAM;IACN,MAAM;CACE,CAAC;AAEX,MAAM,0BAA0B,GAAG,CAAC,KAAc,EAAE,EAAE;IACpD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAC;IACpB,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC5C,IAAI,WAAW,KAAK,GAAG;QAAE,OAAO,GAAG,CAAC;IACpC,IAAI,WAAW,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,WAAW,CAAC;IACpD,gFAAgF;IAChF,OAAO,IAAI,WAAW,EAAE,CAAC;AAC3B,CAAC,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,KAAa,EAAE,EAAE;IAC5C,MAAM,CAAC,GAAG,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC5C,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACnC,iGAAiG;IACjG,OAAO,sDAAsD,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACxE,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAC3D,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;QACxB,IAAI,EAAE,CAAC,CAAC,UAAU,CAChB,0BAA0B,EAC1B,CAAC;aACE,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,MAAM,CAAC,mBAAmB,EAAE;YAC3B,OAAO,EACL,mGAAmG;SACtG,CAAC,CACL;QACD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KAChC,CAAC;IACF,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;IACrC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;IACvC,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;QAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACvB,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KAC/B,CAAC;CACH,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"builderElement.zod.js","sourceRoot":"","sources":["../../../../src/ai/tools/validators/builderElement.zod.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\n\nexport const ELEMENT_TYPES = [\n \"fragment\",\n \"div\",\n \"text\",\n \"image\",\n \"button\",\n \"input\",\n \"textarea\",\n \"link\",\n \"icon\",\n] as const;\n\nconst normalizeInternalRoutePath = (value: unknown) => {\n const raw = String(value ?? \"\").trim();\n if (!raw) return \"\";\n const forwardOnly = raw.replace(/\\\\/g, \"/\");\n if (forwardOnly === \"/\") return \"/\";\n if (forwardOnly.startsWith(\"/\")) return forwardOnly;\n // Fallback: if caller forgot the leading slash, assume they meant an app route.\n return `/${forwardOnly}`;\n};\n\nconst isInternalRoutePath = (value: string) => {\n const s = normalizeInternalRoutePath(value);\n if (!s) return false;\n if (s.includes(\"\\\\\")) return false;\n // Allow \"/\" or \"/a\" or \"/a/b-c_d\" or \"/product/[id]\" or \"/blog/[...slug]\" or \"/blog/[[...slug]]\"\n return /^\\/(?:[A-Za-z0-9_.[\\]-]+(?:\\/[A-Za-z0-9_.[\\]-]+)*)?$/.test(s);\n};\n\nexport const OnClickActionZod = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"route\"),\n href: z.preprocess(\n normalizeInternalRoutePath,\n z\n .string()\n .min(1)\n .refine(isInternalRoutePath, {\n message:\n \"href must be an internal route path like '/' or '/pricing' (forward slashes only; no backslashes)\",\n }),\n ),\n replace: z.boolean().optional(),\n }),\n z.object({ kind: z.literal(\"back\") }),\n z.object({ kind: z.literal(\"reload\") }),\n z.object({\n kind: z.literal(\"external\"),\n href: z.string().min(1),\n newTab: z.boolean().optional(),\n }),\n]);\n\nconst BuilderElementPropsZod = z\n .object({\n onClick: OnClickActionZod.optional(),\n text: z.string().optional(),\n href: z.string().optional(),\n placeholder: z.string().optional(),\n alt: z.string().optional(),\n target: z.string().optional(),\n rel: z.string().optional(),\n value: z.string().optional(),\n type: z.string().optional(),\n name: z.string().optional(),\n size: z.number().optional(),\n color: z.string().optional(),\n strokeWidth: z.number().optional(),\n })\n .passthrough();\n\nexport const BuilderElementZod: z.ZodType<any> = z.object({\n type: z.enum(ELEMENT_TYPES),\n className: z.string().optional(),\n visible: z.boolean().optional(),\n props: BuilderElementPropsZod.optional(),\n children: z.array(z.lazy(() => BuilderElementZod)).optional(),\n});\n\nexport const FlatBuilderElementZod = z.object({\n id: z.string().min(1),\n parentId: z.string().min(1),\n type: z.enum(ELEMENT_TYPES),\n className: z.string().optional(),\n visible: z.boolean().optional(),\n props: BuilderElementPropsZod.optional(),\n});\n\nexport const InsertElementArgsZod = z\n .object({\n route: z.preprocess(\n normalizeInternalRoutePath,\n z\n .string()\n .min(1)\n .refine(isInternalRoutePath, {\n message:\n \"route must be like '/' or '/about' (forward slashes only; no backslashes)\",\n }),\n ),\n parent_id: z.string().min(1),\n before_id: z.string().min(1).optional(),\n element: BuilderElementZod.optional(),\n elements: z.array(FlatBuilderElementZod).min(1).optional(),\n })\n .refine(\n (data) => data.element !== undefined || data.elements !== undefined,\n {\n message: \"Either 'element' or 'elements' must be provided\",\n path: [\"element\"],\n },\n );\n"]}
|
|
@@ -49,7 +49,7 @@ export async function searchUnsplashImage(imgQuery) {
|
|
|
49
49
|
return cached;
|
|
50
50
|
}
|
|
51
51
|
const params = new URLSearchParams({
|
|
52
|
-
imgQuery,
|
|
52
|
+
query: imgQuery,
|
|
53
53
|
per_page: "10",
|
|
54
54
|
});
|
|
55
55
|
const response = await fetchWithTimeout(`${cfg.url}/search/photos?${params.toString()}`, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsplash.service.js","sourceRoot":"","sources":["../../src/image/unsplash.service.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAoB5B,IAAI,cAAc,GAA0B,IAAI,CAAC;AAEjD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAyB,CAAC;AAE/C,KAAK,UAAU,gBAAgB,CAC7B,GAAW,EACX,UAAuB,EAAE;IAEzB,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,MAAM,EAAE,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;IACtD,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,GAAG,EAAE;YACtB,GAAG,OAAO;YACV,MAAM,EAAE,UAAU,CAAC,MAAM;SAC1B,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAAkD;IAElD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAEzD,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;QACvB,cAAc,GAAG,IAAI,CAAC;QACtB,OAAO;IACT,CAAC;IAED,cAAc,GAAG;QACf,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5B,SAAS;KACV,CAAC;AACJ,CAAC;AAED,SAAS,UAAU,CAAC,QAAgB;IAClC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,UAAU,CAAC,KAAU;IAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,KAAK,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,GAAG,CAAC;IAElC,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC/B,KAAK,IAAI,EAAE,CAAC;IACd,CAAC;IAED,KAAK,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC;IAE/C,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB;IAEhB,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,cAAc,CAAC;IAC3B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAErD,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAEtC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEnC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QACjC,QAAQ;
|
|
1
|
+
{"version":3,"file":"unsplash.service.js","sourceRoot":"","sources":["../../src/image/unsplash.service.ts"],"names":[],"mappings":"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","sourcesContent":["import crypto from \"crypto\";\r\nimport { BuilderElement } from \"../types/elements.js\";\r\n\r\nexport interface ResolvedImage {\r\n id: string;\r\n alt: string;\r\n imageUrl: string;\r\n thumbUrl: string;\r\n photographer: string;\r\n photographerUrl: string;\r\n unsplashUrl: string;\r\n width: number;\r\n height: number;\r\n}\r\n\r\ntype UnsplashConfig = {\r\n url: string;\r\n accessKey: string;\r\n};\r\n\r\nlet unsplashConfig: UnsplashConfig | null = null;\r\n\r\nconst cache = new Map<string, ResolvedImage>();\r\n\r\nasync function fetchWithTimeout(\r\n url: string,\r\n options: RequestInit = {},\r\n): Promise<Response> {\r\n const controller = new AbortController();\r\n const id = setTimeout(() => controller.abort(), 5000);\r\n try {\r\n return await fetch(url, {\r\n ...options,\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport function initUnsplash(\r\n config: Partial<UnsplashConfig> | null | undefined,\r\n) {\r\n const url = String(config?.url ?? \"\").trim();\r\n const accessKey = String(config?.accessKey ?? \"\").trim();\r\n\r\n if (!url || !accessKey) {\r\n unsplashConfig = null;\r\n return;\r\n }\r\n\r\n unsplashConfig = {\r\n url: url.replace(/\\/+$/, \"\"),\r\n accessKey,\r\n };\r\n}\r\n\r\nfunction hashIntent(imgQuery: string) {\r\n return crypto.createHash(\"sha256\").update(imgQuery).digest(\"hex\");\r\n}\r\n\r\nfunction scoreImage(photo: any) {\r\n let score = 0;\r\n\r\n score += (photo.likes || 0) * 0.3;\r\n\r\n if (photo.width > photo.height) {\r\n score += 50;\r\n }\r\n\r\n score += (photo.user.total_photos || 0) * 0.05;\r\n\r\n return score;\r\n}\r\n\r\nexport async function searchUnsplashImage(\r\n imgQuery: string,\r\n): Promise<ResolvedImage | null> {\r\n console.log(\"searchUnsplashImage\", imgQuery);\r\n const cfg = unsplashConfig;\r\n if (!cfg) throw new Error(\"Unsplash not configured\");\r\n\r\n const cacheKey = hashIntent(imgQuery);\r\n\r\n const cached = cache.get(cacheKey);\r\n\r\n if (cached) {\r\n return cached;\r\n }\r\n\r\n const params = new URLSearchParams({\r\n query: imgQuery,\r\n per_page: \"10\",\r\n });\r\n\r\n const response = await fetchWithTimeout(\r\n `${cfg.url}/search/photos?${params.toString()}`,\r\n {\r\n headers: {\r\n Authorization: `Client-ID ${cfg.accessKey}`,\r\n },\r\n },\r\n );\r\n\r\n if (!response.ok) {\r\n throw new Error(`Unsplash API failed: ${response.status}`);\r\n }\r\n\r\n const data = await response.json();\r\n\r\n const photos = data.results;\r\n\r\n if (!photos.length) {\r\n return null;\r\n }\r\n\r\n const ranked = [...photos].sort((a, b) => {\r\n return scoreImage(b) - scoreImage(a);\r\n });\r\n\r\n const top3 = ranked.slice(0, 3);\r\n\r\n const selected = top3[Math.floor(Math.random() * top3.length)];\r\n\r\n // IMPORTANT:\r\n // Required by Unsplash API terms\r\n // Tracks image download usage\r\n if (selected.links.download_location) {\r\n await fetchWithTimeout(selected.links.download_location, {\r\n headers: {\r\n Authorization: `Client-ID ${cfg.accessKey}`,\r\n },\r\n });\r\n }\r\n\r\n const resolved: ResolvedImage = {\r\n id: selected.id,\r\n alt: imgQuery,\r\n\r\n imageUrl: selected.urls.regular,\r\n thumbUrl: selected.urls.small,\r\n\r\n photographer: selected.user.name,\r\n photographerUrl: selected.user.links.html,\r\n\r\n unsplashUrl: selected.links.html,\r\n\r\n width: selected.width,\r\n height: selected.height,\r\n };\r\n\r\n cache.set(cacheKey, resolved);\r\n\r\n return resolved;\r\n}\r\n\r\nexport const resolveUnsplashImageForElement = async (\r\n el: BuilderElement,\r\n alt: string,\r\n): Promise<void> => {\r\n if (!unsplashConfig) return;\r\n const query = String(alt ?? \"\").trim();\r\n if (!query) return;\r\n if (el.props?.src) {\r\n console.log(\"src already exists, skipping\");\r\n return;\r\n }\r\n try {\r\n const resolved = await searchUnsplashImage(query);\r\n if (!resolved?.imageUrl) {\r\n console.log(resolved);\r\n return;\r\n }\r\n\r\n const anyEl = el as any;\r\n if (!anyEl.props || typeof anyEl.props !== \"object\") anyEl.props = {};\r\n anyEl.props.src = resolved.imageUrl;\r\n anyEl.props.alt = query;\r\n } catch (error) {\r\n console.error(error);\r\n // Ignore Unsplash lookup errors and still allow prop updates.\r\n }\r\n};\r\n\r\nexport const resolveUnsplashImagesDeep = async (\r\n el: BuilderElement,\r\n): Promise<void> => {\r\n const anyEl = el as any;\r\n\r\n if (anyEl?.type === \"image\") {\r\n const alt = String(anyEl?.props?.alt ?? \"\").trim();\r\n await resolveUnsplashImageForElement(el, alt);\r\n }\r\n\r\n const kids = anyEl?.children;\r\n if (Array.isArray(kids)) {\r\n for (const child of kids) {\r\n await resolveUnsplashImagesDeep(child);\r\n }\r\n }\r\n};\r\n"]}
|
|
@@ -170,4 +170,117 @@ test("dynamic/nested routes resolution in tools", async () => {
|
|
|
170
170
|
await fs.rm(workspaceRoot, { recursive: true, force: true });
|
|
171
171
|
}
|
|
172
172
|
});
|
|
173
|
+
test("insert tool: supports flat elements list with parent-child mapping", async () => {
|
|
174
|
+
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qwintly-core-flat-"));
|
|
175
|
+
try {
|
|
176
|
+
const routeDir = path.join(workspaceRoot, "app", "flat-test");
|
|
177
|
+
await fs.mkdir(routeDir, { recursive: true });
|
|
178
|
+
const filePath = path.join(routeDir, "pageConfig.json");
|
|
179
|
+
await fs.writeFile(filePath, JSON.stringify({
|
|
180
|
+
elements: [
|
|
181
|
+
{
|
|
182
|
+
id: "root",
|
|
183
|
+
type: "div",
|
|
184
|
+
children: [],
|
|
185
|
+
},
|
|
186
|
+
],
|
|
187
|
+
}, null, 2) + "\n", "utf-8");
|
|
188
|
+
const deps = { workspaceRoot, fs: makeRealFs() };
|
|
189
|
+
const insert = createInsertElementImpl(deps);
|
|
190
|
+
// Call insert using the flat elements format
|
|
191
|
+
const inserted = await insert({
|
|
192
|
+
route: "/flat-test",
|
|
193
|
+
parent_id: "root",
|
|
194
|
+
elements: [
|
|
195
|
+
{
|
|
196
|
+
id: "container",
|
|
197
|
+
parentId: "parent",
|
|
198
|
+
type: "div",
|
|
199
|
+
className: "bg-red-500",
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
id: "heading",
|
|
203
|
+
parentId: "container",
|
|
204
|
+
type: "text",
|
|
205
|
+
props: { text: "Hello from Flat List" },
|
|
206
|
+
},
|
|
207
|
+
],
|
|
208
|
+
});
|
|
209
|
+
assert.equal(inserted.success, true, `unexpected response: ${JSON.stringify(inserted)}`);
|
|
210
|
+
const after = JSON.parse(await fs.readFile(filePath, "utf-8"));
|
|
211
|
+
const children = after.elements[0].children;
|
|
212
|
+
assert.equal(children.length, 1);
|
|
213
|
+
const insertedContainer = children[0];
|
|
214
|
+
assert.equal(insertedContainer.className, "bg-red-500");
|
|
215
|
+
assert.equal(insertedContainer.type, "div");
|
|
216
|
+
// Verify children inside the container
|
|
217
|
+
assert.equal(insertedContainer.children.length, 1);
|
|
218
|
+
const insertedHeading = insertedContainer.children[0];
|
|
219
|
+
assert.equal(insertedHeading.type, "text");
|
|
220
|
+
assert.equal(insertedHeading.props.text, "Hello from Flat List");
|
|
221
|
+
// Verify that proper real IDs starting with el_ were generated
|
|
222
|
+
assert.ok(insertedContainer.id.startsWith("el_"));
|
|
223
|
+
assert.ok(insertedHeading.id.startsWith("el_"));
|
|
224
|
+
}
|
|
225
|
+
finally {
|
|
226
|
+
await fs.rm(workspaceRoot, { recursive: true, force: true });
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
test("insert tool: supports multiple sibling root elements in flat array", async () => {
|
|
230
|
+
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qwintly-core-multi-flat-"));
|
|
231
|
+
try {
|
|
232
|
+
const routeDir = path.join(workspaceRoot, "app", "multi-flat-test");
|
|
233
|
+
await fs.mkdir(routeDir, { recursive: true });
|
|
234
|
+
const filePath = path.join(routeDir, "pageConfig.json");
|
|
235
|
+
await fs.writeFile(filePath, JSON.stringify({
|
|
236
|
+
elements: [
|
|
237
|
+
{
|
|
238
|
+
id: "root",
|
|
239
|
+
type: "div",
|
|
240
|
+
children: [],
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
}, null, 2) + "\n", "utf-8");
|
|
244
|
+
const deps = { workspaceRoot, fs: makeRealFs() };
|
|
245
|
+
const insert = createInsertElementImpl(deps);
|
|
246
|
+
// Call insert with two sibling root elements
|
|
247
|
+
const inserted = await insert({
|
|
248
|
+
route: "/multi-flat-test",
|
|
249
|
+
parent_id: "root",
|
|
250
|
+
elements: [
|
|
251
|
+
{
|
|
252
|
+
id: "card_1",
|
|
253
|
+
parentId: "parent",
|
|
254
|
+
type: "div",
|
|
255
|
+
className: "card-1",
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
id: "card_2",
|
|
259
|
+
parentId: "parent",
|
|
260
|
+
type: "div",
|
|
261
|
+
className: "card-2",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
id: "heading_1",
|
|
265
|
+
parentId: "card_1",
|
|
266
|
+
type: "text",
|
|
267
|
+
props: { text: "Heading 1" },
|
|
268
|
+
},
|
|
269
|
+
],
|
|
270
|
+
});
|
|
271
|
+
assert.equal(inserted.success, true, `unexpected response: ${JSON.stringify(inserted)}`);
|
|
272
|
+
assert.ok(Array.isArray(inserted.inserted_ids));
|
|
273
|
+
assert.equal(inserted.inserted_ids.length, 2);
|
|
274
|
+
const after = JSON.parse(await fs.readFile(filePath, "utf-8"));
|
|
275
|
+
const children = after.elements[0].children;
|
|
276
|
+
assert.equal(children.length, 2);
|
|
277
|
+
assert.equal(children[0].className, "card-1");
|
|
278
|
+
assert.equal(children[1].className, "card-2");
|
|
279
|
+
assert.equal(children[0].children.length, 1);
|
|
280
|
+
assert.equal(children[0].children[0].props.text, "Heading 1");
|
|
281
|
+
}
|
|
282
|
+
finally {
|
|
283
|
+
await fs.rm(workspaceRoot, { recursive: true, force: true });
|
|
284
|
+
}
|
|
285
|
+
});
|
|
173
286
|
//# sourceMappingURL=insertUpdate.impl.test.js.map
|