@thyn/vite-plugin 0.0.1
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/extract-imports.d.ts +1 -0
- package/dist/extract-imports.js +37 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +750 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +180 -0
- package/package.json +28 -0
- package/src/index.ts +822 -0
- package/src/utils.ts +197 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
export function extractParts(code) {
|
|
2
|
+
const scriptMatch = code.match(/<script([^>]*?)>([\s\S]*?)<\/script>/);
|
|
3
|
+
const styleMatch = code.match(/<style[^>]*>([\s\S]*?)<\/style>/);
|
|
4
|
+
const html = code
|
|
5
|
+
.replace(/<script[^>]*>[\s\S]*?<\/script>/, "")
|
|
6
|
+
.replace(/<style[^>]*>[\s\S]*?<\/style>/, "")
|
|
7
|
+
.trim();
|
|
8
|
+
let scriptLang = "js";
|
|
9
|
+
if (scriptMatch && scriptMatch[1]) {
|
|
10
|
+
const langMatch = scriptMatch[1].match(/lang\s*=\s*["']([^"']+)["']/);
|
|
11
|
+
if (langMatch) {
|
|
12
|
+
scriptLang = langMatch[1];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
script: scriptMatch?.[2]?.trim() ?? "",
|
|
17
|
+
scriptLang,
|
|
18
|
+
style: styleMatch?.[1]?.trim() ?? "",
|
|
19
|
+
html,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
;
|
|
23
|
+
export function splitScript(script) {
|
|
24
|
+
if (!script || typeof script !== "string") {
|
|
25
|
+
return { imports: [], body: [] };
|
|
26
|
+
}
|
|
27
|
+
const lines = script.split("\n");
|
|
28
|
+
const imports = [];
|
|
29
|
+
const body = [];
|
|
30
|
+
let currentImport = [];
|
|
31
|
+
let inImport = false;
|
|
32
|
+
let braceCount = 0;
|
|
33
|
+
let inString = false;
|
|
34
|
+
let stringChar = "";
|
|
35
|
+
let inMultiLineComment = false;
|
|
36
|
+
// Helper function to check if import is complete without semicolon
|
|
37
|
+
function isImportComplete(line, braceCount, inString) {
|
|
38
|
+
// If we have balanced braces and not in a string, check if next non-empty line starts a new statement
|
|
39
|
+
if (braceCount === 0 && !inString) {
|
|
40
|
+
// Look ahead to see if next line starts a new statement/declaration
|
|
41
|
+
const nextLineIndex = lines.indexOf(line) + 1;
|
|
42
|
+
for (let i = nextLineIndex; i < lines.length; i++) {
|
|
43
|
+
const nextLine = lines[i].trim();
|
|
44
|
+
if (!nextLine || nextLine.startsWith("//") || nextLine.startsWith("/*")) {
|
|
45
|
+
continue; // Skip empty lines and comments
|
|
46
|
+
}
|
|
47
|
+
// If next line starts with typical JS keywords/patterns, current import is complete
|
|
48
|
+
return /^(const|let|var|function|class|export|if|for|while|switch|try|return|\w+\s*[=:]|\w+\()/
|
|
49
|
+
.test(nextLine);
|
|
50
|
+
}
|
|
51
|
+
// If we reached end of file, import is complete
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
for (let i = 0; i < lines.length; i++) {
|
|
57
|
+
const line = lines[i];
|
|
58
|
+
const trimmed = line.trim();
|
|
59
|
+
// Handle multi-line comments
|
|
60
|
+
if (inMultiLineComment) {
|
|
61
|
+
if (inImport) {
|
|
62
|
+
currentImport.push(line);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
body.push(line);
|
|
66
|
+
}
|
|
67
|
+
if (line.includes("*/")) {
|
|
68
|
+
inMultiLineComment = false;
|
|
69
|
+
}
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
// Check for start of multi-line comment
|
|
73
|
+
if (line.includes("/*") && !inString) {
|
|
74
|
+
inMultiLineComment = true;
|
|
75
|
+
if (inImport) {
|
|
76
|
+
currentImport.push(line);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
body.push(line);
|
|
80
|
+
}
|
|
81
|
+
if (!line.includes("*/")) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
inMultiLineComment = false;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Skip single-line comments when not in import
|
|
89
|
+
if (trimmed.startsWith("//") && !inImport) {
|
|
90
|
+
body.push(line);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
// Skip empty lines when not in import
|
|
94
|
+
if (!trimmed && !inImport) {
|
|
95
|
+
body.push(line);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
// Start of import statement
|
|
99
|
+
if (!inImport && trimmed.startsWith("import")) {
|
|
100
|
+
inImport = true;
|
|
101
|
+
currentImport = [line];
|
|
102
|
+
braceCount = 0;
|
|
103
|
+
inString = false;
|
|
104
|
+
// Count braces and track strings in the import line
|
|
105
|
+
for (let j = 0; j < line.length; j++) {
|
|
106
|
+
const char = line[j];
|
|
107
|
+
if (inString) {
|
|
108
|
+
if (char === stringChar && line[j - 1] !== "\\") {
|
|
109
|
+
inString = false;
|
|
110
|
+
stringChar = "";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
115
|
+
inString = true;
|
|
116
|
+
stringChar = char;
|
|
117
|
+
}
|
|
118
|
+
else if (char === "{") {
|
|
119
|
+
braceCount++;
|
|
120
|
+
}
|
|
121
|
+
else if (char === "}") {
|
|
122
|
+
braceCount--;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// Check if import is complete
|
|
127
|
+
if ((trimmed.endsWith(";") ||
|
|
128
|
+
isImportComplete(trimmed, braceCount, inString)) &&
|
|
129
|
+
braceCount === 0 && !inString) {
|
|
130
|
+
imports.push(currentImport.join("\n"));
|
|
131
|
+
currentImport = [];
|
|
132
|
+
inImport = false;
|
|
133
|
+
}
|
|
134
|
+
} // Continue import statement
|
|
135
|
+
else if (inImport) {
|
|
136
|
+
currentImport.push(line);
|
|
137
|
+
// Count braces and track strings in the current line
|
|
138
|
+
for (let j = 0; j < line.length; j++) {
|
|
139
|
+
const char = line[j];
|
|
140
|
+
if (inString) {
|
|
141
|
+
if (char === stringChar && line[j - 1] !== "\\") {
|
|
142
|
+
inString = false;
|
|
143
|
+
stringChar = "";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
148
|
+
inString = true;
|
|
149
|
+
stringChar = char;
|
|
150
|
+
}
|
|
151
|
+
else if (char === "{") {
|
|
152
|
+
braceCount++;
|
|
153
|
+
}
|
|
154
|
+
else if (char === "}") {
|
|
155
|
+
braceCount--;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Check if import is complete
|
|
160
|
+
if ((trimmed.endsWith(";") ||
|
|
161
|
+
isImportComplete(trimmed, braceCount, inString)) &&
|
|
162
|
+
braceCount === 0 && !inString) {
|
|
163
|
+
imports.push(currentImport.join("\n"));
|
|
164
|
+
currentImport = [];
|
|
165
|
+
inImport = false;
|
|
166
|
+
}
|
|
167
|
+
} // Regular body content
|
|
168
|
+
else {
|
|
169
|
+
body.push(line);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// Handle unterminated import (likely malformed)
|
|
173
|
+
if (currentImport.length > 0) {
|
|
174
|
+
imports.push(currentImport.join("\n"));
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
imports: imports.filter((imp) => imp.trim()),
|
|
178
|
+
body: body.length > 0 ? body : [""],
|
|
179
|
+
};
|
|
180
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thyn/vite-plugin",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"scripts": {
|
|
5
|
+
"build": "tsc",
|
|
6
|
+
"pub": "tsc && npm version patch -f && npm -f publish --access=public"
|
|
7
|
+
},
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"description": "",
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"acorn": "^8.14.1",
|
|
19
|
+
"acorn-walk": "^8.3.4",
|
|
20
|
+
"esbuild": "^0.25.5",
|
|
21
|
+
"jsdom": "^26.1.0",
|
|
22
|
+
"magic-string": "^0.30.17",
|
|
23
|
+
"typescript": "^5.8.3"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@types/jsdom": "^21.1.7"
|
|
27
|
+
}
|
|
28
|
+
}
|