create-prisma-php-app 3.0.1 → 3.0.3

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.
@@ -17,10 +17,19 @@ use LibXMLError;
17
17
  use DOMXPath;
18
18
  use ReflectionClass;
19
19
  use ReflectionProperty;
20
+ use ReflectionType;
21
+ use ReflectionNamedType;
20
22
 
21
23
  class TemplateCompiler
22
24
  {
23
25
  protected const BINDING_REGEX = '/\{\{\s*((?:(?!\{\{|\}\})[\s\S])*?)\s*\}\}/uS';
26
+ private const LITERAL_TEXT_TAGS = [
27
+ 'code' => true,
28
+ 'pre' => true,
29
+ 'samp' => true,
30
+ 'kbd' => true,
31
+ 'var' => true,
32
+ ];
24
33
 
25
34
  protected static array $classMappings = [];
26
35
  protected static array $selfClosingTags = [
@@ -141,23 +150,22 @@ class TemplateCompiler
141
150
 
142
151
  public static function convertToXml(string $templateContent): DOMDocument
143
152
  {
144
- $templateContent = self::protectInlineScripts($templateContent);
145
- $templateContent = self::normalizeNamedEntities($templateContent);
153
+ $content = self::protectInlineScripts($templateContent);
154
+ $content = self::normalizeNamedEntities($content);
146
155
 
147
- $templateContent = self::escapeMustacheAngles(
148
- self::escapeAttributeAngles(
149
- self::escapeAmpersands($templateContent)
150
- )
151
- );
156
+ $content = self::escapeAmpersands($content);
157
+ $content = self::escapeAttributeAngles($content);
158
+ $content = self::escapeMustacheAngles($content);
152
159
 
153
- $dom = new DOMDocument();
154
- libxml_use_internal_errors(true);
160
+ $xml = "<root>{$content}</root>";
155
161
 
156
- if (!$dom->loadXML("<root>{$templateContent}</root>")) {
157
- $errors = self::getXmlErrors();
158
- throw new RuntimeException("XML Parsing Failed: " . implode("; ", $errors));
162
+ $dom = new DOMDocument('1.0', 'UTF-8');
163
+ libxml_use_internal_errors(true);
164
+ if (!$dom->loadXML($xml, LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_NONET)) {
165
+ throw new RuntimeException(
166
+ 'XML Parsing Failed: ' . implode('; ', self::getXmlErrors())
167
+ );
159
168
  }
160
-
161
169
  libxml_clear_errors();
162
170
  libxml_use_internal_errors(false);
163
171
  return $dom;
@@ -309,6 +317,15 @@ class TemplateCompiler
309
317
 
310
318
  private static function processTextNode(DOMText $node): string
311
319
  {
320
+ $parent = strtolower($node->parentNode?->nodeName ?? '');
321
+ if (isset(self::LITERAL_TEXT_TAGS[$parent])) {
322
+ return htmlspecialchars(
323
+ $node->textContent,
324
+ ENT_NOQUOTES | ENT_SUBSTITUTE,
325
+ 'UTF-8'
326
+ );
327
+ }
328
+
312
329
  return preg_replace_callback(
313
330
  self::BINDING_REGEX,
314
331
  fn($m) => self::processBindingExpression(trim($m[1])),
@@ -528,9 +545,12 @@ class TemplateCompiler
528
545
 
529
546
  foreach (self::$publicProperties[$className] as $prop) {
530
547
  $name = $prop->getName();
531
- if (array_key_exists($name, $attributes)) {
532
- $inst->$name = $attributes[$name];
548
+
549
+ if (!array_key_exists($name, $attributes)) {
550
+ continue;
533
551
  }
552
+ $value = self::coerce($attributes[$name], $prop->getType());
553
+ $prop->setValue($inst, $value);
534
554
  }
535
555
 
536
556
  if ($ctor) {
@@ -540,6 +560,52 @@ class TemplateCompiler
540
560
  return $inst;
541
561
  }
542
562
 
563
+ private static function coerce(mixed $value, ?ReflectionType $type): mixed
564
+ {
565
+ if (!$type instanceof ReflectionNamedType || $type->isBuiltin() === false) {
566
+ return $value;
567
+ }
568
+
569
+ $name = $type->getName();
570
+ if ($value === '' && $name === 'bool') return true;
571
+
572
+ return match ($name) {
573
+ 'bool' => filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false,
574
+ 'int' => (int) $value,
575
+ 'float' => (float) $value,
576
+ 'array' => self::toArray($value),
577
+
578
+ default => $value,
579
+ };
580
+ }
581
+
582
+ private static function toArray(mixed $v): array
583
+ {
584
+ if (is_array($v)) {
585
+ return $v;
586
+ }
587
+ if (is_string($v)) {
588
+ $decoded = json_decode($v, true);
589
+ if (is_array($decoded)) {
590
+ return $decoded;
591
+ }
592
+ if (str_contains($v, ',')) {
593
+ return array_map('trim', explode(',', $v));
594
+ }
595
+ return [$decoded ?? self::coerceScalarString($v)];
596
+ }
597
+ return [$v];
598
+ }
599
+
600
+ private static function coerceScalarString(string $s): mixed
601
+ {
602
+ return match (strtolower($s)) {
603
+ 'true' => true,
604
+ 'false' => false,
605
+ default => $s,
606
+ };
607
+ }
608
+
543
609
  protected static function initializeClassMappings(): void
544
610
  {
545
611
  foreach (PrismaPHPSettings::$classLogFiles as $tag => $cls) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-prisma-php-app",
3
- "version": "3.0.1",
3
+ "version": "3.0.3",
4
4
  "description": "Prisma-PHP: A Revolutionary Library Bridging PHP with Prisma ORM",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",