@base44-preview/vite-plugin 0.2.22-pr.37.fd9cb1a → 0.2.22-pr.39.4150ff4

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.
Files changed (113) hide show
  1. package/dist/injections/visual-edit-agent.d.ts +1 -1
  2. package/dist/injections/visual-edit-agent.d.ts.map +1 -1
  3. package/dist/injections/visual-edit-agent.js +458 -1
  4. package/dist/injections/visual-edit-agent.js.map +1 -1
  5. package/dist/jsx-processor.d.ts +15 -0
  6. package/dist/jsx-processor.d.ts.map +1 -0
  7. package/dist/jsx-processor.js +106 -0
  8. package/dist/jsx-processor.js.map +1 -0
  9. package/dist/jsx-utils.d.ts +7 -0
  10. package/dist/jsx-utils.d.ts.map +1 -0
  11. package/dist/jsx-utils.js +12 -0
  12. package/dist/jsx-utils.js.map +1 -0
  13. package/dist/processors/shared-utils.d.ts +19 -0
  14. package/dist/processors/shared-utils.d.ts.map +1 -0
  15. package/dist/processors/shared-utils.js +77 -0
  16. package/dist/processors/shared-utils.js.map +1 -0
  17. package/dist/processors/static-array-processor.d.ts +31 -0
  18. package/dist/processors/static-array-processor.d.ts.map +1 -0
  19. package/dist/processors/static-array-processor.js +175 -0
  20. package/dist/processors/static-array-processor.js.map +1 -0
  21. package/dist/statics/index.mjs +1 -5
  22. package/dist/statics/index.mjs.map +1 -1
  23. package/dist/visual-edit-plugin.d.ts.map +1 -1
  24. package/dist/visual-edit-plugin.js +5 -0
  25. package/dist/visual-edit-plugin.js.map +1 -1
  26. package/package.json +2 -1
  27. package/src/injections/visual-edit-agent.ts +561 -1
  28. package/src/jsx-processor.ts +147 -0
  29. package/src/jsx-utils.ts +15 -0
  30. package/src/processors/shared-utils.ts +116 -0
  31. package/src/processors/static-array-processor.ts +257 -0
  32. package/src/visual-edit-plugin.ts +6 -0
  33. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.d.ts +0 -25
  34. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.d.ts.map +0 -1
  35. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.js +0 -95
  36. package/dist/injections/visual-edit-agent/capabilities/inline-editing/core.js.map +0 -1
  37. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.d.ts +0 -4
  38. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.d.ts.map +0 -1
  39. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.js +0 -4
  40. package/dist/injections/visual-edit-agent/capabilities/inline-editing/index.js.map +0 -1
  41. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.d.ts +0 -9
  42. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.d.ts.map +0 -1
  43. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.js +0 -26
  44. package/dist/injections/visual-edit-agent/capabilities/inline-editing/styles.js.map +0 -1
  45. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.d.ts +0 -10
  46. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.d.ts.map +0 -1
  47. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.js +0 -60
  48. package/dist/injections/visual-edit-agent/capabilities/inline-editing/validation.js.map +0 -1
  49. package/dist/injections/visual-edit-agent/constants.d.ts +0 -10
  50. package/dist/injections/visual-edit-agent/constants.d.ts.map +0 -1
  51. package/dist/injections/visual-edit-agent/constants.js +0 -10
  52. package/dist/injections/visual-edit-agent/constants.js.map +0 -1
  53. package/dist/injections/visual-edit-agent/handlers/click-handlers.d.ts +0 -10
  54. package/dist/injections/visual-edit-agent/handlers/click-handlers.d.ts.map +0 -1
  55. package/dist/injections/visual-edit-agent/handlers/click-handlers.js +0 -108
  56. package/dist/injections/visual-edit-agent/handlers/click-handlers.js.map +0 -1
  57. package/dist/injections/visual-edit-agent/handlers/hover-handlers.d.ts +0 -14
  58. package/dist/injections/visual-edit-agent/handlers/hover-handlers.d.ts.map +0 -1
  59. package/dist/injections/visual-edit-agent/handlers/hover-handlers.js +0 -64
  60. package/dist/injections/visual-edit-agent/handlers/hover-handlers.js.map +0 -1
  61. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.d.ts +0 -14
  62. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.d.ts.map +0 -1
  63. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.js +0 -109
  64. package/dist/injections/visual-edit-agent/handlers/inline-edit-handlers.js.map +0 -1
  65. package/dist/injections/visual-edit-agent/handlers/message-handlers.d.ts +0 -26
  66. package/dist/injections/visual-edit-agent/handlers/message-handlers.d.ts.map +0 -1
  67. package/dist/injections/visual-edit-agent/handlers/message-handlers.js +0 -145
  68. package/dist/injections/visual-edit-agent/handlers/message-handlers.js.map +0 -1
  69. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.d.ts +0 -7
  70. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.d.ts.map +0 -1
  71. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.js +0 -54
  72. package/dist/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.js.map +0 -1
  73. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.d.ts +0 -11
  74. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.d.ts.map +0 -1
  75. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.js +0 -32
  76. package/dist/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.js.map +0 -1
  77. package/dist/injections/visual-edit-agent/handlers/messages/types.d.ts +0 -86
  78. package/dist/injections/visual-edit-agent/handlers/messages/types.d.ts.map +0 -1
  79. package/dist/injections/visual-edit-agent/handlers/messages/types.js +0 -28
  80. package/dist/injections/visual-edit-agent/handlers/messages/types.js.map +0 -1
  81. package/dist/injections/visual-edit-agent/index.d.ts +0 -5
  82. package/dist/injections/visual-edit-agent/index.d.ts.map +0 -1
  83. package/dist/injections/visual-edit-agent/index.js +0 -95
  84. package/dist/injections/visual-edit-agent/index.js.map +0 -1
  85. package/dist/injections/visual-edit-agent/state/agent-state.d.ts +0 -17
  86. package/dist/injections/visual-edit-agent/state/agent-state.d.ts.map +0 -1
  87. package/dist/injections/visual-edit-agent/state/agent-state.js +0 -18
  88. package/dist/injections/visual-edit-agent/state/agent-state.js.map +0 -1
  89. package/dist/injections/visual-edit-agent/ui/overlay.d.ts +0 -26
  90. package/dist/injections/visual-edit-agent/ui/overlay.d.ts.map +0 -1
  91. package/dist/injections/visual-edit-agent/ui/overlay.js +0 -104
  92. package/dist/injections/visual-edit-agent/ui/overlay.js.map +0 -1
  93. package/dist/injections/visual-edit-agent/utils/dom-utils.d.ts +0 -14
  94. package/dist/injections/visual-edit-agent/utils/dom-utils.d.ts.map +0 -1
  95. package/dist/injections/visual-edit-agent/utils/dom-utils.js +0 -34
  96. package/dist/injections/visual-edit-agent/utils/dom-utils.js.map +0 -1
  97. package/src/injections/visual-edit-agent/README.md +0 -222
  98. package/src/injections/visual-edit-agent/capabilities/inline-editing/core.ts +0 -120
  99. package/src/injections/visual-edit-agent/capabilities/inline-editing/index.ts +0 -10
  100. package/src/injections/visual-edit-agent/capabilities/inline-editing/styles.ts +0 -26
  101. package/src/injections/visual-edit-agent/capabilities/inline-editing/validation.ts +0 -67
  102. package/src/injections/visual-edit-agent/constants.ts +0 -9
  103. package/src/injections/visual-edit-agent/handlers/click-handlers.ts +0 -135
  104. package/src/injections/visual-edit-agent/handlers/hover-handlers.ts +0 -78
  105. package/src/injections/visual-edit-agent/handlers/inline-edit-handlers.ts +0 -141
  106. package/src/injections/visual-edit-agent/handlers/message-handlers.ts +0 -191
  107. package/src/injections/visual-edit-agent/handlers/messages/toggle-inline-edit-mode.ts +0 -65
  108. package/src/injections/visual-edit-agent/handlers/messages/toggle-visual-edit-mode.ts +0 -40
  109. package/src/injections/visual-edit-agent/handlers/messages/types.ts +0 -112
  110. package/src/injections/visual-edit-agent/index.ts +0 -108
  111. package/src/injections/visual-edit-agent/state/agent-state.ts +0 -31
  112. package/src/injections/visual-edit-agent/ui/overlay.ts +0 -126
  113. package/src/injections/visual-edit-agent/utils/dom-utils.ts +0 -39
@@ -0,0 +1,147 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type * as t from "@babel/types";
3
+ import { StaticArrayProcessor } from "./processors/static-array-processor.js";
4
+
5
+ export class JSXProcessor {
6
+ private staticArrayProcessor: StaticArrayProcessor;
7
+
8
+ constructor(
9
+ private types: typeof t,
10
+ private filename: string
11
+ ) {
12
+ this.staticArrayProcessor = new StaticArrayProcessor(types);
13
+ }
14
+
15
+ processJSXElement(path: NodePath<t.JSXOpeningElement>): void {
16
+ if (this.hasAttribute(path, "data-source-location")) return;
17
+
18
+ this.addSourceLocationAttribute(path);
19
+ this.addDynamicContentAttribute(path);
20
+ this.addContentEditableAttribute(path);
21
+ this.staticArrayProcessor.process(path);
22
+ }
23
+
24
+ private addSourceLocationAttribute(
25
+ path: NodePath<t.JSXOpeningElement>
26
+ ): void {
27
+ const { line, column } = path.node.loc?.start || { line: 1, column: 0 };
28
+ const value = `${this.filename}:${line}:${column}`;
29
+
30
+ path.node.attributes.push(
31
+ this.types.jsxAttribute(
32
+ this.types.jsxIdentifier("data-source-location"),
33
+ this.types.stringLiteral(value)
34
+ )
35
+ );
36
+ }
37
+
38
+ private addDynamicContentAttribute(
39
+ path: NodePath<t.JSXOpeningElement>
40
+ ): void {
41
+ const parentElement = path.parentPath;
42
+ if (!parentElement?.isJSXElement()) return;
43
+
44
+ const isDynamic = this.checkIfElementHasDynamicContent(
45
+ parentElement.node as t.JSXElement
46
+ );
47
+
48
+ path.node.attributes.push(
49
+ this.types.jsxAttribute(
50
+ this.types.jsxIdentifier("data-dynamic-content"),
51
+ this.types.stringLiteral(isDynamic ? "true" : "false")
52
+ )
53
+ );
54
+ }
55
+
56
+ private addContentEditableAttribute(
57
+ path: NodePath<t.JSXOpeningElement>
58
+ ): void {
59
+ path.node.attributes.push(
60
+ this.types.jsxAttribute(
61
+ this.types.jsxIdentifier("content-editable"),
62
+ this.types.stringLiteral("true")
63
+ )
64
+ );
65
+ }
66
+
67
+ private hasAttribute(
68
+ path: NodePath<t.JSXOpeningElement>,
69
+ name: string
70
+ ): boolean {
71
+ return path.node.attributes.some(
72
+ (attr: t.JSXAttribute | t.JSXSpreadAttribute) =>
73
+ this.types.isJSXAttribute(attr) &&
74
+ this.types.isJSXIdentifier(attr.name) &&
75
+ attr.name.name === name
76
+ );
77
+ }
78
+
79
+ private checkIfElementHasDynamicContent(jsxElement: t.JSXElement): boolean {
80
+ let hasDynamicContent = false;
81
+
82
+ const checkNode = (node: t.Node): boolean => {
83
+ if (this.types.isJSXExpressionContainer(node)) {
84
+ const expression = (node as t.JSXExpressionContainer).expression;
85
+ if (this.types.isJSXEmptyExpression(expression)) return false;
86
+ if (!this.types.isLiteral(expression)) return true;
87
+ }
88
+
89
+ if (
90
+ this.types.isTemplateLiteral(node) &&
91
+ (node as t.TemplateLiteral).expressions.length > 0
92
+ ) {
93
+ return true;
94
+ }
95
+ if (this.types.isMemberExpression(node)) return true;
96
+ if (this.types.isCallExpression(node)) return true;
97
+ if (this.types.isConditionalExpression(node)) return true;
98
+
99
+ if (this.types.isIdentifier(node)) {
100
+ const dynamicNames = [
101
+ "props",
102
+ "state",
103
+ "data",
104
+ "item",
105
+ "value",
106
+ "text",
107
+ "content",
108
+ ];
109
+ if (dynamicNames.some((name) => (node as t.Identifier).name.includes(name))) {
110
+ return true;
111
+ }
112
+ }
113
+
114
+ return false;
115
+ };
116
+
117
+ const traverseNode = (node: Record<string, unknown>): void => {
118
+ if (hasDynamicContent) return;
119
+ if (checkNode(node as unknown as t.Node)) {
120
+ hasDynamicContent = true;
121
+ return;
122
+ }
123
+
124
+ for (const key of Object.keys(node)) {
125
+ if (hasDynamicContent) return;
126
+ const value = node[key];
127
+
128
+ if (Array.isArray(value)) {
129
+ for (const child of value) {
130
+ if (child && typeof child === "object" && "type" in child) {
131
+ traverseNode(child as Record<string, unknown>);
132
+ }
133
+ }
134
+ } else if (value && typeof value === "object" && "type" in value) {
135
+ traverseNode(value as Record<string, unknown>);
136
+ }
137
+ }
138
+ };
139
+
140
+ for (const child of jsxElement.children) {
141
+ if (hasDynamicContent) break;
142
+ traverseNode(child as unknown as Record<string, unknown>);
143
+ }
144
+
145
+ return hasDynamicContent;
146
+ }
147
+ }
@@ -0,0 +1,15 @@
1
+ import type * as t from "@babel/types";
2
+
3
+ export class JSXUtils {
4
+ private static types: typeof t;
5
+
6
+ static init(types: typeof t) {
7
+ this.types = types;
8
+ }
9
+
10
+ static getAttributeName(attr: t.JSXAttribute): string {
11
+ return this.types.isJSXNamespacedName(attr.name)
12
+ ? `${attr.name.namespace.name}:${attr.name.name.name}`
13
+ : attr.name.name;
14
+ }
15
+ }
@@ -0,0 +1,116 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type * as t from "@babel/types";
3
+ import { JSXUtils } from "../jsx-utils.js";
4
+
5
+ export class JSXAttributeUtils {
6
+ constructor(private types: typeof t) {}
7
+
8
+ hasAttribute(
9
+ path: NodePath<t.JSXOpeningElement>,
10
+ attributeName: string
11
+ ): boolean {
12
+ return path.node.attributes.some(
13
+ (attr: t.JSXAttribute | t.JSXSpreadAttribute) =>
14
+ this.types.isJSXAttribute(attr) &&
15
+ JSXUtils.getAttributeName(attr) === attributeName
16
+ );
17
+ }
18
+
19
+ addStringAttribute(
20
+ path: NodePath<t.JSXOpeningElement>,
21
+ attributeName: string,
22
+ value: string
23
+ ): void {
24
+ if (!this.hasAttribute(path, attributeName)) {
25
+ path.node.attributes.push(
26
+ this.types.jsxAttribute(
27
+ this.types.jsxIdentifier(attributeName),
28
+ this.types.stringLiteral(value)
29
+ )
30
+ );
31
+ }
32
+ }
33
+
34
+ addExpressionAttribute(
35
+ path: NodePath<t.JSXOpeningElement>,
36
+ attributeName: string,
37
+ expression: t.Expression
38
+ ): void {
39
+ if (!this.hasAttribute(path, attributeName)) {
40
+ path.node.attributes.push(
41
+ this.types.jsxAttribute(
42
+ this.types.jsxIdentifier(attributeName),
43
+ this.types.jsxExpressionContainer(expression)
44
+ )
45
+ );
46
+ }
47
+ }
48
+ }
49
+
50
+ export class StaticValueUtils {
51
+ constructor(private types: typeof t) {}
52
+
53
+ isPrimitiveLiteral(path: NodePath<t.Node>): boolean {
54
+ return (
55
+ path.isStringLiteral() ||
56
+ path.isNumericLiteral() ||
57
+ path.isBooleanLiteral() ||
58
+ path.isNullLiteral()
59
+ );
60
+ }
61
+
62
+ isStaticValue(
63
+ path: NodePath<t.Node>,
64
+ visited: Set<string> = new Set()
65
+ ): boolean {
66
+ if (this.isPrimitiveLiteral(path)) return true;
67
+ if (path.isIdentifier()) return this.isStaticIdentifier(path, visited);
68
+ if (path.isObjectExpression()) return this.isStaticObject(path, visited);
69
+ if (path.isArrayExpression())
70
+ return this.isStaticArrayExpression(path, visited);
71
+ return false;
72
+ }
73
+
74
+ isStaticIdentifier(
75
+ path: NodePath<t.Identifier>,
76
+ visited: Set<string> = new Set()
77
+ ): boolean {
78
+ const binding = path.scope.getBinding(path.node.name);
79
+ if (!binding) return false;
80
+
81
+ if (binding.kind === "module") return true;
82
+
83
+ if (binding.kind === "const" && binding.path.isVariableDeclarator()) {
84
+ const name = path.node.name;
85
+ if (visited.has(name)) return false;
86
+ visited.add(name);
87
+
88
+ const init = binding.path.get("init");
89
+ if (init.hasNode()) {
90
+ return this.isStaticValue(init as NodePath<t.Node>, visited);
91
+ }
92
+ }
93
+
94
+ return false;
95
+ }
96
+
97
+ isStaticObject(
98
+ path: NodePath<t.ObjectExpression>,
99
+ visited: Set<string> = new Set()
100
+ ): boolean {
101
+ return path.get("properties").every((prop: NodePath) => {
102
+ if (!prop.isObjectProperty()) return false;
103
+ return this.isStaticValue(prop.get("value") as NodePath<t.Node>, visited);
104
+ });
105
+ }
106
+
107
+ isStaticArrayExpression(
108
+ arrayExpression: NodePath<t.ArrayExpression>,
109
+ visited: Set<string> = new Set()
110
+ ): boolean {
111
+ return arrayExpression.get("elements").every((element) => {
112
+ if (!element.node || element.isSpreadElement()) return true;
113
+ return this.isStaticValue(element as unknown as NodePath<t.Node>, visited);
114
+ });
115
+ }
116
+ }
@@ -0,0 +1,257 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type * as t from "@babel/types";
3
+ import { JSXAttributeUtils, StaticValueUtils } from "./shared-utils.js";
4
+
5
+ export const DATA_ARR_INDEX = "data-arr-index";
6
+ export const DATA_ARR_VARIABLE_NAME = "data-arr-variable-name";
7
+ export const DATA_ARR_FIELD = "data-arr-field";
8
+ const GENERATED_INDEX_PARAM = "__arrIdx__";
9
+
10
+ interface ArrayMapInfo {
11
+ arrayExpression: NodePath<t.Expression>;
12
+ callbackParam: string;
13
+ indexParam: string | null;
14
+ arrayVariableName: string | null;
15
+ mapCallPath: NodePath<t.CallExpression>;
16
+ }
17
+
18
+ export class StaticArrayProcessor {
19
+ private attributeUtils: JSXAttributeUtils;
20
+ private staticValueUtils: StaticValueUtils;
21
+
22
+ constructor(private types: typeof t) {
23
+ this.attributeUtils = new JSXAttributeUtils(types);
24
+ this.staticValueUtils = new StaticValueUtils(types);
25
+ }
26
+
27
+ process(path: NodePath<t.JSXOpeningElement>): void {
28
+ const arrayInfo = this.findParentArrayMap(path);
29
+ if (!arrayInfo) return;
30
+
31
+ if (!this.isStaticArray(arrayInfo.arrayExpression)) return;
32
+
33
+ const indexIdentifier = this.ensureIndexParam(arrayInfo);
34
+ this.addDataAttributes(path, arrayInfo, indexIdentifier);
35
+ }
36
+
37
+ private addDataAttributes(
38
+ path: NodePath<t.JSXOpeningElement>,
39
+ arrayInfo: ArrayMapInfo,
40
+ indexIdentifier: string
41
+ ): void {
42
+ this.attributeUtils.addExpressionAttribute(
43
+ path,
44
+ DATA_ARR_INDEX,
45
+ this.types.identifier(indexIdentifier)
46
+ );
47
+
48
+ if (arrayInfo.arrayVariableName) {
49
+ this.attributeUtils.addStringAttribute(
50
+ path,
51
+ DATA_ARR_VARIABLE_NAME,
52
+ arrayInfo.arrayVariableName
53
+ );
54
+ }
55
+
56
+ const fieldPath = this.findTextContentFieldPath(
57
+ path,
58
+ arrayInfo.callbackParam
59
+ );
60
+ if (fieldPath) {
61
+ this.attributeUtils.addStringAttribute(path, DATA_ARR_FIELD, fieldPath);
62
+ }
63
+ }
64
+
65
+ private findTextContentFieldPath(
66
+ path: NodePath<t.JSXOpeningElement>,
67
+ callbackParam: string
68
+ ): string | null {
69
+ const parentElement = path.parentPath;
70
+ if (!parentElement?.isJSXElement()) return null;
71
+
72
+ for (const child of parentElement.get("children")) {
73
+ const fieldPath = this.extractFieldPathFromChild(child, callbackParam);
74
+ if (fieldPath) return fieldPath;
75
+ }
76
+
77
+ return null;
78
+ }
79
+
80
+ private extractFieldPathFromChild(
81
+ child: NodePath<t.JSXElement["children"][number]>,
82
+ callbackParam: string
83
+ ): string | null {
84
+ if (!child.isJSXExpressionContainer()) return null;
85
+
86
+ const expression = child.get("expression");
87
+ if (!expression.isMemberExpression()) return null;
88
+
89
+ return this.extractFieldPath(expression, callbackParam);
90
+ }
91
+
92
+ private extractFieldPath(
93
+ expr: NodePath<t.MemberExpression>,
94
+ callbackParam: string
95
+ ): string | null {
96
+ const parts = this.collectMemberExpressionParts(expr);
97
+ if (!parts) return null;
98
+
99
+ const { rootName, propertyNames } = parts;
100
+ return rootName === callbackParam ? propertyNames.join(".") : null;
101
+ }
102
+
103
+ private collectMemberExpressionParts(
104
+ expr: NodePath<t.MemberExpression>
105
+ ): { rootName: string; propertyNames: string[] } | null {
106
+ const propertyNames: string[] = [];
107
+ let current: NodePath<t.Expression> = expr;
108
+
109
+ while (current.isMemberExpression()) {
110
+ const property = current.get("property");
111
+ if (!property.isIdentifier()) return null;
112
+
113
+ propertyNames.unshift(property.node.name);
114
+ current = current.get("object") as NodePath<t.Expression>;
115
+ }
116
+
117
+ if (!current.isIdentifier()) return null;
118
+
119
+ return { rootName: current.node.name, propertyNames };
120
+ }
121
+
122
+ private ensureIndexParam(arrayInfo: ArrayMapInfo): string {
123
+ if (arrayInfo.indexParam) {
124
+ return arrayInfo.indexParam;
125
+ }
126
+
127
+ this.addIndexParamToCallback(arrayInfo.mapCallPath);
128
+ return GENERATED_INDEX_PARAM;
129
+ }
130
+
131
+ private addIndexParamToCallback(
132
+ mapCallPath: NodePath<t.CallExpression>
133
+ ): void {
134
+ const callback = this.getMapCallback(mapCallPath);
135
+ if (!callback) return;
136
+
137
+ const params = callback.get("params");
138
+ if (params.length === 1) {
139
+ callback.node.params.push(this.types.identifier(GENERATED_INDEX_PARAM));
140
+ }
141
+ }
142
+
143
+ private getMapCallback(
144
+ mapCallPath: NodePath<t.CallExpression>
145
+ ): NodePath<t.Function> | null {
146
+ const args = mapCallPath.get("arguments");
147
+ const firstArg = args[0];
148
+ if (firstArg && firstArg.isFunction()) {
149
+ return firstArg as NodePath<t.Function>;
150
+ }
151
+ return null;
152
+ }
153
+
154
+ private findParentArrayMap(
155
+ path: NodePath<t.JSXOpeningElement>,
156
+ maxDepth: number = 5
157
+ ): ArrayMapInfo | null {
158
+ let currentPath: NodePath = path;
159
+ let depth = 0;
160
+
161
+ while (currentPath.parentPath && depth < maxDepth) {
162
+ const mapInfo = this.tryExtractMapInfo(currentPath.parentPath);
163
+ if (mapInfo) return mapInfo;
164
+
165
+ currentPath = currentPath.parentPath;
166
+ depth++;
167
+ }
168
+
169
+ return null;
170
+ }
171
+
172
+ private tryExtractMapInfo(parent: NodePath): ArrayMapInfo | null {
173
+ if (!parent.isCallExpression()) return null;
174
+ if (!this.isMapCall(parent)) return null;
175
+
176
+ return this.extractArrayMapInfo(parent);
177
+ }
178
+
179
+ private isMapCall(callExpr: NodePath<t.CallExpression>): boolean {
180
+ const callee = callExpr.get("callee");
181
+ if (!callee.isMemberExpression()) return false;
182
+
183
+ const property = callee.get("property");
184
+ return property.isIdentifier() && property.node.name === "map";
185
+ }
186
+
187
+ private extractArrayMapInfo(
188
+ mapCall: NodePath<t.CallExpression>
189
+ ): ArrayMapInfo | null {
190
+ const callback = this.getMapCallback(mapCall);
191
+ if (!callback) return null;
192
+
193
+ const params = callback.get("params");
194
+ const firstParam = params[0];
195
+ if (!firstParam || !firstParam.isIdentifier()) return null;
196
+
197
+ const callee = mapCall.get("callee") as NodePath<t.MemberExpression>;
198
+ const arrayExpression = callee.get("object") as NodePath<t.Expression>;
199
+
200
+ return {
201
+ arrayExpression,
202
+ callbackParam: firstParam.node.name,
203
+ indexParam: this.extractIndexParam(params),
204
+ arrayVariableName: this.extractArrayVariableName(arrayExpression),
205
+ mapCallPath: mapCall,
206
+ };
207
+ }
208
+
209
+ private extractIndexParam(params: NodePath<t.Node>[]): string | null {
210
+ const secondParam = params[1];
211
+ return secondParam && secondParam.isIdentifier()
212
+ ? secondParam.node.name
213
+ : null;
214
+ }
215
+
216
+ private extractArrayVariableName(
217
+ arrayExpression: NodePath<t.Expression>
218
+ ): string | null {
219
+ return arrayExpression.isIdentifier() ? arrayExpression.node.name : null;
220
+ }
221
+
222
+ private isStaticArray(arrayExpression: NodePath<t.Expression>): boolean {
223
+ const arrayExpr = this.resolveArrayExpression(arrayExpression);
224
+ return arrayExpr ? this.isStaticArrayExpression(arrayExpr) : false;
225
+ }
226
+
227
+ private resolveArrayExpression(
228
+ expression: NodePath<t.Expression>
229
+ ): NodePath<t.ArrayExpression> | null {
230
+ if (expression.isArrayExpression()) {
231
+ return expression;
232
+ }
233
+
234
+ if (expression.isIdentifier()) {
235
+ return this.resolveIdentifierToArray(expression);
236
+ }
237
+
238
+ return null;
239
+ }
240
+
241
+ private resolveIdentifierToArray(
242
+ identifier: NodePath<t.Identifier>
243
+ ): NodePath<t.ArrayExpression> | null {
244
+ const binding = identifier.scope.getBinding(identifier.node.name);
245
+
246
+ if (!binding?.path.isVariableDeclarator()) return null;
247
+
248
+ const init = binding.path.get("init");
249
+ return init.isArrayExpression() ? init : null;
250
+ }
251
+
252
+ private isStaticArrayExpression(
253
+ arrayExpression: NodePath<t.ArrayExpression>
254
+ ): boolean {
255
+ return this.staticValueUtils.isStaticArrayExpression(arrayExpression);
256
+ }
257
+ }
@@ -3,6 +3,8 @@ import { default as traverse } from "@babel/traverse";
3
3
  import { default as generate } from "@babel/generator";
4
4
  import * as t from "@babel/types";
5
5
  import type { Plugin } from "vite";
6
+ import { StaticArrayProcessor } from "./processors/static-array-processor.js";
7
+ import { JSXUtils } from "./jsx-utils.js";
6
8
 
7
9
  // Helper function to check if JSX element contains dynamic content
8
10
  export function checkIfElementHasDynamicContent(jsxElement: any) {
@@ -213,6 +215,8 @@ export function visualEditPlugin() {
213
215
  });
214
216
 
215
217
  // Traverse the AST and add source location and dynamic content attributes to JSX elements
218
+ JSXUtils.init(t);
219
+ const staticArrayProcessor = new StaticArrayProcessor(t);
216
220
  let elementsProcessed = 0;
217
221
  traverse.default(ast, {
218
222
  JSXElement(path) {
@@ -258,6 +262,8 @@ export function visualEditPlugin() {
258
262
  sourceLocationAttr,
259
263
  dynamicContentAttr
260
264
  );
265
+
266
+ staticArrayProcessor.process(path.get("openingElement"));
261
267
  elementsProcessed++;
262
268
  },
263
269
  });
@@ -1,25 +0,0 @@
1
- /**
2
- * Callback function type for handling text input changes
3
- */
4
- type OnTextInputChange = (element: HTMLElement) => void;
5
- /**
6
- * Set the callback function that will be called on text input changes
7
- */
8
- export declare function setInlineEditCallback(callback: OnTextInputChange | null): void;
9
- /**
10
- * Check if an element should enter inline editing mode
11
- * Called when user clicks on an already-selected element
12
- */
13
- export declare function shouldEnterInlineEditingMode(element: Element): boolean;
14
- /**
15
- * Enable contentEditable mode on an element
16
- * Follows the exact flow from inlineEdit.md
17
- */
18
- export declare function enterInlineEditingMode(element: HTMLElement): void;
19
- /**
20
- * Disable contentEditable mode on an element
21
- * Reverses everything done by enterInlineEditingMode
22
- */
23
- export declare function clearInlineEditingMode(element: HTMLElement): void;
24
- export {};
25
- //# sourceMappingURL=core.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../../../src/injections/visual-edit-agent/capabilities/inline-editing/core.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,KAAK,iBAAiB,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,IAAI,CAAC;AAQxD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,iBAAiB,GAAG,IAAI,GAAG,IAAI,CAE9E;AAkBD;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAYtE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA4BjE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CA0BjE"}
@@ -1,95 +0,0 @@
1
- import { injectFocusOutlineCSS, removeFocusOutlineCSS } from "./styles.js";
2
- import { selectText, isEditableTextElement } from "./validation.js";
3
- /**
4
- * Global callback that gets triggered on every input event
5
- * This is set by the visual-edit-agent and includes both updatePosition and reportInlineEdit
6
- */
7
- let onTextInputChangeCallback = null;
8
- /**
9
- * Set the callback function that will be called on text input changes
10
- */
11
- export function setInlineEditCallback(callback) {
12
- onTextInputChangeCallback = callback;
13
- }
14
- /**
15
- * WeakMap to track AbortControllers for each element's input listener.
16
- * Using WeakMap ensures no memory leaks — when an element is garbage collected,
17
- * its entry is automatically removed.
18
- */
19
- const listenerAbortControllers = new WeakMap();
20
- /**
21
- * Internal handler for the native input event
22
- */
23
- function handleInputEvent(e) {
24
- if (onTextInputChangeCallback) {
25
- onTextInputChangeCallback(this);
26
- }
27
- }
28
- /**
29
- * Check if an element should enter inline editing mode
30
- * Called when user clicks on an already-selected element
31
- */
32
- export function shouldEnterInlineEditingMode(element) {
33
- // Must have data-selected="true"
34
- if (!(element instanceof HTMLElement) || element.dataset.selected !== "true") {
35
- return false;
36
- }
37
- // Must pass all editability checks
38
- if (!isEditableTextElement(element)) {
39
- return false;
40
- }
41
- return true;
42
- }
43
- /**
44
- * Enable contentEditable mode on an element
45
- * Follows the exact flow from inlineEdit.md
46
- */
47
- export function enterInlineEditingMode(element) {
48
- // Inject CSS to suppress focus outline
49
- injectFocusOutlineCSS();
50
- // Store original state
51
- element.dataset.originalTextContent = element.textContent || "";
52
- element.dataset.originalCursor = element.style.cursor;
53
- // Enable contentEditable
54
- element.contentEditable = "true";
55
- // Create an AbortController to manage the input listener lifecycle
56
- const abortController = new AbortController();
57
- listenerAbortControllers.set(element, abortController);
58
- // Add input event listener with AbortSignal for automatic cleanup
59
- element.addEventListener("input", handleInputEvent, { signal: abortController.signal });
60
- // Set cursor to text
61
- element.style.cursor = "text";
62
- // Select all text
63
- selectText(element);
64
- // Focus after render
65
- setTimeout(() => {
66
- element.focus();
67
- }, 0);
68
- }
69
- /**
70
- * Disable contentEditable mode on an element
71
- * Reverses everything done by enterInlineEditingMode
72
- */
73
- export function clearInlineEditingMode(element) {
74
- // Abort the input event listener using the stored AbortController
75
- const abortController = listenerAbortControllers.get(element);
76
- if (abortController) {
77
- abortController.abort();
78
- listenerAbortControllers.delete(element);
79
- }
80
- // If element was removed from DOM before cleanup, skip DOM operations
81
- if (!element.isConnected) {
82
- return;
83
- }
84
- removeFocusOutlineCSS();
85
- // Disable contentEditable
86
- element.contentEditable = "false";
87
- // Remove stored original text content
88
- delete element.dataset.originalTextContent;
89
- // Restore original cursor
90
- if (element.dataset.originalCursor !== undefined) {
91
- element.style.cursor = element.dataset.originalCursor;
92
- delete element.dataset.originalCursor;
93
- }
94
- }
95
- //# sourceMappingURL=core.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.js","sourceRoot":"","sources":["../../../../../src/injections/visual-edit-agent/capabilities/inline-editing/core.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAOpE;;;GAGG;AACH,IAAI,yBAAyB,GAA6B,IAAI,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAAkC;IACtE,yBAAyB,GAAG,QAAQ,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,wBAAwB,GAAG,IAAI,OAAO,EAAgC,CAAC;AAE7E;;GAEG;AACH,SAAS,gBAAgB,CAAoB,CAAQ;IACnD,IAAI,yBAAyB,EAAE,CAAC;QAC9B,yBAAyB,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAgB;IAC3D,iCAAiC;IACjC,IAAI,CAAC,CAAC,OAAO,YAAY,WAAW,CAAC,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;QAC7E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,qBAAqB,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAoB;IACzD,uCAAuC;IACvC,qBAAqB,EAAE,CAAC;IAExB,uBAAuB;IACvB,OAAO,CAAC,OAAO,CAAC,mBAAmB,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC;IAChE,OAAO,CAAC,OAAO,CAAC,cAAc,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;IAEtD,yBAAyB;IACzB,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC;IAEjC,mEAAmE;IACnE,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;IAC9C,wBAAwB,CAAC,GAAG,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAEvD,kEAAkE;IAClE,OAAO,CAAC,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC;IAExF,qBAAqB;IACrB,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;IAE9B,kBAAkB;IAClB,UAAU,CAAC,OAAO,CAAC,CAAC;IAEpB,qBAAqB;IACrB,UAAU,CAAC,GAAG,EAAE;QACd,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,EAAE,CAAC,CAAC,CAAC;AACR,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAoB;IACzD,kEAAkE;IAClE,MAAM,eAAe,GAAG,wBAAwB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC9D,IAAI,eAAe,EAAE,CAAC;QACpB,eAAe,CAAC,KAAK,EAAE,CAAC;QACxB,wBAAwB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IAED,sEAAsE;IACtE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;QACzB,OAAO;IACT,CAAC;IAED,qBAAqB,EAAE,CAAC;IAExB,0BAA0B;IAC1B,OAAO,CAAC,eAAe,GAAG,OAAO,CAAC;IAElC,sCAAsC;IACtC,OAAO,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC;IAE3C,0BAA0B;IAC1B,IAAI,OAAO,CAAC,OAAO,CAAC,cAAc,KAAK,SAAS,EAAE,CAAC;QACjD,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;QACtD,OAAO,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC;IACxC,CAAC;AACH,CAAC"}
@@ -1,4 +0,0 @@
1
- export { enterInlineEditingMode, clearInlineEditingMode, shouldEnterInlineEditingMode, setInlineEditCallback, } from "./core.js";
2
- export { injectFocusOutlineCSS, removeFocusOutlineCSS } from "./styles.js";
3
- export { isEditableTextElement, selectText } from "./validation.js";
4
- //# sourceMappingURL=index.d.ts.map