@thyn/core 0.0.352 → 0.0.354
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/README.md +1 -1
- package/dist/plugin/index.js +1 -1
- package/dist/plugin/utils.js +106 -32
- package/docs/package-lock.json +4 -4
- package/docs/package.json +1 -1
- package/docs/src/pages/Home.thyn +1 -5
- package/package.json +1 -1
- package/src/plugin/index.ts +1 -1
- package/src/plugin/utils.ts +114 -32
- package/tests/CodeSnippet.test.ts +11 -0
package/README.md
CHANGED
package/dist/plugin/index.js
CHANGED
|
@@ -879,7 +879,7 @@ export async function transformSFC(source, id) {
|
|
|
879
879
|
s.append([
|
|
880
880
|
"",
|
|
881
881
|
`export default function ${name}($props) {`,
|
|
882
|
-
...body.map((l) => " " + l),
|
|
882
|
+
...body.map((l) => (l.shouldIndent ? " " + l.text : l.text)),
|
|
883
883
|
removeUnusedThynVars(` ${transformed} return ${root};`),
|
|
884
884
|
`}`,
|
|
885
885
|
].join("\n"));
|
package/dist/plugin/utils.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export function extractParts(code) {
|
|
2
2
|
// Helper to check if a position is inside a string literal or comment
|
|
3
|
-
|
|
3
|
+
// within a specific range (used for checking script content only)
|
|
4
|
+
function isInsideStringOrComment(code, startPos, endPos) {
|
|
4
5
|
let inString = false;
|
|
5
6
|
let stringChar = '';
|
|
6
7
|
let escaped = false;
|
|
7
8
|
let inLineComment = false;
|
|
8
9
|
let inBlockComment = false;
|
|
9
|
-
for (let i =
|
|
10
|
+
for (let i = startPos; i < endPos; i++) {
|
|
10
11
|
const char = code[i];
|
|
11
12
|
const nextChar = code[i + 1];
|
|
12
13
|
if (inLineComment) {
|
|
@@ -52,45 +53,114 @@ export function extractParts(code) {
|
|
|
52
53
|
}
|
|
53
54
|
return inString || inLineComment || inBlockComment;
|
|
54
55
|
}
|
|
55
|
-
// Find
|
|
56
|
-
function
|
|
56
|
+
// Find all script tag positions with their boundaries
|
|
57
|
+
function findScriptBoundaries(code) {
|
|
58
|
+
const boundaries = [];
|
|
57
59
|
const openRegex = /<script([^>]*)>/gi;
|
|
60
|
+
const closeRegex = /<\/script>/gi;
|
|
58
61
|
let openMatch;
|
|
59
62
|
while ((openMatch = openRegex.exec(code)) !== null) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
63
|
+
const openIndex = openMatch.index;
|
|
64
|
+
const openLength = openMatch[0].length;
|
|
65
|
+
const attrs = openMatch[1] || '';
|
|
66
|
+
// Find matching close tag
|
|
67
|
+
closeRegex.lastIndex = openIndex + openLength;
|
|
68
|
+
let closeMatch;
|
|
69
|
+
while ((closeMatch = closeRegex.exec(code)) !== null) {
|
|
70
|
+
// Check if this close tag is inside a JS string within this script
|
|
71
|
+
const contentStart = openIndex + openLength;
|
|
72
|
+
if (!isInsideStringOrComment(code, contentStart, closeMatch.index)) {
|
|
73
|
+
boundaries.push({
|
|
74
|
+
start: openIndex,
|
|
75
|
+
end: closeMatch.index + closeMatch[0].length,
|
|
76
|
+
attrs
|
|
77
|
+
});
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return boundaries;
|
|
83
|
+
}
|
|
84
|
+
// Find the real script section (not inside a string of another script)
|
|
85
|
+
function findScriptSection(code) {
|
|
86
|
+
const allBoundaries = findScriptBoundaries(code);
|
|
87
|
+
if (allBoundaries.length === 0)
|
|
88
|
+
return null;
|
|
89
|
+
// The first script tag is the real one if it's not inside any other script's string
|
|
90
|
+
// Check each boundary to see if it's inside another script's content
|
|
91
|
+
for (const boundary of allBoundaries) {
|
|
92
|
+
let isInsideAnotherScript = false;
|
|
93
|
+
for (const other of allBoundaries) {
|
|
94
|
+
if (other === boundary)
|
|
95
|
+
continue;
|
|
96
|
+
// Check if this boundary is inside another script's content
|
|
97
|
+
const otherContentStart = other.start + code.slice(other.start, other.end).indexOf('>') + 1;
|
|
98
|
+
const otherContentEnd = other.end - code.slice(other.end - 10, other.end).indexOf('<') - 10 + code.slice(other.end - 10, other.end).indexOf('<');
|
|
99
|
+
if (boundary.start > otherContentStart && boundary.start < other.end) {
|
|
100
|
+
// This boundary is inside another script's content area
|
|
101
|
+
// Check if it's inside a JS string
|
|
102
|
+
if (isInsideStringOrComment(code, otherContentStart, boundary.start)) {
|
|
103
|
+
isInsideAnotherScript = true;
|
|
104
|
+
break;
|
|
74
105
|
}
|
|
75
106
|
}
|
|
76
107
|
}
|
|
108
|
+
if (!isInsideAnotherScript) {
|
|
109
|
+
// This is the real script section
|
|
110
|
+
const openTagEnd = code.indexOf('>', boundary.start) + 1;
|
|
111
|
+
const closeTagStart = code.lastIndexOf('<', boundary.end - 1);
|
|
112
|
+
return {
|
|
113
|
+
start: boundary.start,
|
|
114
|
+
contentStart: openTagEnd,
|
|
115
|
+
contentEnd: closeTagStart,
|
|
116
|
+
end: boundary.end,
|
|
117
|
+
attrs: boundary.attrs
|
|
118
|
+
};
|
|
119
|
+
}
|
|
77
120
|
}
|
|
78
121
|
return null;
|
|
79
122
|
}
|
|
80
|
-
// Find
|
|
123
|
+
// Find the real style section (outside of script sections)
|
|
81
124
|
function findStyleSection(code) {
|
|
125
|
+
const scriptBoundaries = findScriptBoundaries(code);
|
|
82
126
|
const openRegex = /<style[^>]*>/gi;
|
|
127
|
+
const closeRegex = /<\/style>/gi;
|
|
83
128
|
let openMatch;
|
|
84
129
|
while ((openMatch = openRegex.exec(code)) !== null) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
130
|
+
const openIndex = openMatch.index;
|
|
131
|
+
// Check if this style tag is inside any script section
|
|
132
|
+
let isInsideScript = false;
|
|
133
|
+
for (const script of scriptBoundaries) {
|
|
134
|
+
const contentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
|
|
135
|
+
const contentEnd = script.end - code.slice(script.end - 10, script.end).indexOf('<') - 10 + code.slice(script.end - 10, script.end).indexOf('<');
|
|
136
|
+
if (openIndex >= contentStart && openIndex < script.end) {
|
|
137
|
+
// It's in the script section, check if inside a JS string
|
|
138
|
+
if (isInsideStringOrComment(code, contentStart, openIndex)) {
|
|
139
|
+
isInsideScript = true;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (!isInsideScript) {
|
|
145
|
+
// Found a real style tag, now find its close tag
|
|
146
|
+
const contentStart = openIndex + openMatch[0].length;
|
|
147
|
+
closeRegex.lastIndex = contentStart;
|
|
89
148
|
let closeMatch;
|
|
90
149
|
while ((closeMatch = closeRegex.exec(code)) !== null) {
|
|
91
|
-
|
|
150
|
+
// Make sure close tag is also outside scripts
|
|
151
|
+
let closeIsInsideScript = false;
|
|
152
|
+
for (const script of scriptBoundaries) {
|
|
153
|
+
const scriptContentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
|
|
154
|
+
if (closeMatch.index >= scriptContentStart && closeMatch.index < script.end) {
|
|
155
|
+
if (isInsideStringOrComment(code, scriptContentStart, closeMatch.index)) {
|
|
156
|
+
closeIsInsideScript = true;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (!closeIsInsideScript) {
|
|
92
162
|
return {
|
|
93
|
-
start:
|
|
163
|
+
start: openIndex,
|
|
94
164
|
contentStart: contentStart,
|
|
95
165
|
contentEnd: closeMatch.index,
|
|
96
166
|
end: closeMatch.index + closeMatch[0].length
|
|
@@ -198,7 +268,7 @@ export function splitScript(script) {
|
|
|
198
268
|
currentImport.push(line);
|
|
199
269
|
}
|
|
200
270
|
else {
|
|
201
|
-
body.push(line);
|
|
271
|
+
body.push({ text: line, shouldIndent: true });
|
|
202
272
|
}
|
|
203
273
|
// Check for end of multi-line comment, tracking strings
|
|
204
274
|
for (let j = 0; j < line.length; j++) {
|
|
@@ -233,7 +303,7 @@ export function splitScript(script) {
|
|
|
233
303
|
currentImport.push(line);
|
|
234
304
|
}
|
|
235
305
|
else {
|
|
236
|
-
body.push(line);
|
|
306
|
+
body.push({ text: line, shouldIndent: !inString });
|
|
237
307
|
}
|
|
238
308
|
// Check if comment ends on same line
|
|
239
309
|
for (let j = 0; j < line.length; j++) {
|
|
@@ -266,12 +336,12 @@ export function splitScript(script) {
|
|
|
266
336
|
}
|
|
267
337
|
// Skip single-line comments when not in import (only if not in string)
|
|
268
338
|
if (!inString && !inImport && trimmed.startsWith("//")) {
|
|
269
|
-
body.push(line);
|
|
339
|
+
body.push({ text: line, shouldIndent: true });
|
|
270
340
|
continue;
|
|
271
341
|
}
|
|
272
342
|
// Skip empty lines when not in import
|
|
273
343
|
if (!trimmed && !inImport) {
|
|
274
|
-
body.push(line);
|
|
344
|
+
body.push({ text: line, shouldIndent: true });
|
|
275
345
|
continue;
|
|
276
346
|
}
|
|
277
347
|
// Process the line character by character to maintain string state
|
|
@@ -335,7 +405,7 @@ export function splitScript(script) {
|
|
|
335
405
|
}
|
|
336
406
|
} // Regular body content
|
|
337
407
|
else {
|
|
338
|
-
body.push(line);
|
|
408
|
+
body.push({ text: line, shouldIndent: !inString });
|
|
339
409
|
// Update global string state
|
|
340
410
|
inString = lineInString;
|
|
341
411
|
stringChar = lineStringChar;
|
|
@@ -349,11 +419,15 @@ export function splitScript(script) {
|
|
|
349
419
|
}
|
|
350
420
|
else {
|
|
351
421
|
// Still in string or incomplete, treat as body
|
|
352
|
-
|
|
422
|
+
// We can't know for sure about indentation here, but if it was part of an import or string,
|
|
423
|
+
// it likely follows previous logic. For safety, if we are in string, don't indent.
|
|
424
|
+
for (const l of currentImport) {
|
|
425
|
+
body.push({ text: l, shouldIndent: !inString });
|
|
426
|
+
}
|
|
353
427
|
}
|
|
354
428
|
}
|
|
355
429
|
return {
|
|
356
430
|
imports: imports.filter((imp) => imp.trim()),
|
|
357
|
-
body: body.length > 0 ? body : [""],
|
|
431
|
+
body: body.length > 0 ? body : [{ text: "", shouldIndent: true }],
|
|
358
432
|
};
|
|
359
433
|
}
|
package/docs/package-lock.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"name": "thyn-app",
|
|
9
9
|
"version": "0.0.0",
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@thyn/core": "^0.0.
|
|
11
|
+
"@thyn/core": "^0.0.353",
|
|
12
12
|
"vite": "^6.3.5"
|
|
13
13
|
}
|
|
14
14
|
},
|
|
@@ -742,9 +742,9 @@
|
|
|
742
742
|
]
|
|
743
743
|
},
|
|
744
744
|
"node_modules/@thyn/core": {
|
|
745
|
-
"version": "0.0.
|
|
746
|
-
"resolved": "https://registry.npmjs.org/@thyn/core/-/core-0.0.
|
|
747
|
-
"integrity": "sha512-
|
|
745
|
+
"version": "0.0.353",
|
|
746
|
+
"resolved": "https://registry.npmjs.org/@thyn/core/-/core-0.0.353.tgz",
|
|
747
|
+
"integrity": "sha512-vg8X99bz1H+cCJtwPY8chIRBiRA+R26uI5XOOqXxL+jW2qWzZd7PID0EzkYi3zbfbCX0I3u5A+kfjbBJucFYAw==",
|
|
748
748
|
"dev": true,
|
|
749
749
|
"license": "MIT",
|
|
750
750
|
"dependencies": {
|
package/docs/package.json
CHANGED
package/docs/src/pages/Home.thyn
CHANGED
|
@@ -49,11 +49,7 @@ mount(App, document.body);`;
|
|
|
49
49
|
<div class="compiled-wrapper">
|
|
50
50
|
<div>
|
|
51
51
|
<h4>source</h4>
|
|
52
|
-
<pre>
|
|
53
|
-
<code class="code language-javascript">
|
|
54
|
-
{{ codeSnippet }}
|
|
55
|
-
</code>
|
|
56
|
-
</pre>
|
|
52
|
+
<pre><code class="code language-javascript">{{ codeSnippet }}</code></pre>
|
|
57
53
|
</div>
|
|
58
54
|
<div>
|
|
59
55
|
<h4>compiled</h4>
|
package/package.json
CHANGED
package/src/plugin/index.ts
CHANGED
|
@@ -977,7 +977,7 @@ export async function transformSFC(source: string, id: string) {
|
|
|
977
977
|
s.append([
|
|
978
978
|
"",
|
|
979
979
|
`export default function ${name}($props) {`,
|
|
980
|
-
...body.map((l) => " " + l),
|
|
980
|
+
...body.map((l: any) => (l.shouldIndent ? " " + l.text : l.text)),
|
|
981
981
|
removeUnusedThynVars(` ${transformed} return ${root};`),
|
|
982
982
|
`}`,
|
|
983
983
|
].join("\n"));
|
package/src/plugin/utils.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
export function extractParts(code: string) {
|
|
2
2
|
// Helper to check if a position is inside a string literal or comment
|
|
3
|
-
|
|
3
|
+
// within a specific range (used for checking script content only)
|
|
4
|
+
function isInsideStringOrComment(code: string, startPos: number, endPos: number): boolean {
|
|
4
5
|
let inString = false;
|
|
5
6
|
let stringChar = '';
|
|
6
7
|
let escaped = false;
|
|
7
8
|
let inLineComment = false;
|
|
8
9
|
let inBlockComment = false;
|
|
9
10
|
|
|
10
|
-
for (let i =
|
|
11
|
+
for (let i = startPos; i < endPos; i++) {
|
|
11
12
|
const char = code[i];
|
|
12
13
|
const nextChar = code[i + 1];
|
|
13
14
|
|
|
@@ -61,50 +62,127 @@ export function extractParts(code: string) {
|
|
|
61
62
|
return inString || inLineComment || inBlockComment;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
// Find
|
|
65
|
-
function
|
|
65
|
+
// Find all script tag positions with their boundaries
|
|
66
|
+
function findScriptBoundaries(code: string): Array<{ start: number; end: number; attrs: string }> {
|
|
67
|
+
const boundaries = [];
|
|
66
68
|
const openRegex = /<script([^>]*)>/gi;
|
|
69
|
+
const closeRegex = /<\/script>/gi;
|
|
67
70
|
let openMatch;
|
|
68
71
|
|
|
69
72
|
while ((openMatch = openRegex.exec(code)) !== null) {
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
const openIndex = openMatch.index;
|
|
74
|
+
const openLength = openMatch[0].length;
|
|
75
|
+
const attrs = openMatch[1] || '';
|
|
76
|
+
|
|
77
|
+
// Find matching close tag
|
|
78
|
+
closeRegex.lastIndex = openIndex + openLength;
|
|
79
|
+
let closeMatch;
|
|
80
|
+
while ((closeMatch = closeRegex.exec(code)) !== null) {
|
|
81
|
+
// Check if this close tag is inside a JS string within this script
|
|
82
|
+
const contentStart = openIndex + openLength;
|
|
83
|
+
if (!isInsideStringOrComment(code, contentStart, closeMatch.index)) {
|
|
84
|
+
boundaries.push({
|
|
85
|
+
start: openIndex,
|
|
86
|
+
end: closeMatch.index + closeMatch[0].length,
|
|
87
|
+
attrs
|
|
88
|
+
});
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return boundaries;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Find the real script section (not inside a string of another script)
|
|
98
|
+
function findScriptSection(code: string): { start: number; contentStart: number; contentEnd: number; end: number; attrs: string } | null {
|
|
99
|
+
const allBoundaries = findScriptBoundaries(code);
|
|
100
|
+
if (allBoundaries.length === 0) return null;
|
|
101
|
+
|
|
102
|
+
// The first script tag is the real one if it's not inside any other script's string
|
|
103
|
+
// Check each boundary to see if it's inside another script's content
|
|
104
|
+
for (const boundary of allBoundaries) {
|
|
105
|
+
let isInsideAnotherScript = false;
|
|
106
|
+
|
|
107
|
+
for (const other of allBoundaries) {
|
|
108
|
+
if (other === boundary) continue;
|
|
72
109
|
|
|
73
|
-
//
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
attrs: openMatch[1] || ''
|
|
84
|
-
};
|
|
110
|
+
// Check if this boundary is inside another script's content
|
|
111
|
+
const otherContentStart = other.start + code.slice(other.start, other.end).indexOf('>') + 1;
|
|
112
|
+
const otherContentEnd = other.end - code.slice(other.end - 10, other.end).indexOf('<') - 10 + code.slice(other.end - 10, other.end).indexOf('<');
|
|
113
|
+
|
|
114
|
+
if (boundary.start > otherContentStart && boundary.start < other.end) {
|
|
115
|
+
// This boundary is inside another script's content area
|
|
116
|
+
// Check if it's inside a JS string
|
|
117
|
+
if (isInsideStringOrComment(code, otherContentStart, boundary.start)) {
|
|
118
|
+
isInsideAnotherScript = true;
|
|
119
|
+
break;
|
|
85
120
|
}
|
|
86
121
|
}
|
|
87
122
|
}
|
|
123
|
+
|
|
124
|
+
if (!isInsideAnotherScript) {
|
|
125
|
+
// This is the real script section
|
|
126
|
+
const openTagEnd = code.indexOf('>', boundary.start) + 1;
|
|
127
|
+
const closeTagStart = code.lastIndexOf('<', boundary.end - 1);
|
|
128
|
+
return {
|
|
129
|
+
start: boundary.start,
|
|
130
|
+
contentStart: openTagEnd,
|
|
131
|
+
contentEnd: closeTagStart,
|
|
132
|
+
end: boundary.end,
|
|
133
|
+
attrs: boundary.attrs
|
|
134
|
+
};
|
|
135
|
+
}
|
|
88
136
|
}
|
|
137
|
+
|
|
89
138
|
return null;
|
|
90
139
|
}
|
|
91
140
|
|
|
92
|
-
// Find
|
|
141
|
+
// Find the real style section (outside of script sections)
|
|
93
142
|
function findStyleSection(code: string): { start: number; contentStart: number; contentEnd: number; end: number } | null {
|
|
143
|
+
const scriptBoundaries = findScriptBoundaries(code);
|
|
94
144
|
const openRegex = /<style[^>]*>/gi;
|
|
145
|
+
const closeRegex = /<\/style>/gi;
|
|
95
146
|
let openMatch;
|
|
96
147
|
|
|
97
148
|
while ((openMatch = openRegex.exec(code)) !== null) {
|
|
98
|
-
|
|
99
|
-
|
|
149
|
+
const openIndex = openMatch.index;
|
|
150
|
+
|
|
151
|
+
// Check if this style tag is inside any script section
|
|
152
|
+
let isInsideScript = false;
|
|
153
|
+
for (const script of scriptBoundaries) {
|
|
154
|
+
const contentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
|
|
155
|
+
const contentEnd = script.end - code.slice(script.end - 10, script.end).indexOf('<') - 10 + code.slice(script.end - 10, script.end).indexOf('<');
|
|
100
156
|
|
|
101
|
-
|
|
102
|
-
|
|
157
|
+
if (openIndex >= contentStart && openIndex < script.end) {
|
|
158
|
+
// It's in the script section, check if inside a JS string
|
|
159
|
+
if (isInsideStringOrComment(code, contentStart, openIndex)) {
|
|
160
|
+
isInsideScript = true;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (!isInsideScript) {
|
|
167
|
+
// Found a real style tag, now find its close tag
|
|
168
|
+
const contentStart = openIndex + openMatch[0].length;
|
|
169
|
+
closeRegex.lastIndex = contentStart;
|
|
103
170
|
let closeMatch;
|
|
104
171
|
while ((closeMatch = closeRegex.exec(code)) !== null) {
|
|
105
|
-
|
|
172
|
+
// Make sure close tag is also outside scripts
|
|
173
|
+
let closeIsInsideScript = false;
|
|
174
|
+
for (const script of scriptBoundaries) {
|
|
175
|
+
const scriptContentStart = script.start + code.slice(script.start, script.end).indexOf('>') + 1;
|
|
176
|
+
if (closeMatch.index >= scriptContentStart && closeMatch.index < script.end) {
|
|
177
|
+
if (isInsideStringOrComment(code, scriptContentStart, closeMatch.index)) {
|
|
178
|
+
closeIsInsideScript = true;
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (!closeIsInsideScript) {
|
|
106
184
|
return {
|
|
107
|
-
start:
|
|
185
|
+
start: openIndex,
|
|
108
186
|
contentStart: contentStart,
|
|
109
187
|
contentEnd: closeMatch.index,
|
|
110
188
|
end: closeMatch.index + closeMatch[0].length
|
|
@@ -226,7 +304,7 @@ export function splitScript(script: string) {
|
|
|
226
304
|
if (inImport) {
|
|
227
305
|
currentImport.push(line);
|
|
228
306
|
} else {
|
|
229
|
-
body.push(line);
|
|
307
|
+
body.push({ text: line, shouldIndent: true });
|
|
230
308
|
}
|
|
231
309
|
|
|
232
310
|
// Check for end of multi-line comment, tracking strings
|
|
@@ -260,7 +338,7 @@ export function splitScript(script: string) {
|
|
|
260
338
|
if (inImport) {
|
|
261
339
|
currentImport.push(line);
|
|
262
340
|
} else {
|
|
263
|
-
body.push(line);
|
|
341
|
+
body.push({ text: line, shouldIndent: !inString });
|
|
264
342
|
}
|
|
265
343
|
|
|
266
344
|
// Check if comment ends on same line
|
|
@@ -294,13 +372,13 @@ export function splitScript(script: string) {
|
|
|
294
372
|
|
|
295
373
|
// Skip single-line comments when not in import (only if not in string)
|
|
296
374
|
if (!inString && !inImport && trimmed.startsWith("//")) {
|
|
297
|
-
body.push(line);
|
|
375
|
+
body.push({ text: line, shouldIndent: true });
|
|
298
376
|
continue;
|
|
299
377
|
}
|
|
300
378
|
|
|
301
379
|
// Skip empty lines when not in import
|
|
302
380
|
if (!trimmed && !inImport) {
|
|
303
|
-
body.push(line);
|
|
381
|
+
body.push({ text: line, shouldIndent: true });
|
|
304
382
|
continue;
|
|
305
383
|
}
|
|
306
384
|
|
|
@@ -373,7 +451,7 @@ export function splitScript(script: string) {
|
|
|
373
451
|
}
|
|
374
452
|
} // Regular body content
|
|
375
453
|
else {
|
|
376
|
-
body.push(line);
|
|
454
|
+
body.push({ text: line, shouldIndent: !inString });
|
|
377
455
|
// Update global string state
|
|
378
456
|
inString = lineInString;
|
|
379
457
|
stringChar = lineStringChar;
|
|
@@ -387,12 +465,16 @@ export function splitScript(script: string) {
|
|
|
387
465
|
imports.push(currentImport.join("\n"));
|
|
388
466
|
} else {
|
|
389
467
|
// Still in string or incomplete, treat as body
|
|
390
|
-
|
|
468
|
+
// We can't know for sure about indentation here, but if it was part of an import or string,
|
|
469
|
+
// it likely follows previous logic. For safety, if we are in string, don't indent.
|
|
470
|
+
for(const l of currentImport) {
|
|
471
|
+
body.push({ text: l, shouldIndent: !inString });
|
|
472
|
+
}
|
|
391
473
|
}
|
|
392
474
|
}
|
|
393
475
|
|
|
394
476
|
return {
|
|
395
477
|
imports: imports.filter((imp) => imp.trim()),
|
|
396
|
-
body: body.length > 0 ? body : [""],
|
|
478
|
+
body: body.length > 0 ? body : [{ text: "", shouldIndent: true }],
|
|
397
479
|
};
|
|
398
480
|
}
|
|
@@ -16,6 +16,17 @@ describe("CodeSnippet component", () => {
|
|
|
16
16
|
expect(display.textContent).toContain("button {");
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
it("should not add extra indentation to template literals", () => {
|
|
20
|
+
const root = CodeSnippet();
|
|
21
|
+
const display = root.querySelector('.display');
|
|
22
|
+
const text = display.textContent;
|
|
23
|
+
|
|
24
|
+
// Check that <script> is at the start of the line (no extra indentation)
|
|
25
|
+
expect(text).toContain("\n<script>");
|
|
26
|
+
// Check that const count has exactly 2 spaces (as in source), not 4
|
|
27
|
+
expect(text).toContain("\n const count");
|
|
28
|
+
});
|
|
29
|
+
|
|
19
30
|
it("should apply the component's actual style, not style from codeSnippet", () => {
|
|
20
31
|
const root = CodeSnippet();
|
|
21
32
|
const display = root.querySelector('.display');
|