@teleporthq/teleport-plugin-common 0.42.35 → 0.43.0

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 (91) hide show
  1. package/__tests__/node-handlers/node-to-jsx/index.ts +164 -0
  2. package/__tests__/node-handlers/node-to-jsx/url-search-params-expression.ts +59 -0
  3. package/__tests__/node-handlers/node-to-jsx/utils.ts +217 -0
  4. package/__tests__/utils/ast-utils.ts +135 -0
  5. package/__tests__/utils/content-property-sanitiser.ts +156 -0
  6. package/__tests__/utils/url-search-params.ts +48 -0
  7. package/dist/cjs/builders/ast-builders.d.ts +1 -0
  8. package/dist/cjs/builders/ast-builders.d.ts.map +1 -1
  9. package/dist/cjs/builders/ast-builders.js +9 -1
  10. package/dist/cjs/builders/ast-builders.js.map +1 -1
  11. package/dist/cjs/builders/style-builders.d.ts +7 -0
  12. package/dist/cjs/builders/style-builders.d.ts.map +1 -1
  13. package/dist/cjs/builders/style-builders.js +35 -1
  14. package/dist/cjs/builders/style-builders.js.map +1 -1
  15. package/dist/cjs/node-handlers/node-to-html/index.d.ts.map +1 -1
  16. package/dist/cjs/node-handlers/node-to-html/index.js +19 -3
  17. package/dist/cjs/node-handlers/node-to-html/index.js.map +1 -1
  18. package/dist/cjs/node-handlers/node-to-html/utils.d.ts +2 -1
  19. package/dist/cjs/node-handlers/node-to-html/utils.d.ts.map +1 -1
  20. package/dist/cjs/node-handlers/node-to-html/utils.js +94 -11
  21. package/dist/cjs/node-handlers/node-to-html/utils.js.map +1 -1
  22. package/dist/cjs/node-handlers/node-to-jsx/index.d.ts.map +1 -1
  23. package/dist/cjs/node-handlers/node-to-jsx/index.js +701 -42
  24. package/dist/cjs/node-handlers/node-to-jsx/index.js.map +1 -1
  25. package/dist/cjs/node-handlers/node-to-jsx/types.d.ts +40 -2
  26. package/dist/cjs/node-handlers/node-to-jsx/types.d.ts.map +1 -1
  27. package/dist/cjs/node-handlers/node-to-jsx/utils.d.ts +50 -5
  28. package/dist/cjs/node-handlers/node-to-jsx/utils.d.ts.map +1 -1
  29. package/dist/cjs/node-handlers/node-to-jsx/utils.js +492 -35
  30. package/dist/cjs/node-handlers/node-to-jsx/utils.js.map +1 -1
  31. package/dist/cjs/tsconfig.tsbuildinfo +1 -1
  32. package/dist/cjs/utils/ast-utils.d.ts +70 -4
  33. package/dist/cjs/utils/ast-utils.d.ts.map +1 -1
  34. package/dist/cjs/utils/ast-utils.js +414 -28
  35. package/dist/cjs/utils/ast-utils.js.map +1 -1
  36. package/dist/cjs/utils/style-utils.d.ts +1 -0
  37. package/dist/cjs/utils/style-utils.d.ts.map +1 -1
  38. package/dist/cjs/utils/style-utils.js +155 -2
  39. package/dist/cjs/utils/style-utils.js.map +1 -1
  40. package/dist/cjs/utils/url-search-params.d.ts +48 -0
  41. package/dist/cjs/utils/url-search-params.d.ts.map +1 -0
  42. package/dist/cjs/utils/url-search-params.js +109 -0
  43. package/dist/cjs/utils/url-search-params.js.map +1 -0
  44. package/dist/esm/builders/ast-builders.d.ts +1 -0
  45. package/dist/esm/builders/ast-builders.d.ts.map +1 -1
  46. package/dist/esm/builders/ast-builders.js +7 -0
  47. package/dist/esm/builders/ast-builders.js.map +1 -1
  48. package/dist/esm/builders/style-builders.d.ts +7 -0
  49. package/dist/esm/builders/style-builders.d.ts.map +1 -1
  50. package/dist/esm/builders/style-builders.js +33 -0
  51. package/dist/esm/builders/style-builders.js.map +1 -1
  52. package/dist/esm/node-handlers/node-to-html/index.d.ts.map +1 -1
  53. package/dist/esm/node-handlers/node-to-html/index.js +20 -4
  54. package/dist/esm/node-handlers/node-to-html/index.js.map +1 -1
  55. package/dist/esm/node-handlers/node-to-html/utils.d.ts +2 -1
  56. package/dist/esm/node-handlers/node-to-html/utils.d.ts.map +1 -1
  57. package/dist/esm/node-handlers/node-to-html/utils.js +93 -11
  58. package/dist/esm/node-handlers/node-to-html/utils.js.map +1 -1
  59. package/dist/esm/node-handlers/node-to-jsx/index.d.ts.map +1 -1
  60. package/dist/esm/node-handlers/node-to-jsx/index.js +703 -44
  61. package/dist/esm/node-handlers/node-to-jsx/index.js.map +1 -1
  62. package/dist/esm/node-handlers/node-to-jsx/types.d.ts +40 -2
  63. package/dist/esm/node-handlers/node-to-jsx/types.d.ts.map +1 -1
  64. package/dist/esm/node-handlers/node-to-jsx/utils.d.ts +50 -5
  65. package/dist/esm/node-handlers/node-to-jsx/utils.d.ts.map +1 -1
  66. package/dist/esm/node-handlers/node-to-jsx/utils.js +486 -33
  67. package/dist/esm/node-handlers/node-to-jsx/utils.js.map +1 -1
  68. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  69. package/dist/esm/utils/ast-utils.d.ts +70 -4
  70. package/dist/esm/utils/ast-utils.d.ts.map +1 -1
  71. package/dist/esm/utils/ast-utils.js +403 -27
  72. package/dist/esm/utils/ast-utils.js.map +1 -1
  73. package/dist/esm/utils/style-utils.d.ts +1 -0
  74. package/dist/esm/utils/style-utils.d.ts.map +1 -1
  75. package/dist/esm/utils/style-utils.js +153 -1
  76. package/dist/esm/utils/style-utils.js.map +1 -1
  77. package/dist/esm/utils/url-search-params.d.ts +48 -0
  78. package/dist/esm/utils/url-search-params.d.ts.map +1 -0
  79. package/dist/esm/utils/url-search-params.js +81 -0
  80. package/dist/esm/utils/url-search-params.js.map +1 -0
  81. package/package.json +4 -4
  82. package/src/builders/ast-builders.ts +26 -0
  83. package/src/builders/style-builders.ts +64 -0
  84. package/src/node-handlers/node-to-html/index.ts +34 -4
  85. package/src/node-handlers/node-to-html/utils.ts +111 -11
  86. package/src/node-handlers/node-to-jsx/index.ts +999 -52
  87. package/src/node-handlers/node-to-jsx/types.ts +48 -3
  88. package/src/node-handlers/node-to-jsx/utils.ts +655 -31
  89. package/src/utils/ast-utils.ts +547 -28
  90. package/src/utils/style-utils.ts +157 -1
  91. package/src/utils/url-search-params.ts +122 -0
@@ -35,12 +35,38 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
35
35
  return (mod && mod.__esModule) ? mod : { "default": mod };
36
36
  };
37
37
  Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.convertToUnaryOperator = exports.convertToBinaryOperator = exports.isJSXElement = exports.getExpressionFromUIDLExpressionNode = exports.convertFilterDestinationToExpression = exports.isUIDLDynamicReference = exports.resolveObjectValue = exports.computeFetchUrl = exports.generateURLParamsAST = exports.generateMemberExpressionASTFromPath = exports.parseValuePath = exports.generateMemberExpressionASTFromBase = exports.generateRemoteResourceASTs = exports.wrapObjectPropertiesWithExpression = exports.generateDynamicWindowImport = exports.createStateHookAST = exports.createReturnExpressionSyntax = exports.createPureComponent = exports.createClassComponent = exports.removeAttributeByName = exports.findAttributeByName = exports.getTSAnnotationForType = exports.addPropertyToASTObject = exports.convertValueToLiteral = exports.objectToObjectExpression = exports.renameJSXTag = exports.addSpreadAttributeToJSXTag = exports.addChildJSXText = exports.addChildJSXTag = exports.addRawAttributeToJSXTag = exports.addAttributeToJSXTag = exports.stringAsTemplateLiteral = exports.addMultipleDynamicAttributesToJSXTag = exports.addDynamicExpressionAttributeToJSXTag = exports.addDynamicAttributeToJSXTag = exports.addClassStringOnJSXTag = void 0;
38
+ exports.convertToUnaryOperator = exports.convertToBinaryOperator = exports.isJSXElement = exports.getExpressionFromUIDLExpressionNode = exports.convertFilterDestinationToExpression = exports.isUIDLDynamicReference = exports.resolveObjectValue = exports.computeFetchUrl = exports.generateURLParamsAST = exports.generateMemberExpressionASTFromPath = exports.parseValuePath = exports.generateMemberExpressionASTFromBase = exports.generateRemoteResourceASTs = exports.wrapObjectPropertiesWithExpression = exports.generateDynamicWindowImport = exports.collectGlobalStateReferencesFromObjectStates = exports.collectGlobalReferencesFromObjectStates = exports.resolveGlobalRefId = exports.GLOBAL_REF_ID_MAP = exports.convertObjectStateDefaultToExpression = exports.isObjectStateWithEntries = exports.createStateHookAST = exports.createReturnExpressionSyntax = exports.createPureComponent = exports.createClassComponent = exports.removeAttributeByName = exports.findAttributeByName = exports.getTSAnnotationForType = exports.addPropertyToASTObject = exports.convertValueToLiteral = exports.objectToObjectExpression = exports.renameJSXTag = exports.addSpreadAttributeToJSXTag = exports.addChildJSXText = exports.addChildJSXTag = exports.addRawAttributeToJSXTag = exports.addAttributeToJSXTag = exports.parseStringWithTemplateExpressions = exports.parseJSExpressionAsAST = exports.containsTemplateExpression = exports.stringAsTemplateLiteral = exports.addMultipleDynamicAttributesToJSXTag = exports.addDynamicExpressionAttributeToJSXTag = exports.sanitizeExprContent = exports.addDynamicAttributeToJSXTag = exports.addClassStringOnJSXTag = exports.convertToReactAttributeName = void 0;
39
39
  var types = __importStar(require("@babel/types"));
40
40
  var core_1 = require("@babel/core");
41
41
  var parsed_ast_1 = __importDefault(require("./parsed-ast"));
42
42
  var teleport_shared_1 = require("@teleporthq/teleport-shared");
43
43
  var preset_react_1 = __importDefault(require("@babel/preset-react"));
44
+ /**
45
+ * Converts HTML attribute names to React/JSX camelCase format
46
+ * Preserves data-* and aria-* attributes as-is
47
+ */
48
+ var convertToReactAttributeName = function (attrName) {
49
+ if (attrName.startsWith('data-') || attrName.startsWith('aria-')) {
50
+ return attrName;
51
+ }
52
+ var htmlToReact = {
53
+ colspan: 'colSpan',
54
+ rowspan: 'rowSpan',
55
+ maxlength: 'maxLength',
56
+ minlength: 'minLength',
57
+ readonly: 'readOnly',
58
+ autocomplete: 'autoComplete',
59
+ autofocus: 'autoFocus',
60
+ tabindex: 'tabIndex',
61
+ contenteditable: 'contentEditable',
62
+ spellcheck: 'spellCheck',
63
+ };
64
+ if (htmlToReact[attrName]) {
65
+ return htmlToReact[attrName];
66
+ }
67
+ return attrName.replace(/-([a-z])/g, function (_, letter) { return letter.toUpperCase(); });
68
+ };
69
+ exports.convertToReactAttributeName = convertToReactAttributeName;
44
70
  /**
45
71
  * Adds a CSS class definition string to an existing string of classes
46
72
  */
@@ -107,10 +133,11 @@ var getClassAttribute = function (jsxNode, _a, t) {
107
133
  var addDynamicAttributeToJSXTag = function (jsxASTNode, name, value, prefix, t) {
108
134
  if (prefix === void 0) { prefix = ''; }
109
135
  if (t === void 0) { t = types; }
136
+ var reactName = (0, exports.convertToReactAttributeName)(name);
110
137
  var content = prefix === ''
111
138
  ? t.identifier(value)
112
139
  : t.memberExpression(t.identifier(prefix), t.identifier(value));
113
- jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier(name), t.jsxExpressionContainer(content)));
140
+ jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier(reactName), t.jsxExpressionContainer(content)));
114
141
  };
115
142
  exports.addDynamicAttributeToJSXTag = addDynamicAttributeToJSXTag;
116
143
  /**
@@ -119,13 +146,48 @@ exports.addDynamicAttributeToJSXTag = addDynamicAttributeToJSXTag;
119
146
  * the corresponding value from the contexts for now
120
147
  * and in the future with other sources.
121
148
  */
149
+ /**
150
+ * UIDL `expr` values are opaque JavaScript expressions, but authoring tools
151
+ * (notably Teleport-GUI while the differentiator-navlink contract is mid-
152
+ * migration) occasionally emit malformed template literals with empty
153
+ * substitutions like `` `/profile/${}` ``. Babel rejects these and the whole
154
+ * generation run fails.
155
+ *
156
+ * We only repair a narrow set of known-safe patterns to avoid silently
157
+ * masking real UIDL bugs:
158
+ * 1. `/profile/${}` → `/profile/${currentUser?.id}` (My Profile navlink
159
+ * per the dual-mode profile page contract).
160
+ * 2. any remaining empty `${}` → `${''}` — at least the output parses and
161
+ * the placeholder is visibly empty at runtime.
162
+ * Each repair logs a warning so the upstream UIDL bug remains visible.
163
+ */
164
+ var sanitizeExprContent = function (content, attrKey) {
165
+ if (typeof content !== 'string' || !content.includes('${}')) {
166
+ return content;
167
+ }
168
+ var repaired = content;
169
+ // My Profile navlink: the differentiator is always the session user's id.
170
+ repaired = repaired.replace(/`([^`]*\/profile\/)\$\{\}([^`]*)`/g, '`$1' + '$' + '{' + 'currentUser?.id}' + '$2`');
171
+ // Generic fallback: any other empty `${}` becomes an empty string literal so
172
+ // downstream Babel parsing succeeds. This is intentionally lossy — the goal
173
+ // is not to guess the original intent, just to keep the build from crashing.
174
+ if (repaired.includes('${}')) {
175
+ repaired = repaired.replace(/\$\{\}/g, '$' + '{' + "'" + "'" + '}');
176
+ }
177
+ if (repaired !== content) {
178
+ // tslint:disable-next-line:no-console
179
+ console.warn("[teleport] Repaired malformed empty template substitution in expr".concat(attrKey ? " attribute \"".concat(attrKey, "\"") : '', ": ").concat(content, " \u2192 ").concat(repaired));
180
+ }
181
+ return repaired;
182
+ };
183
+ exports.sanitizeExprContent = sanitizeExprContent;
122
184
  var addDynamicExpressionAttributeToJSXTag = function (jsxASTNode, dynamicRef, attrKey, t) {
123
185
  if (t === void 0) { t = types; }
124
186
  var dynamicContent = dynamicRef.content;
125
187
  if (dynamicRef.type !== 'expr') {
126
188
  throw new Error("This method only works with dynamic nodes that have code expressions");
127
189
  }
128
- var code = dynamicContent;
190
+ var code = (0, exports.sanitizeExprContent)(dynamicContent, attrKey);
129
191
  var options = {
130
192
  sourceType: 'module',
131
193
  };
@@ -137,7 +199,18 @@ var addDynamicExpressionAttributeToJSXTag = function (jsxASTNode, dynamicRef, at
137
199
  if (theStatementOnlyWihtoutTheProgram.type !== 'ExpressionStatement') {
138
200
  throw new Error("Expr dynamic attribute only support expressions statements at the moment.");
139
201
  }
140
- jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier(attrKey), t.jsxExpressionContainer(theStatementOnlyWihtoutTheProgram.expression)));
202
+ var expression = theStatementOnlyWihtoutTheProgram.expression;
203
+ // When an expression accesses `.value` on a simple identifier (e.g. `galleryImage?.value`),
204
+ // wrap it with a typeof check so that if the item is already a string we use it directly:
205
+ // `typeof galleryImage === 'string' ? galleryImage : galleryImage?.value`
206
+ if ((expression.type === 'OptionalMemberExpression' || expression.type === 'MemberExpression') &&
207
+ expression.object.type === 'Identifier' &&
208
+ expression.property.type === 'Identifier' &&
209
+ expression.property.name === 'value') {
210
+ var varName = expression.object.name;
211
+ expression = t.conditionalExpression(t.binaryExpression('===', t.unaryExpression('typeof', t.identifier(varName)), t.stringLiteral('string')), t.identifier(varName), expression);
212
+ }
213
+ jsxASTNode.openingElement.attributes.push(t.jsxAttribute(t.jsxIdentifier((0, exports.convertToReactAttributeName)(attrKey)), t.jsxExpressionContainer(expression)));
141
214
  };
142
215
  exports.addDynamicExpressionAttributeToJSXTag = addDynamicExpressionAttributeToJSXTag;
143
216
  /*
@@ -182,30 +255,122 @@ var stringAsTemplateLiteral = function (str) {
182
255
  };
183
256
  exports.stringAsTemplateLiteral = stringAsTemplateLiteral;
184
257
  /**
185
- * Converts HTML attribute names to React/JSX camelCase format
186
- * Preserves data-* and aria-* attributes as-is
258
+ * Checks if a string contains {{ expression }} template patterns
187
259
  */
188
- var convertToReactAttributeName = function (attrName) {
189
- // Keep data-* and aria-* attributes as-is (React supports these)
190
- if (attrName.startsWith('data-') || attrName.startsWith('aria-')) {
191
- return attrName;
260
+ var containsTemplateExpression = function (str) {
261
+ return /\{\{.+?\}\}/.test(str);
262
+ };
263
+ exports.containsTemplateExpression = containsTemplateExpression;
264
+ /**
265
+ * Parses a JavaScript expression string into an AST Expression node.
266
+ * e.g. "item.type || 'coin'" → LogicalExpression AST
267
+ */
268
+ var parseJSExpressionAsAST = function (expr) {
269
+ var ast = (0, core_1.parse)("(".concat(expr, ")"), {
270
+ sourceType: 'module',
271
+ });
272
+ if (!ast || !('program' in ast)) {
273
+ throw new Error("Failed to parse expression: ".concat(expr));
192
274
  }
193
- // Convert hyphenated attributes to camelCase for React
194
- return attrName.replace(/-([a-z])/g, function (_, letter) { return letter.toUpperCase(); });
275
+ return ast.program.body[0].expression;
195
276
  };
277
+ exports.parseJSExpressionAsAST = parseJSExpressionAsAST;
278
+ /**
279
+ * Parses a string containing {{ expr }} template patterns into a TemplateLiteral AST node.
280
+ * e.g. "translate({{ enemy.x || '0' }}px)" → `translate(${enemy.x || '0'}px)`
281
+ */
282
+ var parseStringWithTemplateExpressions = function (str) {
283
+ // Step 1: Normalize state references: state.xxx → xxx
284
+ var normalized = str.replace(/state\.(\w+)/g, '$1');
285
+ // Step 2: Convert well-formed {{ expr }} to ${expr}
286
+ var templateStr = normalized.replace(/\{\{\s*(.+?)\s*\}\}/g, function (_, expr) { return '${' + expr.trim() + '}'; });
287
+ // Step 3: Handle unclosed {{ expr (no closing }})
288
+ // After step 2, any remaining {{ was not well-formed
289
+ if (/\{\{/.test(templateStr)) {
290
+ templateStr = templateStr.replace(/\{\{\s*(.+?)$/gm, function (_, expr) { return '${' + expr.trim() + '}'; });
291
+ }
292
+ // Step 4: Detect and fix incomplete CSS function calls
293
+ // If the original string contained a CSS function like translateX(...) or translate(...)
294
+ // but the template expression consumed the closing, we need to re-close it.
295
+ var openParens = (templateStr.match(/\(/g) || []).length;
296
+ var closeParens = (templateStr.match(/\)/g) || []).length;
297
+ if (openParens > closeParens) {
298
+ // Determine the CSS unit by:
299
+ // 1. Looking for existing units already in the string (e.g. "translate(${x}px, ${y" → px)
300
+ // 2. Inferring from the CSS function name
301
+ var existingUnit = templateStr.match(/(px|deg|em|rem|%|vh|vw)[),\s]/);
302
+ var unit = 'px'; // default
303
+ if (existingUnit) {
304
+ unit = existingUnit[1];
305
+ }
306
+ else {
307
+ // Infer unit from the CSS function name
308
+ var fnMatch = templateStr.match(/\b(rotate|skew|skewX|skewY)\s*\(/);
309
+ if (fnMatch) {
310
+ unit = 'deg';
311
+ }
312
+ var noUnitFns = /\b(scale|scaleX|scaleY|scale3d|opacity)\s*\(/;
313
+ if (noUnitFns.test(templateStr)) {
314
+ unit = '';
315
+ }
316
+ }
317
+ var missingCloses = openParens - closeParens;
318
+ templateStr += unit + ')'.repeat(missingCloses);
319
+ }
320
+ var ast = (0, core_1.parse)('const x = `' + templateStr + '`', {
321
+ sourceType: 'module',
322
+ });
323
+ if (!ast || !('program' in ast)) {
324
+ throw new Error("Failed to parse template expression: ".concat(str));
325
+ }
326
+ var decl = ast.program.body[0];
327
+ return decl.declarations[0].init;
328
+ };
329
+ exports.parseStringWithTemplateExpressions = parseStringWithTemplateExpressions;
330
+ var REACT_BOOLEAN_DOM_PROPS = new Set([
331
+ 'disabled',
332
+ 'required',
333
+ 'readOnly',
334
+ 'checked',
335
+ 'multiple',
336
+ 'hidden',
337
+ 'autoFocus',
338
+ 'muted',
339
+ 'loop',
340
+ 'playsInline',
341
+ 'controls',
342
+ 'async',
343
+ 'defer',
344
+ 'inert',
345
+ 'scoped',
346
+ 'reversed',
347
+ 'allowFullScreen',
348
+ 'defaultChecked',
349
+ 'selected',
350
+ 'formNoValidate',
351
+ 'noValidate',
352
+ ]);
196
353
  var addAttributeToJSXTag = function (jsxNode, attrName, attrValue, t) {
197
354
  if (t === void 0) { t = types; }
198
- var reactAttrName = convertToReactAttributeName(attrName);
355
+ var reactAttrName = (0, exports.convertToReactAttributeName)(attrName);
199
356
  var nameOfAttribute = t.jsxIdentifier(reactAttrName);
200
357
  var attributeDefinition;
201
- if (typeof attrValue === 'boolean') {
202
- attributeDefinition = t.jsxAttribute(nameOfAttribute, attrValue === true ? undefined : t.jsxExpressionContainer(t.booleanLiteral(attrValue)));
358
+ var normalizedValue = attrValue;
359
+ if (typeof attrValue === 'string' &&
360
+ (attrValue === 'true' || attrValue === 'false') &&
361
+ REACT_BOOLEAN_DOM_PROPS.has(reactAttrName)) {
362
+ normalizedValue = attrValue === 'true';
363
+ }
364
+ if (typeof normalizedValue === 'boolean') {
365
+ attributeDefinition = t.jsxAttribute(nameOfAttribute, normalizedValue === true
366
+ ? undefined
367
+ : t.jsxExpressionContainer(t.booleanLiteral(normalizedValue)));
203
368
  }
204
369
  else if (t.isNode(attrValue) && t.isJSXElement(attrValue)) {
205
370
  attributeDefinition = t.jsxAttribute(nameOfAttribute, t.jsxExpressionContainer(attrValue));
206
371
  }
207
372
  else {
208
- attributeDefinition = t.jsxAttribute(nameOfAttribute, getProperAttributeValueAssignment(attrValue));
373
+ attributeDefinition = t.jsxAttribute(nameOfAttribute, getProperAttributeValueAssignment(normalizedValue));
209
374
  }
210
375
  var attribute = jsxNode.openingElement.attributes.find(function (attr) {
211
376
  if (attr.type === 'JSXAttribute') {
@@ -248,12 +413,12 @@ exports.addRawAttributeToJSXTag = addRawAttributeToJSXTag;
248
413
  */
249
414
  var getProperAttributeValueAssignment = function (value, t) {
250
415
  if (t === void 0) { t = types; }
251
- if (!value) {
252
- return null;
253
- }
254
416
  if (typeof value === 'string') {
255
417
  return t.stringLiteral(teleport_shared_1.StringUtils.encode(value));
256
418
  }
419
+ if (!value && value !== 0 && value !== false) {
420
+ return null;
421
+ }
257
422
  return t.jsxExpressionContainer((0, exports.convertValueToLiteral)(value));
258
423
  };
259
424
  var addChildJSXTag = function (tag, childNode, t) {
@@ -347,6 +512,21 @@ value, explicitType, t) {
347
512
  if (Array.isArray(value)) {
348
513
  return t.arrayExpression(value.map(function (val) { return (0, exports.convertValueToLiteral)(val); }));
349
514
  }
515
+ if (explicitType === 'array' && typeof value === 'object' && value !== null) {
516
+ var arr = Object.keys(value)
517
+ .sort(function (a, b) { return Number(a) - Number(b); })
518
+ .map(function (key) { return (0, exports.convertValueToLiteral)(value[key]); });
519
+ return t.arrayExpression(arr);
520
+ }
521
+ if ((explicitType === 'array' || explicitType === 'object') && typeof value === 'string') {
522
+ try {
523
+ var parsed = JSON.parse(value);
524
+ return (0, exports.convertValueToLiteral)(parsed, explicitType, t);
525
+ }
526
+ catch (_a) {
527
+ // If parsing fails, fall through to treat as a regular string
528
+ }
529
+ }
350
530
  var actualType = typeof value;
351
531
  var typeToCompare = explicitType && explicitType === actualType ? explicitType : actualType;
352
532
  switch (typeToCompare) {
@@ -396,7 +576,7 @@ var removeAttributeByName = function (jsxTag, attrName) {
396
576
  });
397
577
  };
398
578
  exports.removeAttributeByName = removeAttributeByName;
399
- var createClassComponent = function (name, propDefinitions, stateDefinitions, jsxTagTree, t) {
579
+ var createClassComponent = function (name, propDefinitions, stateDefinitions, jsxTagTree, dynamicReferencePrefixMap, t) {
400
580
  if (t === void 0) { t = types; }
401
581
  // TODO: Add event handlers as separate functions later
402
582
  var classMethodsAndProperties = [];
@@ -407,6 +587,11 @@ var createClassComponent = function (name, propDefinitions, stateDefinitions, js
407
587
  if (Object.keys(stateDefinitions).length > 0) {
408
588
  var stateDeclarationsAST = Object.keys(stateDefinitions).map(function (stateKey) {
409
589
  var stateDefinition = stateDefinitions[stateKey];
590
+ if (stateDefinition.type === 'object' &&
591
+ dynamicReferencePrefixMap &&
592
+ (0, exports.isObjectStateWithEntries)(stateDefinition)) {
593
+ return t.objectProperty(t.identifier(stateKey), (0, exports.convertObjectStateDefaultToExpression)(stateDefinition.defaultValue, dynamicReferencePrefixMap, t));
594
+ }
410
595
  return t.objectProperty(t.identifier(stateKey), (0, exports.convertValueToLiteral)(stateDefinition.defaultValue));
411
596
  });
412
597
  classMethodsAndProperties.push(t.classProperty(t.identifier('state'), t.objectExpression(stateDeclarationsAST)));
@@ -419,22 +604,22 @@ var createClassComponent = function (name, propDefinitions, stateDefinitions, js
419
604
  return classDeclaration;
420
605
  };
421
606
  exports.createClassComponent = createClassComponent;
422
- var createPureComponent = function (name, stateDefinitions, jsxTagTree, windowImports, t) {
607
+ var createPureComponent = function (name, stateDefinitions, jsxTagTree, windowImports, dynamicReferencePrefixMap, t) {
423
608
  if (windowImports === void 0) { windowImports = {}; }
424
609
  if (t === void 0) { t = types; }
425
- var arrowFunctionBody = (0, exports.createReturnExpressionSyntax)(stateDefinitions, jsxTagTree, windowImports);
610
+ var arrowFunctionBody = (0, exports.createReturnExpressionSyntax)(stateDefinitions, jsxTagTree, windowImports, dynamicReferencePrefixMap);
426
611
  var arrowFunction = t.arrowFunctionExpression([t.identifier('props')], arrowFunctionBody);
427
612
  var declarator = t.variableDeclarator(t.identifier(name), arrowFunction);
428
613
  var component = t.variableDeclaration('const', [declarator]);
429
614
  return component;
430
615
  };
431
616
  exports.createPureComponent = createPureComponent;
432
- var createReturnExpressionSyntax = function (stateDefinitions, jsxTagTree, windowImports, t) {
617
+ var createReturnExpressionSyntax = function (stateDefinitions, jsxTagTree, windowImports, dynamicReferencePrefixMap, t) {
433
618
  if (windowImports === void 0) { windowImports = {}; }
434
619
  if (t === void 0) { t = types; }
435
620
  var returnStatement = t.returnStatement(jsxTagTree);
436
621
  var stateHooks = Object.keys(stateDefinitions).map(function (stateKey) {
437
- return (0, exports.createStateHookAST)(stateKey, stateDefinitions[stateKey]);
622
+ return (0, exports.createStateHookAST)(stateKey, stateDefinitions[stateKey], dynamicReferencePrefixMap);
438
623
  });
439
624
  return t.blockStatement(__spreadArray(__spreadArray(__spreadArray([], stateHooks, true), Object.values(windowImports), true), [returnStatement], false));
440
625
  };
@@ -442,17 +627,206 @@ exports.createReturnExpressionSyntax = createReturnExpressionSyntax;
442
627
  /**
443
628
  * Creates an AST line for defining a single state hook
444
629
  */
445
- var createStateHookAST = function (stateKey, stateDefinition, t) {
630
+ var createStateHookAST = function (stateKey, stateDefinition, dynamicReferencePrefixMap, t) {
446
631
  if (t === void 0) { t = types; }
447
- var defaultValueArgument = (0, exports.convertValueToLiteral)(stateDefinition.defaultValue, stateDefinition.type);
632
+ var defaultValueArgument;
633
+ if (stateDefinition.type === 'object' &&
634
+ dynamicReferencePrefixMap &&
635
+ (0, exports.isObjectStateWithEntries)(stateDefinition)) {
636
+ defaultValueArgument = (0, exports.convertObjectStateDefaultToExpression)(stateDefinition.defaultValue, dynamicReferencePrefixMap, t);
637
+ }
638
+ else {
639
+ defaultValueArgument = (0, exports.convertValueToLiteral)(stateDefinition.defaultValue, stateDefinition.type);
640
+ }
641
+ // When the state has a dataSourceBinding, the initial value comes from props
642
+ // Generated: useState(props.stateKey !== undefined ? props.stateKey : defaultValue)
643
+ var useStateArgument = defaultValueArgument;
644
+ if (stateDefinition.dataSourceBinding) {
645
+ var propAccess = t.memberExpression(t.identifier('props'), t.identifier(stateKey));
646
+ useStateArgument = t.conditionalExpression(t.binaryExpression('!==', propAccess, t.identifier('undefined')), propAccess, defaultValueArgument);
647
+ }
648
+ else if (stateDefinition.urlSearchParamBinding &&
649
+ typeof stateDefinition.urlSearchParamBinding.key === 'string' &&
650
+ stateDefinition.urlSearchParamBinding.key !== '') {
651
+ // URL-search-param binding: seed the initial state directly from
652
+ // `window.location.search`. We deliberately DO NOT use Next.js'
653
+ // `router.query` here because on statically-generated pages (getStaticProps
654
+ // / getStaticPaths) `router.query` is empty on the first render and only
655
+ // hydrates after `router.isReady` flips to true — by which point React's
656
+ // `useState` initializer has already captured the fallback default. That
657
+ // regression shipped as "detail panel does not auto-open on deep links to
658
+ // /admin/products?products_detail_panel_item_id=<id>". `window.location`
659
+ // is populated synchronously on both direct loads and client-side
660
+ // navigations, and the `typeof window` guard keeps SSR falling back to
661
+ // the declared static default cleanly.
662
+ //
663
+ // Emitted shape:
664
+ // useState(
665
+ // (typeof window !== "undefined"
666
+ // ? new URLSearchParams(window.location.search).get("<key>")
667
+ // : null) ?? <defaultValueLiteral>
668
+ // )
669
+ var paramKey = stateDefinition.urlSearchParamBinding.key;
670
+ var urlSearchParamsExpr = t.newExpression(t.identifier('URLSearchParams'), [
671
+ t.memberExpression(t.memberExpression(t.identifier('window'), t.identifier('location')), t.identifier('search')),
672
+ ]);
673
+ var readParamExpr = t.callExpression(t.memberExpression(urlSearchParamsExpr, t.identifier('get')), [t.stringLiteral(paramKey)]);
674
+ var browserGuard = t.binaryExpression('!==', t.unaryExpression('typeof', t.identifier('window')), t.stringLiteral('undefined'));
675
+ useStateArgument = t.logicalExpression('??', t.conditionalExpression(browserGuard, readParamExpr, t.nullLiteral()), defaultValueArgument);
676
+ }
448
677
  return t.variableDeclaration('const', [
449
678
  t.variableDeclarator(t.arrayPattern([
450
679
  t.identifier(stateKey),
451
680
  t.identifier(teleport_shared_1.StringUtils.createStateStoringFunction(stateKey)),
452
- ]), t.callExpression(t.identifier('useState'), [defaultValueArgument])),
681
+ ]), t.callExpression(t.identifier('useState'), [useStateArgument])),
453
682
  ]);
454
683
  };
455
684
  exports.createStateHookAST = createStateHookAST;
685
+ var isObjectStateWithEntries = function (stateDefinition) {
686
+ if (stateDefinition.type !== 'object') {
687
+ return false;
688
+ }
689
+ var defaultValue = stateDefinition.defaultValue;
690
+ if (typeof defaultValue !== 'object' || defaultValue === null || Array.isArray(defaultValue)) {
691
+ return false;
692
+ }
693
+ return Object.values(defaultValue).some(function (entry) {
694
+ if (typeof entry !== 'object' || entry === null) {
695
+ return false;
696
+ }
697
+ var typed = entry;
698
+ return (typed.type === 'static' || typed.type === 'dynamic') && 'content' in typed;
699
+ });
700
+ };
701
+ exports.isObjectStateWithEntries = isObjectStateWithEntries;
702
+ var convertObjectStateDefaultToExpression = function (defaultValue, prefixMap, t) {
703
+ if (t === void 0) { t = types; }
704
+ var properties = Object.keys(defaultValue).map(function (key) {
705
+ var valueExpression = resolveObjectStateEntry(defaultValue[key], prefixMap, t);
706
+ return t.objectProperty(t.stringLiteral(key), valueExpression);
707
+ });
708
+ return t.objectExpression(properties);
709
+ };
710
+ exports.convertObjectStateDefaultToExpression = convertObjectStateDefaultToExpression;
711
+ var resolveObjectStateEntry = function (entry, prefixMap, t) {
712
+ if (t === void 0) { t = types; }
713
+ if (typeof entry !== 'object' || entry === null) {
714
+ return (0, exports.convertValueToLiteral)(entry);
715
+ }
716
+ var typed = entry;
717
+ if (typed.type === 'static') {
718
+ return (0, exports.convertValueToLiteral)(typed.content);
719
+ }
720
+ if (typed.type === 'dynamic') {
721
+ var content = typed.content;
722
+ var referenceType = content.referenceType, id = content.id, refPath = content.refPath;
723
+ if (referenceType === 'globalState') {
724
+ var gsRefPath = refPath || [];
725
+ var expr = t.identifier(id);
726
+ for (var _i = 0, gsRefPath_1 = gsRefPath; _i < gsRefPath_1.length; _i++) {
727
+ var segment = gsRefPath_1[_i];
728
+ expr = t.optionalMemberExpression(expr, t.identifier(segment), false, true);
729
+ }
730
+ return expr;
731
+ }
732
+ if (referenceType === 'global') {
733
+ // Normalize Shape B ({ refPath: ['Current User', 'id'] }) to Shape A
734
+ // ({ id: 'currentUser', refPath: ['id'] }) so downstream access is uniform.
735
+ var resolvedId = (0, exports.resolveGlobalRefId)(content);
736
+ if (resolvedId) {
737
+ var tail = !id && refPath && refPath.length > 0 ? refPath.slice(1) : refPath || [];
738
+ var expr = t.identifier(resolvedId);
739
+ for (var _a = 0, tail_1 = tail; _a < tail_1.length; _a++) {
740
+ var segment = tail_1[_a];
741
+ expr = t.optionalMemberExpression(expr, t.identifier(segment), false, true);
742
+ }
743
+ return expr;
744
+ }
745
+ }
746
+ var idWithPath = teleport_shared_1.UIDLUtils.generateIdWithRefPath(id, refPath);
747
+ var prefix = prefixMap[referenceType] || '';
748
+ return prefix === ''
749
+ ? t.identifier(idWithPath)
750
+ : t.memberExpression(t.identifier(prefix), t.identifier(idWithPath));
751
+ }
752
+ return (0, exports.convertValueToLiteral)(entry);
753
+ };
754
+ // Mapping from the UIDL display name used in a global reference refPath
755
+ // to the runtime variable name that holds the value. Kept here so both the
756
+ // JSX emitter and the object-state global-reference collectors stay in sync.
757
+ exports.GLOBAL_REF_ID_MAP = {
758
+ 'E-commerce': 'ecommerce',
759
+ Cart: 'cart',
760
+ 'Current User': 'currentUser',
761
+ };
762
+ var resolveGlobalRefId = function (content) {
763
+ if (!content) {
764
+ return undefined;
765
+ }
766
+ if (content.id) {
767
+ return content.id;
768
+ }
769
+ if (!content.refPath || content.refPath.length === 0) {
770
+ return undefined;
771
+ }
772
+ return exports.GLOBAL_REF_ID_MAP[content.refPath[0]];
773
+ };
774
+ exports.resolveGlobalRefId = resolveGlobalRefId;
775
+ var collectGlobalReferencesFromObjectStates = function (stateDefinitions) {
776
+ var globalRefs = [];
777
+ Object.values(stateDefinitions).forEach(function (stateDef) {
778
+ if (stateDef.type !== 'object') {
779
+ return;
780
+ }
781
+ var defaultValue = stateDef.defaultValue;
782
+ if (typeof defaultValue !== 'object' || defaultValue === null || Array.isArray(defaultValue)) {
783
+ return;
784
+ }
785
+ Object.values(defaultValue).forEach(function (entry) {
786
+ if (typeof entry !== 'object' || entry === null) {
787
+ return;
788
+ }
789
+ var typed = entry;
790
+ if (typed.type === 'dynamic') {
791
+ var content = typed.content;
792
+ if (content.referenceType === 'global') {
793
+ var resolvedId = (0, exports.resolveGlobalRefId)(content);
794
+ if (resolvedId) {
795
+ globalRefs.push(resolvedId);
796
+ }
797
+ }
798
+ }
799
+ });
800
+ });
801
+ return globalRefs;
802
+ };
803
+ exports.collectGlobalReferencesFromObjectStates = collectGlobalReferencesFromObjectStates;
804
+ var collectGlobalStateReferencesFromObjectStates = function (stateDefinitions) {
805
+ var refs = [];
806
+ Object.values(stateDefinitions).forEach(function (stateDef) {
807
+ if (stateDef.type !== 'object') {
808
+ return;
809
+ }
810
+ var defaultValue = stateDef.defaultValue;
811
+ if (typeof defaultValue !== 'object' || defaultValue === null || Array.isArray(defaultValue)) {
812
+ return;
813
+ }
814
+ Object.values(defaultValue).forEach(function (entry) {
815
+ if (typeof entry !== 'object' || entry === null) {
816
+ return;
817
+ }
818
+ var typed = entry;
819
+ if (typed.type === 'dynamic') {
820
+ var content = typed.content;
821
+ if (content.referenceType === 'globalState' && content.id) {
822
+ refs.push({ id: content.id });
823
+ }
824
+ }
825
+ });
826
+ });
827
+ return refs;
828
+ };
829
+ exports.collectGlobalStateReferencesFromObjectStates = collectGlobalStateReferencesFromObjectStates;
456
830
  var generateDynamicWindowImport = function (hookName, dependency) {
457
831
  if (hookName === void 0) { hookName = 'useEffect'; }
458
832
  return types.expressionStatement(types.callExpression(types.identifier(hookName), [
@@ -736,6 +1110,18 @@ var computeFetchUrl = function (resource) {
736
1110
  var cleanBaseUrl = baseUrlStr.endsWith('/') ? baseUrlStr.slice(0, -1) : baseUrlStr;
737
1111
  var cleanRoute = routeStr.startsWith('/') ? routeStr.slice(1) : routeStr;
738
1112
  var stringsToJoin = [cleanBaseUrl, cleanRoute].filter(function (item) { return item; }).join('/');
1113
+ // If the URL is relative (starts with /), add a runtime base URL prefix
1114
+ // so fetch() works in server-side contexts (getStaticProps/getServerSideProps).
1115
+ // Non-NEXT_PUBLIC_ env vars are only available server-side in Next.js,
1116
+ // so NEXTAUTH_URL naturally resolves to undefined on the client (making baseUrl '').
1117
+ if (stringsToJoin.startsWith('/')) {
1118
+ var processEnv = types.memberExpression(types.identifier('process'), types.identifier('env'));
1119
+ var serverBaseUrlExpr = types.logicalExpression('||', types.logicalExpression('||', types.memberExpression(processEnv, types.identifier('NEXT_PUBLIC_SITE_URL')), types.memberExpression(types.memberExpression(types.identifier('process'), types.identifier('env')), types.identifier('NEXTAUTH_URL'))), types.stringLiteral(''));
1120
+ return types.templateLiteral([
1121
+ types.templateElement({ cooked: '', raw: '' }, false),
1122
+ types.templateElement({ cooked: "".concat(stringsToJoin), raw: "".concat(stringsToJoin) }, true),
1123
+ ], [serverBaseUrlExpr]);
1124
+ }
739
1125
  return types.templateLiteral([types.templateElement({ cooked: "".concat(stringsToJoin), raw: "".concat(stringsToJoin) }, true)], []);
740
1126
  }
741
1127
  if (!routeType) {
@@ -859,7 +1245,7 @@ exports.convertFilterDestinationToExpression = convertFilterDestinationToExpress
859
1245
  var getExpressionFromUIDLExpressionNode = function (node) {
860
1246
  var ast;
861
1247
  try {
862
- ast = (0, core_1.parse)(node.content, {
1248
+ ast = (0, core_1.parse)((0, exports.sanitizeExprContent)(node.content), {
863
1249
  sourceType: 'module',
864
1250
  });
865
1251
  }