@runner-ai/vite-uuid-tagger 0.0.4 → 0.0.6
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/index.d.ts +4 -8
- package/dist/index.js +228 -376
- package/package.json +13 -20
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
-
interface
|
|
4
|
-
|
|
5
|
-
enabled?: boolean;
|
|
6
|
-
/** Enable Tailwind theme registry extraction (default: true) */
|
|
7
|
-
extractColors?: boolean;
|
|
3
|
+
interface UuidTaggerOptions {
|
|
4
|
+
projectRoot: string;
|
|
8
5
|
}
|
|
6
|
+
declare function uuidTagger(options: UuidTaggerOptions): Plugin;
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export { type ViteUUIDTaggerOptions, viteUuidTagger as default };
|
|
8
|
+
export { type UuidTaggerOptions, uuidTagger };
|
package/dist/index.js
CHANGED
|
@@ -1,416 +1,268 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
server.middlewares.use((req, res, next) => {
|
|
6
|
-
if (req.url === "/uuid-mappings.json") {
|
|
7
|
-
res.statusCode = 200;
|
|
8
|
-
res.setHeader("content-type", "application/json");
|
|
9
|
-
res.end(JSON.stringify({}));
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
next();
|
|
13
|
-
});
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// src/features/jsx-source-tagger.ts
|
|
19
|
-
var CLIENT_RUNTIME_CODE = `
|
|
20
|
-
import { jsxDEV as _jsxDEV, Fragment } from 'react/jsx-dev-runtime';
|
|
21
|
-
|
|
22
|
-
if (typeof window !== 'undefined' && !window.sourceElementMap) {
|
|
23
|
-
window.sourceElementMap = new Map();
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function getCleanFileName(fileName) {
|
|
27
|
-
if (!fileName) return '';
|
|
28
|
-
return fileName
|
|
29
|
-
.replace(/^.*?\\/src\\//, 'src/')
|
|
30
|
-
.replace(/^\\//, '');
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function wrapRef(originalRef, sourceInfo) {
|
|
34
|
-
return function taggedRef(node) {
|
|
35
|
-
if (node && node instanceof Element) {
|
|
36
|
-
var loc = sourceInfo.fileName + ':' + sourceInfo.lineNumber + ':' + sourceInfo.columnNumber;
|
|
37
|
-
node.setAttribute('data-uuid-loc', loc);
|
|
38
|
-
|
|
39
|
-
var sym = Symbol.for('__jsxSource__');
|
|
40
|
-
node[sym] = sourceInfo;
|
|
41
|
-
|
|
42
|
-
if (typeof window !== 'undefined' && window.sourceElementMap) {
|
|
43
|
-
var key = loc;
|
|
44
|
-
if (!window.sourceElementMap.has(key)) {
|
|
45
|
-
window.sourceElementMap.set(key, new Set());
|
|
46
|
-
}
|
|
47
|
-
window.sourceElementMap.get(key).add(new WeakRef(node));
|
|
48
|
-
}
|
|
49
|
-
}
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import path2 from "path";
|
|
3
|
+
import { parse } from "@babel/parser";
|
|
4
|
+
import MagicString from "magic-string";
|
|
50
5
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
6
|
+
// src/ast-helpers.ts
|
|
7
|
+
import path from "path";
|
|
8
|
+
var NON_TAGGABLE_ELEMENTS = ["Fragment", "React.Fragment"];
|
|
9
|
+
var VALID_EXTENSIONS = /* @__PURE__ */ new Set([".jsx", ".tsx", ".js", ".ts"]);
|
|
10
|
+
function shouldSkipFile(filename) {
|
|
11
|
+
return filename.includes("node_modules") || !VALID_EXTENSIONS.has(path.extname(filename));
|
|
57
12
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
'link','meta','param','source','track','wbr'
|
|
62
|
-
]);
|
|
63
|
-
|
|
64
|
-
var _isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
65
|
-
|
|
66
|
-
export function jsxDEV(type, props, key, isStaticChildren, source, self) {
|
|
67
|
-
if (_isBrowser && source && source.fileName && typeof type === 'string' && !VOID_ELEMENTS.has(type)) {
|
|
68
|
-
var cleanFileName = getCleanFileName(source.fileName);
|
|
69
|
-
var sourceInfo = {
|
|
70
|
-
fileName: cleanFileName,
|
|
71
|
-
lineNumber: source.lineNumber || 0,
|
|
72
|
-
columnNumber: source.columnNumber || 0,
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
var newProps = Object.assign({}, props);
|
|
76
|
-
newProps.ref = wrapRef(props ? props.ref : undefined, sourceInfo);
|
|
77
|
-
|
|
78
|
-
return _jsxDEV(type, newProps, key, isStaticChildren, source, self);
|
|
13
|
+
function getElementName(node) {
|
|
14
|
+
if (node.name.type === "JSXIdentifier") {
|
|
15
|
+
return node.name.name;
|
|
79
16
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
export { Fragment };
|
|
85
|
-
export { jsx, jsxs } from 'react/jsx-dev-runtime';
|
|
86
|
-
`;
|
|
87
|
-
var PASSTHROUGH_CODE = `export * from 'react/jsx-dev-runtime';
|
|
88
|
-
`;
|
|
89
|
-
function createJsxSourceTagger() {
|
|
90
|
-
return {
|
|
91
|
-
resolveId(source, importer, options) {
|
|
92
|
-
if (source !== "react/jsx-dev-runtime") {
|
|
93
|
-
return null;
|
|
94
|
-
}
|
|
95
|
-
if (importer?.includes("\0runner-jsx")) {
|
|
96
|
-
return null;
|
|
97
|
-
}
|
|
98
|
-
const self = this;
|
|
99
|
-
const env = self?.environment;
|
|
100
|
-
const isSSR = env?.config?.consumer === "server" || options?.ssr === true;
|
|
101
|
-
return isSSR ? "\0runner-jsx/passthrough" : "\0runner-jsx/client-runtime";
|
|
102
|
-
},
|
|
103
|
-
load(id) {
|
|
104
|
-
if (id === "\0runner-jsx/client-runtime") {
|
|
105
|
-
return CLIENT_RUNTIME_CODE;
|
|
106
|
-
}
|
|
107
|
-
if (id === "\0runner-jsx/passthrough") {
|
|
108
|
-
return PASSTHROUGH_CODE;
|
|
109
|
-
}
|
|
110
|
-
return null;
|
|
111
|
-
}
|
|
112
|
-
};
|
|
17
|
+
if (node.name.type === "JSXMemberExpression") {
|
|
18
|
+
return `${node.name.object.name}.${node.name.property.name}`;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
113
21
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
import glob from "fast-glob";
|
|
118
|
-
function parseThemeColors(cssContent) {
|
|
119
|
-
const themeColors = {};
|
|
120
|
-
const themeRegex = /@theme\s*\{([^}]*)\}/gs;
|
|
121
|
-
for (const match of cssContent.matchAll(themeRegex)) {
|
|
122
|
-
const content = match[1];
|
|
123
|
-
const colorRegex = /--color-([\w-]+):\s*([^;]+);/g;
|
|
124
|
-
for (const colorMatch of content.matchAll(colorRegex)) {
|
|
125
|
-
themeColors[colorMatch[1]] = colorMatch[2].trim();
|
|
126
|
-
}
|
|
22
|
+
function shouldTagElement(node) {
|
|
23
|
+
if (node.type !== "JSXElement") {
|
|
24
|
+
return false;
|
|
127
25
|
}
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
}
|
|
26
|
+
const openingElement = node.openingElement;
|
|
27
|
+
if (!openingElement) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const elementName = getElementName(openingElement);
|
|
31
|
+
if (!elementName || NON_TAGGABLE_ELEMENTS.includes(elementName)) {
|
|
32
|
+
return false;
|
|
137
33
|
}
|
|
138
|
-
return
|
|
34
|
+
return true;
|
|
139
35
|
}
|
|
140
|
-
function
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (tailwindColors && Object.keys(tailwindColors).length > 0) {
|
|
156
|
-
Object.entries(tailwindColors).forEach(function(entry) {
|
|
157
|
-
var name = entry[0], shades = entry[1];
|
|
158
|
-
if (name === 'lightBlue' || name === 'warmGray' || name === 'trueGray' || name === 'coolGray' || name === 'blueGray' || typeof shades === 'function') return;
|
|
159
|
-
if (typeof shades === 'object' && shades !== null && !Array.isArray(shades)) {
|
|
160
|
-
registry.default[name] = {};
|
|
161
|
-
Object.entries(shades).forEach(function(se) {
|
|
162
|
-
var shade = se[0], value = se[1];
|
|
163
|
-
if (typeof value === 'string') {
|
|
164
|
-
registry.default[name][shade] = {
|
|
165
|
-
value: value,
|
|
166
|
-
classes: { bg: 'bg-' + name + '-' + shade, text: 'text-' + name + '-' + shade, border: 'border-' + name + '-' + shade, ring: 'ring-' + name + '-' + shade }
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
});
|
|
170
|
-
} else if (typeof shades === 'string') {
|
|
171
|
-
registry.default[name] = {
|
|
172
|
-
value: shades,
|
|
173
|
-
classes: { bg: 'bg-' + name, text: 'text-' + name, border: 'border-' + name }
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
});
|
|
36
|
+
function isStaticExpression(expression) {
|
|
37
|
+
if (!expression) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
if (expression.type === "JSXEmptyExpression") {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
if (["NumericLiteral", "BooleanLiteral", "StringLiteral", "NullLiteral"].includes(expression.type)) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (expression.type === "ObjectExpression") {
|
|
47
|
+
const obj = expression;
|
|
48
|
+
return obj.properties.every((prop) => {
|
|
49
|
+
if (prop.type === "SpreadElement") {
|
|
50
|
+
return false;
|
|
177
51
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
var name = entry[0], value = entry[1];
|
|
182
|
-
registry.custom[name] = {
|
|
183
|
-
value: value,
|
|
184
|
-
variable: '--color-' + name,
|
|
185
|
-
classes: { bg: 'bg-' + name, text: 'text-' + name, border: 'border-' + name, ring: 'ring-' + name }
|
|
186
|
-
};
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
var computed = getComputedStyle(document.documentElement);
|
|
190
|
-
var cssVarArray = Array.from(computed).filter(function(p) { return p.startsWith('--'); });
|
|
191
|
-
cssVarArray.forEach(function(prop) {
|
|
192
|
-
if (prop.startsWith('--color-')) {
|
|
193
|
-
var value = computed.getPropertyValue(prop).trim();
|
|
194
|
-
var name = prop.replace('--color-', '').replace(/^-+|-+$/g, '');
|
|
195
|
-
if (!registry.custom[name]) {
|
|
196
|
-
registry.custom[name] = {
|
|
197
|
-
value: value, variable: prop,
|
|
198
|
-
classes: { bg: 'bg-' + name, text: 'text-' + name, border: 'border-' + name, ring: 'ring-' + name }
|
|
199
|
-
};
|
|
200
|
-
}
|
|
52
|
+
if (prop.type === "ObjectProperty") {
|
|
53
|
+
if (prop.computed) {
|
|
54
|
+
return false;
|
|
201
55
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
var tailwindSpacing = ${serializedSpacing};
|
|
205
|
-
var spacingRegistry = {};
|
|
206
|
-
if (tailwindSpacing && Object.keys(tailwindSpacing).length > 0) {
|
|
207
|
-
Object.entries(tailwindSpacing).forEach(function(entry) {
|
|
208
|
-
if (typeof entry[1] === 'string') spacingRegistry[entry[0]] = entry[1];
|
|
209
|
-
});
|
|
56
|
+
return isStaticExpression(prop.value);
|
|
210
57
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
if (
|
|
218
|
-
|
|
219
|
-
scale.forEach(function(step) {
|
|
220
|
-
if (step === 0) { spacingRegistry['0'] = '0'; }
|
|
221
|
-
else if (step === 'px') { spacingRegistry['px'] = '1px'; }
|
|
222
|
-
else {
|
|
223
|
-
var match = baseSpacing.match(/([0-9.]+)([a-z%]+)/);
|
|
224
|
-
if (match) spacingRegistry[String(step)] = (parseFloat(match[1]) * step) + match[2];
|
|
225
|
-
}
|
|
226
|
-
});
|
|
58
|
+
return false;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (expression.type === "ArrayExpression") {
|
|
62
|
+
const arr = expression;
|
|
63
|
+
return arr.elements.every((elem) => {
|
|
64
|
+
if (elem === null) {
|
|
65
|
+
return true;
|
|
227
66
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
colors: registry,
|
|
231
|
-
spacing: spacingRegistry,
|
|
232
|
-
baseSpacing: baseSpacing,
|
|
233
|
-
timestamp: Date.now()
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
if (window.parent !== window) {
|
|
237
|
-
window.parent.postMessage({ type: 'TAILWIND_REGISTRY_UPDATE', data: window.__TAILWIND_REGISTRY__ }, '*');
|
|
67
|
+
if (elem.type === "SpreadElement") {
|
|
68
|
+
return false;
|
|
238
69
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
}
|
|
242
|
-
async function loadTailwindDefaults() {
|
|
243
|
-
try {
|
|
244
|
-
const defaultTheme = await import("tailwindcss/defaultTheme.js");
|
|
245
|
-
const rawColors = defaultTheme?.default?.colors;
|
|
246
|
-
const rawSpacing = defaultTheme?.default?.spacing;
|
|
247
|
-
const colors = typeof rawColors === "function" ? rawColors() : rawColors ?? {};
|
|
248
|
-
const spacing = typeof rawSpacing === "function" ? rawSpacing() : rawSpacing ?? {};
|
|
249
|
-
return { colors, spacing };
|
|
250
|
-
} catch {
|
|
251
|
-
return { colors: {}, spacing: {} };
|
|
70
|
+
return isStaticExpression(elem);
|
|
71
|
+
});
|
|
252
72
|
}
|
|
73
|
+
return false;
|
|
253
74
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
256
|
-
let tailwindSpacing = {};
|
|
257
|
-
let themeColors = {};
|
|
258
|
-
return {
|
|
259
|
-
async buildStart() {
|
|
260
|
-
const tw = await loadTailwindDefaults();
|
|
261
|
-
tailwindColors = tw.colors;
|
|
262
|
-
tailwindSpacing = tw.spacing;
|
|
263
|
-
try {
|
|
264
|
-
const cssFiles = await glob("**/*.css", {
|
|
265
|
-
ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.git/**", "**/build/**"],
|
|
266
|
-
cwd: process.cwd(),
|
|
267
|
-
absolute: true
|
|
268
|
-
});
|
|
269
|
-
for (const file of cssFiles) {
|
|
270
|
-
try {
|
|
271
|
-
const content = await fs.readFile(file, "utf-8");
|
|
272
|
-
const parsed = parseThemeColors(content);
|
|
273
|
-
themeColors = { ...themeColors, ...parsed };
|
|
274
|
-
} catch {
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
} catch {
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
transformIndexHtml(html) {
|
|
281
|
-
const script = buildColorRegistry(tailwindColors, tailwindSpacing, themeColors);
|
|
282
|
-
return html.replace("</body>", `<script>${script}</script></body>`);
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// src/features/virtual-overrides.ts
|
|
288
|
-
var LEADING_DOT_SLASH = /^\.\//;
|
|
289
|
-
var BACKSLASH = /\\/g;
|
|
290
|
-
function normalizePath(path) {
|
|
291
|
-
return path.replace(LEADING_DOT_SLASH, "").replace(BACKSLASH, "/");
|
|
292
|
-
}
|
|
293
|
-
function isPathSafe(path) {
|
|
294
|
-
if (path.includes("..")) {
|
|
75
|
+
function supportsContentEditable(jsxElement) {
|
|
76
|
+
if (!jsxElement.children || jsxElement.children.length === 0) {
|
|
295
77
|
return false;
|
|
296
78
|
}
|
|
297
|
-
|
|
79
|
+
const hasValidChildren = jsxElement.children.every((child) => {
|
|
80
|
+
if (child.type === "JSXText") {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (child.type === "JSXExpressionContainer") {
|
|
84
|
+
return isStaticExpression(child.expression);
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
});
|
|
88
|
+
if (!hasValidChildren) {
|
|
298
89
|
return false;
|
|
299
90
|
}
|
|
300
|
-
return
|
|
91
|
+
return jsxElement.children.some((child) => {
|
|
92
|
+
if (child.type === "JSXText") {
|
|
93
|
+
return child.value.trim().length > 0;
|
|
94
|
+
}
|
|
95
|
+
if (child.type === "JSXExpressionContainer") {
|
|
96
|
+
return child.expression.type !== "JSXEmptyExpression";
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
});
|
|
301
100
|
}
|
|
302
|
-
function
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
if (!_server) {
|
|
307
|
-
return;
|
|
101
|
+
function isInlineEditable(jsxElement) {
|
|
102
|
+
const hasStaticChildren = jsxElement.children && jsxElement.children.length > 0 && jsxElement.children.every((child) => {
|
|
103
|
+
if (child.type === "JSXText") {
|
|
104
|
+
return true;
|
|
308
105
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
timestamp: Date.now()
|
|
321
|
-
}
|
|
322
|
-
]
|
|
323
|
-
});
|
|
106
|
+
if (child.type === "JSXExpressionContainer") {
|
|
107
|
+
return isStaticExpression(child.expression);
|
|
108
|
+
}
|
|
109
|
+
return false;
|
|
110
|
+
});
|
|
111
|
+
const hasEditableContent = jsxElement.children?.some((child) => {
|
|
112
|
+
if (child.type === "JSXText") {
|
|
113
|
+
return child.value.trim().length > 0;
|
|
114
|
+
}
|
|
115
|
+
if (child.type === "JSXExpressionContainer") {
|
|
116
|
+
return child.expression.type !== "JSXEmptyExpression";
|
|
324
117
|
}
|
|
118
|
+
return false;
|
|
119
|
+
});
|
|
120
|
+
if (hasStaticChildren && hasEditableContent) {
|
|
121
|
+
return true;
|
|
325
122
|
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
const normalizedPath = normalizePath(data.path);
|
|
331
|
-
if (!isPathSafe(normalizedPath)) {
|
|
332
|
-
return;
|
|
333
|
-
}
|
|
334
|
-
overrides.set(normalizedPath, data.content);
|
|
335
|
-
invalidateAndUpdate(normalizedPath);
|
|
336
|
-
});
|
|
337
|
-
server.ws.on("runner:clear-override", (data) => {
|
|
338
|
-
const normalizedPath = normalizePath(data.path);
|
|
339
|
-
overrides.delete(normalizedPath);
|
|
340
|
-
invalidateAndUpdate(normalizedPath);
|
|
341
|
-
});
|
|
342
|
-
server.ws.on("runner:clear-all-overrides", () => {
|
|
343
|
-
const paths = Array.from(overrides.keys());
|
|
344
|
-
overrides.clear();
|
|
345
|
-
for (const path of paths) {
|
|
346
|
-
invalidateAndUpdate(path);
|
|
347
|
-
}
|
|
348
|
-
});
|
|
349
|
-
},
|
|
350
|
-
load(id) {
|
|
351
|
-
if (!id) {
|
|
352
|
-
return null;
|
|
123
|
+
if (jsxElement.openingElement.attributes && jsxElement.openingElement.attributes.length > 0) {
|
|
124
|
+
const hasStaticAttributes = jsxElement.openingElement.attributes.some((attr) => {
|
|
125
|
+
if (attr.type === "JSXSpreadAttribute") {
|
|
126
|
+
return false;
|
|
353
127
|
}
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
128
|
+
if (attr.value && attr.value.type === "JSXExpressionContainer") {
|
|
129
|
+
return isStaticExpression(attr.value.expression);
|
|
130
|
+
}
|
|
131
|
+
if (attr.value && attr.value.type === "StringLiteral") {
|
|
132
|
+
return true;
|
|
358
133
|
}
|
|
359
|
-
return
|
|
134
|
+
return false;
|
|
135
|
+
});
|
|
136
|
+
if (hasStaticAttributes) {
|
|
137
|
+
return true;
|
|
360
138
|
}
|
|
361
|
-
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
362
141
|
}
|
|
363
142
|
|
|
364
|
-
// src/
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
143
|
+
// src/uuid-mapping-manager.ts
|
|
144
|
+
import { createHash } from "crypto";
|
|
145
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
146
|
+
import { dirname, join } from "path";
|
|
147
|
+
var UUIDMappingManager = class {
|
|
148
|
+
mappingFile;
|
|
149
|
+
mappings;
|
|
150
|
+
constructor(projectRoot) {
|
|
151
|
+
this.mappingFile = join(projectRoot, "public", "uuid-mappings.json");
|
|
152
|
+
this.mappings = this.loadMappings();
|
|
153
|
+
}
|
|
154
|
+
loadMappings() {
|
|
155
|
+
try {
|
|
156
|
+
if (existsSync(this.mappingFile)) {
|
|
157
|
+
const content = readFileSync(this.mappingFile, "utf8");
|
|
158
|
+
return JSON.parse(content);
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
saveMappings() {
|
|
165
|
+
try {
|
|
166
|
+
const dir = dirname(this.mappingFile);
|
|
167
|
+
if (!existsSync(dir)) {
|
|
168
|
+
mkdirSync(dir, { recursive: true });
|
|
169
|
+
}
|
|
170
|
+
writeFileSync(this.mappingFile, JSON.stringify(this.mappings, null, 2));
|
|
171
|
+
} catch {
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
generateStableUUID(seed) {
|
|
175
|
+
const hash = createHash("sha256").update(seed).digest("hex");
|
|
176
|
+
return [
|
|
177
|
+
hash.substring(0, 8),
|
|
178
|
+
hash.substring(8, 12),
|
|
179
|
+
hash.substring(12, 16),
|
|
180
|
+
hash.substring(16, 20),
|
|
181
|
+
hash.substring(20, 32)
|
|
182
|
+
].join("-");
|
|
183
|
+
}
|
|
184
|
+
getOrCreateUUID(filePath, line, column, elementName) {
|
|
185
|
+
const existingUUID = Object.keys(this.mappings).find((uuid2) => {
|
|
186
|
+
const m = this.mappings[uuid2];
|
|
187
|
+
return m.filePath === filePath && m.line === line && m.column === column && m.elementName === elementName;
|
|
188
|
+
});
|
|
189
|
+
if (existingUUID) {
|
|
190
|
+
return existingUUID;
|
|
191
|
+
}
|
|
192
|
+
const seed = `${filePath}:${line}:${column}:${elementName}`;
|
|
193
|
+
const uuid = this.generateStableUUID(seed);
|
|
194
|
+
this.mappings[uuid] = {
|
|
195
|
+
filePath,
|
|
196
|
+
line,
|
|
197
|
+
column,
|
|
198
|
+
elementName,
|
|
199
|
+
lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
|
|
371
200
|
};
|
|
201
|
+
this.saveMappings();
|
|
202
|
+
return uuid;
|
|
372
203
|
}
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/plugin.ts
|
|
207
|
+
function uuidTagger(options) {
|
|
208
|
+
const { projectRoot } = options;
|
|
209
|
+
const uuidManager = new UUIDMappingManager(projectRoot);
|
|
377
210
|
return {
|
|
378
211
|
name: "vite-uuid-tagger",
|
|
379
212
|
enforce: "pre",
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
load(id) {
|
|
384
|
-
const overrideResult = overrides.load(id);
|
|
385
|
-
if (overrideResult !== null) {
|
|
386
|
-
return overrideResult;
|
|
213
|
+
async transform(code, id) {
|
|
214
|
+
if (shouldSkipFile(id)) {
|
|
215
|
+
return null;
|
|
387
216
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
return {
|
|
392
|
-
optimizeDeps: {
|
|
393
|
-
exclude: ["react/jsx-dev-runtime"]
|
|
394
|
-
}
|
|
395
|
-
};
|
|
396
|
-
},
|
|
397
|
-
configureServer(server) {
|
|
398
|
-
overrides.configureServer(server);
|
|
399
|
-
devMiddleware.configureServer(server);
|
|
400
|
-
},
|
|
401
|
-
async buildStart() {
|
|
402
|
-
if (tailwindRegistry) {
|
|
403
|
-
await tailwindRegistry.buildStart();
|
|
217
|
+
const ext = path2.extname(id);
|
|
218
|
+
if (ext !== ".tsx" && ext !== ".jsx") {
|
|
219
|
+
return null;
|
|
404
220
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
221
|
+
const relativePath = path2.relative(projectRoot, id);
|
|
222
|
+
const { walk } = await import("estree-walker");
|
|
223
|
+
try {
|
|
224
|
+
const ast = parse(code, {
|
|
225
|
+
sourceType: "module",
|
|
226
|
+
plugins: ["jsx", "typescript"]
|
|
227
|
+
});
|
|
228
|
+
const magic = new MagicString(code);
|
|
229
|
+
let changed = 0;
|
|
230
|
+
walk(ast, {
|
|
231
|
+
enter(node) {
|
|
232
|
+
const n = node;
|
|
233
|
+
if (!shouldTagElement(n)) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const openingElement = n.openingElement;
|
|
237
|
+
const elementName = getElementName(openingElement);
|
|
238
|
+
if (!elementName) {
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const { line = 0, column = 0 } = openingElement.loc?.start ?? {};
|
|
242
|
+
const uuid = uuidManager.getOrCreateUUID(relativePath, line, column, elementName);
|
|
243
|
+
magic.appendLeft(openingElement.name.end ?? 0, ` data-uuid-loc="${uuid}"`);
|
|
244
|
+
if (supportsContentEditable(n)) {
|
|
245
|
+
magic.appendLeft(openingElement.name.end ?? 0, " data-content-editable");
|
|
246
|
+
}
|
|
247
|
+
if (isInlineEditable(n)) {
|
|
248
|
+
magic.appendLeft(openingElement.name.end ?? 0, " data-inline-editable");
|
|
249
|
+
}
|
|
250
|
+
changed++;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
if (changed > 0) {
|
|
254
|
+
return {
|
|
255
|
+
code: magic.toString(),
|
|
256
|
+
map: magic.generateMap({ hires: true })
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
} catch {
|
|
261
|
+
return null;
|
|
409
262
|
}
|
|
410
|
-
return html;
|
|
411
263
|
}
|
|
412
264
|
};
|
|
413
265
|
}
|
|
414
266
|
export {
|
|
415
|
-
|
|
267
|
+
uuidTagger
|
|
416
268
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@runner-ai/vite-uuid-tagger",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.6",
|
|
4
4
|
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
5
7
|
"exports": {
|
|
6
8
|
".": {
|
|
7
9
|
"types": "./dist/index.d.ts",
|
|
@@ -12,31 +14,22 @@
|
|
|
12
14
|
"dist"
|
|
13
15
|
],
|
|
14
16
|
"scripts": {
|
|
15
|
-
"build": "tsup",
|
|
17
|
+
"build": "tsup src/index.ts --format esm --dts --out-dir dist",
|
|
16
18
|
"test": "vitest run",
|
|
17
|
-
"test:watch": "vitest",
|
|
18
|
-
"typecheck": "tsc --noEmit",
|
|
19
|
-
"clean": "rm -rf .turbo node_modules dist",
|
|
20
|
-
"publish:dev": "bun run build && npm publish --tag dev --access public",
|
|
21
19
|
"publish:prod": "bun run build && npm publish --access public"
|
|
22
20
|
},
|
|
23
21
|
"dependencies": {
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"@types/react": "^19.0.0",
|
|
28
|
-
"tsup": "^8.5.0",
|
|
29
|
-
"typescript": "^5.8.0",
|
|
30
|
-
"vite": "^7.0.0",
|
|
31
|
-
"vitest": "^3.0.0"
|
|
22
|
+
"@babel/parser": "^7.24.0",
|
|
23
|
+
"estree-walker": "^3.0.3",
|
|
24
|
+
"magic-string": "^0.30.0"
|
|
32
25
|
},
|
|
33
26
|
"peerDependencies": {
|
|
34
|
-
"vite": ">=
|
|
35
|
-
"tailwindcss": ">=3.0.0"
|
|
27
|
+
"vite": ">=4.0.0"
|
|
36
28
|
},
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"tsup": "^8.0.0",
|
|
31
|
+
"vite": "^7.0.0",
|
|
32
|
+
"vitest": "^3.0.0",
|
|
33
|
+
"typescript": "^5.8.0"
|
|
41
34
|
}
|
|
42
35
|
}
|