dolphincss 1.3.1 → 1.3.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/README.md +202 -103
- package/bin/dolphin-exit.js +86 -0
- package/bin/dolphin.js +453 -0
- package/bin/watcher.js +121 -0
- package/core-templates/dolphin-button.html +19 -0
- package/core-templates/dolphin-card.html +1 -0
- package/core-templates/dolphin-form-standard.html +1 -0
- package/core-templates/dolphin-modal.html +5 -0
- package/core-templates/dolphin-navbar.html +1 -0
- package/dist/assets/main-Ceq0_-ZS.css +1 -0
- package/dist/index.html +10 -2
- package/dist/index.js +8 -113
- package/dolphin-css.css +1 -1
- package/dolphincss-plugin.cjs +62 -0
- package/marker.json +42 -0
- package/package.json +71 -61
- package/vite-plugin.js +362 -53
- package/dist/assets/css-BcpnIGsX.css +0 -1
- package/dist/assets/main-tn0RQdqM.css +0 -0
- package/scripts/components.js +0 -388
- package/scripts/dolphin-watch.js +0 -53
- package/scripts/setup-snippets.cjs +0 -44
package/vite-plugin.js
CHANGED
|
@@ -1,76 +1,385 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
6
|
+
const __dirname = path.dirname(__filename);
|
|
7
|
+
|
|
8
|
+
function indentHtmlOrJsx(htmlStr, initialIndent = 8) {
|
|
9
|
+
const lines = htmlStr.split('\n');
|
|
10
|
+
let currentIndent = initialIndent;
|
|
11
|
+
const indentStep = 2; // 2 spaces
|
|
12
|
+
|
|
13
|
+
const formattedLines = lines.map(line => {
|
|
14
|
+
const trimmed = line.trim();
|
|
15
|
+
if (!trimmed) return '';
|
|
9
16
|
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
// Count tags
|
|
18
|
+
const openCount = (trimmed.match(/<[a-zA-Z0-9-]+(?:\s|>)/gi) || []).length;
|
|
19
|
+
const closeCount = (trimmed.match(/<\/[a-zA-Z0-9-]+>/gi) || []).length;
|
|
20
|
+
const selfCloseCount = (trimmed.match(/\/>/g) || []).length;
|
|
21
|
+
|
|
22
|
+
const netChange = (openCount - selfCloseCount) - closeCount;
|
|
23
|
+
|
|
24
|
+
// If the line starts with a closing tag, adjust its indent before printing
|
|
25
|
+
let lineIndent = currentIndent;
|
|
26
|
+
if (trimmed.startsWith('</') || trimmed.startsWith('}')) {
|
|
27
|
+
lineIndent = Math.max(initialIndent, currentIndent - indentStep);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const spaces = ' '.repeat(lineIndent);
|
|
31
|
+
const result = spaces + trimmed;
|
|
32
|
+
|
|
33
|
+
// Apply net depth change for the next lines
|
|
34
|
+
currentIndent = Math.max(initialIndent, currentIndent + netChange * indentStep);
|
|
35
|
+
|
|
36
|
+
return result;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return formattedLines.filter(Boolean).join('\n');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default function dolphincssPlugin() {
|
|
43
|
+
const components = {};
|
|
44
|
+
let remoteMarkerMap = null;
|
|
45
|
+
let remoteBaseUrl = '';
|
|
46
|
+
let initPromise = null;
|
|
47
|
+
const activeFetches = new Map();
|
|
48
|
+
let isDev = false;
|
|
17
49
|
|
|
18
|
-
|
|
19
|
-
|
|
50
|
+
async function ensureInitialized(projectRoot) {
|
|
51
|
+
if (initPromise) return initPromise;
|
|
52
|
+
|
|
53
|
+
initPromise = (async () => {
|
|
54
|
+
// 1. Try to load local markers and templates
|
|
20
55
|
try {
|
|
21
|
-
|
|
56
|
+
let configPath = path.join(__dirname, 'config', 'markers.json');
|
|
57
|
+
if (!fs.existsSync(configPath)) {
|
|
58
|
+
configPath = path.join(__dirname, 'marker.json');
|
|
59
|
+
}
|
|
60
|
+
if (fs.existsSync(configPath)) {
|
|
61
|
+
const localMarkers = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
62
|
+
for (const [marker, data] of Object.entries(localMarkers)) {
|
|
63
|
+
const templateFile = typeof data === 'string' ? data : data.templateFile;
|
|
64
|
+
let templatePath = path.join(__dirname, 'templates', templateFile);
|
|
65
|
+
if (!fs.existsSync(templatePath)) {
|
|
66
|
+
templatePath = path.join(__dirname, 'core-templates', templateFile);
|
|
67
|
+
}
|
|
68
|
+
if (fs.existsSync(templatePath)) {
|
|
69
|
+
components[marker] = {
|
|
70
|
+
content: fs.readFileSync(templatePath, 'utf8'),
|
|
71
|
+
addClasses: data.addClasses || '',
|
|
72
|
+
isJsxTemplate: templateFile.endsWith('.jsx') || templateFile.endsWith('.tsx')
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
22
77
|
} catch (err) {
|
|
23
|
-
|
|
78
|
+
console.error('⚠️ DolphinCSS: Error loading local markers', err);
|
|
24
79
|
}
|
|
25
80
|
|
|
26
|
-
|
|
27
|
-
let
|
|
81
|
+
// 2. Load remote configuration
|
|
82
|
+
let remoteUrl = '';
|
|
83
|
+
const dolphinConfigPath = path.join(projectRoot, 'dolphin.config.json');
|
|
84
|
+
if (fs.existsSync(dolphinConfigPath)) {
|
|
85
|
+
try {
|
|
86
|
+
const userConfig = JSON.parse(fs.readFileSync(dolphinConfigPath, 'utf8'));
|
|
87
|
+
let rawUrl = userConfig.remoteUrl;
|
|
88
|
+
if (rawUrl && rawUrl.includes('github.com') && rawUrl.includes('/blob/')) {
|
|
89
|
+
rawUrl = rawUrl.replace('github.com', 'raw.githubusercontent.com').replace('/blob/', '/');
|
|
90
|
+
}
|
|
91
|
+
remoteUrl = rawUrl;
|
|
92
|
+
} catch (e) {}
|
|
93
|
+
}
|
|
28
94
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const regex = new RegExp(
|
|
33
|
-
`<div\\s+class(?:Name)?=[\"']${marker}[\"']\\s*>\\s*</div>|<div\\s+class(?:Name)?=[\"']${marker}[\"']\\s*/>`,
|
|
34
|
-
'g'
|
|
35
|
-
);
|
|
95
|
+
if (!remoteUrl) {
|
|
96
|
+
remoteUrl = 'https://raw.githubusercontent.com/Phuyalshankar/dolphincss-template/main/config/markers.json';
|
|
97
|
+
}
|
|
36
98
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
99
|
+
try {
|
|
100
|
+
const cacheBustUrl = `${remoteUrl}?t=${Date.now()}`;
|
|
101
|
+
console.log(`🌐 DolphinCSS: Syncing markers from: ${cacheBustUrl}`);
|
|
102
|
+
const response = await fetch(cacheBustUrl);
|
|
103
|
+
if (response.ok) {
|
|
104
|
+
const text = await response.text();
|
|
105
|
+
remoteMarkerMap = JSON.parse(text);
|
|
106
|
+
|
|
107
|
+
const configDirUrl = remoteUrl.substring(0, remoteUrl.lastIndexOf('/'));
|
|
108
|
+
remoteBaseUrl = configDirUrl.substring(0, configDirUrl.lastIndexOf('/'));
|
|
109
|
+
console.log(`✅ DolphinCSS: Remote markers loaded (${Object.keys(remoteMarkerMap).length} items).`);
|
|
42
110
|
}
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.error(`⚠️ DolphinCSS: Failed to load remote markers: ${err.message}`);
|
|
43
113
|
}
|
|
114
|
+
})();
|
|
115
|
+
|
|
116
|
+
return initPromise;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function fetchRemote(url) {
|
|
120
|
+
const response = await fetch(url);
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
throw new Error(`Failed to fetch ${url}: ${response.statusText}`);
|
|
123
|
+
}
|
|
124
|
+
return await response.text();
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async function handleTransform(code, id) {
|
|
128
|
+
const ext = path.extname(id).toLowerCase();
|
|
129
|
+
if (!['.jsx', '.tsx', '.js', '.ts', '.html'].includes(ext) || id.includes('node_modules')) {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const projectRoot = process.cwd();
|
|
134
|
+
await ensureInitialized(projectRoot);
|
|
135
|
+
|
|
136
|
+
let content = code;
|
|
137
|
+
let modified = false;
|
|
138
|
+
const isReact = ['.jsx', '.tsx', '.js', '.ts'].includes(ext);
|
|
139
|
+
const classAttrName = isReact ? 'className' : 'class';
|
|
140
|
+
|
|
141
|
+
// 1. Fetch missing markers on-demand (with race-condition protection)
|
|
142
|
+
const possibleMarkers = content.match(/dolphin-[a-zA-Z0-9-]+/g);
|
|
143
|
+
if (possibleMarkers && remoteMarkerMap) {
|
|
144
|
+
for (const markerClass of possibleMarkers) {
|
|
145
|
+
if (!components[markerClass]) {
|
|
146
|
+
if (activeFetches.has(markerClass)) {
|
|
147
|
+
// If already fetching, wait for the existing fetch to complete
|
|
148
|
+
await activeFetches.get(markerClass);
|
|
149
|
+
} else if (remoteMarkerMap[markerClass]) {
|
|
150
|
+
const fetchPromise = (async () => {
|
|
151
|
+
try {
|
|
152
|
+
const data = remoteMarkerMap[markerClass];
|
|
153
|
+
const templateFile = typeof data === 'string' ? data : data.templateFile;
|
|
154
|
+
let localTemplatePath = path.join(__dirname, 'core-templates', templateFile);
|
|
155
|
+
if (!fs.existsSync(localTemplatePath)) {
|
|
156
|
+
localTemplatePath = path.join(__dirname, 'templates', templateFile);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
let templateContent = '';
|
|
160
|
+
if (fs.existsSync(localTemplatePath)) {
|
|
161
|
+
templateContent = fs.readFileSync(localTemplatePath, 'utf8');
|
|
162
|
+
} else if (remoteBaseUrl) {
|
|
163
|
+
const templateUrl = `${remoteBaseUrl}/templates/${templateFile}?t=${Date.now()}`;
|
|
164
|
+
console.log(`🌐 DolphinCSS: Fetching remote template for ${markerClass}...`);
|
|
165
|
+
templateContent = await fetchRemote(templateUrl);
|
|
166
|
+
}
|
|
44
167
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
168
|
+
if (templateContent) {
|
|
169
|
+
templateContent = templateContent.replace(/>\s*</g, '>\n<');
|
|
170
|
+
templateContent = indentHtmlOrJsx(templateContent, 8);
|
|
171
|
+
components[markerClass] = {
|
|
172
|
+
content: templateContent,
|
|
173
|
+
addClasses: data.addClasses || '',
|
|
174
|
+
isJsxTemplate: templateFile.endsWith('.jsx') || templateFile.endsWith('.tsx')
|
|
175
|
+
};
|
|
176
|
+
console.log(`✅ DolphinCSS: Registered on-demand marker: ${markerClass}`);
|
|
177
|
+
}
|
|
178
|
+
} catch (err) {
|
|
179
|
+
console.error(`❌ DolphinCSS: Failed to fetch template for ${markerClass}:`, err.message);
|
|
180
|
+
}
|
|
181
|
+
})();
|
|
182
|
+
|
|
183
|
+
activeFetches.set(markerClass, fetchPromise);
|
|
184
|
+
await fetchPromise;
|
|
185
|
+
activeFetches.delete(markerClass);
|
|
52
186
|
}
|
|
53
|
-
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const markerKeys = Object.keys(components);
|
|
192
|
+
if (markerKeys.length === 0) return null;
|
|
193
|
+
|
|
194
|
+
// 2. Expand markers in code
|
|
195
|
+
const regex = new RegExp(
|
|
196
|
+
`(<([a-z0-9-]+)\\s+[^>]*${classAttrName}=\\s*["']([^"']*?\\s)?(dolphin-[a-zA-Z0-9-]+)(\\s[^"']*?)?["'][^>]*>)`,
|
|
197
|
+
'gi'
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
let found = true;
|
|
201
|
+
while (found) {
|
|
202
|
+
found = false;
|
|
203
|
+
regex.lastIndex = 0;
|
|
204
|
+
let match;
|
|
205
|
+
|
|
206
|
+
while ((match = regex.exec(content)) !== null) {
|
|
207
|
+
const fullOpeningTag = match[1];
|
|
208
|
+
const tagName = match[2];
|
|
209
|
+
const beforeClasses = match[3];
|
|
210
|
+
const markerClass = match[4];
|
|
211
|
+
const afterClasses = match[5];
|
|
212
|
+
|
|
213
|
+
if (!components[markerClass]) {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Find matching closing tag
|
|
218
|
+
let depth = 1;
|
|
219
|
+
const startIndex = match.index + fullOpeningTag.length;
|
|
220
|
+
const tagPattern = new RegExp(`</?${tagName}(?:\\s|>|/)`, 'gi');
|
|
221
|
+
tagPattern.lastIndex = startIndex;
|
|
54
222
|
|
|
55
|
-
|
|
56
|
-
let
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
'
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
223
|
+
let closingTagIndex = -1;
|
|
224
|
+
let tagMatch;
|
|
225
|
+
while ((tagMatch = tagPattern.exec(content)) !== null) {
|
|
226
|
+
const isClosing = tagMatch[0].startsWith('</');
|
|
227
|
+
if (!isClosing) {
|
|
228
|
+
const tagEnd = content.indexOf('>', tagMatch.index);
|
|
229
|
+
if (tagEnd !== -1 && content[tagEnd - 1] === '/') {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
depth++;
|
|
233
|
+
} else {
|
|
234
|
+
depth--;
|
|
235
|
+
}
|
|
236
|
+
if (depth === 0) {
|
|
237
|
+
closingTagIndex = tagMatch.index;
|
|
238
|
+
break;
|
|
64
239
|
}
|
|
65
240
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
241
|
+
|
|
242
|
+
if (closingTagIndex !== -1) {
|
|
243
|
+
const innerContent = content.substring(startIndex, closingTagIndex);
|
|
244
|
+
const closingTagMatch = content.substring(closingTagIndex).match(new RegExp(`^</${tagName}\\s*>`, 'i'));
|
|
245
|
+
const closingTag = closingTagMatch ? closingTagMatch[0] : `</${tagName}>`;
|
|
246
|
+
|
|
247
|
+
modified = true;
|
|
248
|
+
const templateData = components[markerClass];
|
|
249
|
+
|
|
250
|
+
const classParts = (beforeClasses || '') + (afterClasses || '');
|
|
251
|
+
let allClasses = classParts.trim().split(/\s+/).filter(Boolean);
|
|
252
|
+
allClasses = allClasses.filter(c => c !== markerClass && c !== '');
|
|
253
|
+
|
|
254
|
+
if (templateData.addClasses) {
|
|
255
|
+
const addCls = templateData.addClasses.trim().split(/\s+/).filter(Boolean);
|
|
256
|
+
allClasses = [...new Set([...allClasses, ...addCls])];
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const newClassAttr = allClasses.length > 0 ? ` ${classAttrName}="${allClasses.join(' ')}"` : '';
|
|
260
|
+
|
|
261
|
+
let newOpeningTag = fullOpeningTag.replace(new RegExp(`\\s*${classAttrName}=["'][^"']*["']`, 'i'), newClassAttr ? `${newClassAttr}` : '');
|
|
262
|
+
newOpeningTag = newOpeningTag.replace(/\s+(?:class|className)=["']\s*["']/i, '');
|
|
263
|
+
|
|
264
|
+
let finalTemplate = templateData.content;
|
|
265
|
+
|
|
266
|
+
if (isReact) {
|
|
267
|
+
if (!templateData.isJsxTemplate) {
|
|
268
|
+
finalTemplate = finalTemplate
|
|
269
|
+
.replace(/class=/g, 'className=')
|
|
270
|
+
.replace(/for=/g, 'htmlFor=')
|
|
271
|
+
.replace(/tabindex=/g, 'tabIndex=')
|
|
272
|
+
.replace(/onclick=/g, 'onClick=')
|
|
273
|
+
.replace(/stroke-linecap=/g, 'strokeLinecap=')
|
|
274
|
+
.replace(/stroke-linejoin=/g, 'strokeLinejoin=')
|
|
275
|
+
.replace(/stroke-width=/g, 'strokeWidth=')
|
|
276
|
+
.replace(/fill-rule=/g, 'fillRule=')
|
|
277
|
+
.replace(/clip-rule=/g, 'clipRule=')
|
|
278
|
+
.replace(/<!--([\s\S]*?)-->/g, '{/*$1*/}')
|
|
279
|
+
.replace(/stop-color=/g, 'stopColor=')
|
|
280
|
+
.replace(/style="([^"]*)"/g, (_, s) => {
|
|
281
|
+
const obj = s.split(';').filter(Boolean).map(p => {
|
|
282
|
+
const [k, v] = p.split(':').map(x => x.trim());
|
|
283
|
+
if (!k) return '';
|
|
284
|
+
const camel = k.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
285
|
+
return `${camel}: '${v}'`;
|
|
286
|
+
}).filter(Boolean).join(', ');
|
|
287
|
+
return `style={{${obj}}}`;
|
|
288
|
+
})
|
|
289
|
+
.replace(/<(input|img|br|hr|meta|link)\b([^>]*?)>/gi, (m, t, a) => {
|
|
290
|
+
if (a.trim().endsWith('/')) return m;
|
|
291
|
+
return `<${t}${a} />`;
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
finalTemplate = finalTemplate.replace(/className=/g, 'class=');
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
if (finalTemplate.includes('{/* INNER */}')) {
|
|
299
|
+
finalTemplate = finalTemplate.replace('{/* INNER */}', innerContent.trim());
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
const fullMatchString = content.substring(match.index, closingTagIndex + closingTag.length);
|
|
303
|
+
if (templateData.isJsxTemplate && finalTemplate.includes('export default') && content.trim() === fullMatchString.trim()) {
|
|
304
|
+
content = finalTemplate;
|
|
305
|
+
found = false;
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const expanded = `${newOpeningTag}\n${finalTemplate}\n${closingTag}`;
|
|
310
|
+
content = content.substring(0, match.index) + expanded + content.substring(closingTagIndex + closingTag.length);
|
|
311
|
+
found = true;
|
|
312
|
+
break;
|
|
313
|
+
}
|
|
71
314
|
}
|
|
315
|
+
}
|
|
72
316
|
|
|
73
|
-
|
|
317
|
+
if (modified) {
|
|
318
|
+
return {
|
|
319
|
+
code: content,
|
|
320
|
+
map: null
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return {
|
|
328
|
+
name: 'vite-plugin-dolphincss',
|
|
329
|
+
enforce: 'pre',
|
|
330
|
+
|
|
331
|
+
configResolved(config) {
|
|
332
|
+
isDev = config.command === 'serve';
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
async buildStart() {
|
|
336
|
+
if (!isDev) return;
|
|
337
|
+
const projectRoot = process.cwd();
|
|
338
|
+
await ensureInitialized(projectRoot);
|
|
339
|
+
|
|
340
|
+
const srcDir = path.join(projectRoot, 'src');
|
|
341
|
+
if (!fs.existsSync(srcDir)) return;
|
|
342
|
+
|
|
343
|
+
const scanDirectory = async (dir) => {
|
|
344
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
345
|
+
for (const entry of entries) {
|
|
346
|
+
const fullPath = path.join(dir, entry.name);
|
|
347
|
+
if (entry.isDirectory()) {
|
|
348
|
+
if (entry.name !== 'node_modules' && entry.name !== '.git') {
|
|
349
|
+
await scanDirectory(fullPath);
|
|
350
|
+
}
|
|
351
|
+
} else if (entry.isFile()) {
|
|
352
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
353
|
+
if (['.jsx', '.tsx', '.js', '.ts', '.html'].includes(ext)) {
|
|
354
|
+
try {
|
|
355
|
+
const code = fs.readFileSync(fullPath, 'utf8');
|
|
356
|
+
const result = await handleTransform(code, fullPath);
|
|
357
|
+
if (result && result.code) {
|
|
358
|
+
fs.writeFileSync(fullPath, result.code, 'utf8');
|
|
359
|
+
console.log(`\n✨ DolphinCSS: Auto-injected template on startup in: ${entry.name}`);
|
|
360
|
+
}
|
|
361
|
+
} catch (e) {
|
|
362
|
+
// Ignore individual file errors
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
await scanDirectory(srcDir);
|
|
370
|
+
},
|
|
371
|
+
|
|
372
|
+
async transform(code, id) {
|
|
373
|
+
const result = await handleTransform(code, id);
|
|
374
|
+
if (result && result.code && isDev) {
|
|
375
|
+
try {
|
|
376
|
+
fs.writeFileSync(id, result.code, 'utf8');
|
|
377
|
+
console.log(`\n✨ DolphinCSS: Injected and updated source file: ${path.basename(id)}`);
|
|
378
|
+
} catch (err) {
|
|
379
|
+
console.error(`⚠️ DolphinCSS: Failed to write back to ${id}:`, err.message);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return result;
|
|
74
383
|
}
|
|
75
384
|
};
|
|
76
385
|
}
|