@vedangiitb/qwintly-core 1.4.3 → 1.4.5
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/tools/helpers/pageConfigJson.helpers.d.ts +3 -0
- package/dist/ai/tools/helpers/pageConfigJson.helpers.d.ts.map +1 -1
- package/dist/ai/tools/helpers/pageConfigJson.helpers.js +61 -0
- package/dist/ai/tools/helpers/pageConfigJson.helpers.js.map +1 -1
- package/dist/ai/tools/implementations/deleteElement.impl.js +2 -2
- package/dist/ai/tools/implementations/deleteElement.impl.js.map +1 -1
- package/dist/ai/tools/implementations/insertElement.impl.js +2 -2
- package/dist/ai/tools/implementations/insertElement.impl.js.map +1 -1
- package/dist/ai/tools/implementations/updateClassName.impl.js +2 -2
- package/dist/ai/tools/implementations/updateClassName.impl.js.map +1 -1
- package/dist/ai/tools/implementations/updateProps.impl.js +2 -2
- package/dist/ai/tools/implementations/updateProps.impl.js.map +1 -1
- package/dist/ai/tools/schemas/createNewRoute.schema.js +1 -1
- package/dist/ai/tools/schemas/createNewRoute.schema.js.map +1 -1
- package/dist/ai/tools/schemas/deleteElement.schema.js +1 -1
- package/dist/ai/tools/schemas/deleteElement.schema.js.map +1 -1
- package/dist/ai/tools/schemas/insertElement.schema.js +1 -1
- package/dist/ai/tools/schemas/insertElement.schema.js.map +1 -1
- package/dist/ai/tools/schemas/updateClassName.schema.js +1 -1
- package/dist/ai/tools/schemas/updateClassName.schema.js.map +1 -1
- package/dist/ai/tools/schemas/updateProps.schema.js +1 -1
- package/dist/ai/tools/schemas/updateProps.schema.js.map +1 -1
- package/dist/ai/tools/validators/builderElement.zod.js +2 -2
- 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/indexer/projectInfoIndex.d.ts.map +1 -1
- package/dist/indexer/projectInfoIndex.js +70 -203
- package/dist/indexer/projectInfoIndex.js.map +1 -1
- package/dist/tests/insertUpdate.impl.test.js +93 -0
- package/dist/tests/insertUpdate.impl.test.js.map +1 -1
- package/dist/tests/projectInfoIndex.test.d.ts +2 -0
- package/dist/tests/projectInfoIndex.test.d.ts.map +1 -0
- package/dist/tests/projectInfoIndex.test.js +75 -0
- package/dist/tests/projectInfoIndex.test.js.map +1 -0
- package/dist/tests/unsplash.service.test.d.ts +2 -0
- package/dist/tests/unsplash.service.test.d.ts.map +1 -0
- package/dist/tests/unsplash.service.test.js +94 -0
- package/dist/tests/unsplash.service.test.js.map +1 -0
- package/package.json +1 -1
|
@@ -122,7 +122,7 @@ export const resolveUnsplashImagesDeep = async (el) => {
|
|
|
122
122
|
const anyEl = el;
|
|
123
123
|
if (anyEl?.type === "image") {
|
|
124
124
|
const alt = String(anyEl?.props?.alt ?? "").trim();
|
|
125
|
-
resolveUnsplashImageForElement(el, alt);
|
|
125
|
+
await resolveUnsplashImageForElement(el, alt);
|
|
126
126
|
}
|
|
127
127
|
const kids = anyEl?.children;
|
|
128
128
|
if (Array.isArray(kids)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unsplash.service.js","sourceRoot":"","sources":["../../src/image/unsplash.service.ts"],"names":[],"mappings":"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
|
|
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(url: string, options: RequestInit = {}): 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 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) return;\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 {\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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectInfoIndex.d.ts","sourceRoot":"","sources":["../../src/indexer/projectInfoIndex.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"projectInfoIndex.d.ts","sourceRoot":"","sources":["../../src/indexer/projectInfoIndex.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAyF5D,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,CAAC,CAkDtB"}
|
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { getAvailableRoutes, getPageConfigJsonPath, } from "../ai/tools/helpers/pageConfigJson.helpers.js";
|
|
2
2
|
import { readFile, safeReadDir } from "../utils/workspace.js";
|
|
3
|
-
const isRouteGroup = (segment) => segment.startsWith("(") && segment.endsWith(")");
|
|
4
|
-
const isParallelRoute = (segment) => segment.startsWith("@");
|
|
5
|
-
const toPosixPath = (p) => p.replace(/\\/g, "/");
|
|
6
|
-
const extractQuotedString = (match) => {
|
|
7
|
-
if (!match)
|
|
8
|
-
return "";
|
|
9
|
-
return String(match[1] ?? match[2] ?? match[3] ?? "").trim();
|
|
10
|
-
};
|
|
11
|
-
const extractPropString = (objText, prop) => {
|
|
12
|
-
const re = prop === "id"
|
|
13
|
-
? /\bid\s*:\s*(?:"([^"]+)"|'([^']+)'|`([^`]+)`)/
|
|
14
|
-
: /\btype\s*:\s*(?:"([^"]+)"|'([^']+)'|`([^`]+)`)/;
|
|
15
|
-
return extractQuotedString(objText.match(re));
|
|
16
|
-
};
|
|
17
3
|
const sectionNameFromId = (id) => {
|
|
18
4
|
if (!id)
|
|
19
5
|
return "";
|
|
@@ -23,216 +9,97 @@ const sectionNameFromId = (id) => {
|
|
|
23
9
|
return id.slice(0, -"-container".length);
|
|
24
10
|
return id;
|
|
25
11
|
};
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const objectStartStack = [];
|
|
31
|
-
let inString = null;
|
|
32
|
-
for (let i = 0; i < arrayText.length; i++) {
|
|
33
|
-
const ch = arrayText[i];
|
|
34
|
-
if (inString) {
|
|
35
|
-
if (inString !== "`" && ch === "\\") {
|
|
36
|
-
i += 1;
|
|
37
|
-
continue;
|
|
38
|
-
}
|
|
39
|
-
if (ch === inString)
|
|
40
|
-
inString = null;
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
if (ch === '"' || ch === "'" || ch === "`") {
|
|
44
|
-
inString = ch;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (ch === "[") {
|
|
48
|
-
bracketDepth += 1;
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
if (ch === "]") {
|
|
52
|
-
bracketDepth -= 1;
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
if (ch === "{") {
|
|
56
|
-
if (bracketDepth >= 1)
|
|
57
|
-
objectStartStack.push(i);
|
|
58
|
-
continue;
|
|
59
|
-
}
|
|
60
|
-
if (ch === "}") {
|
|
61
|
-
const start = objectStartStack.pop();
|
|
62
|
-
if (start === undefined)
|
|
63
|
-
continue;
|
|
64
|
-
// only consider objects that are direct children of the current array
|
|
65
|
-
if (bracketDepth !== 1 || objectStartStack.length !== 0)
|
|
66
|
-
continue;
|
|
67
|
-
const objText = arrayText.slice(start, i + 1);
|
|
68
|
-
const id = extractPropString(objText, "id");
|
|
69
|
-
const type = extractPropString(objText, "type");
|
|
70
|
-
if (type === "div" && id && id !== "root" && !seen.has(id)) {
|
|
71
|
-
seen.add(id);
|
|
72
|
-
results.push(id);
|
|
73
|
-
}
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
return results;
|
|
12
|
+
const computePageNameFromRoute = (pageRoute) => {
|
|
13
|
+
if (pageRoute === "/")
|
|
14
|
+
return "root";
|
|
15
|
+
return pageRoute.slice(1).split("/").join("-");
|
|
78
16
|
};
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
if (childrenKey < 0)
|
|
17
|
+
const extractSectionNamesFromParsedConfig = (config) => {
|
|
18
|
+
if (!config || !Array.isArray(config.elements))
|
|
82
19
|
return [];
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
20
|
+
const elements = config.elements;
|
|
21
|
+
// Let's find the root element (where type === "div" && id === "root") recursively
|
|
22
|
+
let rootElement = null;
|
|
23
|
+
const findRoot = (els) => {
|
|
24
|
+
for (const el of els) {
|
|
25
|
+
if (el && typeof el === "object") {
|
|
26
|
+
if (el.type === "div" && el.id === "root") {
|
|
27
|
+
rootElement = el;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (Array.isArray(el.children)) {
|
|
31
|
+
findRoot(el.children);
|
|
32
|
+
if (rootElement)
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
95
35
|
}
|
|
96
|
-
if (ch === inString)
|
|
97
|
-
inString = null;
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
if (ch === '"' || ch === "'" || ch === "`") {
|
|
101
|
-
inString = ch;
|
|
102
|
-
continue;
|
|
103
36
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
37
|
+
};
|
|
38
|
+
findRoot(elements);
|
|
39
|
+
if (rootElement && Array.isArray(rootElement.children)) {
|
|
40
|
+
const rootSections = [];
|
|
41
|
+
for (const child of rootElement.children) {
|
|
42
|
+
if (child &&
|
|
43
|
+
typeof child === "object" &&
|
|
44
|
+
child.type === "div" &&
|
|
45
|
+
child.id &&
|
|
46
|
+
child.id !== "root") {
|
|
47
|
+
const name = sectionNameFromId(child.id);
|
|
48
|
+
if (name) {
|
|
49
|
+
rootSections.push(name);
|
|
50
|
+
}
|
|
112
51
|
}
|
|
113
52
|
}
|
|
53
|
+
if (rootSections.length > 0) {
|
|
54
|
+
return rootSections;
|
|
55
|
+
}
|
|
114
56
|
}
|
|
115
|
-
|
|
116
|
-
};
|
|
117
|
-
const extractSectionNamesFromConfig = (content) => {
|
|
118
|
-
if (!content)
|
|
119
|
-
return [];
|
|
120
|
-
const elementsKey = content.indexOf("elements");
|
|
121
|
-
if (elementsKey < 0)
|
|
122
|
-
return [];
|
|
123
|
-
const arrayStart = content.indexOf("[", elementsKey);
|
|
124
|
-
if (arrayStart < 0)
|
|
125
|
-
return [];
|
|
57
|
+
// Fallback: collect all divs with id ending in "-section" or "-container"
|
|
126
58
|
const seen = new Set();
|
|
127
59
|
const results = [];
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
continue;
|
|
137
|
-
}
|
|
138
|
-
if (ch === inString) {
|
|
139
|
-
inString = null;
|
|
140
|
-
}
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (ch === '"' || ch === "'" || ch === "`") {
|
|
144
|
-
inString = ch;
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (ch === "[") {
|
|
148
|
-
bracketDepth += 1;
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
if (ch === "]") {
|
|
152
|
-
bracketDepth -= 1;
|
|
153
|
-
if (bracketDepth <= 0)
|
|
154
|
-
break;
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (ch === "{") {
|
|
158
|
-
if (bracketDepth >= 1) {
|
|
159
|
-
objectStartStack.push(i);
|
|
160
|
-
}
|
|
161
|
-
continue;
|
|
162
|
-
}
|
|
163
|
-
if (ch === "}") {
|
|
164
|
-
const objectStart = objectStartStack.pop();
|
|
165
|
-
if (bracketDepth >= 1 && objectStart !== undefined) {
|
|
166
|
-
const objText = content.slice(objectStart, i + 1);
|
|
167
|
-
const id = extractPropString(objText, "id");
|
|
168
|
-
const type = extractPropString(objText, "type");
|
|
169
|
-
if (type === "div" && id === "root") {
|
|
170
|
-
const rootSections = extractRootChildSectionNames(objText);
|
|
171
|
-
if (rootSections.length > 0) {
|
|
172
|
-
return rootSections;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (type === "div" &&
|
|
176
|
-
id &&
|
|
177
|
-
id !== "root" &&
|
|
178
|
-
(id.endsWith("-section") || id.endsWith("-container"))) {
|
|
179
|
-
const sectionName = sectionNameFromId(id);
|
|
60
|
+
const collectFallback = (els) => {
|
|
61
|
+
for (const el of els) {
|
|
62
|
+
if (el && typeof el === "object") {
|
|
63
|
+
if (el.type === "div" &&
|
|
64
|
+
el.id &&
|
|
65
|
+
el.id !== "root" &&
|
|
66
|
+
(el.id.endsWith("-section") || el.id.endsWith("-container"))) {
|
|
67
|
+
const sectionName = sectionNameFromId(el.id);
|
|
180
68
|
if (sectionName && !seen.has(sectionName)) {
|
|
181
69
|
seen.add(sectionName);
|
|
182
70
|
results.push(sectionName);
|
|
183
71
|
}
|
|
184
72
|
}
|
|
73
|
+
if (Array.isArray(el.children)) {
|
|
74
|
+
collectFallback(el.children);
|
|
75
|
+
}
|
|
185
76
|
}
|
|
186
|
-
continue;
|
|
187
77
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
};
|
|
191
|
-
const computePageRouteFromSegments = (segments) => {
|
|
192
|
-
const filtered = segments.filter((s) => s && !isRouteGroup(s) && !isParallelRoute(s));
|
|
193
|
-
if (filtered.length === 0)
|
|
194
|
-
return "/";
|
|
195
|
-
return `/${filtered.join("/")}`;
|
|
196
|
-
};
|
|
197
|
-
const computePageNameFromRoute = (pageRoute) => {
|
|
198
|
-
if (pageRoute === "/")
|
|
199
|
-
return "root";
|
|
200
|
-
return pageRoute.slice(1).split("/").join("-");
|
|
201
|
-
};
|
|
202
|
-
const findPageConfigFiles = async (dir) => {
|
|
203
|
-
const entries = await safeReadDir(dir);
|
|
204
|
-
const results = [];
|
|
205
|
-
for (const entry of entries) {
|
|
206
|
-
if (!entry.isDirectory() && !entry.isFile())
|
|
207
|
-
continue;
|
|
208
|
-
const fullPath = path.join(dir, entry.name);
|
|
209
|
-
if (entry.isDirectory()) {
|
|
210
|
-
results.push(...(await findPageConfigFiles(fullPath)));
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
213
|
-
if (entry.name === "page.config.ts") {
|
|
214
|
-
results.push(fullPath);
|
|
215
|
-
}
|
|
216
|
-
}
|
|
78
|
+
};
|
|
79
|
+
collectFallback(elements);
|
|
217
80
|
return results;
|
|
218
81
|
};
|
|
219
82
|
export async function computeProjectInfo(rootDir) {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
83
|
+
const routes = await getAvailableRoutes({
|
|
84
|
+
workspaceRoot: rootDir,
|
|
85
|
+
fs: { safeReadDir },
|
|
86
|
+
});
|
|
223
87
|
const uiPages = [];
|
|
224
|
-
for (const
|
|
225
|
-
const relFromApp = toPosixPath(path.relative(appDir, filePath));
|
|
226
|
-
const relDir = path.posix.dirname(relFromApp);
|
|
227
|
-
const segments = relDir === "." ? [] : relDir.split("/").filter(Boolean);
|
|
228
|
-
if (segments.some(isParallelRoute)) {
|
|
229
|
-
continue;
|
|
230
|
-
}
|
|
231
|
-
const pageRoute = computePageRouteFromSegments(segments);
|
|
88
|
+
for (const pageRoute of routes) {
|
|
232
89
|
const pageName = computePageNameFromRoute(pageRoute);
|
|
233
90
|
const description = `${pageName} page for this project`;
|
|
234
|
-
|
|
235
|
-
|
|
91
|
+
let sectionNames = [];
|
|
92
|
+
try {
|
|
93
|
+
const configPath = getPageConfigJsonPath(rootDir, pageRoute);
|
|
94
|
+
const content = await readFile(configPath);
|
|
95
|
+
if (content) {
|
|
96
|
+
const config = JSON.parse(content);
|
|
97
|
+
sectionNames = extractSectionNamesFromParsedConfig(config);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
// Ignore reading/parsing errors, treat as no sections
|
|
102
|
+
}
|
|
236
103
|
const page = {
|
|
237
104
|
pageRoute,
|
|
238
105
|
pageName,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectInfoIndex.js","sourceRoot":"","sources":["../../src/indexer/projectInfoIndex.ts"],"names":[],"mappings":"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","sourcesContent":["import path from \"node:path\";\nimport { ContextRepository } from \"../repository/context.repository.js\";\nimport { ProjectInfo } from \"../types/projectInfo.types.js\";\nimport { readFile, safeReadDir } from \"../utils/workspace.js\";\n\ntype UiPage = ProjectInfo[\"uiPages\"][number];\n\nconst isRouteGroup = (segment: string) =>\n segment.startsWith(\"(\") && segment.endsWith(\")\");\n\nconst isParallelRoute = (segment: string) => segment.startsWith(\"@\");\n\nconst toPosixPath = (p: string) => p.replace(/\\\\/g, \"/\");\n\nconst extractQuotedString = (match: RegExpMatchArray | null): string => {\n if (!match) return \"\";\n return String(match[1] ?? match[2] ?? match[3] ?? \"\").trim();\n};\n\nconst extractPropString = (objText: string, prop: \"id\" | \"type\"): string => {\n const re =\n prop === \"id\"\n ? /\\bid\\s*:\\s*(?:\"([^\"]+)\"|'([^']+)'|`([^`]+)`)/\n : /\\btype\\s*:\\s*(?:\"([^\"]+)\"|'([^']+)'|`([^`]+)`)/;\n\n return extractQuotedString(objText.match(re));\n};\n\nconst sectionNameFromId = (id: string): string => {\n if (!id) return \"\";\n if (id.endsWith(\"-section\")) return id.slice(0, -\"-section\".length);\n if (id.endsWith(\"-container\")) return id.slice(0, -\"-container\".length);\n return id;\n};\n\nconst extractDirectContainerIdsFromArrayText = (\n arrayText: string,\n): string[] => {\n const seen = new Set<string>();\n const results: string[] = [];\n\n let bracketDepth = 0;\n const objectStartStack: number[] = [];\n let inString: '\"' | \"'\" | \"`\" | null = null;\n\n for (let i = 0; i < arrayText.length; i++) {\n const ch = arrayText[i]!;\n\n if (inString) {\n if (inString !== \"`\" && ch === \"\\\\\") {\n i += 1;\n continue;\n }\n if (ch === inString) inString = null;\n continue;\n }\n\n if (ch === '\"' || ch === \"'\" || ch === \"`\") {\n inString = ch;\n continue;\n }\n\n if (ch === \"[\") {\n bracketDepth += 1;\n continue;\n }\n if (ch === \"]\") {\n bracketDepth -= 1;\n continue;\n }\n\n if (ch === \"{\") {\n if (bracketDepth >= 1) objectStartStack.push(i);\n continue;\n }\n\n if (ch === \"}\") {\n const start = objectStartStack.pop();\n if (start === undefined) continue;\n\n // only consider objects that are direct children of the current array\n if (bracketDepth !== 1 || objectStartStack.length !== 0) continue;\n\n const objText = arrayText.slice(start, i + 1);\n const id = extractPropString(objText, \"id\");\n const type = extractPropString(objText, \"type\");\n\n if (type === \"div\" && id && id !== \"root\" && !seen.has(id)) {\n seen.add(id);\n results.push(id);\n }\n\n continue;\n }\n }\n\n return results;\n};\n\nconst extractRootChildSectionNames = (rootObjText: string): string[] => {\n const childrenKey = rootObjText.indexOf(\"children\");\n if (childrenKey < 0) return [];\n\n const arrayStart = rootObjText.indexOf(\"[\", childrenKey);\n if (arrayStart < 0) return [];\n\n // isolate the children array text (including brackets)\n let bracketDepth = 0;\n let inString: '\"' | \"'\" | \"`\" | null = null;\n\n for (let i = arrayStart; i < rootObjText.length; i++) {\n const ch = rootObjText[i]!;\n\n if (inString) {\n if (inString !== \"`\" && ch === \"\\\\\") {\n i += 1;\n continue;\n }\n if (ch === inString) inString = null;\n continue;\n }\n\n if (ch === '\"' || ch === \"'\" || ch === \"`\") {\n inString = ch;\n continue;\n }\n\n if (ch === \"[\") bracketDepth += 1;\n if (ch === \"]\") {\n bracketDepth -= 1;\n if (bracketDepth === 0) {\n const arrayText = rootObjText.slice(arrayStart, i + 1);\n const ids = extractDirectContainerIdsFromArrayText(arrayText);\n return ids.map(sectionNameFromId).filter(Boolean);\n }\n }\n }\n\n return [];\n};\n\nconst extractSectionNamesFromConfig = (content: string): string[] => {\n if (!content) return [];\n\n const elementsKey = content.indexOf(\"elements\");\n if (elementsKey < 0) return [];\n\n const arrayStart = content.indexOf(\"[\", elementsKey);\n if (arrayStart < 0) return [];\n\n const seen = new Set<string>();\n const results: string[] = [];\n\n let bracketDepth = 0;\n const objectStartStack: number[] = [];\n let inString: '\"' | \"'\" | \"`\" | null = null;\n\n for (let i = arrayStart; i < content.length; i++) {\n const ch = content[i]!;\n\n if (inString) {\n if (inString !== \"`\" && ch === \"\\\\\") {\n i += 1;\n continue;\n }\n\n if (ch === inString) {\n inString = null;\n }\n\n continue;\n }\n\n if (ch === '\"' || ch === \"'\" || ch === \"`\") {\n inString = ch;\n continue;\n }\n\n if (ch === \"[\") {\n bracketDepth += 1;\n continue;\n }\n\n if (ch === \"]\") {\n bracketDepth -= 1;\n if (bracketDepth <= 0) break;\n continue;\n }\n\n if (ch === \"{\") {\n if (bracketDepth >= 1) {\n objectStartStack.push(i);\n }\n continue;\n }\n\n if (ch === \"}\") {\n const objectStart = objectStartStack.pop();\n if (bracketDepth >= 1 && objectStart !== undefined) {\n const objText = content.slice(objectStart, i + 1);\n const id = extractPropString(objText, \"id\");\n const type = extractPropString(objText, \"type\");\n\n if (type === \"div\" && id === \"root\") {\n const rootSections = extractRootChildSectionNames(objText);\n if (rootSections.length > 0) {\n return rootSections;\n }\n }\n\n if (\n type === \"div\" &&\n id &&\n id !== \"root\" &&\n (id.endsWith(\"-section\") || id.endsWith(\"-container\"))\n ) {\n const sectionName = sectionNameFromId(id);\n if (sectionName && !seen.has(sectionName)) {\n seen.add(sectionName);\n results.push(sectionName);\n }\n }\n }\n continue;\n }\n }\n\n return results;\n};\n\nconst computePageRouteFromSegments = (segments: string[]): string => {\n const filtered = segments.filter(\n (s) => s && !isRouteGroup(s) && !isParallelRoute(s),\n );\n\n if (filtered.length === 0) return \"/\";\n return `/${filtered.join(\"/\")}`;\n};\n\nconst computePageNameFromRoute = (pageRoute: string): string => {\n if (pageRoute === \"/\") return \"root\";\n return pageRoute.slice(1).split(\"/\").join(\"-\");\n};\n\nconst findPageConfigFiles = async (dir: string): Promise<string[]> => {\n const entries = await safeReadDir(dir);\n const results: string[] = [];\n\n for (const entry of entries) {\n if (!entry.isDirectory() && !entry.isFile()) continue;\n\n const fullPath = path.join(dir, entry.name);\n if (entry.isDirectory()) {\n results.push(...(await findPageConfigFiles(fullPath)));\n continue;\n }\n\n if (entry.name === \"page.config.ts\") {\n results.push(fullPath);\n }\n }\n\n return results;\n};\n\nexport async function computeProjectInfo(\n rootDir: string,\n): Promise<ProjectInfo> {\n const effectiveRoot = rootDir;\n\n const appDir = path.join(effectiveRoot, \"app\");\n const pageConfigFiles = await findPageConfigFiles(appDir);\n\n const uiPages: UiPage[] = [];\n\n for (const filePath of pageConfigFiles) {\n const relFromApp = toPosixPath(path.relative(appDir, filePath));\n const relDir = path.posix.dirname(relFromApp);\n const segments = relDir === \".\" ? [] : relDir.split(\"/\").filter(Boolean);\n\n if (segments.some(isParallelRoute)) {\n continue;\n }\n\n const pageRoute = computePageRouteFromSegments(segments);\n const pageName = computePageNameFromRoute(pageRoute);\n const description = `${pageName} page for this project`;\n\n const content = await readFile(filePath);\n const sectionNames = extractSectionNamesFromConfig(content);\n\n const page: UiPage = {\n pageRoute,\n pageName,\n description,\n };\n\n if (sectionNames.length > 0) {\n page.sections = sectionNames.map((sectionName) => ({\n sectionName,\n description: `${sectionName} section for this page`,\n }));\n }\n\n uiPages.push(page);\n }\n\n uiPages.sort((a, b) =>\n a.pageRoute.localeCompare(b.pageRoute, undefined, {\n sensitivity: \"base\",\n }),\n );\n\n return {\n uiPages,\n lastUpdatedPlanVersion: 1,\n };\n}"]}
|
|
1
|
+
{"version":3,"file":"projectInfoIndex.js","sourceRoot":"","sources":["../../src/indexer/projectInfoIndex.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getAvailableRoutes,\n getPageConfigJsonPath,\n} from \"../ai/tools/helpers/pageConfigJson.helpers.js\";\nimport { ProjectInfo } from \"../types/projectInfo.types.js\";\nimport { readFile, safeReadDir } from \"../utils/workspace.js\";\n\ntype UiPage = ProjectInfo[\"uiPages\"][number];\n\nconst sectionNameFromId = (id: string): string => {\n if (!id) return \"\";\n if (id.endsWith(\"-section\")) return id.slice(0, -\"-section\".length);\n if (id.endsWith(\"-container\")) return id.slice(0, -\"-container\".length);\n return id;\n};\n\nconst computePageNameFromRoute = (pageRoute: string): string => {\n if (pageRoute === \"/\") return \"root\";\n return pageRoute.slice(1).split(\"/\").join(\"-\");\n};\n\nconst extractSectionNamesFromParsedConfig = (config: any): string[] => {\n if (!config || !Array.isArray(config.elements)) return [];\n\n const elements = config.elements;\n\n // Let's find the root element (where type === \"div\" && id === \"root\") recursively\n let rootElement: any = null;\n const findRoot = (els: any[]) => {\n for (const el of els) {\n if (el && typeof el === \"object\") {\n if (el.type === \"div\" && el.id === \"root\") {\n rootElement = el;\n return;\n }\n if (Array.isArray(el.children)) {\n findRoot(el.children);\n if (rootElement) return;\n }\n }\n }\n };\n findRoot(elements);\n\n if (rootElement && Array.isArray(rootElement.children)) {\n const rootSections: string[] = [];\n for (const child of rootElement.children) {\n if (\n child &&\n typeof child === \"object\" &&\n child.type === \"div\" &&\n child.id &&\n child.id !== \"root\"\n ) {\n const name = sectionNameFromId(child.id);\n if (name) {\n rootSections.push(name);\n }\n }\n }\n if (rootSections.length > 0) {\n return rootSections;\n }\n }\n\n // Fallback: collect all divs with id ending in \"-section\" or \"-container\"\n const seen = new Set<string>();\n const results: string[] = [];\n const collectFallback = (els: any[]) => {\n for (const el of els) {\n if (el && typeof el === \"object\") {\n if (\n el.type === \"div\" &&\n el.id &&\n el.id !== \"root\" &&\n (el.id.endsWith(\"-section\") || el.id.endsWith(\"-container\"))\n ) {\n const sectionName = sectionNameFromId(el.id);\n if (sectionName && !seen.has(sectionName)) {\n seen.add(sectionName);\n results.push(sectionName);\n }\n }\n if (Array.isArray(el.children)) {\n collectFallback(el.children);\n }\n }\n }\n };\n collectFallback(elements);\n return results;\n};\n\nexport async function computeProjectInfo(\n rootDir: string,\n): Promise<ProjectInfo> {\n const routes = await getAvailableRoutes({\n workspaceRoot: rootDir,\n fs: { safeReadDir },\n });\n\n const uiPages: UiPage[] = [];\n\n for (const pageRoute of routes) {\n const pageName = computePageNameFromRoute(pageRoute);\n const description = `${pageName} page for this project`;\n\n let sectionNames: string[] = [];\n try {\n const configPath = getPageConfigJsonPath(rootDir, pageRoute);\n const content = await readFile(configPath);\n if (content) {\n const config = JSON.parse(content);\n sectionNames = extractSectionNamesFromParsedConfig(config);\n }\n } catch (err) {\n // Ignore reading/parsing errors, treat as no sections\n }\n\n const page: UiPage = {\n pageRoute,\n pageName,\n description,\n };\n\n if (sectionNames.length > 0) {\n page.sections = sectionNames.map((sectionName) => ({\n sectionName,\n description: `${sectionName} section for this page`,\n }));\n }\n\n uiPages.push(page);\n }\n\n uiPages.sort((a, b) =>\n a.pageRoute.localeCompare(b.pageRoute, undefined, {\n sensitivity: \"base\",\n }),\n );\n\n return {\n uiPages,\n lastUpdatedPlanVersion: 1,\n };\n}"]}
|
|
@@ -6,6 +6,8 @@ import fs from "node:fs/promises";
|
|
|
6
6
|
import { createInsertElementImpl } from "../ai/tools/implementations/insertElement.impl.js";
|
|
7
7
|
import { createUpdatePropsImpl } from "../ai/tools/implementations/updateProps.impl.js";
|
|
8
8
|
import { createUpdateClassNameImpl } from "../ai/tools/implementations/updateClassName.impl.js";
|
|
9
|
+
import { createDeleteElementImpl } from "../ai/tools/implementations/deleteElement.impl.js";
|
|
10
|
+
import { matchRoute } from "../ai/tools/helpers/pageConfigJson.helpers.js";
|
|
9
11
|
const makeRealFs = (overrides) => {
|
|
10
12
|
return {
|
|
11
13
|
readFile: async (absolutePath) => fs.readFile(absolutePath, "utf-8"),
|
|
@@ -77,4 +79,95 @@ test("insert/update tools: inject ids, insert under parent, update props and cla
|
|
|
77
79
|
await fs.rm(workspaceRoot, { recursive: true, force: true });
|
|
78
80
|
}
|
|
79
81
|
});
|
|
82
|
+
test("matchRoute helper correctly matches physical paths", () => {
|
|
83
|
+
// exact match
|
|
84
|
+
assert.equal(matchRoute("/", "/"), true);
|
|
85
|
+
assert.equal(matchRoute("/dashboard", "/dashboard"), true);
|
|
86
|
+
assert.equal(matchRoute("/dashboard", "/dashboard/"), true);
|
|
87
|
+
assert.equal(matchRoute("/dashboard/", "/dashboard"), true);
|
|
88
|
+
// dynamic segment
|
|
89
|
+
assert.equal(matchRoute("/product/[id]", "/product/123"), true);
|
|
90
|
+
assert.equal(matchRoute("/product/[id]", "/product/hi"), true);
|
|
91
|
+
assert.equal(matchRoute("/product/[id]", "/product/"), false);
|
|
92
|
+
assert.equal(matchRoute("/product/[id]", "/product/123/reviews"), false);
|
|
93
|
+
assert.equal(matchRoute("/product/[id]/reviews", "/product/abc/reviews"), true);
|
|
94
|
+
// catch-all segment
|
|
95
|
+
assert.equal(matchRoute("/blog/[...slug]", "/blog/react"), true);
|
|
96
|
+
assert.equal(matchRoute("/blog/[...slug]", "/blog/react/hooks/state"), true);
|
|
97
|
+
assert.equal(matchRoute("/blog/[...slug]", "/blog"), false); // required catch-all requires at least one segment
|
|
98
|
+
// optional catch-all segment
|
|
99
|
+
assert.equal(matchRoute("/blog/[[...slug]]", "/blog"), true);
|
|
100
|
+
assert.equal(matchRoute("/blog/[[...slug]]", "/blog/react"), true);
|
|
101
|
+
assert.equal(matchRoute("/blog/[[...slug]]", "/blog/react/hooks"), true);
|
|
102
|
+
});
|
|
103
|
+
test("dynamic/nested routes resolution in tools", async () => {
|
|
104
|
+
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qwintly-core-dynamic-"));
|
|
105
|
+
try {
|
|
106
|
+
// 1. Create a dynamic route /product/[id]
|
|
107
|
+
const routeDir = path.join(workspaceRoot, "app", "product", "[id]");
|
|
108
|
+
await fs.mkdir(routeDir, { recursive: true });
|
|
109
|
+
const filePath = path.join(routeDir, "pageConfig.json");
|
|
110
|
+
await fs.writeFile(filePath, JSON.stringify({
|
|
111
|
+
elements: [
|
|
112
|
+
{
|
|
113
|
+
id: "root",
|
|
114
|
+
type: "div",
|
|
115
|
+
children: [{ id: "prod_title", type: "text", props: { text: "Product Name" } }],
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
}, null, 2) + "\n", "utf-8");
|
|
119
|
+
// 2. Create a catch-all route /blog/[...slug]
|
|
120
|
+
const blogDir = path.join(workspaceRoot, "app", "blog", "[...slug]");
|
|
121
|
+
await fs.mkdir(blogDir, { recursive: true });
|
|
122
|
+
const blogFilePath = path.join(blogDir, "pageConfig.json");
|
|
123
|
+
await fs.writeFile(blogFilePath, JSON.stringify({
|
|
124
|
+
elements: [
|
|
125
|
+
{
|
|
126
|
+
id: "blog_root",
|
|
127
|
+
type: "div",
|
|
128
|
+
children: [{ id: "blog_content", type: "text", props: { text: "Blog Post" } }],
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
}, null, 2) + "\n", "utf-8");
|
|
132
|
+
const deps = { workspaceRoot, fs: makeRealFs() };
|
|
133
|
+
const insert = createInsertElementImpl(deps);
|
|
134
|
+
const updateProps = createUpdatePropsImpl(deps);
|
|
135
|
+
const updateClassName = createUpdateClassNameImpl(deps);
|
|
136
|
+
const deleteElement = createDeleteElementImpl(deps);
|
|
137
|
+
// Test insert_element on dynamic route '/product/123'
|
|
138
|
+
const insRes = await insert("/product/123", "root", {
|
|
139
|
+
type: "button",
|
|
140
|
+
props: { text: "Buy Now" },
|
|
141
|
+
});
|
|
142
|
+
assert.equal(insRes.success, true);
|
|
143
|
+
// Verify it updated '/app/product/[id]/pageConfig.json'
|
|
144
|
+
const afterProduct = JSON.parse(await fs.readFile(filePath, "utf-8"));
|
|
145
|
+
assert.equal(afterProduct.elements[0].children.length, 2);
|
|
146
|
+
const newBtn = afterProduct.elements[0].children[1];
|
|
147
|
+
assert.equal(newBtn.type, "button");
|
|
148
|
+
assert.equal(newBtn.props.text, "Buy Now");
|
|
149
|
+
// Test update_props on dynamic route '/product/hi-there'
|
|
150
|
+
const upRes = await updateProps({
|
|
151
|
+
route: "/product/hi-there",
|
|
152
|
+
element_id: "prod_title",
|
|
153
|
+
text: "Updated Product Title",
|
|
154
|
+
});
|
|
155
|
+
assert.equal(upRes.success, true);
|
|
156
|
+
// Test update_classname on catch-all route '/blog/react/hooks/state'
|
|
157
|
+
const classRes = await updateClassName("/blog/react/hooks/state", "blog_content", "text-blue-500");
|
|
158
|
+
assert.equal(classRes.success, true);
|
|
159
|
+
// Verify blog config updated
|
|
160
|
+
const afterBlog = JSON.parse(await fs.readFile(blogFilePath, "utf-8"));
|
|
161
|
+
const updatedTitle = afterBlog.elements[0].children[0];
|
|
162
|
+
assert.equal(updatedTitle.className, "text-blue-500");
|
|
163
|
+
// Test delete_element on catch-all route
|
|
164
|
+
const delRes = await deleteElement("/blog/react/something-else", "blog_content");
|
|
165
|
+
assert.equal(delRes.success, true);
|
|
166
|
+
const afterDelBlog = JSON.parse(await fs.readFile(blogFilePath, "utf-8"));
|
|
167
|
+
assert.equal(afterDelBlog.elements[0].children.length, 0);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
await fs.rm(workspaceRoot, { recursive: true, force: true });
|
|
171
|
+
}
|
|
172
|
+
});
|
|
80
173
|
//# sourceMappingURL=insertUpdate.impl.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insertUpdate.impl.test.js","sourceRoot":"","sources":["../../src/tests/insertUpdate.impl.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport fs from \"node:fs/promises\";\nimport { createInsertElementImpl } from \"../ai/tools/implementations/insertElement.impl.js\";\nimport { createUpdatePropsImpl } from \"../ai/tools/implementations/updateProps.impl.js\";\nimport { createUpdateClassNameImpl } from \"../ai/tools/implementations/updateClassName.impl.js\";\n\ntype Deps = Parameters<typeof createInsertElementImpl>[0];\ntype CoreFs = Deps[\"fs\"];\n\nconst makeRealFs = (overrides?: Partial<CoreFs>): CoreFs => {\n return {\n readFile: async (absolutePath) => fs.readFile(absolutePath, \"utf-8\"),\n writeFile: async (absolutePath, content) =>\n fs.writeFile(absolutePath, content ?? \"\", \"utf-8\"),\n mkdirp: async (absoluteDir) => {\n await fs.mkdir(absoluteDir, { recursive: true });\n },\n rmFile: async (absolutePath) => fs.rm(absolutePath, { force: true }),\n stat: async (absolutePath) => fs.stat(absolutePath),\n safeReadDir: async (absoluteDir) =>\n fs.readdir(absoluteDir, { withFileTypes: true }),\n ...(overrides ?? {}),\n };\n};\n\ntest(\"insert/update tools: inject ids, insert under parent, update props and classname\", async () => {\n const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), \"qwintly-core-\"));\n try {\n const routeDir = path.join(workspaceRoot, \"app\", \"a\");\n await fs.mkdir(routeDir, { recursive: true });\n const filePath = path.join(routeDir, \"pageConfig.json\");\n await fs.writeFile(\n filePath,\n JSON.stringify(\n {\n elements: [\n {\n id: \"root\",\n type: \"div\",\n children: [{ id: \"existing\", type: \"text\", props: { text: \"x\" } }],\n },\n ],\n },\n null,\n 2,\n ) + \"\\n\",\n \"utf-8\",\n );\n\n const deps = { workspaceRoot, fs: makeRealFs() } as any;\n const insert = createInsertElementImpl(deps);\n const updateProps = createUpdatePropsImpl(deps);\n const updateClassName = createUpdateClassNameImpl(deps);\n\n const inserted = await insert(\"/a\", \"root\", {\n type: \"text\",\n props: { text: \"hello\" },\n } as any);\n assert.equal(\n (inserted as any).success,\n true,\n `unexpected response: ${JSON.stringify(inserted)}`,\n );\n const insertedId = (inserted as any).inserted_id as string;\n assert.ok(typeof insertedId === \"string\" && insertedId.startsWith(\"el_\"));\n\n const inserted2 = await insert({\n route: \"/a\",\n parent_id: \"root\",\n before_id: \"existing\",\n element: { type: \"text\", props: { text: \"first\" } },\n } as any);\n assert.equal(\n (inserted2 as any).success,\n true,\n `unexpected response: ${JSON.stringify(inserted2)}`,\n );\n const inserted2Id = (inserted2 as any).inserted_id as string;\n assert.ok(typeof inserted2Id === \"string\" && inserted2Id.startsWith(\"el_\"));\n\n const up1 = await updateProps({\n route: \"/a\",\n element_id: insertedId,\n text: \"updated\",\n href: \"/x\",\n } as any);\n assert.equal((up1 as any).success, true);\n\n const up2 = await updateClassName(\"/a\", insertedId, \"text-red-500\");\n assert.equal((up2 as any).success, true);\n\n const after = JSON.parse(await fs.readFile(filePath, \"utf-8\"));\n const children = after.elements[0].children as any[];\n assert.equal(children[0].id, inserted2Id);\n assert.equal(children[1].id, \"existing\");\n\n const found = children.find((e) => e.id === insertedId);\n assert.ok(found);\n assert.equal(found.props.text, \"updated\");\n assert.equal(found.props.href, \"/x\");\n assert.equal(found.className, \"text-red-500\");\n } finally {\n await fs.rm(workspaceRoot, { recursive: true, force: true });\n }\n});\n"]}
|
|
1
|
+
{"version":3,"file":"insertUpdate.impl.test.js","sourceRoot":"","sources":["../../src/tests/insertUpdate.impl.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport fs from \"node:fs/promises\";\nimport { createInsertElementImpl } from \"../ai/tools/implementations/insertElement.impl.js\";\nimport { createUpdatePropsImpl } from \"../ai/tools/implementations/updateProps.impl.js\";\nimport { createUpdateClassNameImpl } from \"../ai/tools/implementations/updateClassName.impl.js\";\nimport { createDeleteElementImpl } from \"../ai/tools/implementations/deleteElement.impl.js\";\nimport { matchRoute } from \"../ai/tools/helpers/pageConfigJson.helpers.js\";\n\ntype Deps = Parameters<typeof createInsertElementImpl>[0];\ntype CoreFs = Deps[\"fs\"];\n\nconst makeRealFs = (overrides?: Partial<CoreFs>): CoreFs => {\n return {\n readFile: async (absolutePath) => fs.readFile(absolutePath, \"utf-8\"),\n writeFile: async (absolutePath, content) =>\n fs.writeFile(absolutePath, content ?? \"\", \"utf-8\"),\n mkdirp: async (absoluteDir) => {\n await fs.mkdir(absoluteDir, { recursive: true });\n },\n rmFile: async (absolutePath) => fs.rm(absolutePath, { force: true }),\n stat: async (absolutePath) => fs.stat(absolutePath),\n safeReadDir: async (absoluteDir) =>\n fs.readdir(absoluteDir, { withFileTypes: true }),\n ...(overrides ?? {}),\n };\n};\n\ntest(\"insert/update tools: inject ids, insert under parent, update props and classname\", async () => {\n const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), \"qwintly-core-\"));\n try {\n const routeDir = path.join(workspaceRoot, \"app\", \"a\");\n await fs.mkdir(routeDir, { recursive: true });\n const filePath = path.join(routeDir, \"pageConfig.json\");\n await fs.writeFile(\n filePath,\n JSON.stringify(\n {\n elements: [\n {\n id: \"root\",\n type: \"div\",\n children: [{ id: \"existing\", type: \"text\", props: { text: \"x\" } }],\n },\n ],\n },\n null,\n 2,\n ) + \"\\n\",\n \"utf-8\",\n );\n\n const deps = { workspaceRoot, fs: makeRealFs() } as any;\n const insert = createInsertElementImpl(deps);\n const updateProps = createUpdatePropsImpl(deps);\n const updateClassName = createUpdateClassNameImpl(deps);\n\n const inserted = await insert(\"/a\", \"root\", {\n type: \"text\",\n props: { text: \"hello\" },\n } as any);\n assert.equal(\n (inserted as any).success,\n true,\n `unexpected response: ${JSON.stringify(inserted)}`,\n );\n const insertedId = (inserted as any).inserted_id as string;\n assert.ok(typeof insertedId === \"string\" && insertedId.startsWith(\"el_\"));\n\n const inserted2 = await insert({\n route: \"/a\",\n parent_id: \"root\",\n before_id: \"existing\",\n element: { type: \"text\", props: { text: \"first\" } },\n } as any);\n assert.equal(\n (inserted2 as any).success,\n true,\n `unexpected response: ${JSON.stringify(inserted2)}`,\n );\n const inserted2Id = (inserted2 as any).inserted_id as string;\n assert.ok(typeof inserted2Id === \"string\" && inserted2Id.startsWith(\"el_\"));\n\n const up1 = await updateProps({\n route: \"/a\",\n element_id: insertedId,\n text: \"updated\",\n href: \"/x\",\n } as any);\n assert.equal((up1 as any).success, true);\n\n const up2 = await updateClassName(\"/a\", insertedId, \"text-red-500\");\n assert.equal((up2 as any).success, true);\n\n const after = JSON.parse(await fs.readFile(filePath, \"utf-8\"));\n const children = after.elements[0].children as any[];\n assert.equal(children[0].id, inserted2Id);\n assert.equal(children[1].id, \"existing\");\n\n const found = children.find((e) => e.id === insertedId);\n assert.ok(found);\n assert.equal(found.props.text, \"updated\");\n assert.equal(found.props.href, \"/x\");\n assert.equal(found.className, \"text-red-500\");\n } finally {\n await fs.rm(workspaceRoot, { recursive: true, force: true });\n }\n});\n\ntest(\"matchRoute helper correctly matches physical paths\", () => {\n // exact match\n assert.equal(matchRoute(\"/\", \"/\"), true);\n assert.equal(matchRoute(\"/dashboard\", \"/dashboard\"), true);\n assert.equal(matchRoute(\"/dashboard\", \"/dashboard/\"), true);\n assert.equal(matchRoute(\"/dashboard/\", \"/dashboard\"), true);\n \n // dynamic segment\n assert.equal(matchRoute(\"/product/[id]\", \"/product/123\"), true);\n assert.equal(matchRoute(\"/product/[id]\", \"/product/hi\"), true);\n assert.equal(matchRoute(\"/product/[id]\", \"/product/\"), false);\n assert.equal(matchRoute(\"/product/[id]\", \"/product/123/reviews\"), false);\n assert.equal(matchRoute(\"/product/[id]/reviews\", \"/product/abc/reviews\"), true);\n\n // catch-all segment\n assert.equal(matchRoute(\"/blog/[...slug]\", \"/blog/react\"), true);\n assert.equal(matchRoute(\"/blog/[...slug]\", \"/blog/react/hooks/state\"), true);\n assert.equal(matchRoute(\"/blog/[...slug]\", \"/blog\"), false); // required catch-all requires at least one segment\n\n // optional catch-all segment\n assert.equal(matchRoute(\"/blog/[[...slug]]\", \"/blog\"), true);\n assert.equal(matchRoute(\"/blog/[[...slug]]\", \"/blog/react\"), true);\n assert.equal(matchRoute(\"/blog/[[...slug]]\", \"/blog/react/hooks\"), true);\n});\n\ntest(\"dynamic/nested routes resolution in tools\", async () => {\n const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), \"qwintly-core-dynamic-\"));\n try {\n // 1. Create a dynamic route /product/[id]\n const routeDir = path.join(workspaceRoot, \"app\", \"product\", \"[id]\");\n await fs.mkdir(routeDir, { recursive: true });\n const filePath = path.join(routeDir, \"pageConfig.json\");\n await fs.writeFile(\n filePath,\n JSON.stringify(\n {\n elements: [\n {\n id: \"root\",\n type: \"div\",\n children: [{ id: \"prod_title\", type: \"text\", props: { text: \"Product Name\" } }],\n },\n ],\n },\n null,\n 2,\n ) + \"\\n\",\n \"utf-8\",\n );\n\n // 2. Create a catch-all route /blog/[...slug]\n const blogDir = path.join(workspaceRoot, \"app\", \"blog\", \"[...slug]\");\n await fs.mkdir(blogDir, { recursive: true });\n const blogFilePath = path.join(blogDir, \"pageConfig.json\");\n await fs.writeFile(\n blogFilePath,\n JSON.stringify(\n {\n elements: [\n {\n id: \"blog_root\",\n type: \"div\",\n children: [{ id: \"blog_content\", type: \"text\", props: { text: \"Blog Post\" } }],\n },\n ],\n },\n null,\n 2,\n ) + \"\\n\",\n \"utf-8\",\n );\n\n const deps = { workspaceRoot, fs: makeRealFs() } as any;\n const insert = createInsertElementImpl(deps);\n const updateProps = createUpdatePropsImpl(deps);\n const updateClassName = createUpdateClassNameImpl(deps);\n const deleteElement = createDeleteElementImpl(deps);\n\n // Test insert_element on dynamic route '/product/123'\n const insRes = await insert(\"/product/123\", \"root\", {\n type: \"button\",\n props: { text: \"Buy Now\" },\n } as any);\n assert.equal(insRes.success, true);\n\n // Verify it updated '/app/product/[id]/pageConfig.json'\n const afterProduct = JSON.parse(await fs.readFile(filePath, \"utf-8\"));\n assert.equal(afterProduct.elements[0].children.length, 2);\n const newBtn = afterProduct.elements[0].children[1];\n assert.equal(newBtn.type, \"button\");\n assert.equal(newBtn.props.text, \"Buy Now\");\n\n // Test update_props on dynamic route '/product/hi-there'\n const upRes = await updateProps({\n route: \"/product/hi-there\",\n element_id: \"prod_title\",\n text: \"Updated Product Title\",\n } as any);\n assert.equal(upRes.success, true);\n\n // Test update_classname on catch-all route '/blog/react/hooks/state'\n const classRes = await updateClassName(\"/blog/react/hooks/state\", \"blog_content\", \"text-blue-500\");\n assert.equal(classRes.success, true);\n\n // Verify blog config updated\n const afterBlog = JSON.parse(await fs.readFile(blogFilePath, \"utf-8\"));\n const updatedTitle = afterBlog.elements[0].children[0];\n assert.equal(updatedTitle.className, \"text-blue-500\");\n\n // Test delete_element on catch-all route\n const delRes = await deleteElement(\"/blog/react/something-else\", \"blog_content\");\n assert.equal(delRes.success, true);\n\n const afterDelBlog = JSON.parse(await fs.readFile(blogFilePath, \"utf-8\"));\n assert.equal(afterDelBlog.elements[0].children.length, 0);\n\n } finally {\n await fs.rm(workspaceRoot, { recursive: true, force: true });\n }\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectInfoIndex.test.d.ts","sourceRoot":"","sources":["../../src/tests/projectInfoIndex.test.ts"],"names":[],"mappings":""}
|