@runner-ai/vite-uuid-tagger 0.0.3 → 0.0.5
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 +6 -8
- package/dist/index.js +231 -372
- package/package.json +13 -20
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
-
interface
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
extractColors?: boolean;
|
|
3
|
+
interface UuidTaggerOptions {
|
|
4
|
+
projectRoot: string;
|
|
5
|
+
/** Env var name for @runner-ai/design script tag version. Default: VITE_DESIGN_SCRIPT_TAG */
|
|
6
|
+
scriptTagEnvVar?: string;
|
|
8
7
|
}
|
|
8
|
+
declare function uuidTagger(options: UuidTaggerOptions): Plugin;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
export { type ViteUUIDTaggerOptions, viteUuidTagger as default };
|
|
10
|
+
export { type UuidTaggerOptions, uuidTagger };
|
package/dist/index.js
CHANGED
|
@@ -1,414 +1,273 @@
|
|
|
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
|
-
}
|
|
1
|
+
// src/plugin.ts
|
|
2
|
+
import path2 from "path";
|
|
3
|
+
import { parse } from "@babel/parser";
|
|
4
|
+
import MagicString from "magic-string";
|
|
25
5
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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));
|
|
31
12
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
-
}
|
|
50
|
-
|
|
51
|
-
if (typeof originalRef === 'function') {
|
|
52
|
-
originalRef(node);
|
|
53
|
-
} else if (originalRef && typeof originalRef === 'object') {
|
|
54
|
-
originalRef.current = node;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
var VOID_ELEMENTS = new Set([
|
|
60
|
-
'area','base','br','col','embed','hr','img','input',
|
|
61
|
-
'link','meta','param','source','track','wbr'
|
|
62
|
-
]);
|
|
63
|
-
|
|
64
|
-
export function jsxDEV(type, props, key, isStaticChildren, source, self) {
|
|
65
|
-
if (source && source.fileName && typeof type === 'string' && !VOID_ELEMENTS.has(type)) {
|
|
66
|
-
var cleanFileName = getCleanFileName(source.fileName);
|
|
67
|
-
var sourceInfo = {
|
|
68
|
-
fileName: cleanFileName,
|
|
69
|
-
lineNumber: source.lineNumber || 0,
|
|
70
|
-
columnNumber: source.columnNumber || 0,
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
var newProps = Object.assign({}, props);
|
|
74
|
-
newProps.ref = wrapRef(props ? props.ref : undefined, sourceInfo);
|
|
75
|
-
|
|
76
|
-
return _jsxDEV(type, newProps, key, isStaticChildren, source, self);
|
|
13
|
+
function getElementName(node) {
|
|
14
|
+
if (node.name.type === "JSXIdentifier") {
|
|
15
|
+
return node.name.name;
|
|
77
16
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export { Fragment };
|
|
83
|
-
export { jsx, jsxs } from 'react/jsx-dev-runtime';
|
|
84
|
-
`;
|
|
85
|
-
var PASSTHROUGH_CODE = `export * from 'react/jsx-dev-runtime';
|
|
86
|
-
`;
|
|
87
|
-
function createJsxSourceTagger() {
|
|
88
|
-
return {
|
|
89
|
-
resolveId(source, importer, options) {
|
|
90
|
-
if (source !== "react/jsx-dev-runtime") {
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
|
-
if (importer?.includes("\0runner-jsx")) {
|
|
94
|
-
return null;
|
|
95
|
-
}
|
|
96
|
-
const self = this;
|
|
97
|
-
const env = self?.environment;
|
|
98
|
-
const isSSR = env?.config?.consumer === "server" || options?.ssr === true;
|
|
99
|
-
return isSSR ? "\0runner-jsx/passthrough" : "\0runner-jsx/client-runtime";
|
|
100
|
-
},
|
|
101
|
-
load(id) {
|
|
102
|
-
if (id === "\0runner-jsx/client-runtime") {
|
|
103
|
-
return CLIENT_RUNTIME_CODE;
|
|
104
|
-
}
|
|
105
|
-
if (id === "\0runner-jsx/passthrough") {
|
|
106
|
-
return PASSTHROUGH_CODE;
|
|
107
|
-
}
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
};
|
|
17
|
+
if (node.name.type === "JSXMemberExpression") {
|
|
18
|
+
return `${node.name.object.name}.${node.name.property.name}`;
|
|
19
|
+
}
|
|
20
|
+
return null;
|
|
111
21
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
import glob from "fast-glob";
|
|
116
|
-
function parseThemeColors(cssContent) {
|
|
117
|
-
const themeColors = {};
|
|
118
|
-
const themeRegex = /@theme\s*\{([^}]*)\}/gs;
|
|
119
|
-
for (const match of cssContent.matchAll(themeRegex)) {
|
|
120
|
-
const content = match[1];
|
|
121
|
-
const colorRegex = /--color-([\w-]+):\s*([^;]+);/g;
|
|
122
|
-
for (const colorMatch of content.matchAll(colorRegex)) {
|
|
123
|
-
themeColors[colorMatch[1]] = colorMatch[2].trim();
|
|
124
|
-
}
|
|
22
|
+
function shouldTagElement(node) {
|
|
23
|
+
if (node.type !== "JSXElement") {
|
|
24
|
+
return false;
|
|
125
25
|
}
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
}
|
|
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;
|
|
135
33
|
}
|
|
136
|
-
return
|
|
34
|
+
return true;
|
|
137
35
|
}
|
|
138
|
-
function
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (tailwindColors && Object.keys(tailwindColors).length > 0) {
|
|
154
|
-
Object.entries(tailwindColors).forEach(function(entry) {
|
|
155
|
-
var name = entry[0], shades = entry[1];
|
|
156
|
-
if (name === 'lightBlue' || name === 'warmGray' || name === 'trueGray' || name === 'coolGray' || name === 'blueGray' || typeof shades === 'function') return;
|
|
157
|
-
if (typeof shades === 'object' && shades !== null && !Array.isArray(shades)) {
|
|
158
|
-
registry.default[name] = {};
|
|
159
|
-
Object.entries(shades).forEach(function(se) {
|
|
160
|
-
var shade = se[0], value = se[1];
|
|
161
|
-
if (typeof value === 'string') {
|
|
162
|
-
registry.default[name][shade] = {
|
|
163
|
-
value: value,
|
|
164
|
-
classes: { bg: 'bg-' + name + '-' + shade, text: 'text-' + name + '-' + shade, border: 'border-' + name + '-' + shade, ring: 'ring-' + name + '-' + shade }
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
});
|
|
168
|
-
} else if (typeof shades === 'string') {
|
|
169
|
-
registry.default[name] = {
|
|
170
|
-
value: shades,
|
|
171
|
-
classes: { bg: 'bg-' + name, text: 'text-' + name, border: 'border-' + name }
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
});
|
|
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;
|
|
175
51
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
var name = entry[0], value = entry[1];
|
|
180
|
-
registry.custom[name] = {
|
|
181
|
-
value: value,
|
|
182
|
-
variable: '--color-' + name,
|
|
183
|
-
classes: { bg: 'bg-' + name, text: 'text-' + name, border: 'border-' + name, ring: 'ring-' + name }
|
|
184
|
-
};
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
var computed = getComputedStyle(document.documentElement);
|
|
188
|
-
var cssVarArray = Array.from(computed).filter(function(p) { return p.startsWith('--'); });
|
|
189
|
-
cssVarArray.forEach(function(prop) {
|
|
190
|
-
if (prop.startsWith('--color-')) {
|
|
191
|
-
var value = computed.getPropertyValue(prop).trim();
|
|
192
|
-
var name = prop.replace('--color-', '').replace(/^-+|-+$/g, '');
|
|
193
|
-
if (!registry.custom[name]) {
|
|
194
|
-
registry.custom[name] = {
|
|
195
|
-
value: value, variable: prop,
|
|
196
|
-
classes: { bg: 'bg-' + name, text: 'text-' + name, border: 'border-' + name, ring: 'ring-' + name }
|
|
197
|
-
};
|
|
198
|
-
}
|
|
52
|
+
if (prop.type === "ObjectProperty") {
|
|
53
|
+
if (prop.computed) {
|
|
54
|
+
return false;
|
|
199
55
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
var tailwindSpacing = ${serializedSpacing};
|
|
203
|
-
var spacingRegistry = {};
|
|
204
|
-
if (tailwindSpacing && Object.keys(tailwindSpacing).length > 0) {
|
|
205
|
-
Object.entries(tailwindSpacing).forEach(function(entry) {
|
|
206
|
-
if (typeof entry[1] === 'string') spacingRegistry[entry[0]] = entry[1];
|
|
207
|
-
});
|
|
56
|
+
return isStaticExpression(prop.value);
|
|
208
57
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (
|
|
216
|
-
|
|
217
|
-
scale.forEach(function(step) {
|
|
218
|
-
if (step === 0) { spacingRegistry['0'] = '0'; }
|
|
219
|
-
else if (step === 'px') { spacingRegistry['px'] = '1px'; }
|
|
220
|
-
else {
|
|
221
|
-
var match = baseSpacing.match(/([0-9.]+)([a-z%]+)/);
|
|
222
|
-
if (match) spacingRegistry[String(step)] = (parseFloat(match[1]) * step) + match[2];
|
|
223
|
-
}
|
|
224
|
-
});
|
|
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;
|
|
225
66
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
colors: registry,
|
|
229
|
-
spacing: spacingRegistry,
|
|
230
|
-
baseSpacing: baseSpacing,
|
|
231
|
-
timestamp: Date.now()
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
if (window.parent !== window) {
|
|
235
|
-
window.parent.postMessage({ type: 'TAILWIND_REGISTRY_UPDATE', data: window.__TAILWIND_REGISTRY__ }, '*');
|
|
67
|
+
if (elem.type === "SpreadElement") {
|
|
68
|
+
return false;
|
|
236
69
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
async function loadTailwindDefaults() {
|
|
241
|
-
try {
|
|
242
|
-
const defaultTheme = await import("tailwindcss/defaultTheme.js");
|
|
243
|
-
const rawColors = defaultTheme?.default?.colors;
|
|
244
|
-
const rawSpacing = defaultTheme?.default?.spacing;
|
|
245
|
-
const colors = typeof rawColors === "function" ? rawColors() : rawColors ?? {};
|
|
246
|
-
const spacing = typeof rawSpacing === "function" ? rawSpacing() : rawSpacing ?? {};
|
|
247
|
-
return { colors, spacing };
|
|
248
|
-
} catch {
|
|
249
|
-
return { colors: {}, spacing: {} };
|
|
70
|
+
return isStaticExpression(elem);
|
|
71
|
+
});
|
|
250
72
|
}
|
|
73
|
+
return false;
|
|
251
74
|
}
|
|
252
|
-
function
|
|
253
|
-
|
|
254
|
-
let tailwindSpacing = {};
|
|
255
|
-
let themeColors = {};
|
|
256
|
-
return {
|
|
257
|
-
async buildStart() {
|
|
258
|
-
const tw = await loadTailwindDefaults();
|
|
259
|
-
tailwindColors = tw.colors;
|
|
260
|
-
tailwindSpacing = tw.spacing;
|
|
261
|
-
try {
|
|
262
|
-
const cssFiles = await glob("**/*.css", {
|
|
263
|
-
ignore: ["**/node_modules/**", "**/dist/**", "**/.next/**", "**/.git/**", "**/build/**"],
|
|
264
|
-
cwd: process.cwd(),
|
|
265
|
-
absolute: true
|
|
266
|
-
});
|
|
267
|
-
for (const file of cssFiles) {
|
|
268
|
-
try {
|
|
269
|
-
const content = await fs.readFile(file, "utf-8");
|
|
270
|
-
const parsed = parseThemeColors(content);
|
|
271
|
-
themeColors = { ...themeColors, ...parsed };
|
|
272
|
-
} catch {
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
} catch {
|
|
276
|
-
}
|
|
277
|
-
},
|
|
278
|
-
transformIndexHtml(html) {
|
|
279
|
-
const script = buildColorRegistry(tailwindColors, tailwindSpacing, themeColors);
|
|
280
|
-
return html.replace("</body>", `<script>${script}</script></body>`);
|
|
281
|
-
}
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
// src/features/virtual-overrides.ts
|
|
286
|
-
var LEADING_DOT_SLASH = /^\.\//;
|
|
287
|
-
var BACKSLASH = /\\/g;
|
|
288
|
-
function normalizePath(path) {
|
|
289
|
-
return path.replace(LEADING_DOT_SLASH, "").replace(BACKSLASH, "/");
|
|
290
|
-
}
|
|
291
|
-
function isPathSafe(path) {
|
|
292
|
-
if (path.includes("..")) {
|
|
75
|
+
function supportsContentEditable(jsxElement) {
|
|
76
|
+
if (!jsxElement.children || jsxElement.children.length === 0) {
|
|
293
77
|
return false;
|
|
294
78
|
}
|
|
295
|
-
|
|
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) {
|
|
296
89
|
return false;
|
|
297
90
|
}
|
|
298
|
-
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
|
+
});
|
|
299
100
|
}
|
|
300
|
-
function
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if (!_server) {
|
|
305
|
-
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;
|
|
306
105
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
timestamp: Date.now()
|
|
319
|
-
}
|
|
320
|
-
]
|
|
321
|
-
});
|
|
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";
|
|
322
117
|
}
|
|
118
|
+
return false;
|
|
119
|
+
});
|
|
120
|
+
if (hasStaticChildren && hasEditableContent) {
|
|
121
|
+
return true;
|
|
323
122
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const normalizedPath = normalizePath(data.path);
|
|
329
|
-
if (!isPathSafe(normalizedPath)) {
|
|
330
|
-
return;
|
|
331
|
-
}
|
|
332
|
-
overrides.set(normalizedPath, data.content);
|
|
333
|
-
invalidateAndUpdate(normalizedPath);
|
|
334
|
-
});
|
|
335
|
-
server.ws.on("runner:clear-override", (data) => {
|
|
336
|
-
const normalizedPath = normalizePath(data.path);
|
|
337
|
-
overrides.delete(normalizedPath);
|
|
338
|
-
invalidateAndUpdate(normalizedPath);
|
|
339
|
-
});
|
|
340
|
-
server.ws.on("runner:clear-all-overrides", () => {
|
|
341
|
-
const paths = Array.from(overrides.keys());
|
|
342
|
-
overrides.clear();
|
|
343
|
-
for (const path of paths) {
|
|
344
|
-
invalidateAndUpdate(path);
|
|
345
|
-
}
|
|
346
|
-
});
|
|
347
|
-
},
|
|
348
|
-
load(id) {
|
|
349
|
-
if (!id) {
|
|
350
|
-
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;
|
|
351
127
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
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;
|
|
356
133
|
}
|
|
357
|
-
return
|
|
134
|
+
return false;
|
|
135
|
+
});
|
|
136
|
+
if (hasStaticAttributes) {
|
|
137
|
+
return true;
|
|
358
138
|
}
|
|
359
|
-
}
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
360
141
|
}
|
|
361
142
|
|
|
362
|
-
// src/
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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()
|
|
369
200
|
};
|
|
201
|
+
this.saveMappings();
|
|
202
|
+
return uuid;
|
|
370
203
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// src/plugin.ts
|
|
207
|
+
function uuidTagger(options) {
|
|
208
|
+
const { projectRoot, scriptTagEnvVar = "VITE_DESIGN_SCRIPT_TAG" } = options;
|
|
209
|
+
const uuidManager = new UUIDMappingManager(projectRoot);
|
|
375
210
|
return {
|
|
376
211
|
name: "vite-uuid-tagger",
|
|
377
212
|
enforce: "pre",
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
load(id) {
|
|
382
|
-
const overrideResult = overrides.load(id);
|
|
383
|
-
if (overrideResult !== null) {
|
|
384
|
-
return overrideResult;
|
|
213
|
+
async transform(code, id) {
|
|
214
|
+
if (shouldSkipFile(id)) {
|
|
215
|
+
return null;
|
|
385
216
|
}
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
217
|
+
const ext = path2.extname(id);
|
|
218
|
+
if (ext !== ".tsx" && ext !== ".jsx") {
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
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
|
+
};
|
|
392
258
|
}
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
overrides.configureServer(server);
|
|
397
|
-
devMiddleware.configureServer(server);
|
|
398
|
-
},
|
|
399
|
-
async buildStart() {
|
|
400
|
-
if (tailwindRegistry) {
|
|
401
|
-
await tailwindRegistry.buildStart();
|
|
259
|
+
return null;
|
|
260
|
+
} catch {
|
|
261
|
+
return null;
|
|
402
262
|
}
|
|
403
263
|
},
|
|
404
264
|
transformIndexHtml(html) {
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
}
|
|
408
|
-
return html;
|
|
265
|
+
const tag = process.env[scriptTagEnvVar];
|
|
266
|
+
const src = `https://unpkg.com/@runner-ai/design${tag ? `@${tag}` : ""}`;
|
|
267
|
+
return html.replace("</body>", `<script src="${src}"></script></body>`);
|
|
409
268
|
}
|
|
410
269
|
};
|
|
411
270
|
}
|
|
412
271
|
export {
|
|
413
|
-
|
|
272
|
+
uuidTagger
|
|
414
273
|
};
|
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.5",
|
|
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
|
}
|