@archie/devtools 0.0.9 → 0.0.11

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.mts CHANGED
@@ -1,31 +1,36 @@
1
- import { Plugin } from 'vite';
1
+ import { ResolvedConfig } from 'vite';
2
2
 
3
3
  interface ArchieDevToolsOptions {
4
4
  /**
5
- * Enable debug logging
5
+ * Enable debug logging.
6
6
  * @default false
7
7
  */
8
8
  debug?: boolean;
9
+ /**
10
+ * Files matching this pattern get the DnD auto-transform applied.
11
+ * @default /src\/pages\//
12
+ */
13
+ dndPages?: RegExp;
14
+ }
15
+ interface ArchieDevToolsPlugin {
16
+ name: string;
17
+ enforce?: 'pre' | 'post';
18
+ config?: () => {
19
+ resolve: {
20
+ dedupe: string[];
21
+ };
22
+ };
23
+ configResolved?: (config: ResolvedConfig) => void;
24
+ resolveId?: (id: string) => string | null;
25
+ load?: (id: string) => string | null;
26
+ api?: {
27
+ reactBabel?: (babelOptions: {
28
+ plugins: unknown[];
29
+ }, context: {
30
+ id: string;
31
+ }) => void;
32
+ };
9
33
  }
10
- /**
11
- * Archie DevTools Vite Plugin
12
- *
13
- * Provides build-time integration for Archie generated applications.
14
- * Currently serves as an extensibility point for future features:
15
- * - Component tagging (click-to-edit)
16
- * - HMR overrides
17
- * - Virtual file injection
18
- *
19
- * @example
20
- * ```typescript
21
- * // vite.config.ts
22
- * import { archieDevTools } from '@archie/devtools';
23
- *
24
- * export default defineConfig({
25
- * plugins: [archieDevTools()]
26
- * })
27
- * ```
28
- */
29
- declare function archieDevTools(options?: ArchieDevToolsOptions): Plugin;
34
+ declare function archieDevTools(options?: ArchieDevToolsOptions): ArchieDevToolsPlugin;
30
35
 
31
- export { type ArchieDevToolsOptions, archieDevTools };
36
+ export { archieDevTools };
package/dist/index.d.ts CHANGED
@@ -1,31 +1,36 @@
1
- import { Plugin } from 'vite';
1
+ import { ResolvedConfig } from 'vite';
2
2
 
3
3
  interface ArchieDevToolsOptions {
4
4
  /**
5
- * Enable debug logging
5
+ * Enable debug logging.
6
6
  * @default false
7
7
  */
8
8
  debug?: boolean;
9
+ /**
10
+ * Files matching this pattern get the DnD auto-transform applied.
11
+ * @default /src\/pages\//
12
+ */
13
+ dndPages?: RegExp;
14
+ }
15
+ interface ArchieDevToolsPlugin {
16
+ name: string;
17
+ enforce?: 'pre' | 'post';
18
+ config?: () => {
19
+ resolve: {
20
+ dedupe: string[];
21
+ };
22
+ };
23
+ configResolved?: (config: ResolvedConfig) => void;
24
+ resolveId?: (id: string) => string | null;
25
+ load?: (id: string) => string | null;
26
+ api?: {
27
+ reactBabel?: (babelOptions: {
28
+ plugins: unknown[];
29
+ }, context: {
30
+ id: string;
31
+ }) => void;
32
+ };
9
33
  }
10
- /**
11
- * Archie DevTools Vite Plugin
12
- *
13
- * Provides build-time integration for Archie generated applications.
14
- * Currently serves as an extensibility point for future features:
15
- * - Component tagging (click-to-edit)
16
- * - HMR overrides
17
- * - Virtual file injection
18
- *
19
- * @example
20
- * ```typescript
21
- * // vite.config.ts
22
- * import { archieDevTools } from '@archie/devtools';
23
- *
24
- * export default defineConfig({
25
- * plugins: [archieDevTools()]
26
- * })
27
- * ```
28
- */
29
- declare function archieDevTools(options?: ArchieDevToolsOptions): Plugin;
34
+ declare function archieDevTools(options?: ArchieDevToolsOptions): ArchieDevToolsPlugin;
30
35
 
31
- export { type ArchieDevToolsOptions, archieDevTools };
36
+ export { archieDevTools };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,6 +17,14 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
 
20
30
  // src/index.ts
@@ -23,23 +33,505 @@ __export(index_exports, {
23
33
  archieDevTools: () => archieDevTools
24
34
  });
25
35
  module.exports = __toCommonJS(index_exports);
26
- function archieDevTools(options = {}) {
27
- const { debug = false } = options;
28
- const log = (...args) => {
29
- if (debug) {
30
- console.log("[Archie DevTools]", ...args);
36
+
37
+ // src/client/dnd/virtual/dndScopeVirtualModule.ts
38
+ var INTERNAL_DND_SCOPE_IMPORT_SOURCE = "virtual:archie-devtools/dnd-scope";
39
+ var RESOLVED_DND_SCOPE_MODULE_ID = `\0${INTERNAL_DND_SCOPE_IMPORT_SOURCE}`;
40
+ function getDndScopeVirtualModuleSource() {
41
+ return `
42
+ import React from 'react';
43
+
44
+ export function DndScope({ id, tag = 'div', tagProps = {}, items = [], direction }) {
45
+ void direction;
46
+ const children = Array.isArray(items)
47
+ ? items.map((item) => React.createElement(React.Fragment, { key: item.id }, item.node))
48
+ : [];
49
+
50
+ return React.createElement(
51
+ tag,
52
+ { ...(tagProps || {}), 'data-dnd-scope': id },
53
+ ...children,
54
+ );
55
+ }
56
+ `;
57
+ }
58
+
59
+ // src/client/dnd/babel-plugin-dnd-auto.ts
60
+ var SCOPE_LOCAL = "__DndScope";
61
+ function babelPluginDndAuto({ types: t }, opts = {}) {
62
+ const {
63
+ fileMatch,
64
+ fileExclude = /node_modules/,
65
+ minComponents = 2,
66
+ importSource = INTERNAL_DND_SCOPE_IMPORT_SOURCE
67
+ } = opts;
68
+ function getJSXTagName(el) {
69
+ const { name } = el;
70
+ if (t.isJSXIdentifier(name)) return name.name;
71
+ if (t.isJSXMemberExpression(name)) {
72
+ const obj = t.isJSXIdentifier(name.object) ? name.object.name : "";
73
+ return `${obj}.${name.property.name}`;
74
+ }
75
+ return "";
76
+ }
77
+ function isHTMLTag(name) {
78
+ return name.length > 0 && name[0] === name[0].toLowerCase();
79
+ }
80
+ function isPascalTag(name) {
81
+ return name.length > 0 && name[0] !== name[0].toLowerCase();
82
+ }
83
+ function attrsToObject(attrs) {
84
+ const props = [];
85
+ for (const attr of attrs) {
86
+ if (!t.isJSXAttribute(attr)) continue;
87
+ const keyName = t.isJSXIdentifier(attr.name) ? attr.name.name : attr.name.name.name;
88
+ let value;
89
+ if (attr.value === null || attr.value === void 0) {
90
+ value = t.booleanLiteral(true);
91
+ } else if (t.isStringLiteral(attr.value)) {
92
+ value = attr.value;
93
+ } else if (t.isJSXExpressionContainer(attr.value)) {
94
+ const expr = attr.value.expression;
95
+ value = t.isJSXEmptyExpression(expr) ? t.booleanLiteral(true) : expr;
96
+ } else {
97
+ continue;
98
+ }
99
+ props.push(t.objectProperty(t.identifier(keyName), value));
100
+ }
101
+ return t.objectExpression(props);
102
+ }
103
+ function buildItemObject(itemId, type, draggable, node) {
104
+ return t.objectExpression([
105
+ t.objectProperty(t.identifier("id"), t.stringLiteral(itemId)),
106
+ t.objectProperty(t.identifier("type"), t.stringLiteral(type)),
107
+ t.objectProperty(t.identifier("label"), t.stringLiteral(type)),
108
+ // `node` is a JSX element — valid inside a JS object literal
109
+ t.objectProperty(t.identifier("node"), node),
110
+ t.objectProperty(t.identifier("draggable"), t.booleanLiteral(draggable))
111
+ ]);
112
+ }
113
+ function maybeTransformRoot(jsxEl, componentName, scopeCounter) {
114
+ const { openingElement, children } = jsxEl;
115
+ const tagName = getJSXTagName(openingElement);
116
+ if (!isHTMLTag(tagName)) return null;
117
+ const elementChildren = children.filter(
118
+ (c) => t.isJSXElement(c)
119
+ );
120
+ const pascalCount = elementChildren.filter(
121
+ (c) => isPascalTag(getJSXTagName(c.openingElement))
122
+ ).length;
123
+ if (pascalCount < minComponents) return null;
124
+ scopeCounter.n += 1;
125
+ const scopeId = `${componentName}_s${scopeCounter.n}`;
126
+ const itemObjects = [];
127
+ elementChildren.forEach((child, idx) => {
128
+ const childTag = getJSXTagName(child.openingElement);
129
+ const draggable = isPascalTag(childTag);
130
+ const type = draggable ? childTag : `__html_${idx}`;
131
+ const itemId = `${scopeId}_${childTag}_${idx}`;
132
+ itemObjects.push(buildItemObject(itemId, type, draggable, child));
133
+ });
134
+ const jsxAttrs = openingElement.attributes.filter(
135
+ (a) => t.isJSXAttribute(a)
136
+ );
137
+ const tagPropsObj = attrsToObject(jsxAttrs);
138
+ const dndScopeEl = t.jsxElement(
139
+ t.jsxOpeningElement(
140
+ t.jsxIdentifier(SCOPE_LOCAL),
141
+ [
142
+ t.jsxAttribute(t.jsxIdentifier("id"), t.stringLiteral(scopeId)),
143
+ t.jsxAttribute(t.jsxIdentifier("tag"), t.stringLiteral(tagName)),
144
+ t.jsxAttribute(
145
+ t.jsxIdentifier("tagProps"),
146
+ t.jsxExpressionContainer(tagPropsObj)
147
+ ),
148
+ t.jsxAttribute(
149
+ t.jsxIdentifier("items"),
150
+ t.jsxExpressionContainer(t.arrayExpression(itemObjects))
151
+ )
152
+ ],
153
+ true
154
+ // self-closing
155
+ ),
156
+ null,
157
+ // no closing element (self-closing)
158
+ [],
159
+ true
160
+ );
161
+ return dndScopeEl;
162
+ }
163
+ return {
164
+ name: "babel-plugin-dnd-auto",
165
+ visitor: {
166
+ ExportDefaultDeclaration(path, state) {
167
+ const filename = state.filename ?? "";
168
+ if (fileExclude.test(filename)) return;
169
+ if (fileMatch && !fileMatch.test(filename)) return;
170
+ const { declaration } = path.node;
171
+ if (!t.isFunctionDeclaration(declaration)) return;
172
+ const componentName = declaration.id?.name ?? "Component";
173
+ const scopeCounter = { n: 0 };
174
+ let didTransform = false;
175
+ path.traverse({
176
+ ReturnStatement(retPath) {
177
+ const fnParent = retPath.getFunctionParent();
178
+ if (fnParent?.node !== declaration) return;
179
+ const arg = retPath.node.argument;
180
+ if (!arg || !t.isJSXElement(arg)) return;
181
+ const transformed = maybeTransformRoot(arg, componentName, scopeCounter);
182
+ if (transformed) {
183
+ retPath.node.argument = transformed;
184
+ didTransform = true;
185
+ }
186
+ }
187
+ });
188
+ if (didTransform && !state._dndInjected) {
189
+ state._dndInjected = true;
190
+ state.file.path.unshiftContainer(
191
+ "body",
192
+ t.importDeclaration(
193
+ [t.importSpecifier(t.identifier(SCOPE_LOCAL), t.identifier("DndScope"))],
194
+ t.stringLiteral(importSource)
195
+ )
196
+ );
197
+ }
198
+ }
31
199
  }
32
200
  };
201
+ }
202
+
203
+ // src/babel-plugin-editor-meta.ts
204
+ var nodePath = __toESM(require("path"));
205
+ function isPackageImport(src) {
206
+ if (src.startsWith(".") || src.startsWith("/")) return false;
207
+ if (src.startsWith("@")) {
208
+ const slashIdx = src.indexOf("/");
209
+ if (slashIdx === 1) return false;
210
+ if (slashIdx > 1) return true;
211
+ return true;
212
+ }
213
+ if (src.startsWith("~/") || src.startsWith("#/")) return false;
214
+ return true;
215
+ }
216
+ function babelPluginEditorMeta({ types: t }, opts = {}) {
217
+ const {
218
+ fileExclude = /node_modules/,
219
+ instrumentImported = true,
220
+ includeHostSourceRef = false
221
+ } = opts;
222
+ function getJSXTagName(el) {
223
+ const { name } = el;
224
+ if (t.isJSXIdentifier(name)) return name.name;
225
+ if (t.isJSXMemberExpression(name)) {
226
+ const parts = [];
227
+ let current = name;
228
+ while (t.isJSXMemberExpression(current)) {
229
+ parts.unshift(current.property.name);
230
+ current = current.object;
231
+ }
232
+ if (t.isJSXIdentifier(current)) parts.unshift(current.name);
233
+ return parts.join(".");
234
+ }
235
+ return "";
236
+ }
237
+ function computeNodeId(file, line, col, componentName) {
238
+ return `${file}:${line}:${col}:${componentName}`;
239
+ }
240
+ function isMovable(path) {
241
+ const elPath = path.parentPath;
242
+ if (!elPath) return false;
243
+ const parentEl = elPath.parentPath;
244
+ if (!parentEl || !parentEl.isJSXElement()) return false;
245
+ const siblings = parentEl.node.children.filter(
246
+ (c) => t.isJSXElement(c)
247
+ );
248
+ return siblings.length >= 2;
249
+ }
250
+ function getParentNodeId(path, file) {
251
+ const elPath = path.parentPath;
252
+ if (!elPath) return null;
253
+ let ancestor = elPath.parentPath;
254
+ while (ancestor) {
255
+ if (ancestor.isJSXElement()) {
256
+ const opening = ancestor.node.openingElement;
257
+ const loc = opening.loc?.start;
258
+ if (loc) {
259
+ const tag = getJSXTagName(opening);
260
+ return computeNodeId(file, loc.line, loc.column, tag);
261
+ }
262
+ return null;
263
+ }
264
+ ancestor = ancestor.parentPath;
265
+ }
266
+ return null;
267
+ }
268
+ function extractStaticProps(attrs) {
269
+ const props = [];
270
+ let hasAny = false;
271
+ for (const attr of attrs) {
272
+ if (t.isJSXSpreadAttribute(attr)) continue;
273
+ if (!t.isJSXAttribute(attr)) continue;
274
+ const keyName = t.isJSXIdentifier(attr.name) ? attr.name.name : attr.name.name.name;
275
+ if (keyName === "__editorMeta") continue;
276
+ let value;
277
+ if (attr.value === null || attr.value === void 0) {
278
+ value = t.booleanLiteral(true);
279
+ } else if (t.isStringLiteral(attr.value)) {
280
+ value = attr.value;
281
+ } else if (t.isJSXExpressionContainer(attr.value)) {
282
+ const expr = attr.value.expression;
283
+ if (t.isNumericLiteral(expr)) {
284
+ value = expr;
285
+ } else if (t.isBooleanLiteral(expr)) {
286
+ value = expr;
287
+ } else if (t.isNullLiteral(expr)) {
288
+ value = expr;
289
+ } else if (t.isStringLiteral(expr)) {
290
+ value = expr;
291
+ } else {
292
+ value = t.stringLiteral("__dynamic__");
293
+ }
294
+ } else {
295
+ continue;
296
+ }
297
+ props.push(t.objectProperty(t.stringLiteral(keyName), value));
298
+ hasAny = true;
299
+ }
300
+ return hasAny ? t.objectExpression(props) : null;
301
+ }
302
+ function isMetaStripSpreadExpression(arg) {
303
+ if (!t.isCallExpression(arg)) return false;
304
+ if (!t.isArrowFunctionExpression(arg.callee)) return false;
305
+ const [firstParam] = arg.callee.params;
306
+ if (!firstParam || !t.isObjectPattern(firstParam)) return false;
307
+ return firstParam.properties.some((prop) => {
308
+ if (!t.isObjectProperty(prop)) return false;
309
+ if (!t.isIdentifier(prop.key)) return false;
310
+ return prop.key.name === "__editorMeta";
311
+ });
312
+ }
313
+ function hasTruthyAsChildProp(attrs) {
314
+ for (const attr of attrs) {
315
+ if (!t.isJSXAttribute(attr) || !t.isJSXIdentifier(attr.name, { name: "asChild" })) {
316
+ continue;
317
+ }
318
+ if (attr.value == null) return true;
319
+ if (t.isJSXExpressionContainer(attr.value)) {
320
+ const expr = attr.value.expression;
321
+ if (t.isBooleanLiteral(expr)) return expr.value;
322
+ }
323
+ if (t.isStringLiteral(attr.value)) return attr.value.value !== "false";
324
+ return true;
325
+ }
326
+ return false;
327
+ }
328
+ function sanitizeSpreadAttributes(attrs) {
329
+ for (const attr of attrs) {
330
+ if (!t.isJSXSpreadAttribute(attr)) continue;
331
+ if (isMetaStripSpreadExpression(attr.argument)) continue;
332
+ const origArg = attr.argument;
333
+ attr.argument = t.callExpression(
334
+ t.arrowFunctionExpression(
335
+ [
336
+ t.objectPattern([
337
+ t.objectProperty(
338
+ t.identifier("__editorMeta"),
339
+ t.identifier("_$em"),
340
+ false,
341
+ false
342
+ ),
343
+ t.restElement(t.identifier("_$r"))
344
+ ])
345
+ ],
346
+ t.identifier("_$r")
347
+ ),
348
+ [t.objectExpression([t.spreadElement(origArg)])]
349
+ );
350
+ }
351
+ }
33
352
  return {
353
+ name: "babel-plugin-editor-meta",
354
+ visitor: {
355
+ CallExpression(path, state) {
356
+ const filename = state.filename ?? "";
357
+ if (fileExclude.test(filename)) return;
358
+ const callee = path.node.callee;
359
+ let isCreateElement = false;
360
+ let isCloneElement = false;
361
+ if (t.isIdentifier(callee, { name: "createElement" })) {
362
+ isCreateElement = true;
363
+ } else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: "createElement" })) {
364
+ isCreateElement = true;
365
+ } else if (t.isIdentifier(callee, { name: "cloneElement" })) {
366
+ isCloneElement = true;
367
+ } else if (t.isMemberExpression(callee) && t.isIdentifier(callee.property, { name: "cloneElement" })) {
368
+ isCloneElement = true;
369
+ }
370
+ if (!isCreateElement && !isCloneElement) return;
371
+ const args = path.node.arguments;
372
+ if (args.length < 2) return;
373
+ if (isCreateElement && !t.isStringLiteral(args[0])) return;
374
+ const propsArg = args[1];
375
+ if (!propsArg || t.isNullLiteral(propsArg)) return;
376
+ if (!t.isExpression(propsArg)) return;
377
+ if (isMetaStripSpreadExpression(propsArg)) return;
378
+ args[1] = t.callExpression(
379
+ t.arrowFunctionExpression(
380
+ [
381
+ t.objectPattern([
382
+ t.objectProperty(
383
+ t.identifier("__editorMeta"),
384
+ t.identifier("_$em"),
385
+ false,
386
+ false
387
+ ),
388
+ t.restElement(t.identifier("_$r"))
389
+ ])
390
+ ],
391
+ t.identifier("_$r")
392
+ ),
393
+ [t.objectExpression([t.spreadElement(propsArg)])]
394
+ );
395
+ },
396
+ JSXOpeningElement(path, state) {
397
+ const filename = state.filename ?? "";
398
+ if (fileExclude.test(filename)) return;
399
+ const existing = path.node.attributes.find(
400
+ (a) => t.isJSXAttribute(a) && t.isJSXIdentifier(a.name, { name: "__editorMeta" })
401
+ );
402
+ if (existing) return;
403
+ const loc = path.node.loc?.start;
404
+ if (!loc) return;
405
+ const root = state.file.opts.root ?? "";
406
+ const file = root ? nodePath.relative(root, filename) : filename;
407
+ const line = loc.line;
408
+ const col = loc.column;
409
+ const componentName = getJSXTagName(path.node);
410
+ if (!componentName) return;
411
+ const isHostElement = componentName[0] === componentName[0].toLowerCase();
412
+ sanitizeSpreadAttributes(path.node.attributes);
413
+ if (hasTruthyAsChildProp(path.node.attributes)) {
414
+ return;
415
+ }
416
+ let rootName = null;
417
+ if (t.isJSXIdentifier(path.node.name)) {
418
+ rootName = path.node.name.name;
419
+ } else if (t.isJSXMemberExpression(path.node.name)) {
420
+ let cur = path.node.name;
421
+ while (t.isJSXMemberExpression(cur)) cur = cur.object;
422
+ if (t.isJSXIdentifier(cur)) rootName = cur.name;
423
+ }
424
+ if (rootName) {
425
+ const binding = path.scope.getBinding(rootName);
426
+ if (binding) {
427
+ const bp = binding.path;
428
+ if (bp.isImportSpecifier() || bp.isImportDefaultSpecifier() || bp.isImportNamespaceSpecifier()) {
429
+ if (!instrumentImported) return;
430
+ const decl = bp.parentPath;
431
+ if (decl?.isImportDeclaration()) {
432
+ const src = decl.node.source.value;
433
+ if (isPackageImport(src)) return;
434
+ }
435
+ }
436
+ const programScope = path.scope.getProgramParent();
437
+ if (binding.scope !== programScope) return;
438
+ }
439
+ }
440
+ const nodeId = computeNodeId(file, line, col, componentName);
441
+ const movable = isMovable(path);
442
+ const parentNodeId = getParentNodeId(path, file);
443
+ const staticPropsObj = extractStaticProps(path.node.attributes);
444
+ const metaObj = t.objectExpression([
445
+ t.objectProperty(t.identifier("nodeId"), t.stringLiteral(nodeId)),
446
+ t.objectProperty(t.identifier("file"), t.stringLiteral(file)),
447
+ t.objectProperty(t.identifier("line"), t.numericLiteral(line)),
448
+ t.objectProperty(t.identifier("col"), t.numericLiteral(col)),
449
+ t.objectProperty(t.identifier("componentName"), t.stringLiteral(componentName)),
450
+ t.objectProperty(
451
+ t.identifier("staticProps"),
452
+ staticPropsObj ?? t.nullLiteral()
453
+ ),
454
+ t.objectProperty(t.identifier("movable"), t.booleanLiteral(movable)),
455
+ t.objectProperty(
456
+ t.identifier("parentNodeId"),
457
+ parentNodeId ? t.stringLiteral(parentNodeId) : t.nullLiteral()
458
+ )
459
+ ]);
460
+ if (isHostElement && includeHostSourceRef) {
461
+ path.node.attributes.push(
462
+ t.jsxAttribute(
463
+ t.jsxIdentifier("data-archie-source-ref"),
464
+ t.stringLiteral(`${file}::${line}::${col}`)
465
+ )
466
+ );
467
+ }
468
+ path.node.attributes.push(
469
+ t.jsxAttribute(
470
+ t.jsxIdentifier("__editorMeta"),
471
+ t.jsxExpressionContainer(metaObj)
472
+ )
473
+ );
474
+ }
475
+ }
476
+ };
477
+ }
478
+
479
+ // src/index.ts
480
+ function archieDevTools(options = {}) {
481
+ const {
482
+ debug = false,
483
+ dndPages = /src\/pages\//
484
+ } = options;
485
+ const log = (...args) => {
486
+ if (debug) console.log("[Archie DevTools]", ...args);
487
+ };
488
+ let includeHostSourceRef = false;
489
+ const plugin = {
34
490
  name: "vite-plugin-archie-devtools",
35
491
  enforce: "pre",
492
+ config() {
493
+ return {
494
+ resolve: {
495
+ dedupe: ["react", "react-dom"]
496
+ }
497
+ };
498
+ },
36
499
  configResolved(config) {
37
- log("Plugin initialized for project:", config.root);
500
+ includeHostSourceRef = !config.isProduction;
501
+ },
502
+ resolveId(id) {
503
+ if (id === INTERNAL_DND_SCOPE_IMPORT_SOURCE) {
504
+ return RESOLVED_DND_SCOPE_MODULE_ID;
505
+ }
506
+ return null;
507
+ },
508
+ load(id) {
509
+ if (id === RESOLVED_DND_SCOPE_MODULE_ID) {
510
+ return getDndScopeVirtualModuleSource();
511
+ }
512
+ return null;
38
513
  },
39
- configureServer() {
40
- log("Dev server configured");
514
+ api: {
515
+ reactBabel(babelOptions, context) {
516
+ if (!/node_modules/.test(context.id)) {
517
+ babelOptions.plugins.push(
518
+ (babel) => babelPluginEditorMeta(babel, {
519
+ includeHostSourceRef
520
+ })
521
+ );
522
+ }
523
+ if (dndPages.test(context.id)) {
524
+ log("Applying DnD transform to:", context.id);
525
+ babelOptions.plugins.push(
526
+ (babel) => babelPluginDndAuto(babel, {
527
+ importSource: INTERNAL_DND_SCOPE_IMPORT_SOURCE
528
+ })
529
+ );
530
+ }
531
+ }
41
532
  }
42
533
  };
534
+ return plugin;
43
535
  }
44
536
  // Annotate the CommonJS export names for ESM import in node:
45
537
  0 && (module.exports = {