routesync 1.0.40 → 1.0.42

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 (2) hide show
  1. package/dist/cli.js +139 -231
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -8361,189 +8361,25 @@ var import_path = __toESM(require("path"));
8361
8361
  var LaravelRouteParser = class {
8362
8362
  async parse(filePath, options = {}) {
8363
8363
  const projectRoot = import_path.default.resolve(import_path.default.dirname(filePath), "..");
8364
- const extractModels = options.extractModels ? "true" : "false";
8365
8364
  const phpScript = `<?php
8366
8365
  require __DIR__.'/vendor/autoload.php';
8367
8366
  $app = require_once __DIR__.'/bootstrap/app.php';
8368
- $kernel = $app->make(IlluminateContractsConsoleKernel::class);
8367
+ $kernel = $app->make(Illuminate\\Contracts\\Console\\Kernel::class);
8369
8368
  $kernel->bootstrap();
8370
8369
 
8371
- $result = ['routes' => [], 'models' => []];
8372
-
8373
- // \u2500\u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
8374
-
8375
- function rsync_get_source(ReflectionFunctionAbstract $ref): ?string {
8376
- $file = $ref->getFileName();
8377
- $start = $ref->getStartLine();
8378
- $end = $ref->getEndLine();
8379
- if (!$file || $start === false || $end === false) return null;
8380
- return implode('', array_slice(file($file), $start - 1, $end - $start + 1));
8381
- }
8382
-
8383
- /**
8384
- * Try to resolve responseMetadata from a Resource class.
8385
- * Checks (in order):
8386
- * 1. PHP 8 #[RouteSyncResponse] attribute on class
8387
- * 2. @mixin docblock
8388
- * 3. Constructor parameter type hint \u2190 NEW
8389
- * 4. $this->resource @var docblock \u2190 NEW
8390
- * 5. Strip Resource suffix \u2192 match AppModels*
8391
- * 6. toArray() field vs DB column intersection
8392
- */
8393
- function rsync_infer_from_resource(string $resourceClass, bool $collection): ?array {
8394
- if (!class_exists($resourceClass)) return null;
8395
- $resRef = new ReflectionClass($resourceClass);
8396
-
8397
- // 1. PHP 8 attribute
8398
- foreach ($resRef->getAttributes() as $attr) {
8399
- $short = class_basename($attr->getName());
8400
- if (in_array($short, ['Response', 'RouteSyncResponse'])) {
8401
- $args = $attr->getArguments();
8402
- $type = $args[0] ?? $args['type'] ?? $args['model'] ?? $args['response'] ?? null;
8403
- if ($type) return ['type' => class_basename($type), 'collection' => $collection];
8404
- }
8405
- }
8406
-
8407
- // 2. @mixin docblock
8408
- $doc = $resRef->getDocComment();
8409
- if ($doc && preg_match('/@mixins+([\\\\w]+)/', $doc, $m)) {
8410
- return ['type' => class_basename($m[1]), 'collection' => $collection];
8411
- }
8412
-
8413
- // 3. Constructor parameter type hint: __construct(User $user)
8414
- if ($resRef->hasMethod('__construct')) {
8415
- $ctor = $resRef->getMethod('__construct');
8416
- foreach ($ctor->getParameters() as $param) {
8417
- $ptype = $param->getType();
8418
- if ($ptype && !$ptype->isBuiltin()) {
8419
- $cn = $ptype->getName();
8420
- if (is_subclass_of($cn, 'IlluminateDatabaseEloquentModel')) {
8421
- return ['type' => class_basename($cn), 'collection' => $collection];
8422
- }
8423
- }
8424
- }
8425
- }
8426
-
8427
- // 4. $this->resource @var docblock in class body or toArray()
8428
- $classDoc = $resRef->getDocComment() ?: '';
8429
- foreach (['toArray', 'toResponse'] as $mname) {
8430
- if ($resRef->hasMethod($mname)) {
8431
- $src = rsync_get_source($resRef->getMethod($mname)) ?? '';
8432
- $classDoc .= $src;
8433
- }
8434
- }
8435
- if (preg_match('/@vars+([\\\\w]+)s+$(?:resource|model)/', $classDoc, $m)) {
8436
- $cn = ltrim($m[1], '\\');
8437
- $fqcn = str_contains($cn, '\\') ? $cn : 'App\\Models\\' . $cn;
8438
- if (class_exists($fqcn)) {
8439
- return ['type' => class_basename($fqcn), 'collection' => $collection];
8440
- }
8441
- }
8442
-
8443
- // 5. Strip Resource suffix \u2192 AppModels<Name>
8444
- $inferredName = preg_replace('/Resource$/', '', class_basename($resourceClass));
8445
- if ($inferredName) {
8446
- $mc = 'App\\Models\\' . $inferredName;
8447
- if (class_exists($mc)) {
8448
- return ['type' => $inferredName, 'collection' => $collection];
8449
- }
8450
- }
8451
-
8452
- // 6. toArray() field vs DB column intersection
8453
- if ($resRef->hasMethod('toArray')) {
8454
- $src = rsync_get_source($resRef->getMethod('toArray')) ?? '';
8455
- preg_match_all('/['"]([a-zA-Z0-9_]+)['"]s*=>/', $src, $km);
8456
- $resFields = array_unique($km[1] ?? []);
8457
- if (!empty($resFields)) {
8458
- $bestModel = null; $bestScore = 0;
8459
- $modelsPath = app_path('Models');
8460
- if (is_dir($modelsPath)) {
8461
- foreach (IlluminateSupportFacadesFile::allFiles($modelsPath) as $mf) {
8462
- $mn = preg_replace('/.php$/', '', $mf->getFilename());
8463
- $mc = 'App\\Models\\' . $mn;
8464
- if (!class_exists($mc)) continue;
8465
- try {
8466
- $mi = new $mc();
8467
- $cols = array_column(IlluminateSupportFacadesSchema::getColumns($mi->getTable()), 'name');
8468
- $score = count(array_intersect($resFields, $cols));
8469
- if ($score > $bestScore) { $bestScore = $score; $bestModel = $mn; }
8470
- } catch (Exception $e) {}
8471
- }
8472
- }
8473
- if ($bestModel && $bestScore > 0) {
8474
- return ['type' => $bestModel, 'collection' => $collection];
8475
- }
8476
- }
8477
- }
8478
-
8479
- return null;
8480
- }
8481
-
8482
- /**
8483
- * Try to resolve responseMetadata directly from controller method source.
8484
- * Handles cases where no Resource class is used at all.
8485
- */
8486
- function rsync_infer_from_source(?string $source): ?array {
8487
- if (!$source) return null;
8488
-
8489
- // return new SomeResource($x)
8490
- if (preg_match('/returns+news+([a-zA-Z0-9_]+Resource)s*(/', $source, $m)) {
8491
- $rc = 'App\\Http\\Resources\\' . $m[1];
8492
- $result = rsync_infer_from_resource($rc, false);
8493
- if ($result) return $result;
8494
- }
8495
-
8496
- // SomeResource::collection(...)
8497
- if (preg_match('/([a-zA-Z0-9_]+Resource)::collections*(/', $source, $m)) {
8498
- $rc = 'App\\Http\\Resources\\' . $m[1];
8499
- $result = rsync_infer_from_resource($rc, true);
8500
- if ($result) return $result;
8501
- }
8502
-
8503
- // ->paginate() or ->simplePaginate() with Resource
8504
- if (preg_match('/([a-zA-Z0-9_]+Resource)::collection.*paginate/s', $source, $m)) {
8505
- $rc = 'App\\Http\\Resources\\' . $m[1];
8506
- $result = rsync_infer_from_resource($rc, true);
8507
- if ($result) { $result['paginated'] = true; return $result; }
8508
- }
8509
-
8510
- // response()->json(['token' => ..., 'user' => ...]) \u2014 inline array
8511
- // Extract top-level keys and try to match a model
8512
- if (preg_match('/response()s*->s*jsons*(s*[([^]]{0,800})]/', $source, $jsonMatch)) {
8513
- preg_match_all('/['"]([a-zA-Z0-9_]+)['"]s*=>/', $jsonMatch[1], $km);
8514
- $keys = array_unique($km[1] ?? []);
8515
- if (!empty($keys)) {
8516
- $bestModel = null; $bestScore = 0;
8517
- foreach (IlluminateSupportFacadesFile::allFiles(app_path('Models')) as $mf) {
8518
- $mn = preg_replace('/.php$/', '', $mf->getFilename());
8519
- $mc = 'App\\Models\\' . $mn;
8520
- if (!class_exists($mc)) continue;
8521
- try {
8522
- $mi = new $mc();
8523
- $cols = array_column(IlluminateSupportFacadesSchema::getColumns($mi->getTable()), 'name');
8524
- $camelCols = array_map(fn($c) => lcfirst(str_replace('_', '', ucwords($c, '_'))), $cols);
8525
- $score = count(array_intersect($keys, array_merge($cols, $camelCols)));
8526
- if ($score > $bestScore) { $bestScore = $score; $bestModel = $mn; }
8527
- } catch (Exception $e) {}
8528
- }
8529
- if ($bestModel && $bestScore >= 2) {
8530
- return ['type' => $bestModel, 'collection' => false];
8531
- }
8532
- }
8533
- }
8534
-
8535
- return null;
8536
- }
8537
-
8538
- // \u2500\u2500\u2500 Main Route Loop \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
8370
+ $result = [
8371
+ 'routes' => [],
8372
+ 'models' => []
8373
+ ];
8539
8374
 
8375
+ // Extract Routes
8540
8376
  $routes = app('router')->getRoutes();
8541
8377
  foreach ($routes as $route) {
8542
8378
  if (!str_starts_with($route->uri(), 'api/')) continue;
8543
-
8379
+
8544
8380
  $methods = array_diff($route->methods(), ['HEAD']);
8545
8381
  $middlewares = $route->gatherMiddleware();
8546
-
8382
+
8547
8383
  $auth = false;
8548
8384
  foreach ($middlewares as $mw) {
8549
8385
  if (is_string($mw) && (str_contains($mw, 'auth') || str_contains($mw, 'sanctum'))) {
@@ -8552,21 +8388,17 @@ foreach ($routes as $route) {
8552
8388
  }
8553
8389
 
8554
8390
  $schema = [];
8555
- $responseMetadata = null;
8556
8391
  $action = $route->getAction();
8557
-
8558
8392
  if (isset($action['uses']) && is_string($action['uses']) && str_contains($action['uses'], '@')) {
8559
8393
  list($controller, $method) = explode('@', $action['uses']);
8560
8394
  if (class_exists($controller)) {
8561
8395
  try {
8562
8396
  $reflector = new ReflectionMethod($controller, $method);
8563
-
8564
- // \u2500\u2500 Request schema from FormRequest \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
8565
8397
  foreach ($reflector->getParameters() as $param) {
8566
8398
  $type = $param->getType();
8567
8399
  if ($type && !$type->isBuiltin()) {
8568
8400
  $className = $type->getName();
8569
- if (is_subclass_of($className, 'IlluminateFoundationHttpFormRequest')) {
8401
+ if (is_subclass_of($className, 'Illuminate\\Foundation\\Http\\FormRequest')) {
8570
8402
  $request = new $className();
8571
8403
  if (method_exists($request, 'rules')) {
8572
8404
  $schema = $request->rules();
@@ -8574,97 +8406,174 @@ foreach ($routes as $route) {
8574
8406
  }
8575
8407
  }
8576
8408
  }
8577
-
8578
- // \u2500\u2500 Stage 1: PHP 8 Attribute on controller method \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
8579
- foreach ($reflector->getAttributes() as $attr) {
8580
- $short = class_basename($attr->getName());
8581
- if (in_array($short, ['Response', 'RouteSyncResponse'])) {
8409
+
8410
+ // Parse PHP 8 Attributes for Response Metadata
8411
+ $responseMetadata = null;
8412
+ $attributes = $reflector->getAttributes();
8413
+ foreach ($attributes as $attr) {
8414
+ $attrName = $attr->getName();
8415
+ $shortName = class_basename($attrName);
8416
+
8417
+ if (in_array($shortName, ['Response', 'RouteSyncResponse'])) {
8582
8418
  $args = $attr->getArguments();
8583
- $type = $args[0] ?? $args['type'] ?? $args['model'] ?? $args['response'] ?? null;
8419
+
8420
+ $type = null;
8421
+ if (isset($args[0])) {
8422
+ $type = $args[0];
8423
+ } elseif (isset($args['type'])) {
8424
+ $type = $args['type'];
8425
+ } elseif (isset($args['model'])) {
8426
+ $type = $args['model'];
8427
+ } elseif (isset($args['response'])) {
8428
+ $type = $args['response'];
8429
+ }
8430
+
8431
+ $collection = false;
8432
+ if (isset($args[1])) {
8433
+ $collection = (bool) $args[1];
8434
+ } elseif (isset($args['collection'])) {
8435
+ $collection = (bool) $args['collection'];
8436
+ }
8437
+
8584
8438
  if ($type) {
8585
- $collection = (bool)($args[1] ?? $args['collection'] ?? false);
8586
- $responseMetadata = ['type' => class_basename($type), 'collection' => $collection];
8439
+ $responseMetadata = [
8440
+ 'type' => class_basename($type),
8441
+ 'collection' => $collection
8442
+ ];
8587
8443
  break;
8588
8444
  }
8589
8445
  }
8590
8446
  }
8591
-
8592
- $methodSource = rsync_get_source($reflector);
8593
-
8594
- // \u2500\u2500 Stage 2: Source-based inference \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
8595
- if (!$responseMetadata) {
8596
- $responseMetadata = rsync_infer_from_source($methodSource);
8447
+
8448
+
8449
+ $fileName = $reflector->getFileName();
8450
+ $startLine = $reflector->getStartLine();
8451
+ $endLine = $reflector->getEndLine();
8452
+ $methodSource = null;
8453
+
8454
+ if ($fileName && $startLine !== false && $endLine !== false) {
8455
+ $lines = file($fileName);
8456
+ $methodSource = implode("", array_slice($lines, $startLine - 1, $endLine - $startLine + 1));
8597
8457
  }
8598
8458
 
8599
- // \u2500\u2500 Stage 3: Fallback $request->validate([...]) for schema \u2500\u2500
8459
+ // Resource Discovery
8460
+ if (!$responseMetadata && $methodSource) {
8461
+ $resourceName = null;
8462
+ $collection = false;
8463
+
8464
+ if (preg_match('/return\\s+new\\s+([a-zA-Z0-9_]+Resource)/', $methodSource, $matches)) {
8465
+ $resourceName = $matches[1];
8466
+ } elseif (preg_match('/return\\s+([a-zA-Z0-9_]+Resource)::collection/', $methodSource, $matches)) {
8467
+ $resourceName = $matches[1];
8468
+ $collection = true;
8469
+ }
8470
+
8471
+ if ($resourceName) {
8472
+ $resourceClass = 'App\\\\Http\\\\Resources\\\\' . $resourceName;
8473
+ if (class_exists($resourceClass)) {
8474
+ $resReflector = new ReflectionClass($resourceClass);
8475
+ $resAttrs = $resReflector->getAttributes();
8476
+ foreach ($resAttrs as $attr) {
8477
+ $shortName = class_basename($attr->getName());
8478
+ if (in_array($shortName, ['Response', 'RouteSyncResponse'])) {
8479
+ $args = $attr->getArguments();
8480
+ $type = $args[0] ?? $args['type'] ?? $args['model'] ?? $args['response'] ?? null;
8481
+ if ($type) {
8482
+ $responseMetadata = [
8483
+ 'type' => class_basename($type),
8484
+ 'collection' => $collection
8485
+ ];
8486
+ }
8487
+ }
8488
+ }
8489
+
8490
+ if (!$responseMetadata) {
8491
+ $docComment = $resReflector->getDocComment();
8492
+ if ($docComment && preg_match('/@mixin\\s+([\\\\\\\\a-zA-Z0-9_]+)/', $docComment, $mixinMatches)) {
8493
+ $responseMetadata = [
8494
+ 'type' => class_basename($mixinMatches[1]),
8495
+ 'collection' => $collection
8496
+ ];
8497
+ }
8498
+ }
8499
+ }
8500
+ }
8501
+ }
8502
+
8503
+ // Fallback: Try to parse $request->validate([...]) from source code
8600
8504
  if (empty($schema) && $methodSource) {
8601
- if (preg_match('/$request->validates*(s*[(.*?)]s*)/s', $methodSource, $vm)) {
8602
- preg_match_all('/['"]([a-zA-Z0-9_.*]+)['"]s*=>s*['"]([^'"]*)['"]/', $vm[1], $rm);
8603
- foreach ($rm[1] as $i => $field) {
8604
- $schema[$field] = $rm[2][$i];
8505
+ // Look for $request->validate([ ... ])
8506
+ if (preg_match('/\\\\$request->validate\\\\s*\\\\(\\\\s*\\\\[(.*?)\\\\]\\\\s*\\\\)/s', $methodSource, $matches)) {
8507
+ $rulesString = $matches[1];
8508
+ // Match 'field' => 'rules'
8509
+ preg_match_all('~[\\'"]([a-zA-Z0-9_.*]+)[\\'"]\\\\s*=>\\\\s*[\\'"](.*?)[\\'"]~', $rulesString, $ruleMatches);
8510
+ if (!empty($ruleMatches[1])) {
8511
+ foreach ($ruleMatches[1] as $index => $field) {
8512
+ $schema[$field] = $ruleMatches[2][$index];
8513
+ }
8605
8514
  }
8606
8515
  }
8607
8516
  }
8608
-
8609
- } catch (Exception $e) {}
8517
+ } catch (\\Exception $e) {}
8610
8518
  }
8611
8519
  }
8612
8520
 
8613
8521
  foreach ($methods as $method) {
8614
- $nameParts = explode('/', preg_replace('/^api//', '', $route->uri()));
8615
- $resource = preg_replace('/{.*}/', '', $nameParts[0]);
8522
+ $nameParts = explode('/', preg_replace('/^api\\//', '', $route->uri()));
8523
+ $resource = preg_replace('/\\{.*\\}/', '', $nameParts[0]);
8616
8524
  if (empty($resource)) $resource = 'api';
8617
-
8525
+
8526
+ $name = $resource . '.' . strtolower($method);
8527
+
8618
8528
  $result['routes'][] = [
8619
- 'name' => $route->getName() ?: ($resource . '.' . strtolower($method)),
8620
- 'method' => $method,
8621
- 'path' => '/' . preg_replace('/^api//', '', $route->uri()),
8622
- 'auth' => $auth,
8529
+ 'name' => $route->getName() ?: $name,
8530
+ 'method' => $method,
8531
+ 'path' => '/' . preg_replace('/^api\\//', '', $route->uri()),
8532
+ 'auth' => $auth,
8623
8533
  'middleware' => $middlewares,
8624
- 'schema' => empty($schema) ? null : ['rules' => $schema],
8625
- 'response' => $responseMetadata,
8534
+ 'schema' => empty($schema) ? null : ['rules' => $schema],
8535
+ 'response' => $responseMetadata
8626
8536
  ];
8627
8537
  }
8628
8538
  }
8629
8539
 
8630
- // \u2500\u2500\u2500 Extract Models \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
8631
-
8632
- $extractModels = ${extractModels};
8540
+ // Extract Models if requested
8541
+ $extractModels = ${options.extractModels ? "true" : "false"};
8633
8542
  if ($extractModels) {
8634
8543
  $modelsPath = app_path('Models');
8635
8544
  if (is_dir($modelsPath)) {
8636
- $files = IlluminateSupportFacadesFile::allFiles($modelsPath);
8545
+ $files = \\Illuminate\\Support\\Facades\\File::allFiles($modelsPath);
8637
8546
  foreach ($files as $file) {
8638
- $class = 'App\\Models\\' . str_replace('/', '\\', $file->getRelativePathname());
8639
- $class = preg_replace('/.php$/', '', $class);
8640
-
8641
- if (class_exists($class) && is_subclass_of($class, 'Illuminate\\Database\\Eloquent\\Model')) {
8547
+ $class = 'App\\\\Models\\\\' . str_replace('/', '\\\\', $file->getRelativePathname());
8548
+ $class = preg_replace('/\\.php$/', '', $class);
8549
+
8550
+ if (class_exists($class) && is_subclass_of($class, 'Illuminate\\\\Database\\\\Eloquent\\\\Model')) {
8642
8551
  try {
8643
8552
  $reflection = new ReflectionClass($class);
8644
8553
  if ($reflection->isAbstract()) continue;
8645
-
8646
- $model = new $class();
8647
- $table = $model->getTable();
8648
- $columns = IlluminateSupportFacadesSchema::getColumns($table);
8649
-
8554
+
8555
+ $model = new $class();
8556
+ $table = $model->getTable();
8557
+ $columns = \\Illuminate\\Support\\Facades\\Schema::getColumns($table);
8558
+
8650
8559
  $parsedColumns = [];
8651
8560
  foreach ($columns as $col) {
8652
8561
  $parsedColumns[] = [
8653
- 'name' => $col['name'],
8654
- 'type' => $col['type'],
8655
- 'nullable' => $col['nullable'],
8562
+ 'name' => $col['name'],
8563
+ 'type' => $col['type'], // Use 'type' which contains the raw type like enum('a','b') instead of 'type_name'
8564
+ 'nullable' => $col['nullable']
8656
8565
  ];
8657
8566
  }
8658
-
8567
+
8659
8568
  $result['models'][] = [
8660
- 'name' => class_basename($class),
8661
- 'table' => $table,
8569
+ 'name' => class_basename($class),
8570
+ 'table' => $table,
8662
8571
  'columns' => $parsedColumns,
8663
- 'hidden' => $model->getHidden(),
8572
+ 'hidden' => $model->getHidden(),
8664
8573
  'appends' => $model->getAppends(),
8665
- 'casts' => $model->getCasts(),
8574
+ 'casts' => $model->getCasts()
8666
8575
  ];
8667
- } catch (Exception $e) {}
8576
+ } catch (\\Exception $e) {}
8668
8577
  }
8669
8578
  }
8670
8579
  }
@@ -9582,7 +9491,6 @@ var watchCommand = new Command("watch").description("Watch routes file and re-sy
9582
9491
  var import_child_process2 = require("child_process");
9583
9492
  var import_fs_extra16 = __toESM(require_lib());
9584
9493
  var import_path12 = __toESM(require("path"));
9585
- var import_os = __toESM(require("os"));
9586
9494
  var annotateCommand = new Command("annotate").description("Auto-inject #[Response] PHP 8 attributes into controller methods based on Resource discovery").option("--input <file>", "Path to routes/api.php", "routes/api.php").option("--dry-run", "Preview changes without writing files").option("--force", "Re-annotate methods that already have #[Response]").action(async (options) => {
9587
9495
  const filePath = import_path12.default.resolve(options.input);
9588
9496
  if (!import_fs_extra16.default.existsSync(filePath)) {
@@ -9717,7 +9625,7 @@ foreach ($routes as $route) {
9717
9625
 
9718
9626
  echo json_encode($result);
9719
9627
  `;
9720
- const tmpFile = import_path12.default.join(import_os.default.tmpdir(), `routesync-annotate-${Date.now()}.php`);
9628
+ const tmpFile = import_path12.default.join(projectRoot, `routesync-annotate-${Date.now()}.php`);
9721
9629
  import_fs_extra16.default.writeFileSync(tmpFile, phpScript);
9722
9630
  let annotations;
9723
9631
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "routesync",
3
- "version": "1.0.40",
3
+ "version": "1.0.42",
4
4
  "description": "Laravel routes to typed frontend SDKs.",
5
5
  "main": "./dist/sdk.js",
6
6
  "module": "./dist/sdk.mjs",