@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
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import fs from "node:fs/promises";
|
|
6
|
+
import { computeProjectInfo } from "../indexer/projectInfoIndex.js";
|
|
7
|
+
test("computeProjectInfo: scans routes and sections from pageConfig.json files", async () => {
|
|
8
|
+
const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), "qwintly-core-project-info-"));
|
|
9
|
+
try {
|
|
10
|
+
// 1. Create a root pageConfig.json with a div root and two sections
|
|
11
|
+
const rootDir = path.join(workspaceRoot, "app");
|
|
12
|
+
await fs.mkdir(rootDir, { recursive: true });
|
|
13
|
+
await fs.writeFile(path.join(rootDir, "pageConfig.json"), JSON.stringify({
|
|
14
|
+
elements: [
|
|
15
|
+
{
|
|
16
|
+
id: "root",
|
|
17
|
+
type: "div",
|
|
18
|
+
children: [
|
|
19
|
+
{ id: "hero-section", type: "div", children: [] },
|
|
20
|
+
{ id: "footer-container", type: "div", children: [] },
|
|
21
|
+
{ id: "some-text", type: "text", props: { text: "hello" } }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}));
|
|
26
|
+
// 2. Create a nested pageConfig.json under /dashboard/settings with a fallback section
|
|
27
|
+
const settingsDir = path.join(workspaceRoot, "app", "dashboard", "settings");
|
|
28
|
+
await fs.mkdir(settingsDir, { recursive: true });
|
|
29
|
+
await fs.writeFile(path.join(settingsDir, "pageConfig.json"), JSON.stringify({
|
|
30
|
+
elements: [
|
|
31
|
+
{
|
|
32
|
+
id: "settings-container",
|
|
33
|
+
type: "div",
|
|
34
|
+
children: []
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}));
|
|
38
|
+
// 3. Create a nested pageConfig.json under /dashboard with no sections
|
|
39
|
+
const dashboardDir = path.join(workspaceRoot, "app", "dashboard");
|
|
40
|
+
await fs.mkdir(dashboardDir, { recursive: true });
|
|
41
|
+
await fs.writeFile(path.join(dashboardDir, "pageConfig.json"), JSON.stringify({
|
|
42
|
+
elements: []
|
|
43
|
+
}));
|
|
44
|
+
const projectInfo = await computeProjectInfo(workspaceRoot);
|
|
45
|
+
assert.equal(projectInfo.uiPages.length, 3);
|
|
46
|
+
assert.equal(projectInfo.lastUpdatedPlanVersion, 1);
|
|
47
|
+
// / route
|
|
48
|
+
const rootPage = projectInfo.uiPages.find(p => p.pageRoute === "/");
|
|
49
|
+
assert.ok(rootPage);
|
|
50
|
+
assert.equal(rootPage.pageName, "root");
|
|
51
|
+
assert.equal(rootPage.description, "root page for this project");
|
|
52
|
+
assert.deepEqual(rootPage.sections, [
|
|
53
|
+
{ sectionName: "hero", description: "hero section for this page" },
|
|
54
|
+
{ sectionName: "footer", description: "footer section for this page" }
|
|
55
|
+
]);
|
|
56
|
+
// /dashboard route
|
|
57
|
+
const dashboardPage = projectInfo.uiPages.find(p => p.pageRoute === "/dashboard");
|
|
58
|
+
assert.ok(dashboardPage);
|
|
59
|
+
assert.equal(dashboardPage.pageName, "dashboard");
|
|
60
|
+
assert.equal(dashboardPage.description, "dashboard page for this project");
|
|
61
|
+
assert.equal(dashboardPage.sections, undefined);
|
|
62
|
+
// /dashboard/settings route
|
|
63
|
+
const settingsPage = projectInfo.uiPages.find(p => p.pageRoute === "/dashboard/settings");
|
|
64
|
+
assert.ok(settingsPage);
|
|
65
|
+
assert.equal(settingsPage.pageName, "dashboard-settings");
|
|
66
|
+
assert.equal(settingsPage.description, "dashboard-settings page for this project");
|
|
67
|
+
assert.deepEqual(settingsPage.sections, [
|
|
68
|
+
{ sectionName: "settings", description: "settings section for this page" }
|
|
69
|
+
]);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
await fs.rm(workspaceRoot, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
//# sourceMappingURL=projectInfoIndex.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"projectInfoIndex.test.js","sourceRoot":"","sources":["../../src/tests/projectInfoIndex.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 { computeProjectInfo } from \"../indexer/projectInfoIndex.js\";\n\ntest(\"computeProjectInfo: scans routes and sections from pageConfig.json files\", async () => {\n const workspaceRoot = await fs.mkdtemp(path.join(os.tmpdir(), \"qwintly-core-project-info-\"));\n try {\n // 1. Create a root pageConfig.json with a div root and two sections\n const rootDir = path.join(workspaceRoot, \"app\");\n await fs.mkdir(rootDir, { recursive: true });\n await fs.writeFile(\n path.join(rootDir, \"pageConfig.json\"),\n JSON.stringify({\n elements: [\n {\n id: \"root\",\n type: \"div\",\n children: [\n { id: \"hero-section\", type: \"div\", children: [] },\n { id: \"footer-container\", type: \"div\", children: [] },\n { id: \"some-text\", type: \"text\", props: { text: \"hello\" } }\n ]\n }\n ]\n })\n );\n\n // 2. Create a nested pageConfig.json under /dashboard/settings with a fallback section\n const settingsDir = path.join(workspaceRoot, \"app\", \"dashboard\", \"settings\");\n await fs.mkdir(settingsDir, { recursive: true });\n await fs.writeFile(\n path.join(settingsDir, \"pageConfig.json\"),\n JSON.stringify({\n elements: [\n {\n id: \"settings-container\",\n type: \"div\",\n children: []\n }\n ]\n })\n );\n\n // 3. Create a nested pageConfig.json under /dashboard with no sections\n const dashboardDir = path.join(workspaceRoot, \"app\", \"dashboard\");\n await fs.mkdir(dashboardDir, { recursive: true });\n await fs.writeFile(\n path.join(dashboardDir, \"pageConfig.json\"),\n JSON.stringify({\n elements: []\n })\n );\n\n const projectInfo = await computeProjectInfo(workspaceRoot);\n\n assert.equal(projectInfo.uiPages.length, 3);\n assert.equal(projectInfo.lastUpdatedPlanVersion, 1);\n\n // / route\n const rootPage = projectInfo.uiPages.find(p => p.pageRoute === \"/\");\n assert.ok(rootPage);\n assert.equal(rootPage.pageName, \"root\");\n assert.equal(rootPage.description, \"root page for this project\");\n assert.deepEqual(rootPage.sections, [\n { sectionName: \"hero\", description: \"hero section for this page\" },\n { sectionName: \"footer\", description: \"footer section for this page\" }\n ]);\n\n // /dashboard route\n const dashboardPage = projectInfo.uiPages.find(p => p.pageRoute === \"/dashboard\");\n assert.ok(dashboardPage);\n assert.equal(dashboardPage.pageName, \"dashboard\");\n assert.equal(dashboardPage.description, \"dashboard page for this project\");\n assert.equal(dashboardPage.sections, undefined);\n\n // /dashboard/settings route\n const settingsPage = projectInfo.uiPages.find(p => p.pageRoute === \"/dashboard/settings\");\n assert.ok(settingsPage);\n assert.equal(settingsPage.pageName, \"dashboard-settings\");\n assert.equal(settingsPage.description, \"dashboard-settings page for this project\");\n assert.deepEqual(settingsPage.sections, [\n { sectionName: \"settings\", description: \"settings section for this page\" }\n ]);\n\n } finally {\n await fs.rm(workspaceRoot, { recursive: true, force: true });\n }\n});\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsplash.service.test.d.ts","sourceRoot":"","sources":["../../src/tests/unsplash.service.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { initUnsplash, resolveUnsplashImagesDeep } from "../image/unsplash.service.js";
|
|
4
|
+
test("resolveUnsplashImagesDeep: resolves and inserts src for images", async () => {
|
|
5
|
+
const originalFetch = globalThis.fetch;
|
|
6
|
+
// Setup fetch mock
|
|
7
|
+
const calls = [];
|
|
8
|
+
globalThis.fetch = async (url, init) => {
|
|
9
|
+
const urlString = String(url);
|
|
10
|
+
calls.push(urlString);
|
|
11
|
+
if (urlString.includes("/search/photos")) {
|
|
12
|
+
return {
|
|
13
|
+
ok: true,
|
|
14
|
+
status: 200,
|
|
15
|
+
json: async () => ({
|
|
16
|
+
results: [
|
|
17
|
+
{
|
|
18
|
+
id: "photo_1",
|
|
19
|
+
likes: 100,
|
|
20
|
+
width: 800,
|
|
21
|
+
height: 600,
|
|
22
|
+
user: {
|
|
23
|
+
total_photos: 10,
|
|
24
|
+
name: "Photographer Name",
|
|
25
|
+
links: {
|
|
26
|
+
html: "https://unsplash.com/@photographer"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
links: {
|
|
30
|
+
download_location: "https://api.unsplash.com/photos/photo_1/download",
|
|
31
|
+
html: "https://unsplash.com/photos/photo_1"
|
|
32
|
+
},
|
|
33
|
+
urls: {
|
|
34
|
+
regular: "https://images.unsplash.com/photo_1_regular",
|
|
35
|
+
small: "https://images.unsplash.com/photo_1_small"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
})
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (urlString.includes("/download")) {
|
|
43
|
+
return {
|
|
44
|
+
ok: true,
|
|
45
|
+
status: 200,
|
|
46
|
+
json: async () => ({})
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
ok: false,
|
|
51
|
+
status: 404
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
try {
|
|
55
|
+
initUnsplash({
|
|
56
|
+
url: "https://api.unsplash.com",
|
|
57
|
+
accessKey: "fake_key",
|
|
58
|
+
});
|
|
59
|
+
const element = {
|
|
60
|
+
type: "div",
|
|
61
|
+
children: [
|
|
62
|
+
{
|
|
63
|
+
type: "image",
|
|
64
|
+
props: {
|
|
65
|
+
alt: "rustic sourdough bread"
|
|
66
|
+
},
|
|
67
|
+
className: "w-full h-64"
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
type: "text",
|
|
71
|
+
props: {
|
|
72
|
+
text: "Artisanal Breads, Baked Fresh Daily"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
};
|
|
77
|
+
// Before calling, image prop has no src
|
|
78
|
+
const imageElement = element.children[0];
|
|
79
|
+
assert.ok(!imageElement.props.src);
|
|
80
|
+
// Call and await resolution
|
|
81
|
+
await resolveUnsplashImagesDeep(element);
|
|
82
|
+
// After calling, image prop must have the resolved src
|
|
83
|
+
assert.equal(imageElement.props.src, "https://images.unsplash.com/photo_1_regular");
|
|
84
|
+
assert.equal(imageElement.props.alt, "rustic sourdough bread");
|
|
85
|
+
// Make sure we have fetch calls
|
|
86
|
+
assert.ok(calls.some(c => c.includes("/search/photos")));
|
|
87
|
+
assert.ok(calls.some(c => c.includes("/download")));
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
globalThis.fetch = originalFetch;
|
|
91
|
+
initUnsplash(null);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=unsplash.service.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unsplash.service.test.js","sourceRoot":"","sources":["../../src/tests/unsplash.service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import assert from \"node:assert/strict\";\nimport test from \"node:test\";\nimport { initUnsplash, resolveUnsplashImagesDeep } from \"../image/unsplash.service.js\";\n\ntest(\"resolveUnsplashImagesDeep: resolves and inserts src for images\", async () => {\n const originalFetch = globalThis.fetch;\n \n // Setup fetch mock\n const calls: string[] = [];\n globalThis.fetch = async (url: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const urlString = String(url);\n calls.push(urlString);\n \n if (urlString.includes(\"/search/photos\")) {\n return {\n ok: true,\n status: 200,\n json: async () => ({\n results: [\n {\n id: \"photo_1\",\n likes: 100,\n width: 800,\n height: 600,\n user: {\n total_photos: 10,\n name: \"Photographer Name\",\n links: {\n html: \"https://unsplash.com/@photographer\"\n }\n },\n links: {\n download_location: \"https://api.unsplash.com/photos/photo_1/download\",\n html: \"https://unsplash.com/photos/photo_1\"\n },\n urls: {\n regular: \"https://images.unsplash.com/photo_1_regular\",\n small: \"https://images.unsplash.com/photo_1_small\"\n }\n }\n ]\n })\n } as Response;\n }\n \n if (urlString.includes(\"/download\")) {\n return {\n ok: true,\n status: 200,\n json: async () => ({})\n } as Response;\n }\n \n return {\n ok: false,\n status: 404\n } as Response;\n };\n\n try {\n initUnsplash({\n url: \"https://api.unsplash.com\",\n accessKey: \"fake_key\",\n });\n\n const element = {\n type: \"div\",\n children: [\n {\n type: \"image\",\n props: {\n alt: \"rustic sourdough bread\"\n },\n className: \"w-full h-64\"\n },\n {\n type: \"text\",\n props: {\n text: \"Artisanal Breads, Baked Fresh Daily\"\n }\n }\n ]\n };\n\n // Before calling, image prop has no src\n const imageElement = element.children[0] as any;\n assert.ok(!imageElement.props.src);\n\n // Call and await resolution\n await resolveUnsplashImagesDeep(element as any);\n\n // After calling, image prop must have the resolved src\n assert.equal(imageElement.props.src, \"https://images.unsplash.com/photo_1_regular\");\n assert.equal(imageElement.props.alt, \"rustic sourdough bread\");\n\n // Make sure we have fetch calls\n assert.ok(calls.some(c => c.includes(\"/search/photos\")));\n assert.ok(calls.some(c => c.includes(\"/download\")));\n\n } finally {\n globalThis.fetch = originalFetch;\n initUnsplash(null);\n }\n});\n"]}
|