rampkit-expo-dev 0.0.43 → 0.0.45

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.
@@ -424,9 +424,190 @@ function preloadRampkitOverlay(opts) {
424
424
  // best-effort preloading; ignore errors
425
425
  }
426
426
  }
427
+ /**
428
+ * Decode HTML entities in a string
429
+ */
430
+ function decodeHtmlEntities(str) {
431
+ return str
432
+ .replace(/"/g, '"')
433
+ .replace(/"/g, '"')
434
+ .replace(/"/g, '"')
435
+ .replace(/'/g, "'")
436
+ .replace(/'/g, "'")
437
+ .replace(/'/g, "'")
438
+ .replace(/&lt;/g, '<')
439
+ .replace(/&gt;/g, '>')
440
+ .replace(/&amp;/g, '&');
441
+ }
442
+ /**
443
+ * Evaluate a comparison condition against variables
444
+ * Supports: ==, !=, >, <, >=, <=, and truthy checks
445
+ */
446
+ function evaluateCondition(condition, vars) {
447
+ condition = decodeHtmlEntities(condition.trim());
448
+ // Match comparison operators: ==, !=, >=, <=, >, <
449
+ const comparisonMatch = condition.match(/^([A-Za-z_][A-Za-z0-9_.]*)\s*(==|!=|>=|<=|>|<)\s*(.+)$/);
450
+ if (comparisonMatch) {
451
+ const [, varName, operator, rawRight] = comparisonMatch;
452
+ const leftValue = vars.hasOwnProperty(varName) ? vars[varName] : undefined;
453
+ let rightValue = decodeHtmlEntities(rawRight.trim());
454
+ // Parse right side - could be a quoted string or a number or a variable
455
+ if ((rightValue.startsWith('"') && rightValue.endsWith('"')) ||
456
+ (rightValue.startsWith("'") && rightValue.endsWith("'"))) {
457
+ // Quoted string literal - strip the quotes
458
+ rightValue = rightValue.slice(1, -1);
459
+ }
460
+ else if (!isNaN(Number(rightValue))) {
461
+ // Numeric literal
462
+ rightValue = Number(rightValue);
463
+ }
464
+ else if (rightValue === "true") {
465
+ rightValue = true;
466
+ }
467
+ else if (rightValue === "false") {
468
+ rightValue = false;
469
+ }
470
+ else if (rightValue === "null") {
471
+ rightValue = null;
472
+ }
473
+ else if (vars.hasOwnProperty(rightValue)) {
474
+ // Variable reference
475
+ rightValue = vars[rightValue];
476
+ }
477
+ // Perform comparison
478
+ switch (operator) {
479
+ case "==":
480
+ return leftValue == rightValue;
481
+ case "!=":
482
+ return leftValue != rightValue;
483
+ case ">":
484
+ return Number(leftValue) > Number(rightValue);
485
+ case "<":
486
+ return Number(leftValue) < Number(rightValue);
487
+ case ">=":
488
+ return Number(leftValue) >= Number(rightValue);
489
+ case "<=":
490
+ return Number(leftValue) <= Number(rightValue);
491
+ default:
492
+ return false;
493
+ }
494
+ }
495
+ // Truthy check - just the variable name
496
+ const varName = condition.trim();
497
+ if (vars.hasOwnProperty(varName)) {
498
+ const value = vars[varName];
499
+ // Consider empty string as falsy
500
+ if (value === "")
501
+ return false;
502
+ return !!value;
503
+ }
504
+ // Unknown variable - treat as falsy
505
+ return false;
506
+ }
507
+ /**
508
+ * Parse a ternary value (the part after ? or after :)
509
+ * Returns the resolved value, handling both quoted strings and variable references
510
+ */
511
+ function parseTernaryValue(value, vars) {
512
+ value = decodeHtmlEntities(value.trim());
513
+ // Check if it's a quoted string (double quotes)
514
+ if (value.startsWith('"') && value.endsWith('"') && value.length >= 2) {
515
+ return value.slice(1, -1);
516
+ }
517
+ // Check if it's a quoted string (single quotes)
518
+ if (value.startsWith("'") && value.endsWith("'") && value.length >= 2) {
519
+ return value.slice(1, -1);
520
+ }
521
+ // Otherwise treat as a variable reference
522
+ if (vars.hasOwnProperty(value)) {
523
+ const varValue = vars[value];
524
+ if (varValue === undefined || varValue === null)
525
+ return "";
526
+ if (typeof varValue === "boolean")
527
+ return varValue ? "true" : "false";
528
+ if (typeof varValue === "object")
529
+ return JSON.stringify(varValue);
530
+ return String(varValue);
531
+ }
532
+ // Return as-is if not found (could be a literal like a number)
533
+ return value;
534
+ }
535
+ /**
536
+ * Parse a ternary expression and find the colon that separates true/false values
537
+ * Handles nested quotes properly (including HTML-encoded quotes)
538
+ */
539
+ function splitTernary(expr) {
540
+ // First decode HTML entities to normalize the expression
541
+ const decodedExpr = decodeHtmlEntities(expr);
542
+ // Find the ? that starts the ternary
543
+ let questionIdx = -1;
544
+ let inQuote = false;
545
+ let quoteChar = "";
546
+ for (let i = 0; i < decodedExpr.length; i++) {
547
+ const char = decodedExpr[i];
548
+ const prevChar = i > 0 ? decodedExpr[i - 1] : "";
549
+ if ((char === '"' || char === "'") && prevChar !== "\\") {
550
+ if (!inQuote) {
551
+ inQuote = true;
552
+ quoteChar = char;
553
+ }
554
+ else if (char === quoteChar) {
555
+ inQuote = false;
556
+ }
557
+ }
558
+ if (!inQuote && char === "?") {
559
+ questionIdx = i;
560
+ break;
561
+ }
562
+ }
563
+ if (questionIdx === -1)
564
+ return null;
565
+ const condition = decodedExpr.slice(0, questionIdx).trim();
566
+ const rest = decodedExpr.slice(questionIdx + 1);
567
+ // Find the : that separates true/false values
568
+ let colonIdx = -1;
569
+ inQuote = false;
570
+ quoteChar = "";
571
+ for (let i = 0; i < rest.length; i++) {
572
+ const char = rest[i];
573
+ const prevChar = i > 0 ? rest[i - 1] : "";
574
+ if ((char === '"' || char === "'") && prevChar !== "\\") {
575
+ if (!inQuote) {
576
+ inQuote = true;
577
+ quoteChar = char;
578
+ }
579
+ else if (char === quoteChar) {
580
+ inQuote = false;
581
+ }
582
+ }
583
+ if (!inQuote && char === ":") {
584
+ colonIdx = i;
585
+ break;
586
+ }
587
+ }
588
+ if (colonIdx === -1)
589
+ return null;
590
+ const trueValue = rest.slice(0, colonIdx).trim();
591
+ const falseValue = rest.slice(colonIdx + 1).trim();
592
+ return { condition, trueValue, falseValue };
593
+ }
427
594
  /**
428
595
  * Resolve device/user templates in a string
429
- * Replaces ${device.xxx} and ${user.xxx} with actual values from context
596
+ * Supports both simple variables ${varName} and conditional ternary expressions
597
+ * ${condition ? "trueValue" : "falseValue"}
598
+ *
599
+ * Supported operators in conditions:
600
+ * - == (equals)
601
+ * - != (not equals)
602
+ * - > (greater than)
603
+ * - < (less than)
604
+ * - >= (greater or equal)
605
+ * - <= (less or equal)
606
+ * - Truthy check (just variable name)
607
+ *
608
+ * Values can be:
609
+ * - Quoted strings: "hello" or 'hello'
610
+ * - Variable references: username
430
611
  */
431
612
  function resolveContextTemplates(text, context) {
432
613
  if (!text || !text.includes("${"))
@@ -446,8 +627,23 @@ function resolveContextTemplates(text, context) {
446
627
  });
447
628
  }
448
629
  console.log("[RampKit] Resolving templates with vars:", JSON.stringify(vars));
449
- // Replace ${varName} patterns
450
- return text.replace(/\$\{([A-Za-z_][A-Za-z0-9_.]*)\}/g, (match, varName) => {
630
+ // Match ${...} expressions - use a more permissive regex to capture full expressions
631
+ // including ternary operators with quotes
632
+ return text.replace(/\$\{([^}]+)\}/g, (match, innerExpr) => {
633
+ const expr = innerExpr.trim();
634
+ // Check if this is a ternary expression
635
+ const ternary = splitTernary(expr);
636
+ if (ternary) {
637
+ const { condition, trueValue, falseValue } = ternary;
638
+ const result = evaluateCondition(condition, vars);
639
+ const value = result
640
+ ? parseTernaryValue(trueValue, vars)
641
+ : parseTernaryValue(falseValue, vars);
642
+ console.log(`[RampKit] Ternary: ${condition} ? ${trueValue} : ${falseValue} => ${result} => "${value}"`);
643
+ return value;
644
+ }
645
+ // Simple variable substitution
646
+ const varName = expr;
451
647
  if (vars.hasOwnProperty(varName)) {
452
648
  const value = vars[varName];
453
649
  console.log(`[RampKit] Replacing ${match} with:`, value);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rampkit-expo-dev",
3
- "version": "0.0.43",
3
+ "version": "0.0.45",
4
4
  "description": "The Expo SDK for RampKit. Build, test, and personalize app onboardings with instant updates.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",