@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
@@ -32,7 +32,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
32
32
  return to.concat(ar || Array.prototype.slice.call(from));
33
33
  };
34
34
  Object.defineProperty(exports, "__esModule", { value: true });
35
- exports.getRepeatSourceIdentifier = exports.createBinaryExpression = exports.createConditionalJSXExpression = exports.createConditionIdentifier = exports.createDynamicValueExpression = exports.addEventHandlerToTag = void 0;
35
+ exports.getRepeatSourceIdentifier = exports.createBinaryExpression = exports.createConditionalJSXExpression = exports.createConditionIdentifier = exports.createDynamicValueExpression = exports.createGlobalStateExpression = exports.resolveAndRegisterGlobalStateSource = exports.resolveGlobalStateName = exports.createStateChangeStatement = exports.addEventHandlerToTag = void 0;
36
36
  var types = __importStar(require("@babel/types"));
37
37
  var ast_utils_1 = require("../../utils/ast-utils");
38
38
  var teleport_shared_1 = require("@teleporthq/teleport-shared");
@@ -45,7 +45,7 @@ var addEventHandlerToTag = function (tag, eventKey, eventHandlerStatements, para
45
45
  var propDefinitions = params.propDefinitions, stateDefinitions = params.stateDefinitions;
46
46
  eventHandlerStatements.forEach(function (eventHandlerAction) {
47
47
  if (eventHandlerAction.type === 'stateChange') {
48
- var handler = createStateChangeStatement(eventHandlerAction, stateDefinitions, options);
48
+ var handler = (0, exports.createStateChangeStatement)(eventHandlerAction, stateDefinitions, options);
49
49
  if (handler) {
50
50
  eventHandlerASTStatements.push(handler);
51
51
  }
@@ -91,7 +91,27 @@ var createPropCallStatement = function (eventHandlerStatement, propDefinitions,
91
91
  : '';
92
92
  return t.expressionStatement(t.callExpression(t.identifier(prefix + propFunctionKey), __spreadArray([], args.map(function (arg) { return (0, ast_utils_1.convertValueToLiteral)(arg); }), true)));
93
93
  };
94
+ /**
95
+ * Plan v14 — Type-aware state setter emitter.
96
+ *
97
+ * The old emitter unconditionally produced `setX(!x)` for `$toggle` and
98
+ * `setX(<literal>)` for primitives, regardless of the declared state
99
+ * type. That broke every multi-step form: `$toggle` on a numeric step
100
+ * state turned `1` into `false`, hiding every `state === N` panel; a
101
+ * primitive written to an object state replaced the whole object.
102
+ *
103
+ * The codegen here is now the safety net for what server-side Layers 1-3
104
+ * could not catch (legacy projects, AI bypass). When a combination is
105
+ * incoherent (e.g. `$toggle` on a number, or a bare string targeting an
106
+ * object), we skip the statement and warn — the workflow runtime handler
107
+ * remains the source of truth. Coherent combinations emit the same code
108
+ * as before, plus four new modifier shapes (`$increment` / `$decrement` /
109
+ * `$patch` / `$append`) that produce React functional setters.
110
+ *
111
+ * Returns `null` when the emitter declines (caller already handles null).
112
+ */
94
113
  var createStateChangeStatement = function (eventHandlerStatement, stateDefinitions, options, t) {
114
+ var _a;
95
115
  if (t === void 0) { t = types; }
96
116
  if (!eventHandlerStatement.modifies) {
97
117
  console.warn("No state identifier referenced under the \"modifies\" field");
@@ -99,98 +119,451 @@ var createStateChangeStatement = function (eventHandlerStatement, stateDefinitio
99
119
  }
100
120
  var stateKey = eventHandlerStatement.modifies;
101
121
  var stateDefinition = stateDefinitions[stateKey];
122
+ if (!stateDefinition) {
123
+ console.warn("State change references an undeclared state \"".concat(stateKey, "\" \u2014 skipping setter emission."));
124
+ return null;
125
+ }
102
126
  var statePrefix = options.dynamicReferencePrefixMap.state
103
127
  ? options.dynamicReferencePrefixMap.state + '.'
104
128
  : '';
129
+ var declaredType = stateDefinition.type;
130
+ var newState = eventHandlerStatement.newState;
105
131
  var newStateValue;
106
- if (eventHandlerStatement.newState === '$toggle') {
132
+ var useFunctionalSetter = false;
133
+ var functionalSetterBuilder;
134
+ if (newState === '$toggle') {
135
+ // Boolean-only. Reject for number / object / array — emitting `!x`
136
+ // on those types is the v13/v14 regression we are fixing.
137
+ if (declaredType !== 'boolean') {
138
+ console.warn("[createStateChangeStatement] '$toggle' is only valid for boolean state; state \"".concat(stateKey, "\" is declared as ").concat(declaredType, ". Skipping setter to avoid corrupting state."));
139
+ return null;
140
+ }
107
141
  newStateValue = t.unaryExpression('!', t.identifier(statePrefix + stateKey));
108
142
  }
109
- else if (typeof eventHandlerStatement.newState === 'object') {
110
- if (eventHandlerStatement.newState.type === 'expr') {
111
- newStateValue = (0, ast_utils_1.getExpressionFromUIDLExpressionNode)(eventHandlerStatement.newState);
143
+ else if (typeof newState === 'object' && newState !== null) {
144
+ var obj = newState;
145
+ var objType = obj.type;
146
+ if (objType === 'expr') {
147
+ newStateValue = (0, ast_utils_1.getExpressionFromUIDLExpressionNode)(newState);
148
+ }
149
+ else if (objType === 'dynamic') {
150
+ newStateValue = (0, exports.createDynamicValueExpression)(newState, options);
151
+ }
152
+ else if (objType === '$increment' || objType === '$decrement') {
153
+ if (declaredType !== 'number') {
154
+ console.warn("[createStateChangeStatement] '".concat(objType, "' requires a numeric state; \"").concat(stateKey, "\" is declared as ").concat(declaredType, ". Skipping setter."));
155
+ return null;
156
+ }
157
+ // Honor the sign of `delta`: an $increment with delta -2 is a
158
+ // deliberate decrement by 2 (the type doc documents this). The
159
+ // builder emits `prev + delta` for $increment and `prev - delta`
160
+ // for $decrement, then the absolute value of |delta| is the
161
+ // numeric literal we feed in. Math.abs prevents the rare double-
162
+ // negative case where someone writes `{ type: '$decrement', delta: -1 }`
163
+ // (intended +1) from emitting `prev - -1` (which would be `+1`
164
+ // via JS coercion but is unreadable).
165
+ var rawDelta = (_a = obj.delta) !== null && _a !== void 0 ? _a : 1;
166
+ var operator_1 = objType === '$increment' ? (rawDelta < 0 ? '-' : '+') : rawDelta < 0 ? '+' : '-';
167
+ var magnitude_1 = Math.abs(rawDelta);
168
+ useFunctionalSetter = true;
169
+ functionalSetterBuilder = function (prevId) {
170
+ return t.binaryExpression(operator_1, prevId, t.numericLiteral(magnitude_1));
171
+ };
172
+ }
173
+ else if (objType === '$patch') {
174
+ if (declaredType !== 'object') {
175
+ console.warn("[createStateChangeStatement] '$patch' requires an object state; \"".concat(stateKey, "\" is declared as ").concat(declaredType, ". Skipping setter."));
176
+ return null;
177
+ }
178
+ var patch_1 = obj;
179
+ if (!patch_1.path || typeof patch_1.path !== 'string') {
180
+ console.warn("[createStateChangeStatement] '$patch' requires a string \"path\"; received \"".concat(String(patch_1.path), "\" for state \"").concat(stateKey, "\". Skipping setter."));
181
+ return null;
182
+ }
183
+ var patchValueAst_1 = (0, ast_utils_1.convertValueToLiteral)(patch_1.value, 'string');
184
+ useFunctionalSetter = true;
185
+ functionalSetterBuilder = function (prevId) {
186
+ return t.objectExpression([
187
+ t.spreadElement(prevId),
188
+ t.objectProperty(t.identifier(patch_1.path), patchValueAst_1, false, false),
189
+ ]);
190
+ };
112
191
  }
113
- else if (eventHandlerStatement.newState.type === 'dynamic') {
114
- newStateValue = (0, exports.createDynamicValueExpression)(eventHandlerStatement.newState, options);
192
+ else if (objType === '$append') {
193
+ if (declaredType !== 'array') {
194
+ console.warn("[createStateChangeStatement] '$append' requires an array state; \"".concat(stateKey, "\" is declared as ").concat(declaredType, ". Skipping setter."));
195
+ return null;
196
+ }
197
+ var appended = obj;
198
+ var appendedValueAst_1 = (0, ast_utils_1.convertValueToLiteral)(appended.value, 'string');
199
+ useFunctionalSetter = true;
200
+ functionalSetterBuilder = function (prevId) {
201
+ return t.arrayExpression([t.spreadElement(prevId), appendedValueAst_1]);
202
+ };
115
203
  }
116
204
  else {
117
- newStateValue = (0, ast_utils_1.convertValueToLiteral)(eventHandlerStatement.newState, stateDefinition.type);
205
+ // Unknown object shape — fall back to literal conversion only when
206
+ // the declared type accepts a primitive write.
207
+ if (declaredType === 'object' || declaredType === 'array') {
208
+ console.warn("[createStateChangeStatement] Unrecognised modifier shape on a ".concat(declaredType, " state \"").concat(stateKey, "\"; skipping setter to avoid corrupting state."));
209
+ return null;
210
+ }
211
+ newStateValue = (0, ast_utils_1.convertValueToLiteral)(newState, declaredType);
118
212
  }
119
213
  }
120
214
  else {
121
- newStateValue = (0, ast_utils_1.convertValueToLiteral)(eventHandlerStatement.newState, stateDefinition.type);
215
+ // Bare primitive (`'oily'`, `2`, `true`). Coerce against the declared type.
216
+ // For object/array state, writing a primitive REPLACES the structure.
217
+ // That is the bug — fail safe.
218
+ if (declaredType === 'object' || declaredType === 'array') {
219
+ console.warn("[createStateChangeStatement] Refusing to overwrite ".concat(declaredType, " state \"").concat(stateKey, "\" with a primitive value (").concat(JSON.stringify(newState), "). Use '$patch' / '$append' modifiers instead. Skipping setter."));
220
+ return null;
221
+ }
222
+ newStateValue = (0, ast_utils_1.convertValueToLiteral)(newState, declaredType);
122
223
  }
123
224
  switch (options.stateHandling) {
124
- case 'hooks':
125
- return t.expressionStatement(t.callExpression(t.identifier(teleport_shared_1.StringUtils.createStateStoringFunction(stateKey)), [
126
- newStateValue,
127
- ]));
128
- case 'function':
225
+ case 'hooks': {
226
+ var setterId = t.identifier(teleport_shared_1.StringUtils.createStateStoringFunction(stateKey));
227
+ if (useFunctionalSetter && functionalSetterBuilder) {
228
+ var prevId = t.identifier('prev');
229
+ var arrow = t.arrowFunctionExpression([prevId], functionalSetterBuilder(prevId));
230
+ return t.expressionStatement(t.callExpression(setterId, [arrow]));
231
+ }
232
+ if (!newStateValue) {
233
+ return null;
234
+ }
235
+ return t.expressionStatement(t.callExpression(setterId, [newStateValue]));
236
+ }
237
+ case 'function': {
238
+ // Class-component setState path is legacy; functional setters aren't
239
+ // supported via `this.setState(prev => …)` here, so for the new
240
+ // modifiers we fall back to skipping. The hooks path is the path the
241
+ // multi-step form actually exercises.
242
+ if (useFunctionalSetter) {
243
+ console.warn("[createStateChangeStatement] Functional-setter modifiers are only supported under stateHandling=\"hooks\". Skipping setter for \"".concat(stateKey, "\"."));
244
+ return null;
245
+ }
246
+ if (!newStateValue) {
247
+ return null;
248
+ }
129
249
  return t.expressionStatement(t.callExpression(t.identifier('this.setState'), [
130
250
  t.objectExpression([t.objectProperty(t.identifier(stateKey), newStateValue)]),
131
251
  ]));
252
+ }
132
253
  case 'mutation':
133
- default:
254
+ default: {
255
+ if (useFunctionalSetter) {
256
+ console.warn("[createStateChangeStatement] Functional-setter modifiers are only supported under stateHandling=\"hooks\". Skipping setter for \"".concat(stateKey, "\"."));
257
+ return null;
258
+ }
259
+ if (!newStateValue) {
260
+ return null;
261
+ }
134
262
  return t.expressionStatement(t.assignmentExpression('=', t.identifier(statePrefix + stateKey), newStateValue));
263
+ }
264
+ }
265
+ };
266
+ exports.createStateChangeStatement = createStateChangeStatement;
267
+ var resolveGlobalStateName = function (id, definitions) {
268
+ if (!definitions) {
269
+ return id;
270
+ }
271
+ for (var _i = 0, _a = Object.values(definitions); _i < _a.length; _i++) {
272
+ var def = _a[_i];
273
+ if (def.id === id) {
274
+ return def.name;
275
+ }
135
276
  }
277
+ return id;
136
278
  };
279
+ exports.resolveGlobalStateName = resolveGlobalStateName;
280
+ // Matches the leading JS identifier of an expression, e.g. `foo` from
281
+ // `foo?.['bar'] || []`. Used to recognise when a string-encoded UIDL source
282
+ // (cms-list-repeater `source`) is rooted at a global-state name so the
283
+ // generator can register the reference for `useGlobalState()` destructuring.
284
+ var LEADING_IDENTIFIER_RE = /^([A-Za-z_$][A-Za-z0-9_$]*)/;
285
+ // Older versions of the UIDL emitter encoded a global-state reference as the
286
+ // magic literal `globalState_<defId>` instead of the declared variable name.
287
+ // Detect that prefix so we can rewrite it to the proper identifier and fix
288
+ // already-published UIDL documents without forcing them to be regenerated.
289
+ var LEGACY_GLOBAL_STATE_RE = /^globalState_([A-Za-z0-9_-]+)/;
290
+ /**
291
+ * Given a string-encoded UIDL `source` expression, resolve any global-state
292
+ * reference into the proper JS identifier for the generator and ensure the
293
+ * reference is registered for `useGlobalState()` destructuring.
294
+ *
295
+ * Two upstream encodings are accepted:
296
+ * 1. Modern shape — leading identifier is the declared state name
297
+ * (e.g. `countriesWithDescriptions || []`). We just register it.
298
+ * 2. Legacy shape — leading identifier is the magic placeholder
299
+ * `globalState_<defId>` (e.g. `globalState_TQ_96vaRH5pdf['key']`). We
300
+ * rewrite the placeholder to the declared name AND register it.
301
+ *
302
+ * Returns the (possibly rewritten) source string. The caller should embed
303
+ * the returned string instead of the input.
304
+ */
305
+ var resolveAndRegisterGlobalStateSource = function (source, params) {
306
+ var original = source !== null && source !== void 0 ? source : '';
307
+ if (!original) {
308
+ return original;
309
+ }
310
+ var definitions = params.globalStateDefinitions;
311
+ if (!definitions || Object.keys(definitions).length === 0) {
312
+ return original;
313
+ }
314
+ var legacyMatch = original.match(LEGACY_GLOBAL_STATE_RE);
315
+ if (legacyMatch) {
316
+ var id = legacyMatch[1];
317
+ for (var _i = 0, _a = Object.values(definitions); _i < _a.length; _i++) {
318
+ var def = _a[_i];
319
+ if (def.id === id) {
320
+ params.globalStateReferences.push({ id: def.id, name: def.name });
321
+ return original.replace(LEGACY_GLOBAL_STATE_RE, def.name);
322
+ }
323
+ }
324
+ // Legacy prefix found but no matching definition (orphaned reference).
325
+ // Leave the source untouched; the downstream identifier creation will
326
+ // still emit something, and a separate sanity pass can flag it.
327
+ return original;
328
+ }
329
+ var leadingMatch = original.match(LEADING_IDENTIFIER_RE);
330
+ if (leadingMatch) {
331
+ var leadingName = leadingMatch[1];
332
+ for (var _b = 0, _c = Object.values(definitions); _b < _c.length; _b++) {
333
+ var def = _c[_b];
334
+ if (def.name === leadingName) {
335
+ params.globalStateReferences.push({ id: def.id, name: def.name });
336
+ return original;
337
+ }
338
+ }
339
+ }
340
+ return original;
341
+ };
342
+ exports.resolveAndRegisterGlobalStateSource = resolveAndRegisterGlobalStateSource;
343
+ var createGlobalStateExpression = function (ref, definitions, t) {
344
+ if (t === void 0) { t = types; }
345
+ var name = (0, exports.resolveGlobalStateName)(ref.content.id, definitions);
346
+ var refPath = ref.content.refPath || [];
347
+ if (refPath.length === 0) {
348
+ return t.identifier(name);
349
+ }
350
+ var expr = t.identifier(name);
351
+ for (var _i = 0, refPath_1 = refPath; _i < refPath_1.length; _i++) {
352
+ var segment = refPath_1[_i];
353
+ expr = t.optionalMemberExpression(expr, t.identifier(segment), false, true);
354
+ }
355
+ return expr;
356
+ };
357
+ exports.createGlobalStateExpression = createGlobalStateExpression;
137
358
  var createDynamicValueExpression = function (identifier, options, t) {
359
+ var _a;
360
+ if (t === void 0) { t = types; }
361
+ var inner = createDynamicValueExpressionRaw(identifier, options, t);
362
+ // When the UIDL content carries a `valueMapper`, wrap the resolved
363
+ // expression in a sandboxed IIFE that runs the user's `mapValue(value)`
364
+ // and falls back to the raw value on error. This mirrors the state
365
+ // definition `wrapWithMappingFunction` pattern and lets any framework
366
+ // that re-uses `createDynamicValueExpression` inherit the behaviour.
367
+ var valueMapper = ((_a = identifier.content.valueMapper) === null || _a === void 0 ? void 0 : _a.trim()) || '';
368
+ if (!valueMapper) {
369
+ return inner;
370
+ }
371
+ return wrapExpressionWithValueMapperAst(inner, valueMapper, t);
372
+ };
373
+ exports.createDynamicValueExpression = createDynamicValueExpression;
374
+ var wrapExpressionWithValueMapperAst = function (innerExpression, valueMapper, t) {
375
+ if (t === void 0) { t = types; }
376
+ // Build: ((v) => { try { return (new Function('value', '"use strict"; <mapper>; return mapValue(value);')).call(null, v) } catch (_e) { return v } })(<inner>)
377
+ //
378
+ // We deliberately use `new Function(...)` at runtime rather than parsing
379
+ // the mapper body into AST statements here. That keeps this plugin free
380
+ // of a parser dependency, matches the sandboxing used by state-definition
381
+ // `wrapWithMappingFunction`, and ensures the generated code is framework
382
+ // agnostic — only stringify semantics + `toString()` on primitives are
383
+ // required for the output to render correctly.
384
+ var tryBlock = t.tryStatement(t.blockStatement([
385
+ t.returnStatement(t.callExpression(t.memberExpression(t.newExpression(t.identifier('Function'), [
386
+ t.stringLiteral('value'),
387
+ t.stringLiteral("\"use strict\"; ".concat(valueMapper, "; return mapValue(value);")),
388
+ ]), t.identifier('call')), [t.nullLiteral(), t.identifier('v')])),
389
+ ]), t.catchClause(t.identifier('_e'), t.blockStatement([t.returnStatement(t.identifier('v'))])));
390
+ var arrow = t.arrowFunctionExpression([t.identifier('v')], t.blockStatement([tryBlock]));
391
+ return t.callExpression(arrow, [innerExpression]);
392
+ };
393
+ var createDynamicValueExpressionRaw = function (identifier, options, t) {
394
+ var _a;
138
395
  if (t === void 0) { t = types; }
139
396
  var identifierContent = identifier.content;
140
397
  var refPath = identifier.content.refPath || [];
141
398
  var referenceType = identifierContent.referenceType, id = identifierContent.id;
142
- var idWithPath = (0, uidl_utils_1.generateIdWithRefPath)(id, refPath);
143
399
  if (referenceType === 'attr' || referenceType === 'children' || referenceType === 'token') {
144
400
  throw new Error("Dynamic reference type \"".concat(referenceType, "\" is not supported yet"));
145
401
  }
402
+ // 'ctx' references resolve to the data source context render prop identifier
403
+ // using only the refPath to build property access
404
+ if (referenceType === 'ctx') {
405
+ var ctxPrefix = options.dynamicReferencePrefixMap.ctx || '';
406
+ if (ctxPrefix && refPath.length > 0) {
407
+ var expr = t.identifier(ctxPrefix);
408
+ for (var _i = 0, refPath_2 = refPath; _i < refPath_2.length; _i++) {
409
+ var path = refPath_2[_i];
410
+ expr = t.optionalMemberExpression(expr, t.identifier(path), false, true);
411
+ }
412
+ return expr;
413
+ }
414
+ // Fallback: use the id with refPath if no local prefix
415
+ var ctxFallbackIdWithPath = (0, uidl_utils_1.generateIdWithRefPath)(id, refPath);
416
+ return t.identifier(ctxFallbackIdWithPath);
417
+ }
418
+ // `urlSearchParams` references read a declared key from the URL query string.
419
+ // Next.js generators typically set `dynamicReferencePrefixMap.urlSearchParams`
420
+ // to `'router.query'` so we emit `router.query.<key>`. Static / HTML
421
+ // generators set it to `'__urlSearchParams'` and inject a `const
422
+ // __urlSearchParams = new URLSearchParams(location.search)` prelude.
423
+ //
424
+ // `options.urlSearchParamsRegistry` (set by the plugin based on the page
425
+ // UIDL's `searchParams` definition) supplies per-key defaults so we emit
426
+ // `(router.query.category ?? 'food')` with the declared fallback.
427
+ if (referenceType === 'urlSearchParams') {
428
+ var paramKey = refPath[0] || id;
429
+ var urlParamsPrefix = options.dynamicReferencePrefixMap.urlSearchParams ||
430
+ 'router.query';
431
+ var _b = urlParamsPrefix.split('.'), rootPrefix = _b[0], restPath = _b.slice(1);
432
+ var expr = t.identifier(rootPrefix);
433
+ for (var _c = 0, restPath_1 = restPath; _c < restPath_1.length; _c++) {
434
+ var segment = restPath_1[_c];
435
+ expr = t.memberExpression(expr, t.identifier(segment));
436
+ }
437
+ expr = t.optionalMemberExpression(expr, t.identifier(paramKey), false, true);
438
+ var registry = options.urlSearchParamsRegistry;
439
+ var declaredDefault = (_a = registry === null || registry === void 0 ? void 0 : registry[paramKey]) === null || _a === void 0 ? void 0 : _a.defaultValue;
440
+ if (declaredDefault !== undefined && declaredDefault !== '') {
441
+ expr = t.logicalExpression('??', expr, t.stringLiteral(declaredDefault));
442
+ }
443
+ return expr;
444
+ }
445
+ // 'local' references resolve to the iteration variable of the enclosing repeater.
446
+ // The reference id in UIDL is a node id (e.g. "TQ_xxxxxx") and carries no meaning
447
+ // at runtime — the only load-bearing pieces are the refPath and the current
448
+ // localIdentifier (set when walking into a repeater/data-provider's children).
449
+ if (referenceType === 'local') {
450
+ var localPrefix = options.localIdentifier ||
451
+ options.dynamicReferencePrefixMap.local ||
452
+ '';
453
+ if (localPrefix) {
454
+ if (refPath.length === 0) {
455
+ return t.identifier(localPrefix);
456
+ }
457
+ var expr = t.identifier(localPrefix);
458
+ for (var _d = 0, refPath_3 = refPath; _d < refPath_3.length; _d++) {
459
+ var path = refPath_3[_d];
460
+ expr = t.optionalMemberExpression(expr, t.identifier(path), false, true);
461
+ }
462
+ return expr;
463
+ }
464
+ // Details-page fallback: a page-root `local` reference (no enclosing
465
+ // repeater) means "a column on the fetched row" exposed as a prop under
466
+ // `initialPropsData.exposeAs.name`. Resolve to `props.<name>.<refPath>`.
467
+ if (options.detailsPageExposeAsName && refPath.length > 0) {
468
+ var propPrefix = options.dynamicReferencePrefixMap.prop || 'props';
469
+ var expr = t.memberExpression(t.identifier(propPrefix), t.identifier(options.detailsPageExposeAsName));
470
+ for (var _e = 0, refPath_4 = refPath; _e < refPath_4.length; _e++) {
471
+ var path = refPath_4[_e];
472
+ expr = t.optionalMemberExpression(expr, t.identifier(path), false, true);
473
+ }
474
+ return expr;
475
+ }
476
+ }
477
+ var idWithPath = (0, uidl_utils_1.generateIdWithRefPath)(id, refPath);
146
478
  var prefix = options.dynamicReferencePrefixMap[referenceType] || '';
147
479
  return prefix === ''
148
480
  ? t.identifier(idWithPath)
149
481
  : t.memberExpression(t.identifier(prefix), t.identifier(idWithPath));
150
482
  };
151
- exports.createDynamicValueExpression = createDynamicValueExpression;
152
483
  // Prepares an identifier (from props or state or an expr) to be used as a conditional rendering identifier
153
484
  // Assumes the type from the corresponding props/state definitions if not expr. Expressions are expected to have a boolean return here
154
485
  var createConditionIdentifier = function (dynamicReference, params, options) {
155
- var _a, _b;
486
+ var _a, _b, _c, _d;
156
487
  if (dynamicReference.type === 'expr') {
157
488
  return {
158
489
  key: dynamicReference.content,
159
490
  type: 'boolean',
160
491
  };
161
492
  }
162
- var _c = dynamicReference.content, id = _c.id, referenceType = _c.referenceType, refPath = _c.refPath;
493
+ var _e = dynamicReference.content, id = _e.id, referenceType = _e.referenceType, refPath = _e.refPath;
163
494
  // Handle local references (from repeaters/loops) - they don't have an id
164
495
  if (referenceType === 'local') {
165
496
  // For local references, the identifier comes from the refPath
166
- var key = refPath && refPath.length > 0 ? refPath.join('.') : '';
497
+ var refPathKey = refPath && refPath.length > 0 ? refPath.join('.') : '';
167
498
  var prefix = options.localIdentifier || '';
499
+ // Details-page fallback: at the page root there is no enclosing repeater,
500
+ // so a `local` reference means "a column on the fetched row" exposed as a
501
+ // prop under `initialPropsData.exposeAs.name`.
502
+ if (!prefix && options.detailsPageExposeAsName && refPathKey) {
503
+ var propPrefix = ((_a = options.dynamicReferencePrefixMap) === null || _a === void 0 ? void 0 : _a.prop) || 'props';
504
+ return {
505
+ key: "".concat(options.detailsPageExposeAsName, ".").concat(refPathKey),
506
+ type: 'string',
507
+ prefix: propPrefix,
508
+ };
509
+ }
168
510
  return {
169
- key: key,
511
+ key: refPathKey,
170
512
  type: 'string',
171
513
  prefix: prefix,
172
514
  };
173
515
  }
174
- // Handle global references early - they don't use prop/state definitions
175
516
  if (referenceType === 'global') {
176
517
  return {
177
518
  key: teleport_shared_1.UIDLUtils.generateIdWithRefPath(id, refPath),
178
519
  type: 'string',
179
520
  prefix: '',
521
+ referenceType: 'global',
522
+ };
523
+ }
524
+ if (referenceType === 'globalState') {
525
+ var resolvedName = (0, exports.resolveGlobalStateName)(id, params.globalStateDefinitions);
526
+ var refPathSegments = refPath || [];
527
+ var key = refPathSegments.length > 0
528
+ ? refPathSegments.reduce(function (acc, seg) { return "".concat(acc, "?.").concat(seg); }, resolvedName)
529
+ : resolvedName;
530
+ return {
531
+ key: key,
532
+ type: 'string',
533
+ prefix: '',
534
+ referenceType: 'globalState',
180
535
  };
181
536
  }
182
537
  // in case the id is a member expression: eg: fields.name
183
538
  var referenceRoot = id.split('.')[0];
184
539
  var currentType = referenceType === 'prop'
185
- ? (_a = params.propDefinitions[referenceRoot]) === null || _a === void 0 ? void 0 : _a.type
186
- : (_b = params.stateDefinitions[referenceRoot]) === null || _b === void 0 ? void 0 : _b.type;
540
+ ? (_b = params.propDefinitions[referenceRoot]) === null || _b === void 0 ? void 0 : _b.type
541
+ : (_c = params.stateDefinitions[referenceRoot]) === null || _c === void 0 ? void 0 : _c.type;
187
542
  var type = currentType;
188
543
  if (refPath === null || refPath === void 0 ? void 0 : refPath.length) {
189
- var currentValue = params.propDefinitions[referenceRoot].defaultValue;
190
- for (var _i = 0, refPath_1 = refPath; _i < refPath_1.length; _i++) {
191
- var path = refPath_1[_i];
192
- currentValue = currentValue === null || currentValue === void 0 ? void 0 : currentValue[path];
193
- type = currentValue ? typeof currentValue : currentType;
544
+ if (referenceType === 'prop' && ((_d = params.propDefinitions[referenceRoot]) === null || _d === void 0 ? void 0 : _d.defaultValue)) {
545
+ var currentValue = params.propDefinitions[referenceRoot].defaultValue;
546
+ for (var _i = 0, refPath_5 = refPath; _i < refPath_5.length; _i++) {
547
+ var path = refPath_5[_i];
548
+ currentValue = currentValue === null || currentValue === void 0 ? void 0 : currentValue[path];
549
+ type = currentValue ? typeof currentValue : currentType;
550
+ }
551
+ }
552
+ else if (referenceType === 'state' && currentType === 'object') {
553
+ var stateDef = params.stateDefinitions[referenceRoot];
554
+ if (stateDef &&
555
+ typeof stateDef.defaultValue === 'object' &&
556
+ stateDef.defaultValue !== null &&
557
+ !Array.isArray(stateDef.defaultValue)) {
558
+ var objectDefault = stateDef.defaultValue;
559
+ var entry = objectDefault[refPath[0]];
560
+ if ((entry === null || entry === void 0 ? void 0 : entry.type) === 'static' && entry.content !== undefined) {
561
+ type = typeof entry.content;
562
+ }
563
+ else {
564
+ type = 'string';
565
+ }
566
+ }
194
567
  }
195
568
  }
196
569
  switch (referenceType) {
@@ -216,7 +589,8 @@ var createConditionIdentifier = function (dynamicReference, params, options) {
216
589
  }
217
590
  };
218
591
  exports.createConditionIdentifier = createConditionIdentifier;
219
- var createConditionalJSXExpression = function (content, conditionalExpression, conditionalIdentifier, t) {
592
+ var createConditionalJSXExpression = function (content, conditionalExpression, conditionalIdentifier, options, t) {
593
+ if (options === void 0) { options = {}; }
220
594
  if (t === void 0) { t = types; }
221
595
  var contentNode;
222
596
  if (typeof content === 'string') {
@@ -232,7 +606,7 @@ var createConditionalJSXExpression = function (content, conditionalExpression, c
232
606
  // When the stateValue is an object we will compute a logical/binary expression on the left side
233
607
  var conditions = conditionalExpression.conditions, matchingCriteria = conditionalExpression.matchingCriteria;
234
608
  var binaryExpressions = conditions.map(function (condition) {
235
- return (0, exports.createBinaryExpression)(condition, conditionalIdentifier);
609
+ return (0, exports.createBinaryExpression)(condition, conditionalIdentifier, options);
236
610
  });
237
611
  if (binaryExpressions.length === 1) {
238
612
  binaryExpression = binaryExpressions[0];
@@ -251,12 +625,89 @@ var createConditionalJSXExpression = function (content, conditionalExpression, c
251
625
  return t.logicalExpression('&&', binaryExpression, contentNode);
252
626
  };
253
627
  exports.createConditionalJSXExpression = createConditionalJSXExpression;
254
- var createBinaryExpression = function (condition, conditionalIdentifier, t) {
628
+ /**
629
+ * Resolves an operand value to an AST expression, handling dynamic refs, expressions, and static values.
630
+ */
631
+ var resolveOperandExpression = function (operand, conditionalIdentifier, options) {
632
+ if (typeof operand === 'object' && 'type' in operand && operand.type === 'expr') {
633
+ return (0, ast_utils_1.getExpressionFromUIDLExpressionNode)(operand);
634
+ }
635
+ if (typeof operand === 'object' && 'type' in operand && operand.type === 'dynamic') {
636
+ return (0, exports.createDynamicValueExpression)(operand, {
637
+ dynamicReferencePrefixMap: {
638
+ prop: 'props',
639
+ state: '',
640
+ local: '',
641
+ },
642
+ localIdentifier: options.localIdentifier,
643
+ detailsPageExposeAsName: options.detailsPageExposeAsName,
644
+ });
645
+ }
646
+ return (0, ast_utils_1.convertValueToLiteral)(operand, conditionalIdentifier.type);
647
+ };
648
+ var createBinaryExpression = function (condition, conditionalIdentifier, options, t) {
649
+ if (options === void 0) { options = {}; }
255
650
  if (t === void 0) { t = types; }
256
- var operand = condition.operand, operation = condition.operation;
651
+ var operand = condition.operand, operation = condition.operation, containsField = condition.containsField;
257
652
  var identifier = conditionalIdentifier.prefix
258
653
  ? t.memberExpression(t.identifier(conditionalIdentifier.prefix), t.identifier(conditionalIdentifier.key))
259
654
  : t.identifier(conditionalIdentifier.key);
655
+ // Array/Object operators
656
+ if (operation === 'isEmpty') {
657
+ // For objects, use Object.keys(x).length; for arrays (or unknown), use x.length
658
+ var lengthExpr = conditionalIdentifier.type === 'object'
659
+ ? t.memberExpression(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('keys')), [
660
+ identifier,
661
+ ]), t.identifier('length'))
662
+ : t.memberExpression(identifier, t.identifier('length'));
663
+ return t.binaryExpression('===', lengthExpr, t.numericLiteral(0));
664
+ }
665
+ if (operation === 'isNotEmpty') {
666
+ var lengthExpr = conditionalIdentifier.type === 'object'
667
+ ? t.memberExpression(t.callExpression(t.memberExpression(t.identifier('Object'), t.identifier('keys')), [
668
+ identifier,
669
+ ]), t.identifier('length'))
670
+ : t.memberExpression(identifier, t.identifier('length'));
671
+ return t.binaryExpression('>', lengthExpr, t.numericLiteral(0));
672
+ }
673
+ if (operation === 'lengthEquals' && operand !== undefined) {
674
+ return t.binaryExpression('===', t.memberExpression(identifier, t.identifier('length')), resolveOperandExpression(operand, conditionalIdentifier, options));
675
+ }
676
+ if (operation === 'lengthGreaterThan' && operand !== undefined) {
677
+ return t.binaryExpression('>', t.memberExpression(identifier, t.identifier('length')), resolveOperandExpression(operand, conditionalIdentifier, options));
678
+ }
679
+ if (operation === 'lengthLessThan' && operand !== undefined) {
680
+ return t.binaryExpression('<', t.memberExpression(identifier, t.identifier('length')), resolveOperandExpression(operand, conditionalIdentifier, options));
681
+ }
682
+ if (operation === 'contains' && operand !== undefined) {
683
+ var operandExpr = resolveOperandExpression(operand, conditionalIdentifier, options);
684
+ if (containsField) {
685
+ var itemParam = t.identifier('__item');
686
+ return t.callExpression(t.memberExpression(identifier, t.identifier('some')), [
687
+ t.arrowFunctionExpression([itemParam], t.binaryExpression('===', t.memberExpression(itemParam, t.identifier(containsField)), operandExpr)),
688
+ ]);
689
+ }
690
+ return t.callExpression(t.memberExpression(identifier, t.identifier('includes')), [operandExpr]);
691
+ }
692
+ if (operation === 'notContains' && operand !== undefined) {
693
+ var operandExpr = resolveOperandExpression(operand, conditionalIdentifier, options);
694
+ if (containsField) {
695
+ var itemParam = t.identifier('__item');
696
+ return t.unaryExpression('!', t.callExpression(t.memberExpression(identifier, t.identifier('some')), [
697
+ t.arrowFunctionExpression([itemParam], t.binaryExpression('===', t.memberExpression(itemParam, t.identifier(containsField)), operandExpr)),
698
+ ]));
699
+ }
700
+ return t.unaryExpression('!', t.callExpression(t.memberExpression(identifier, t.identifier('includes')), [operandExpr]));
701
+ }
702
+ if (operation === 'hasKey' && operand !== undefined) {
703
+ var operandExpr = resolveOperandExpression(operand, conditionalIdentifier, options);
704
+ return t.callExpression(t.memberExpression(t.memberExpression(t.memberExpression(t.identifier('Object'), t.identifier('prototype')), t.identifier('hasOwnProperty')), t.identifier('call')), [identifier, operandExpr]);
705
+ }
706
+ if (operation === 'notHasKey' && operand !== undefined) {
707
+ var operandExpr = resolveOperandExpression(operand, conditionalIdentifier, options);
708
+ return t.unaryExpression('!', t.callExpression(t.memberExpression(t.memberExpression(t.memberExpression(t.identifier('Object'), t.identifier('prototype')), t.identifier('hasOwnProperty')), t.identifier('call')), [identifier, operandExpr]));
709
+ }
710
+ // Standard binary operators
260
711
  if (operation === '===') {
261
712
  if (operand === true) {
262
713
  return identifier;
@@ -277,11 +728,17 @@ var createBinaryExpression = function (condition, conditionalIdentifier, t) {
277
728
  state: '',
278
729
  local: '',
279
730
  },
731
+ localIdentifier: options.localIdentifier,
280
732
  });
281
733
  return t.binaryExpression((0, ast_utils_1.convertToBinaryOperator)(operation), identifier, dynamicValueIdentifier);
282
734
  }
283
735
  var stateValueIdentifier = (0, ast_utils_1.convertValueToLiteral)(operand, conditionalIdentifier.type);
284
- return t.binaryExpression((0, ast_utils_1.convertToBinaryOperator)(operation), identifier, stateValueIdentifier);
736
+ var lhs = (conditionalIdentifier.referenceType === 'global' ||
737
+ conditionalIdentifier.referenceType === 'globalState') &&
738
+ typeof operand === 'string'
739
+ ? t.optionalCallExpression(t.optionalMemberExpression(identifier, t.identifier('toString'), false, true), [], false)
740
+ : identifier;
741
+ return t.binaryExpression((0, ast_utils_1.convertToBinaryOperator)(operation), lhs, stateValueIdentifier);
285
742
  }
286
743
  else {
287
744
  return operation ? t.unaryExpression((0, ast_utils_1.convertToUnaryOperator)(operation), identifier) : identifier;