tkeron 5.0.1 → 5.0.2
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/changelog.md +12 -0
- package/package.json +1 -1
- package/src/processCom.ts +90 -52
- package/src/processComMd.ts +90 -48
- package/src/processComTs.ts +110 -52
- package/src/processPre.ts +10 -2
package/changelog.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# v5.0.2
|
|
2
|
+
|
|
3
|
+
## Performance: component processing optimization
|
|
4
|
+
|
|
5
|
+
- Perf: single glob scan per build pass to pre-load all component paths into a `Map<tagName, filePath[]>` — eliminates O(pages × components) filesystem scans in `processCom`, `processComTs`, `processComMd`
|
|
6
|
+
- Perf: `Map<path, content>` cache avoids redundant disk reads when the same component is used across multiple pages
|
|
7
|
+
- Perf: `Map<code, jsCode>` transpilation cache in `processComTs` — `Bun.Transpiler.transformSync` result reused for unchanged `.com.ts` files
|
|
8
|
+
- Perf: parallel page processing via `Promise.all` instead of sequential `for...of` — independent pages now process concurrently
|
|
9
|
+
- Perf: lazy `package.json` read in `processPre` — removed top-level `await` that ran on module import regardless of whether pre-rendering was needed
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# v5.0.1
|
|
2
14
|
|
|
3
15
|
## Documentation fixes and dependency updates
|
package/package.json
CHANGED
package/src/processCom.ts
CHANGED
|
@@ -12,10 +12,50 @@ const ensureHtmlDocument = (html: string): string => {
|
|
|
12
12
|
return `${DOCTYPE}<html><head></head><body>${html}</body></html>`;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
interface ComponentCache {
|
|
16
|
+
componentMap: Map<string, string[]>;
|
|
17
|
+
contentCache: Map<string, string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const buildComponentMap = (rootDir: string): Map<string, string[]> => {
|
|
21
|
+
const allFiles = getFilePaths(rootDir, "**/*.com.html", true);
|
|
22
|
+
const map = new Map<string, string[]>();
|
|
23
|
+
for (const file of allFiles) {
|
|
24
|
+
const basename = file.split("/").pop()!;
|
|
25
|
+
const tagName = basename.replace(/\.com\.html$/, "");
|
|
26
|
+
if (!map.has(tagName)) map.set(tagName, []);
|
|
27
|
+
map.get(tagName)!.push(file);
|
|
28
|
+
}
|
|
29
|
+
return map;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getCachedContent = async (
|
|
33
|
+
path: string,
|
|
34
|
+
cache: Map<string, string>,
|
|
35
|
+
): Promise<string> => {
|
|
36
|
+
const cached = cache.get(path);
|
|
37
|
+
if (cached !== undefined) return cached;
|
|
38
|
+
const content = await Bun.file(path).text();
|
|
39
|
+
cache.set(path, content);
|
|
40
|
+
return content;
|
|
41
|
+
};
|
|
42
|
+
|
|
15
43
|
export interface ProcessComOptions {
|
|
16
44
|
logger?: Logger;
|
|
17
45
|
}
|
|
18
46
|
|
|
47
|
+
const resolveComponent = (
|
|
48
|
+
tagName: string,
|
|
49
|
+
currentDir: string,
|
|
50
|
+
componentMap: Map<string, string[]>,
|
|
51
|
+
): string | null => {
|
|
52
|
+
const matches = componentMap.get(tagName);
|
|
53
|
+
if (!matches || matches.length === 0) return null;
|
|
54
|
+
const localPath = join(currentDir, `${tagName}.com.html`);
|
|
55
|
+
if (matches.includes(localPath)) return localPath;
|
|
56
|
+
return matches[0]!;
|
|
57
|
+
};
|
|
58
|
+
|
|
19
59
|
export const processCom = async (
|
|
20
60
|
tempDir: string,
|
|
21
61
|
options: ProcessComOptions = {},
|
|
@@ -27,37 +67,45 @@ export const processCom = async (
|
|
|
27
67
|
return false;
|
|
28
68
|
}
|
|
29
69
|
|
|
70
|
+
const componentMap = buildComponentMap(tempDir);
|
|
71
|
+
const cache: ComponentCache = {
|
|
72
|
+
componentMap,
|
|
73
|
+
contentCache: new Map(),
|
|
74
|
+
};
|
|
75
|
+
|
|
30
76
|
const htmlFiles = getFilePaths(tempDir, "**/*.html", true).filter(
|
|
31
77
|
(p) => !p.endsWith(".com.html"),
|
|
32
78
|
);
|
|
33
79
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
80
|
+
const results = await Promise.all(
|
|
81
|
+
htmlFiles.map(async (htmlFile) => {
|
|
82
|
+
const htmlContent = await Bun.file(htmlFile).text();
|
|
83
|
+
const document = parseHTML(ensureHtmlDocument(htmlContent));
|
|
84
|
+
|
|
85
|
+
const htmlElement =
|
|
86
|
+
document.querySelector("html") || document.documentElement;
|
|
87
|
+
let changed = false;
|
|
88
|
+
if (htmlElement) {
|
|
89
|
+
changed = await processComponents(
|
|
90
|
+
htmlElement,
|
|
91
|
+
dirname(htmlFile),
|
|
92
|
+
tempDir,
|
|
93
|
+
[],
|
|
94
|
+
0,
|
|
95
|
+
log,
|
|
96
|
+
cache,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
53
99
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
100
|
+
const output =
|
|
101
|
+
DOCTYPE +
|
|
102
|
+
(htmlElement?.outerHTML || document.documentElement?.outerHTML || "");
|
|
103
|
+
await Bun.write(htmlFile, output);
|
|
104
|
+
return changed;
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
59
107
|
|
|
60
|
-
return
|
|
108
|
+
return results.some(Boolean);
|
|
61
109
|
};
|
|
62
110
|
|
|
63
111
|
const processComponents = async (
|
|
@@ -67,6 +115,7 @@ const processComponents = async (
|
|
|
67
115
|
componentStack: string[],
|
|
68
116
|
depth: number = 0,
|
|
69
117
|
log: Logger = silentLogger,
|
|
118
|
+
cache: ComponentCache,
|
|
70
119
|
): Promise<boolean> => {
|
|
71
120
|
let hasChanges = false;
|
|
72
121
|
const MAX_DEPTH = 50;
|
|
@@ -82,13 +131,10 @@ const processComponents = async (
|
|
|
82
131
|
|
|
83
132
|
if (tagName) {
|
|
84
133
|
if (!tagName.includes("-")) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
true,
|
|
90
|
-
);
|
|
91
|
-
if ((await Bun.file(localPath).exists()) || globMatches.length > 0) {
|
|
134
|
+
const matches = cache.componentMap.get(tagName);
|
|
135
|
+
if (matches && matches.length > 0) {
|
|
136
|
+
const localPath = join(currentDir, `${tagName}.com.html`);
|
|
137
|
+
const filePath = matches.includes(localPath) ? localPath : matches[0];
|
|
92
138
|
log.error(
|
|
93
139
|
`\n❌ Error: Component name '${tagName}' must contain at least one hyphen.`,
|
|
94
140
|
);
|
|
@@ -96,30 +142,17 @@ const processComponents = async (
|
|
|
96
142
|
log.error(
|
|
97
143
|
` Rename '${tagName}.com.html' to 'tk-${tagName}.com.html' or similar.`,
|
|
98
144
|
);
|
|
99
|
-
log.error(
|
|
100
|
-
` File: ${(await Bun.file(localPath).exists()) ? localPath : globMatches[0]}\n`,
|
|
101
|
-
);
|
|
145
|
+
log.error(` File: ${filePath}\n`);
|
|
102
146
|
throw new Error(
|
|
103
147
|
`Component name '${tagName}' must contain at least one hyphen`,
|
|
104
148
|
);
|
|
105
149
|
}
|
|
106
150
|
} else {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
componentPath = localPath;
|
|
113
|
-
} else {
|
|
114
|
-
const globMatches = getFilePaths(
|
|
115
|
-
rootDir,
|
|
116
|
-
`**/${tagName}.com.html`,
|
|
117
|
-
true,
|
|
118
|
-
);
|
|
119
|
-
if (globMatches.length > 0) {
|
|
120
|
-
componentPath = globMatches[0];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
151
|
+
const componentPath = resolveComponent(
|
|
152
|
+
tagName,
|
|
153
|
+
currentDir,
|
|
154
|
+
cache.componentMap,
|
|
155
|
+
);
|
|
123
156
|
|
|
124
157
|
if (componentPath) {
|
|
125
158
|
hasChanges = true;
|
|
@@ -137,7 +170,10 @@ const processComponents = async (
|
|
|
137
170
|
throw new Error(`Circular dependency: ${chain}`);
|
|
138
171
|
}
|
|
139
172
|
|
|
140
|
-
const componentHtml = await
|
|
173
|
+
const componentHtml = await getCachedContent(
|
|
174
|
+
componentPath,
|
|
175
|
+
cache.contentCache,
|
|
176
|
+
);
|
|
141
177
|
|
|
142
178
|
const tempDoc = parseHTML(
|
|
143
179
|
`<html><body><div id="__tkeron_component_root__">${componentHtml}</div></body></html>`,
|
|
@@ -182,6 +218,7 @@ const processComponents = async (
|
|
|
182
218
|
nextStack,
|
|
183
219
|
depth + 1,
|
|
184
220
|
log,
|
|
221
|
+
cache,
|
|
185
222
|
);
|
|
186
223
|
hasChanges = hasChanges || nestedChanged;
|
|
187
224
|
}
|
|
@@ -197,6 +234,7 @@ const processComponents = async (
|
|
|
197
234
|
componentStack,
|
|
198
235
|
depth,
|
|
199
236
|
log,
|
|
237
|
+
cache,
|
|
200
238
|
);
|
|
201
239
|
hasChanges = hasChanges || childChanged;
|
|
202
240
|
}
|
package/src/processComMd.ts
CHANGED
|
@@ -12,10 +12,50 @@ const ensureHtmlDocument = (html: string): string => {
|
|
|
12
12
|
return `${DOCTYPE}<html><head></head><body>${html}</body></html>`;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
interface ComponentCache {
|
|
16
|
+
componentMap: Map<string, string[]>;
|
|
17
|
+
contentCache: Map<string, string>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const buildComponentMap = (rootDir: string): Map<string, string[]> => {
|
|
21
|
+
const allFiles = getFilePaths(rootDir, "**/*.com.md", true);
|
|
22
|
+
const map = new Map<string, string[]>();
|
|
23
|
+
for (const file of allFiles) {
|
|
24
|
+
const basename = file.split("/").pop()!;
|
|
25
|
+
const tagName = basename.replace(/\.com\.md$/, "");
|
|
26
|
+
if (!map.has(tagName)) map.set(tagName, []);
|
|
27
|
+
map.get(tagName)!.push(file);
|
|
28
|
+
}
|
|
29
|
+
return map;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const getCachedContent = async (
|
|
33
|
+
path: string,
|
|
34
|
+
cache: Map<string, string>,
|
|
35
|
+
): Promise<string> => {
|
|
36
|
+
const cached = cache.get(path);
|
|
37
|
+
if (cached !== undefined) return cached;
|
|
38
|
+
const content = await Bun.file(path).text();
|
|
39
|
+
cache.set(path, content);
|
|
40
|
+
return content;
|
|
41
|
+
};
|
|
42
|
+
|
|
15
43
|
export interface ProcessComMdOptions {
|
|
16
44
|
logger?: Logger;
|
|
17
45
|
}
|
|
18
46
|
|
|
47
|
+
const resolveComponent = (
|
|
48
|
+
tagName: string,
|
|
49
|
+
currentDir: string,
|
|
50
|
+
componentMap: Map<string, string[]>,
|
|
51
|
+
): string | null => {
|
|
52
|
+
const matches = componentMap.get(tagName);
|
|
53
|
+
if (!matches || matches.length === 0) return null;
|
|
54
|
+
const localPath = join(currentDir, `${tagName}.com.md`);
|
|
55
|
+
if (matches.includes(localPath)) return localPath;
|
|
56
|
+
return matches[0]!;
|
|
57
|
+
};
|
|
58
|
+
|
|
19
59
|
export const processComMd = async (
|
|
20
60
|
tempDir: string,
|
|
21
61
|
options: ProcessComMdOptions = {},
|
|
@@ -27,37 +67,45 @@ export const processComMd = async (
|
|
|
27
67
|
return false;
|
|
28
68
|
}
|
|
29
69
|
|
|
70
|
+
const componentMap = buildComponentMap(tempDir);
|
|
71
|
+
const cache: ComponentCache = {
|
|
72
|
+
componentMap,
|
|
73
|
+
contentCache: new Map(),
|
|
74
|
+
};
|
|
75
|
+
|
|
30
76
|
const htmlFiles = getFilePaths(tempDir, "**/*.html", true).filter(
|
|
31
77
|
(p) => !p.endsWith(".com.html"),
|
|
32
78
|
);
|
|
33
79
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
80
|
+
const results = await Promise.all(
|
|
81
|
+
htmlFiles.map(async (htmlFile) => {
|
|
82
|
+
const htmlContent = await Bun.file(htmlFile).text();
|
|
83
|
+
const document = parseHTML(ensureHtmlDocument(htmlContent));
|
|
84
|
+
|
|
85
|
+
const htmlElement =
|
|
86
|
+
document.querySelector("html") || document.documentElement;
|
|
87
|
+
let changed = false;
|
|
88
|
+
if (htmlElement) {
|
|
89
|
+
changed = await processComponents(
|
|
90
|
+
htmlElement,
|
|
91
|
+
dirname(htmlFile),
|
|
92
|
+
tempDir,
|
|
93
|
+
[],
|
|
94
|
+
0,
|
|
95
|
+
log,
|
|
96
|
+
cache,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
53
99
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
100
|
+
const output =
|
|
101
|
+
DOCTYPE +
|
|
102
|
+
(htmlElement?.outerHTML || document.documentElement?.outerHTML || "");
|
|
103
|
+
await Bun.write(htmlFile, output);
|
|
104
|
+
return changed;
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
59
107
|
|
|
60
|
-
return
|
|
108
|
+
return results.some(Boolean);
|
|
61
109
|
};
|
|
62
110
|
|
|
63
111
|
const processComponents = async (
|
|
@@ -67,6 +115,7 @@ const processComponents = async (
|
|
|
67
115
|
componentStack: string[],
|
|
68
116
|
depth: number = 0,
|
|
69
117
|
log: Logger = silentLogger,
|
|
118
|
+
cache: ComponentCache,
|
|
70
119
|
): Promise<boolean> => {
|
|
71
120
|
let hasChanges = false;
|
|
72
121
|
const MAX_DEPTH = 50;
|
|
@@ -82,9 +131,10 @@ const processComponents = async (
|
|
|
82
131
|
|
|
83
132
|
if (tagName) {
|
|
84
133
|
if (!tagName.includes("-")) {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
134
|
+
const matches = cache.componentMap.get(tagName);
|
|
135
|
+
if (matches && matches.length > 0) {
|
|
136
|
+
const localPath = join(currentDir, `${tagName}.com.md`);
|
|
137
|
+
const filePath = matches.includes(localPath) ? localPath : matches[0];
|
|
88
138
|
log.error(
|
|
89
139
|
`\n❌ Error: Component name '${tagName}' must contain at least one hyphen.`,
|
|
90
140
|
);
|
|
@@ -92,30 +142,17 @@ const processComponents = async (
|
|
|
92
142
|
log.error(
|
|
93
143
|
` Rename '${tagName}.com.md' to 'tk-${tagName}.com.md' or similar.`,
|
|
94
144
|
);
|
|
95
|
-
log.error(
|
|
96
|
-
` File: ${(await Bun.file(localPath).exists()) ? localPath : globMatches[0]}\n`,
|
|
97
|
-
);
|
|
145
|
+
log.error(` File: ${filePath}\n`);
|
|
98
146
|
throw new Error(
|
|
99
147
|
`Component name '${tagName}' must contain at least one hyphen`,
|
|
100
148
|
);
|
|
101
149
|
}
|
|
102
150
|
} else {
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
componentPath = localPath;
|
|
109
|
-
} else {
|
|
110
|
-
const globMatches = getFilePaths(
|
|
111
|
-
rootDir,
|
|
112
|
-
`**/${tagName}.com.md`,
|
|
113
|
-
true,
|
|
114
|
-
);
|
|
115
|
-
if (globMatches.length > 0) {
|
|
116
|
-
componentPath = globMatches[0];
|
|
117
|
-
}
|
|
118
|
-
}
|
|
151
|
+
const componentPath = resolveComponent(
|
|
152
|
+
tagName,
|
|
153
|
+
currentDir,
|
|
154
|
+
cache.componentMap,
|
|
155
|
+
);
|
|
119
156
|
|
|
120
157
|
if (componentPath) {
|
|
121
158
|
hasChanges = true;
|
|
@@ -131,7 +168,10 @@ const processComponents = async (
|
|
|
131
168
|
throw new Error(`Circular dependency: ${chain}`);
|
|
132
169
|
}
|
|
133
170
|
|
|
134
|
-
const mdContent = await
|
|
171
|
+
const mdContent = await getCachedContent(
|
|
172
|
+
componentPath,
|
|
173
|
+
cache.contentCache,
|
|
174
|
+
);
|
|
135
175
|
const componentHtml = Bun.markdown.html(mdContent);
|
|
136
176
|
|
|
137
177
|
const tempDoc = parseHTML(
|
|
@@ -177,6 +217,7 @@ const processComponents = async (
|
|
|
177
217
|
nextStack,
|
|
178
218
|
depth + 1,
|
|
179
219
|
log,
|
|
220
|
+
cache,
|
|
180
221
|
);
|
|
181
222
|
hasChanges = hasChanges || nestedChanged;
|
|
182
223
|
}
|
|
@@ -192,6 +233,7 @@ const processComponents = async (
|
|
|
192
233
|
componentStack,
|
|
193
234
|
depth,
|
|
194
235
|
log,
|
|
236
|
+
cache,
|
|
195
237
|
);
|
|
196
238
|
hasChanges = hasChanges || childChanged;
|
|
197
239
|
}
|
package/src/processComTs.ts
CHANGED
|
@@ -12,6 +12,47 @@ const ensureHtmlDocument = (html: string): string => {
|
|
|
12
12
|
return `${DOCTYPE}<html><head></head><body>${html}</body></html>`;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
interface ComponentCache {
|
|
16
|
+
componentMap: Map<string, string[]>;
|
|
17
|
+
contentCache: Map<string, string>;
|
|
18
|
+
transpileCache: Map<string, string>;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const buildComponentMap = (rootDir: string): Map<string, string[]> => {
|
|
22
|
+
const allFiles = getFilePaths(rootDir, "**/*.com.ts", true);
|
|
23
|
+
const map = new Map<string, string[]>();
|
|
24
|
+
for (const file of allFiles) {
|
|
25
|
+
const basename = file.split("/").pop()!;
|
|
26
|
+
const tagName = basename.replace(/\.com\.ts$/, "");
|
|
27
|
+
if (!map.has(tagName)) map.set(tagName, []);
|
|
28
|
+
map.get(tagName)!.push(file);
|
|
29
|
+
}
|
|
30
|
+
return map;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const getCachedContent = async (
|
|
34
|
+
path: string,
|
|
35
|
+
cache: Map<string, string>,
|
|
36
|
+
): Promise<string> => {
|
|
37
|
+
const cached = cache.get(path);
|
|
38
|
+
if (cached !== undefined) return cached;
|
|
39
|
+
const content = await Bun.file(path).text();
|
|
40
|
+
cache.set(path, content);
|
|
41
|
+
return content;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const getCachedTranspile = (
|
|
45
|
+
tsCode: string,
|
|
46
|
+
cache: Map<string, string>,
|
|
47
|
+
): string => {
|
|
48
|
+
const cached = cache.get(tsCode);
|
|
49
|
+
if (cached !== undefined) return cached;
|
|
50
|
+
const transpiler = new Bun.Transpiler({ loader: "ts" });
|
|
51
|
+
const jsCode = transpiler.transformSync(tsCode);
|
|
52
|
+
cache.set(tsCode, jsCode);
|
|
53
|
+
return jsCode;
|
|
54
|
+
};
|
|
55
|
+
|
|
15
56
|
export interface ProcessComTsOptions {
|
|
16
57
|
logger?: Logger;
|
|
17
58
|
}
|
|
@@ -27,38 +68,59 @@ export const processComTs = async (
|
|
|
27
68
|
return false;
|
|
28
69
|
}
|
|
29
70
|
|
|
71
|
+
const componentMap = buildComponentMap(tempDir);
|
|
72
|
+
const cache: ComponentCache = {
|
|
73
|
+
componentMap,
|
|
74
|
+
contentCache: new Map(),
|
|
75
|
+
transpileCache: new Map(),
|
|
76
|
+
};
|
|
77
|
+
|
|
30
78
|
const htmlFiles = getFilePaths(tempDir, "**/*.html", true).filter(
|
|
31
79
|
(p) => !p.endsWith(".com.html"),
|
|
32
80
|
);
|
|
33
81
|
|
|
34
|
-
|
|
82
|
+
const results = await Promise.all(
|
|
83
|
+
htmlFiles.map(async (htmlFile) => {
|
|
84
|
+
const htmlContent = await Bun.file(htmlFile).text();
|
|
85
|
+
const document = parseHTML(ensureHtmlDocument(htmlContent));
|
|
86
|
+
|
|
87
|
+
const htmlElement =
|
|
88
|
+
document.querySelector("html") || document.documentElement;
|
|
89
|
+
let changed = false;
|
|
90
|
+
if (htmlElement) {
|
|
91
|
+
changed = await processComponentsTs(
|
|
92
|
+
htmlElement,
|
|
93
|
+
dirname(htmlFile),
|
|
94
|
+
tempDir,
|
|
95
|
+
[],
|
|
96
|
+
0,
|
|
97
|
+
log,
|
|
98
|
+
options,
|
|
99
|
+
cache,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
35
102
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const changed = await processComponentsTs(
|
|
44
|
-
htmlElement,
|
|
45
|
-
dirname(htmlFile),
|
|
46
|
-
tempDir,
|
|
47
|
-
[],
|
|
48
|
-
0,
|
|
49
|
-
log,
|
|
50
|
-
options,
|
|
51
|
-
);
|
|
52
|
-
hasChanges = hasChanges || changed;
|
|
53
|
-
}
|
|
103
|
+
const output =
|
|
104
|
+
DOCTYPE +
|
|
105
|
+
(htmlElement?.outerHTML || document.documentElement?.outerHTML || "");
|
|
106
|
+
await Bun.write(htmlFile, output);
|
|
107
|
+
return changed;
|
|
108
|
+
}),
|
|
109
|
+
);
|
|
54
110
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(htmlElement?.outerHTML || document.documentElement?.outerHTML || "");
|
|
58
|
-
await Bun.write(htmlFile, output);
|
|
59
|
-
}
|
|
111
|
+
return results.some(Boolean);
|
|
112
|
+
};
|
|
60
113
|
|
|
61
|
-
|
|
114
|
+
const resolveComponent = (
|
|
115
|
+
tagName: string,
|
|
116
|
+
currentDir: string,
|
|
117
|
+
componentMap: Map<string, string[]>,
|
|
118
|
+
): string | null => {
|
|
119
|
+
const matches = componentMap.get(tagName);
|
|
120
|
+
if (!matches || matches.length === 0) return null;
|
|
121
|
+
const localPath = join(currentDir, `${tagName}.com.ts`);
|
|
122
|
+
if (matches.includes(localPath)) return localPath;
|
|
123
|
+
return matches[0]!;
|
|
62
124
|
};
|
|
63
125
|
|
|
64
126
|
const processComponentsTs = async (
|
|
@@ -69,6 +131,7 @@ const processComponentsTs = async (
|
|
|
69
131
|
depth: number = 0,
|
|
70
132
|
log: Logger = silentLogger,
|
|
71
133
|
options: ProcessComTsOptions = {},
|
|
134
|
+
cache: ComponentCache,
|
|
72
135
|
): Promise<boolean> => {
|
|
73
136
|
let hasChanges = false;
|
|
74
137
|
const MAX_DEPTH = 50;
|
|
@@ -84,9 +147,10 @@ const processComponentsTs = async (
|
|
|
84
147
|
|
|
85
148
|
if (tagName) {
|
|
86
149
|
if (!tagName.includes("-")) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
|
|
150
|
+
const matches = cache.componentMap.get(tagName);
|
|
151
|
+
if (matches && matches.length > 0) {
|
|
152
|
+
const localPath = join(currentDir, `${tagName}.com.ts`);
|
|
153
|
+
const filePath = matches.includes(localPath) ? localPath : matches[0];
|
|
90
154
|
log.error(
|
|
91
155
|
`\n❌ Error: Component name '${tagName}' must contain at least one hyphen.`,
|
|
92
156
|
);
|
|
@@ -94,30 +158,17 @@ const processComponentsTs = async (
|
|
|
94
158
|
log.error(
|
|
95
159
|
` Rename '${tagName}.com.ts' to 'tk-${tagName}.com.ts' or similar.`,
|
|
96
160
|
);
|
|
97
|
-
log.error(
|
|
98
|
-
` File: ${(await Bun.file(localPath).exists()) ? localPath : globMatches[0]}\n`,
|
|
99
|
-
);
|
|
161
|
+
log.error(` File: ${filePath}\n`);
|
|
100
162
|
throw new Error(
|
|
101
163
|
`Component name '${tagName}' must contain at least one hyphen`,
|
|
102
164
|
);
|
|
103
165
|
}
|
|
104
166
|
} else {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
componentPath = localPath;
|
|
111
|
-
} else {
|
|
112
|
-
const globMatches = getFilePaths(
|
|
113
|
-
rootDir,
|
|
114
|
-
`**/${tagName}.com.ts`,
|
|
115
|
-
true,
|
|
116
|
-
);
|
|
117
|
-
if (globMatches.length > 0) {
|
|
118
|
-
componentPath = globMatches[0];
|
|
119
|
-
}
|
|
120
|
-
}
|
|
167
|
+
const componentPath = resolveComponent(
|
|
168
|
+
tagName,
|
|
169
|
+
currentDir,
|
|
170
|
+
cache.componentMap,
|
|
171
|
+
);
|
|
121
172
|
|
|
122
173
|
if (componentPath) {
|
|
123
174
|
hasChanges = true;
|
|
@@ -133,7 +184,10 @@ const processComponentsTs = async (
|
|
|
133
184
|
throw new Error(`Circular dependency: ${chain}`);
|
|
134
185
|
}
|
|
135
186
|
|
|
136
|
-
const originalComponentCode = await
|
|
187
|
+
const originalComponentCode = await getCachedContent(
|
|
188
|
+
componentPath,
|
|
189
|
+
cache.contentCache,
|
|
190
|
+
);
|
|
137
191
|
|
|
138
192
|
const elementHTML = (child as any).outerHTML;
|
|
139
193
|
|
|
@@ -187,13 +241,15 @@ ${codeWithoutImports}
|
|
|
187
241
|
await module.component(com);
|
|
188
242
|
} finally {
|
|
189
243
|
try {
|
|
190
|
-
const
|
|
191
|
-
await
|
|
244
|
+
const { unlink } = await import("fs/promises");
|
|
245
|
+
await unlink(tempPath);
|
|
192
246
|
} catch {}
|
|
193
247
|
}
|
|
194
248
|
} else {
|
|
195
|
-
const
|
|
196
|
-
|
|
249
|
+
const jsCode = getCachedTranspile(
|
|
250
|
+
originalComponentCode,
|
|
251
|
+
cache.transpileCache,
|
|
252
|
+
);
|
|
197
253
|
const AsyncFunction = Object.getPrototypeOf(
|
|
198
254
|
async function () {},
|
|
199
255
|
).constructor;
|
|
@@ -232,6 +288,7 @@ ${codeWithoutImports}
|
|
|
232
288
|
depth + 1,
|
|
233
289
|
log,
|
|
234
290
|
options,
|
|
291
|
+
cache,
|
|
235
292
|
);
|
|
236
293
|
|
|
237
294
|
const nodesToInsert = Array.from((div as any).childNodes || []).map(
|
|
@@ -266,6 +323,7 @@ ${codeWithoutImports}
|
|
|
266
323
|
depth,
|
|
267
324
|
log,
|
|
268
325
|
options,
|
|
326
|
+
cache,
|
|
269
327
|
);
|
|
270
328
|
hasChanges = hasChanges || childChanged;
|
|
271
329
|
}
|
package/src/processPre.ts
CHANGED
|
@@ -4,8 +4,14 @@ import type { Logger } from "@tkeron/tools";
|
|
|
4
4
|
import { silentLogger } from "@tkeron/tools";
|
|
5
5
|
|
|
6
6
|
const packageJsonPath = join(import.meta.dir, "..", "package.json");
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
|
|
8
|
+
let _tkeronVersion: string | null = null;
|
|
9
|
+
const getTkeronVersion = async (): Promise<string> => {
|
|
10
|
+
if (_tkeronVersion) return _tkeronVersion;
|
|
11
|
+
const packageJson = await Bun.file(packageJsonPath).json();
|
|
12
|
+
_tkeronVersion = packageJson.version;
|
|
13
|
+
return _tkeronVersion!;
|
|
14
|
+
};
|
|
9
15
|
|
|
10
16
|
const HTML_PARSER_PATH = import.meta.resolve("@tkeron/html-parser");
|
|
11
17
|
|
|
@@ -40,6 +46,8 @@ export const processPre = async (
|
|
|
40
46
|
|
|
41
47
|
const hasChanges = preFiles.length > 0;
|
|
42
48
|
|
|
49
|
+
const TKERON_VERSION = hasChanges ? await getTkeronVersion() : "";
|
|
50
|
+
|
|
43
51
|
for (const preFile of preFiles) {
|
|
44
52
|
const htmlFile = preFile.replace(/\.pre\.ts$/, ".html");
|
|
45
53
|
|