tkeron 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/bun.lock +13 -13
  2. package/changelog.md +19 -0
  3. package/docs/testing.md +1 -1
  4. package/examples/with_com_html_in_ts/{src → websrc}/index.html +4 -5
  5. package/examples/with_com_html_in_ts/websrc/info-panel.com.ts +14 -0
  6. package/mcp-server.ts +3 -7
  7. package/package.json +8 -7
  8. package/src/build.ts +3 -0
  9. package/src/develop.ts +28 -13
  10. package/src/processCom.ts +12 -0
  11. package/src/processComTs.ts +12 -0
  12. package/src/processPost.ts +80 -0
  13. package/tkeron.d.ts +1 -0
  14. package/examples/with_com_html_in_ts/src/info-panel.com.ts +0 -3
  15. /package/examples/basic_build/{src → websrc}/index.html +0 -0
  16. /package/examples/basic_build/{src → websrc}/index.ts +0 -0
  17. /package/examples/with_assets/{src → websrc}/index.html +0 -0
  18. /package/examples/with_assets/{src → websrc}/index.ts +0 -0
  19. /package/examples/with_assets/{src → websrc}/profile.png +0 -0
  20. /package/examples/with_assets/{src → websrc}/section/index.html +0 -0
  21. /package/examples/with_com_html_in_ts/{src → websrc}/info-panel.com.html +0 -0
  22. /package/examples/with_com_html_in_ts/{src → websrc}/user-card.com.html +0 -0
  23. /package/examples/with_com_html_in_ts/{src → websrc}/user-card.com.ts +0 -0
  24. /package/examples/with_com_html_priority/{src → websrc}/admin/admin-panel.com.html +0 -0
  25. /package/examples/with_com_html_priority/{src → websrc}/admin/dashboard.html +0 -0
  26. /package/examples/with_com_html_priority/{src → websrc}/admin/dashboard.ts +0 -0
  27. /package/examples/with_com_html_priority/{src → websrc}/admin/nested-stat.com.html +0 -0
  28. /package/examples/with_com_html_priority/{src → websrc}/admin/site-header.com.html +0 -0
  29. /package/examples/with_com_html_priority/{src → websrc}/blog/comment-item.com.html +0 -0
  30. /package/examples/with_com_html_priority/{src → websrc}/blog/comment-section.com.html +0 -0
  31. /package/examples/with_com_html_priority/{src → websrc}/blog/post.html +0 -0
  32. /package/examples/with_com_html_priority/{src → websrc}/blog/post.ts +0 -0
  33. /package/examples/with_com_html_priority/{src → websrc}/index.html +0 -0
  34. /package/examples/with_com_html_priority/{src → websrc}/index.ts +0 -0
  35. /package/examples/with_com_html_priority/{src → websrc}/info-box.com.html +0 -0
  36. /package/examples/with_com_html_priority/{src → websrc}/site-header.com.html +0 -0
  37. /package/examples/with_com_mixed_priority/{src → websrc}/dashboard/main.html +0 -0
  38. /package/examples/with_com_mixed_priority/{src → websrc}/dashboard/main.ts +0 -0
  39. /package/examples/with_com_mixed_priority/{src → websrc}/dashboard/page-header.com.ts +0 -0
  40. /package/examples/with_com_mixed_priority/{src → websrc}/dashboard/stats-widget.com.ts +0 -0
  41. /package/examples/with_com_mixed_priority/{src → websrc}/feature-card.com.ts +0 -0
  42. /package/examples/with_com_mixed_priority/{src → websrc}/footer-info.com.html +0 -0
  43. /package/examples/with_com_mixed_priority/{src → websrc}/index.html +0 -0
  44. /package/examples/with_com_mixed_priority/{src → websrc}/index.ts +0 -0
  45. /package/examples/with_com_mixed_priority/{src → websrc}/page-header.com.html +0 -0
  46. /package/examples/with_com_mixed_priority/{src → websrc}/settings/config.html +0 -0
  47. /package/examples/with_com_mixed_priority/{src → websrc}/settings/config.ts +0 -0
  48. /package/examples/with_com_mixed_priority/{src → websrc}/settings/priority-test.com.html +0 -0
  49. /package/examples/with_com_mixed_priority/{src → websrc}/settings/priority-test.com.ts +0 -0
  50. /package/examples/with_com_mixed_priority/{src → websrc}/users/profiles/activity-feed.com.ts +0 -0
  51. /package/examples/with_com_mixed_priority/{src → websrc}/users/profiles/page-header.com.html +0 -0
  52. /package/examples/with_com_mixed_priority/{src → websrc}/users/profiles/profile-actions.com.html +0 -0
  53. /package/examples/with_com_mixed_priority/{src → websrc}/users/profiles/user-profile.com.ts +0 -0
  54. /package/examples/with_com_mixed_priority/{src → websrc}/users/profiles/view.html +0 -0
  55. /package/examples/with_com_mixed_priority/{src → websrc}/users/profiles/view.ts +0 -0
  56. /package/examples/with_com_ts/{src → websrc}/dynamic-list.com.ts +0 -0
  57. /package/examples/with_com_ts/{src → websrc}/greeting-message.com.ts +0 -0
  58. /package/examples/with_com_ts/{src → websrc}/index.html +0 -0
  59. /package/examples/with_com_ts/{src → websrc}/user-card.com.ts +0 -0
  60. /package/examples/with_com_ts_priority/{src → websrc}/analytics/chart-widget.com.ts +0 -0
  61. /package/examples/with_com_ts_priority/{src → websrc}/analytics/report.html +0 -0
  62. /package/examples/with_com_ts_priority/{src → websrc}/analytics/report.ts +0 -0
  63. /package/examples/with_com_ts_priority/{src → websrc}/analytics/user-stats.com.ts +0 -0
  64. /package/examples/with_com_ts_priority/{src → websrc}/data-table.com.ts +0 -0
  65. /package/examples/with_com_ts_priority/{src → websrc}/index.html +0 -0
  66. /package/examples/with_com_ts_priority/{src → websrc}/index.ts +0 -0
  67. /package/examples/with_com_ts_priority/{src → websrc}/sales/regional/data-table.com.ts +0 -0
  68. /package/examples/with_com_ts_priority/{src → websrc}/sales/regional/overview.html +0 -0
  69. /package/examples/with_com_ts_priority/{src → websrc}/sales/regional/overview.ts +0 -0
  70. /package/examples/with_com_ts_priority/{src → websrc}/sales/regional/sales-summary.com.ts +0 -0
  71. /package/examples/with_com_ts_priority/{src → websrc}/user-stats.com.ts +0 -0
  72. /package/examples/with_component_iteration/{src → websrc}/card-list.com.ts +0 -0
  73. /package/examples/with_component_iteration/{src → websrc}/engagement-meter.com.ts +0 -0
  74. /package/examples/with_component_iteration/{src → websrc}/index.html +0 -0
  75. /package/examples/with_component_iteration/{src → websrc}/index.ts +0 -0
  76. /package/examples/with_component_iteration/{src → websrc}/note-box.com.html +0 -0
  77. /package/examples/with_component_iteration/{src → websrc}/status-badge.com.ts +0 -0
  78. /package/examples/with_component_iteration/{src → websrc}/user-card.com.ts +0 -0
  79. /package/examples/with_pre/{src → websrc}/contact.pre.ts +0 -0
  80. /package/examples/with_pre/{src → websrc}/index.html +0 -0
  81. /package/examples/with_pre/{src → websrc}/index.ts +0 -0
  82. /package/examples/with_pre/{src → websrc}/profile.png +0 -0
  83. /package/examples/with_pre/{src → websrc}/section/index.html +0 -0
  84. /package/examples/with_pre/{src → websrc}/section/index.pre.ts +0 -0
  85. /package/examples/with_pre/{src → websrc}/section/no-linked-profile.png +0 -0
package/bun.lock CHANGED
@@ -5,30 +5,30 @@
5
5
  "": {
6
6
  "name": "tkeron",
7
7
  "dependencies": {
8
- "@modelcontextprotocol/sdk": "^1.27.0",
9
- "@tkeron/commands": "0.4.6",
10
- "@tkeron/html-parser": "1.5.5",
11
- "@tkeron/tools": "^0.4.0",
8
+ "@modelcontextprotocol/sdk": "^1.29.0",
9
+ "@tkeron/commands": "0.4.7",
10
+ "@tkeron/html-parser": "1.5.6",
11
+ "@tkeron/tools": "^0.4.1",
12
12
  },
13
13
  "devDependencies": {
14
- "@types/bun": "^1.3.9",
14
+ "@types/bun": "^1.3.11",
15
15
  "prettier": "^3.8.1",
16
- "typescript": "^5.9.3",
16
+ "typescript": "^6.0.2",
17
17
  },
18
18
  },
19
19
  },
20
20
  "packages": {
21
21
  "@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
22
22
 
23
- "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-qOdO524oPMkUsOJTrsH9vz/HN3B5pKyW+9zIW51A9kDMVe7ON70drz1ouoyoyOcfzc+oxhkQ6jWmbyKnlWmYqA=="],
23
+ "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.29.0", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ=="],
24
24
 
25
- "@tkeron/commands": ["@tkeron/commands@0.4.6", "", { "peerDependencies": { "typescript": "^5.9.3" } }, "sha512-Bojs3GmIpvd/4Mcw7FvbohRcDyHEzs3ZJHxwIeXE0diQzN+ER3R30xIFovgzwE8QfWvC9uFDaN2VTk4O+0ffyA=="],
25
+ "@tkeron/commands": ["@tkeron/commands@0.4.7", "", { "peerDependencies": { "typescript": "^5.9.3" } }, "sha512-QGYLnPcOFir5cMJpeUuLMZdW5IrcDyY/jjbML3o23yATI8Y3XzwYhRDW2l8kex0waLV7KsAwnGsb2zl8sRn1PQ=="],
26
26
 
27
- "@tkeron/html-parser": ["@tkeron/html-parser@1.5.5", "", { "peerDependencies": { "typescript": "^5.9.3" } }, "sha512-GSmlscPWxb2XqlmGNvtQ9ArETIPQmt3vIFlUgpTftLglkcCVgsA/pVZNW9AKJ8OZMfy8Jfmq+tf8QpbUWBVnsQ=="],
27
+ "@tkeron/html-parser": ["@tkeron/html-parser@1.5.6", "", { "peerDependencies": { "typescript": "^5.9.3" } }, "sha512-dATXoSjxOuUjyjde5ocrZdd5xKfpKf7R9dwRklXHVCAvGwPR2UlJfISWmfmYIwlwFuidg+jmujXmLlLwA7hQgA=="],
28
28
 
29
- "@tkeron/tools": ["@tkeron/tools@0.4.0", "", { "peerDependencies": { "typescript": "^5.9.3" } }, "sha512-lceNx2BGfEvL0U79BgLAb9ObGMwqeXoFYTdwbks1fDrxHaIinE1XWsQzF4k6jOSw00GFD++byUQMKgpiUilY5w=="],
29
+ "@tkeron/tools": ["@tkeron/tools@0.4.1", "", { "peerDependencies": { "typescript": "^5.9.3" } }, "sha512-nsmguSq/Ukx930ChwO11V433R786aJ/tniugzDdlfT/rzLrFxPJoHZerA71XGOIuD8/FRlvS7kJR9YI0CcxmqQ=="],
30
30
 
31
- "@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
31
+ "@types/bun": ["@types/bun@1.3.11", "", { "dependencies": { "bun-types": "1.3.11" } }, "sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg=="],
32
32
 
33
33
  "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="],
34
34
 
@@ -40,7 +40,7 @@
40
40
 
41
41
  "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
42
42
 
43
- "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
43
+ "bun-types": ["bun-types@1.3.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg=="],
44
44
 
45
45
  "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
46
46
 
@@ -202,7 +202,7 @@
202
202
 
203
203
  "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
204
204
 
205
- "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
205
+ "typescript": ["typescript@6.0.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ=="],
206
206
 
207
207
  "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
208
208
 
package/changelog.md CHANGED
@@ -1,3 +1,22 @@
1
+ # v5.2.0
2
+
3
+ ## Feature: `.post.ts` post-processing support
4
+
5
+ - New file type `.post.ts`: runs after the build to post-process the corresponding `.html` file
6
+ - The `.post.ts` script receives a `document` object (parsed from the HTML) and writes the result back to the HTML file after execution
7
+ - Executes with `bun run` in the project root context
8
+ - Useful for final DOM manipulation, injecting metadata, or any transformation after components are resolved
9
+ - `processPost` returns `false` when no `.post.ts` files are found (no-op)
10
+
11
+ ## Feature: `data-tk-id` attribute on component `<style>` elements
12
+
13
+ - Root-level `<style>` elements in component output now receive a `data-tk-id="component-name"` attribute
14
+ - Nested `<style>` elements (inside wrappers) also receive `data-tk-id`
15
+ - Applies to both `.com.html` and `.com.ts` components
16
+ - Enables per-component style scoping and identification in the final HTML
17
+
18
+ ---
19
+
1
20
  # v5.1.0
2
21
 
3
22
  ## Feature: .com.html template injection into .com.ts components
package/docs/testing.md CHANGED
@@ -61,7 +61,7 @@ import { getBuildResult, type BuildResult } from "tkeron";
61
61
  import { join } from "path";
62
62
 
63
63
  describe("my project", () => {
64
- const sourcePath = join(import.meta.dir, "src");
64
+ const sourcePath = join(import.meta.dir, "websrc");
65
65
  let result: BuildResult;
66
66
 
67
67
  beforeAll(async () => {
@@ -11,10 +11,9 @@
11
11
  <user-card data-name="Alice" data-role="Developer"></user-card>
12
12
  <user-card data-name="Bob" data-role="Designer"></user-card>
13
13
 
14
- <info-panel data-title="Features">
15
- <li>HTML templates for structure</li>
16
- <li>TypeScript for logic</li>
17
- <li>Clean separation of concerns</li>
18
- </info-panel>
14
+ <info-panel
15
+ data-title="Features"
16
+ data-items="HTML templates for structure,TypeScript for logic,Clean separation of concerns"
17
+ ></info-panel>
19
18
  </body>
20
19
  </html>
@@ -0,0 +1,14 @@
1
+ const title = com.getAttribute("data-title") || "Info";
2
+ const rawItems = com.getAttribute("data-items") || "";
3
+ const items = rawItems
4
+ .split(",")
5
+ .map((s: string) => s.trim())
6
+ .filter((s: string) => s.length > 0);
7
+
8
+ const titleEl = com.querySelector(".title");
9
+ if (titleEl) titleEl.textContent = title;
10
+
11
+ const itemsEl = com.querySelector(".items");
12
+ if (itemsEl) {
13
+ itemsEl.innerHTML = items.map((item: string) => `<li>${item}</li>`).join("");
14
+ }
package/mcp-server.ts CHANGED
@@ -177,8 +177,7 @@ server.registerTool(
177
177
  const examplePath = join(EXAMPLES_DIR, name);
178
178
  return (
179
179
  statSync(examplePath).isDirectory() &&
180
- (existsSync(join(examplePath, "src")) ||
181
- existsSync(join(examplePath, "websrc")))
180
+ existsSync(join(examplePath, "websrc"))
182
181
  );
183
182
  });
184
183
 
@@ -228,17 +227,14 @@ server.registerTool(
228
227
  };
229
228
  }
230
229
 
231
- let srcPath = join(examplePath, "src");
232
- if (!existsSync(srcPath)) {
233
- srcPath = join(examplePath, "websrc");
234
- }
230
+ const srcPath = join(examplePath, "websrc");
235
231
 
236
232
  if (!existsSync(srcPath)) {
237
233
  return {
238
234
  content: [
239
235
  {
240
236
  type: "text" as const,
241
- text: `Example ${exampleName} does not have a src or websrc directory`,
237
+ text: `Example ${exampleName} does not have a websrc directory`,
242
238
  },
243
239
  ],
244
240
  isError: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tkeron",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "CLI build tool for vanilla web development with TypeScript.",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -32,15 +32,15 @@
32
32
  "author": "tkeron",
33
33
  "license": "MIT",
34
34
  "dependencies": {
35
- "@modelcontextprotocol/sdk": "^1.27.0",
36
- "@tkeron/commands": "0.4.6",
37
- "@tkeron/html-parser": "1.5.5",
38
- "@tkeron/tools": "^0.4.0"
35
+ "@modelcontextprotocol/sdk": "^1.29.0",
36
+ "@tkeron/commands": "0.4.7",
37
+ "@tkeron/html-parser": "1.5.6",
38
+ "@tkeron/tools": "^0.4.1"
39
39
  },
40
40
  "devDependencies": {
41
- "@types/bun": "^1.3.9",
41
+ "@types/bun": "^1.3.11",
42
42
  "prettier": "^3.8.1",
43
- "typescript": "^5.9.3"
43
+ "typescript": "^6.0.2"
44
44
  },
45
45
  "keywords": [
46
46
  "cli",
@@ -57,6 +57,7 @@
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  },
60
+ "homepage": "https://tkeron.com",
60
61
  "repository": {
61
62
  "type": "git",
62
63
  "url": "git+https://github.com/tkeron/tkeron.git"
package/src/build.ts CHANGED
@@ -4,6 +4,7 @@ import { processPre } from "./processPre";
4
4
  import { processCom } from "./processCom";
5
5
  import { processComTs } from "./processComTs";
6
6
  import { processComMd } from "./processComMd";
7
+ import { processPost } from "./processPost";
7
8
  import { rm, exists, mkdir, cp } from "fs/promises";
8
9
  import type { Logger } from "@tkeron/tools";
9
10
  import { silentLogger } from "@tkeron/tools";
@@ -56,6 +57,8 @@ export const build = async (options: BuildOptions) => {
56
57
  }
57
58
  }
58
59
 
60
+ await processPost(tempDir, { logger: log, projectRoot: sourceParent });
61
+
59
62
  if (await exists(target)) {
60
63
  await rm(target, { recursive: true, force: true });
61
64
  }
package/src/develop.ts CHANGED
@@ -130,30 +130,45 @@ export const develop = async (
130
130
 
131
131
  log.log(`🚀 Development server running at http://${host}:${port}`);
132
132
 
133
+ let currentBuild: Promise<void> | null = null;
134
+ let isStopped = false;
135
+
133
136
  const watcher = watch(
134
137
  source,
135
138
  { recursive: true },
136
139
  async (event, filename) => {
137
- if (filename) {
138
- log.log(`📝 File changed: ${filename}`);
139
- log.log("🔨 Rebuilding...");
140
- await build({ sourceDir: source, targetDir: target, logger: log });
141
- log.log("✅ Build complete!");
142
-
143
- reloadClients.forEach((controller) => {
144
- try {
145
- controller.enqueue("data: reload\n\n");
146
- } catch (e) {
147
- reloadClients.delete(controller);
148
- }
149
- });
140
+ if (!filename || isStopped || currentBuild) return;
141
+ log.log(`📝 File changed: ${filename}`);
142
+ log.log("🔨 Rebuilding...");
143
+ const buildPromise = build({
144
+ sourceDir: source,
145
+ targetDir: target,
146
+ logger: log,
147
+ });
148
+ currentBuild = buildPromise;
149
+ try {
150
+ await buildPromise;
151
+ } finally {
152
+ if (currentBuild === buildPromise) currentBuild = null;
150
153
  }
154
+ if (isStopped) return;
155
+ log.log("✅ Build complete!");
156
+
157
+ reloadClients.forEach((controller) => {
158
+ try {
159
+ controller.enqueue("data: reload\n\n");
160
+ } catch (e) {
161
+ reloadClients.delete(controller);
162
+ }
163
+ });
151
164
  },
152
165
  );
153
166
 
154
167
  const stop = async () => {
155
168
  log.log("\n👋 Shutting down server...");
169
+ isStopped = true;
156
170
  watcher.close();
171
+ await currentBuild?.catch(() => {});
157
172
  server.stop();
158
173
 
159
174
  await new Promise((resolve) => setTimeout(resolve, 100));
package/src/processCom.ts CHANGED
@@ -189,6 +189,18 @@ const processComponents = async (
189
189
  (tempContainer as any).childNodes || [],
190
190
  ).map((node: any) => (node?.cloneNode ? node.cloneNode(true) : node));
191
191
 
192
+ for (const node of nodesToInsert) {
193
+ if ((node as any).nodeType === 1) {
194
+ if ((node as any).tagName?.toLowerCase() === "style") {
195
+ (node as any).setAttribute("data-tk-id", tagName);
196
+ }
197
+ const nested = (node as any).querySelectorAll?.("style") || [];
198
+ for (const styleEl of nested) {
199
+ (styleEl as any).setAttribute("data-tk-id", tagName);
200
+ }
201
+ }
202
+ }
203
+
192
204
  const parent = (child as any).parentNode;
193
205
 
194
206
  if (parent) {
@@ -335,6 +335,18 @@ ${codeWithoutImports}
335
335
  (node: any) => (node?.cloneNode ? node.cloneNode(true) : node),
336
336
  );
337
337
 
338
+ for (const node of nodesToInsert) {
339
+ if ((node as any).nodeType === 1) {
340
+ if ((node as any).tagName?.toLowerCase() === "style") {
341
+ (node as any).setAttribute("data-tk-id", tagName);
342
+ }
343
+ const nested = (node as any).querySelectorAll?.("style") || [];
344
+ for (const styleEl of nested) {
345
+ (styleEl as any).setAttribute("data-tk-id", tagName);
346
+ }
347
+ }
348
+ }
349
+
338
350
  const parent = (child as any).parentNode;
339
351
 
340
352
  if (parent) {
@@ -0,0 +1,80 @@
1
+ import { join, dirname } from "path";
2
+ import { getFilePaths } from "@tkeron/tools";
3
+ import type { Logger } from "@tkeron/tools";
4
+ import { silentLogger } from "@tkeron/tools";
5
+
6
+ const HTML_PARSER_PATH = import.meta.resolve("@tkeron/html-parser");
7
+
8
+ export interface ProcessPostOptions {
9
+ logger?: Logger;
10
+ projectRoot?: string;
11
+ }
12
+
13
+ export const processPost = async (
14
+ tempDir: string,
15
+ options: ProcessPostOptions = {},
16
+ ): Promise<boolean> => {
17
+ const log = options.logger || silentLogger;
18
+
19
+ if (!tempDir || typeof tempDir !== "string") {
20
+ log.error(`\n❌ Error: Invalid tempDir provided for processPost.`);
21
+ return false;
22
+ }
23
+
24
+ const postFiles = getFilePaths(tempDir, "**/*.post.ts", true);
25
+
26
+ if (postFiles.length === 0) return false;
27
+
28
+ for (const postFile of postFiles) {
29
+ const htmlFile = postFile.replace(/\.post\.ts$/, ".html");
30
+
31
+ const originalCode = await Bun.file(postFile).text();
32
+
33
+ const htmlContent = await Bun.file(htmlFile).text();
34
+
35
+ const modifiedCode = `
36
+ import { parseHTML } from ${JSON.stringify(HTML_PARSER_PATH)};
37
+
38
+ const htmlPath = ${JSON.stringify(htmlFile)};
39
+ const htmlContent = ${JSON.stringify(htmlContent)};
40
+ const document = parseHTML(htmlContent);
41
+
42
+ ${originalCode}
43
+
44
+
45
+ const doctype = '<!DOCTYPE html>\\n';
46
+ const htmlOutput = doctype + document.documentElement.outerHTML;
47
+ await Bun.write(htmlPath, htmlOutput);
48
+ `;
49
+
50
+ await Bun.write(postFile, modifiedCode);
51
+
52
+ const proc = Bun.spawn(["bun", "run", postFile], {
53
+ cwd: options.projectRoot || dirname(postFile),
54
+ stdout: "pipe",
55
+ stderr: "pipe",
56
+ env: { ...process.env },
57
+ });
58
+
59
+ await proc.exited;
60
+
61
+ if (proc.exitCode !== 0) {
62
+ const stderr = await new Response(proc.stderr).text();
63
+ const stdout = await new Response(proc.stdout).text();
64
+ log.error(
65
+ `\n❌ Error: Post-processing failed for ${postFile.split("/").pop()}`,
66
+ );
67
+ log.error(`\n💡 File: ${postFile}`);
68
+ if (stderr) {
69
+ log.error(`\nError details:\n${stderr}`);
70
+ }
71
+ if (stdout) {
72
+ log.error(`\nOutput:\n${stdout}`);
73
+ }
74
+ log.error("");
75
+ throw new Error(`Post-processing failed for ${postFile}`);
76
+ }
77
+ }
78
+
79
+ return true;
80
+ };
package/tkeron.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  declare const com: HTMLElement;
2
+ declare const document: Document;
@@ -1,3 +0,0 @@
1
- const title = com.getAttribute("data-title") || "Info";
2
- const titleEl = com.querySelector(".title");
3
- if (titleEl) titleEl.textContent = title;
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes