@thyn/core 0.0.349 → 0.0.351
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/.github/workflows/test.yml +0 -10
- package/dist/plugin/index.js +1 -1
- package/dist/plugin/utils.js +131 -10
- package/docs/package-lock.json +1163 -557
- package/docs/package.json +1 -1
- package/docs/src/pages/Home.thyn +24 -22
- package/package.json +4 -1
- package/src/plugin/index.ts +1 -1
- package/src/plugin/utils.ts +150 -10
- package/tests/CodeSnippet.test.ts +28 -0
- package/tests/CodeSnippet.thyn +31 -0
|
@@ -23,17 +23,7 @@ jobs:
|
|
|
23
23
|
node-version: ${{ matrix.node-version }}
|
|
24
24
|
|
|
25
25
|
- name: Install core dependencies
|
|
26
|
-
working-directory: packages/core
|
|
27
26
|
run: npm install
|
|
28
27
|
|
|
29
28
|
- name: Run core tests
|
|
30
|
-
working-directory: packages/core
|
|
31
|
-
run: npm test
|
|
32
|
-
|
|
33
|
-
- name: Install vite-plugin dependencies
|
|
34
|
-
working-directory: packages/vite-plugin
|
|
35
|
-
run: npm install
|
|
36
|
-
|
|
37
|
-
- name: Run vite-plugin tests
|
|
38
|
-
working-directory: packages/vite-plugin
|
|
39
29
|
run: npm test
|
package/dist/plugin/index.js
CHANGED
|
@@ -815,7 +815,7 @@ async function transformHTMLtoJSX(html, style) {
|
|
|
815
815
|
const template = parseHTML("<template>" + processedHTML + "</template>");
|
|
816
816
|
const rootElement = template.content.firstElementChild;
|
|
817
817
|
let scopedStyle = null;
|
|
818
|
-
if (style) {
|
|
818
|
+
if (style && rootElement) {
|
|
819
819
|
addScopeId(rootElement, scopeId);
|
|
820
820
|
scopedStyle = await scopeSelectors(style, scopeId);
|
|
821
821
|
}
|
package/dist/plugin/utils.js
CHANGED
|
@@ -1,21 +1,142 @@
|
|
|
1
1
|
export function extractParts(code) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
// Helper to check if a position is inside a string literal or comment
|
|
3
|
+
function isInsideStringOrComment(code, pos) {
|
|
4
|
+
let inString = false;
|
|
5
|
+
let stringChar = '';
|
|
6
|
+
let escaped = false;
|
|
7
|
+
let inLineComment = false;
|
|
8
|
+
let inBlockComment = false;
|
|
9
|
+
for (let i = 0; i < pos; i++) {
|
|
10
|
+
const char = code[i];
|
|
11
|
+
const nextChar = code[i + 1];
|
|
12
|
+
if (inLineComment) {
|
|
13
|
+
if (char === '\n') {
|
|
14
|
+
inLineComment = false;
|
|
15
|
+
}
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (inBlockComment) {
|
|
19
|
+
if (char === '*' && nextChar === '/') {
|
|
20
|
+
inBlockComment = false;
|
|
21
|
+
i++; // skip the '/'
|
|
22
|
+
}
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (escaped) {
|
|
26
|
+
escaped = false;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (char === '\\') {
|
|
30
|
+
escaped = true;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
// Check for comment start
|
|
34
|
+
if (char === '/' && nextChar === '/') {
|
|
35
|
+
inLineComment = true;
|
|
36
|
+
i++; // skip the second '/'
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (char === '/' && nextChar === '*') {
|
|
40
|
+
inBlockComment = true;
|
|
41
|
+
i++; // skip the '*'
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
if (!inString && (char === '"' || char === "'" || char === '`')) {
|
|
45
|
+
inString = true;
|
|
46
|
+
stringChar = char;
|
|
47
|
+
}
|
|
48
|
+
else if (inString && char === stringChar) {
|
|
49
|
+
inString = false;
|
|
50
|
+
stringChar = '';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return inString || inLineComment || inBlockComment;
|
|
54
|
+
}
|
|
55
|
+
// Find first real <script> tag (not inside a string)
|
|
56
|
+
function findScriptSection(code) {
|
|
57
|
+
const openRegex = /<script([^>]*)>/gi;
|
|
58
|
+
let openMatch;
|
|
59
|
+
while ((openMatch = openRegex.exec(code)) !== null) {
|
|
60
|
+
if (!isInsideStringOrComment(code, openMatch.index)) {
|
|
61
|
+
const contentStart = openMatch.index + openMatch[0].length;
|
|
62
|
+
// Find the first </script> that is not inside a string
|
|
63
|
+
const closeRegex = /<\/script>/gi;
|
|
64
|
+
let closeMatch;
|
|
65
|
+
while ((closeMatch = closeRegex.exec(code)) !== null) {
|
|
66
|
+
if (closeMatch.index >= contentStart && !isInsideStringOrComment(code, closeMatch.index)) {
|
|
67
|
+
return {
|
|
68
|
+
start: openMatch.index,
|
|
69
|
+
contentStart: contentStart,
|
|
70
|
+
contentEnd: closeMatch.index,
|
|
71
|
+
end: closeMatch.index + closeMatch[0].length,
|
|
72
|
+
attrs: openMatch[1] || ''
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
// Find first real <style> tag (not inside a string)
|
|
81
|
+
function findStyleSection(code) {
|
|
82
|
+
const openRegex = /<style[^>]*>/gi;
|
|
83
|
+
let openMatch;
|
|
84
|
+
while ((openMatch = openRegex.exec(code)) !== null) {
|
|
85
|
+
if (!isInsideStringOrComment(code, openMatch.index)) {
|
|
86
|
+
const contentStart = openMatch.index + openMatch[0].length;
|
|
87
|
+
// Find the first </style> that is not inside a string
|
|
88
|
+
const closeRegex = /<\/style>/gi;
|
|
89
|
+
let closeMatch;
|
|
90
|
+
while ((closeMatch = closeRegex.exec(code)) !== null) {
|
|
91
|
+
if (closeMatch.index >= contentStart && !isInsideStringOrComment(code, closeMatch.index)) {
|
|
92
|
+
return {
|
|
93
|
+
start: openMatch.index,
|
|
94
|
+
contentStart: contentStart,
|
|
95
|
+
contentEnd: closeMatch.index,
|
|
96
|
+
end: closeMatch.index + closeMatch[0].length
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
// Extract sections
|
|
105
|
+
const scriptSection = findScriptSection(code);
|
|
106
|
+
const styleSection = findStyleSection(code);
|
|
107
|
+
let script = "";
|
|
8
108
|
let scriptLang = "js";
|
|
9
|
-
if (
|
|
10
|
-
|
|
109
|
+
if (scriptSection) {
|
|
110
|
+
script = code.slice(scriptSection.contentStart, scriptSection.contentEnd).trim();
|
|
111
|
+
const langMatch = scriptSection.attrs.match(/lang\s*=\s*["']([^"']+)["']/);
|
|
11
112
|
if (langMatch) {
|
|
12
113
|
scriptLang = langMatch[1];
|
|
13
114
|
}
|
|
14
115
|
}
|
|
116
|
+
let style = "";
|
|
117
|
+
if (styleSection) {
|
|
118
|
+
style = code.slice(styleSection.contentStart, styleSection.contentEnd).trim();
|
|
119
|
+
}
|
|
120
|
+
// Build HTML by removing script and style sections
|
|
121
|
+
// Remove from highest index to lowest to preserve indices
|
|
122
|
+
let html = code;
|
|
123
|
+
const sections = [];
|
|
124
|
+
if (scriptSection) {
|
|
125
|
+
sections.push({ start: scriptSection.start, end: scriptSection.end });
|
|
126
|
+
}
|
|
127
|
+
if (styleSection) {
|
|
128
|
+
sections.push({ start: styleSection.start, end: styleSection.end });
|
|
129
|
+
}
|
|
130
|
+
// Sort by start position descending (remove from end first)
|
|
131
|
+
sections.sort((a, b) => b.start - a.start);
|
|
132
|
+
for (const section of sections) {
|
|
133
|
+
html = html.slice(0, section.start) + html.slice(section.end);
|
|
134
|
+
}
|
|
135
|
+
html = html.trim();
|
|
15
136
|
return {
|
|
16
|
-
script
|
|
137
|
+
script,
|
|
17
138
|
scriptLang,
|
|
18
|
-
style
|
|
139
|
+
style,
|
|
19
140
|
html,
|
|
20
141
|
};
|
|
21
142
|
}
|