|
13 | 13 | --- - Aliased requests only accessible via #alias.Name, not bare #Name |
14 | 14 | --- - Bare import name collisions: later overrides earlier (warning) |
15 | 15 | local state = require("poste.state") |
| 16 | +local request_vars = require("poste.http.request_vars") |
16 | 17 |
|
17 | 18 | local M = {} |
18 | 19 |
|
@@ -475,81 +476,88 @@ function M.execute_run_directive(opts, callback) |
475 | 476 | local block_end = find_block_end(content, opts.line) |
476 | 477 | local orig_block_end = block_end -- original bounds for post-script on original content |
477 | 478 |
|
478 | | - -- Process pre-script from target block |
479 | | - local modified_content, injected_count = process_target_pre_script(content, opts.line, block_end) |
480 | | - block_end = block_end + injected_count |
| 479 | + -- Resolve request variable dependencies in target block first. |
| 480 | + -- This executes any uncached {{Name.response.body.*}} refs pointing to |
| 481 | + -- requests in the same file, then substitutes their values before proceeding. |
| 482 | + request_vars.resolve_content_dependencies(binary, opts.path, state.current_env, content, opts.line, function(dep_resolved_content) |
| 483 | + -- Process pre-script from target block (on dependency-resolved content) |
| 484 | + local modified_content, injected_count = process_target_pre_script(dep_resolved_content, opts.line, block_end) |
| 485 | + block_end = block_end + injected_count |
| 486 | + |
| 487 | + -- Apply variable overrides if specified |
| 488 | + if opts.vars and next(opts.vars) then |
| 489 | + opts.line = opts.line + injected_count |
| 490 | + modified_content = M.apply_variable_overrides(modified_content, opts.line, opts.vars) |
| 491 | + end |
481 | 492 |
|
482 | | - -- Apply variable overrides if specified |
483 | | - if opts.vars and next(opts.vars) then |
484 | | - opts.line = opts.line + injected_count |
485 | | - modified_content = M.apply_variable_overrides(modified_content, opts.line, opts.vars) |
486 | | - end |
| 493 | + local cmd = string.format("%s run %s --line %d --env %s --json --stdin", |
| 494 | + vim.fn.shellescape(binary), |
| 495 | + vim.fn.shellescape(opts.path), |
| 496 | + opts.line, |
| 497 | + vim.fn.shellescape(state.current_env) |
| 498 | + ) |
| 499 | + |
| 500 | + state.log("INFO", string.format("import run: %s", cmd)) |
| 501 | + |
| 502 | + local stdout_buf = {} |
| 503 | + local stderr_buf = {} |
| 504 | + |
| 505 | + local job_id = vim.fn.jobstart(cmd, { |
| 506 | + stdin = "pipe", |
| 507 | + stdout_buffered = true, |
| 508 | + stderr_buffered = true, |
| 509 | + on_stdout = function(_, data) |
| 510 | + if not data then return end |
| 511 | + for _, line in ipairs(data) do |
| 512 | + if line ~= "" then table.insert(stdout_buf, line) end |
| 513 | + end |
| 514 | + end, |
| 515 | + on_stderr = function(_, data) |
| 516 | + if not data then return end |
| 517 | + for _, line in ipairs(data) do |
| 518 | + if line ~= "" then table.insert(stderr_buf, line) end |
| 519 | + end |
| 520 | + end, |
| 521 | + on_exit = function(_, code) |
| 522 | + if code ~= 0 then |
| 523 | + vim.schedule(function() |
| 524 | + vim.notify(string.format("run directive failed (exit %d): %s", code, |
| 525 | + table.concat(stderr_buf, "\n")), vim.log.levels.ERROR, { title = "Poste" }) |
| 526 | + if callback then callback(false, { |
| 527 | + status = 0, |
| 528 | + status_text = "Failed (exit " .. code .. ")", |
| 529 | + body = table.concat(stderr_buf, "\n"), |
| 530 | + }) end |
| 531 | + end) |
| 532 | + return |
| 533 | + end |
487 | 534 |
|
488 | | - local cmd = string.format("%s run %s --line %d --env %s --json --stdin", |
489 | | - vim.fn.shellescape(binary), |
490 | | - vim.fn.shellescape(opts.path), |
491 | | - opts.line, |
492 | | - vim.fn.shellescape(state.current_env) |
493 | | - ) |
494 | | - |
495 | | - state.log("INFO", string.format("import run: %s", cmd)) |
496 | | - |
497 | | - local stdout_buf = {} |
498 | | - local stderr_buf = {} |
499 | | - |
500 | | - local job_id = vim.fn.jobstart(cmd, { |
501 | | - stdin = "pipe", |
502 | | - stdout_buffered = true, |
503 | | - stderr_buffered = true, |
504 | | - on_stdout = function(_, data) |
505 | | - if not data then return end |
506 | | - for _, line in ipairs(data) do |
507 | | - if line ~= "" then table.insert(stdout_buf, line) end |
508 | | - end |
509 | | - end, |
510 | | - on_stderr = function(_, data) |
511 | | - if not data then return end |
512 | | - for _, line in ipairs(data) do |
513 | | - if line ~= "" then table.insert(stderr_buf, line) end |
514 | | - end |
515 | | - end, |
516 | | - on_exit = function(_, code) |
517 | | - if code ~= 0 then |
518 | | - vim.schedule(function() |
519 | | - vim.notify(string.format("run directive failed (exit %d): %s", code, |
520 | | - table.concat(stderr_buf, "\n")), vim.log.levels.ERROR, { title = "Poste" }) |
| 535 | + local stdout_text = table.concat(stdout_buf, "\n") |
| 536 | + local ok, parsed = pcall(vim.json.decode, stdout_text) |
| 537 | + if ok and type(parsed) == "table" then |
| 538 | + -- Run target block's post-script (so client.global.set() persists) |
| 539 | + process_target_post_script(parsed, content, opts.line, orig_block_end) |
| 540 | + -- Cache the response for cross-request variable resolution |
| 541 | + request_vars.cache_response(opts.request_name, parsed) |
| 542 | + if callback then callback(true, parsed) end |
| 543 | + else |
521 | 544 | if callback then callback(false, { |
522 | 545 | status = 0, |
523 | | - status_text = "Failed (exit " .. code .. ")", |
524 | | - body = table.concat(stderr_buf, "\n"), |
| 546 | + status_text = "JSON parse failed", |
| 547 | + body = stdout_text, |
525 | 548 | }) end |
526 | | - end) |
527 | | - return |
528 | | - end |
529 | | - |
530 | | - local stdout_text = table.concat(stdout_buf, "\n") |
531 | | - local ok, parsed = pcall(vim.json.decode, stdout_text) |
532 | | - if ok and type(parsed) == "table" then |
533 | | - -- Run target block's post-script (so client.global.set() persists) |
534 | | - process_target_post_script(parsed, content, opts.line, orig_block_end) |
535 | | - if callback then callback(true, parsed) end |
536 | | - else |
537 | | - if callback then callback(false, { |
538 | | - status = 0, |
539 | | - status_text = "JSON parse failed", |
540 | | - body = stdout_text, |
541 | | - }) end |
542 | | - end |
543 | | - end, |
544 | | - }) |
| 549 | + end |
| 550 | + end, |
| 551 | + }) |
545 | 552 |
|
546 | | - if job_id > 0 then |
547 | | - vim.fn.chansend(job_id, modified_content) |
548 | | - vim.fn.chanclose(job_id, "stdin") |
549 | | - else |
550 | | - vim.notify("Failed to start poste job for run directive", vim.log.levels.ERROR, { title = "Poste" }) |
551 | | - if callback then callback(false, nil) end |
552 | | - end |
| 553 | + if job_id > 0 then |
| 554 | + vim.fn.chansend(job_id, modified_content) |
| 555 | + vim.fn.chanclose(job_id, "stdin") |
| 556 | + else |
| 557 | + vim.notify("Failed to start poste job for run directive", vim.log.levels.ERROR, { title = "Poste" }) |
| 558 | + if callback then callback(false, nil) end |
| 559 | + end |
| 560 | + end) |
553 | 561 |
|
554 | 562 | elseif opts.action == "execute_all" then |
555 | 563 | -- Execute all requests in the target file |
@@ -589,73 +597,80 @@ function M.execute_all_requests(file_path, content, vars, callback) |
589 | 597 | local req = requests[idx] |
590 | 598 | idx = idx + 1 |
591 | 599 |
|
592 | | - -- Find block bounds and process pre-script from target block |
593 | | - local block_end = find_block_end(content, req.line) |
594 | | - local modified_content, _ = process_target_pre_script(content, req.line, block_end) |
| 600 | + -- Resolve request variable dependencies in this block first. |
| 601 | + -- This executes any uncached {{Name.response.body.*}} refs pointing to |
| 602 | + -- requests in the same file, then substitutes their values. |
| 603 | + request_vars.resolve_content_dependencies(binary, file_path, state.current_env, content, req.line, function(dep_resolved_content) |
| 604 | + -- Find block bounds and process pre-script from target block (on dependency-resolved content) |
| 605 | + local block_end = find_block_end(dep_resolved_content, req.line) |
| 606 | + local modified_content, _ = process_target_pre_script(dep_resolved_content, req.line, block_end) |
595 | 607 |
|
596 | | - if vars and next(vars) then |
597 | | - modified_content = M.apply_variable_overrides(modified_content, req.line, vars) |
598 | | - end |
| 608 | + if vars and next(vars) then |
| 609 | + modified_content = M.apply_variable_overrides(modified_content, req.line, vars) |
| 610 | + end |
599 | 611 |
|
600 | | - local cmd = string.format("%s run %s --line %d --env %s --json --stdin", |
601 | | - vim.fn.shellescape(binary), |
602 | | - vim.fn.shellescape(file_path), |
603 | | - req.line, |
604 | | - vim.fn.shellescape(state.current_env) |
605 | | - ) |
606 | | - |
607 | | - local stdout_buf = {} |
608 | | - local stderr_buf = {} |
609 | | - |
610 | | - local job_id = vim.fn.jobstart(cmd, { |
611 | | - stdin = "pipe", |
612 | | - stdout_buffered = true, |
613 | | - stderr_buffered = true, |
614 | | - on_stdout = function(_, data) |
615 | | - if not data then return end |
616 | | - for _, line in ipairs(data) do |
617 | | - if line ~= "" then table.insert(stdout_buf, line) end |
618 | | - end |
619 | | - end, |
620 | | - on_stderr = function(_, data) |
621 | | - if not data then return end |
622 | | - for _, line in ipairs(data) do |
623 | | - if line ~= "" then table.insert(stderr_buf, line) end |
624 | | - end |
625 | | - end, |
626 | | - on_exit = function(_, code) |
627 | | - local stdout_text = table.concat(stdout_buf, "\n") |
628 | | - local ok, parsed = pcall(vim.json.decode, stdout_text) |
629 | | - if ok and type(parsed) == "table" then |
630 | | - -- Run target block's post-script so client.global.set() persists |
631 | | - process_target_post_script(parsed, content, req.line, block_end) |
632 | | - table.insert(results, { name = req.name, response = parsed }) |
633 | | - else |
634 | | - table.insert(results, { name = req.name, response = { |
635 | | - status = code, |
636 | | - status_text = "Failed", |
637 | | - body = stdout_text, |
638 | | - stderr = table.concat(stderr_buf, "\n"), |
639 | | - }}) |
640 | | - end |
641 | | - vim.schedule(function() |
642 | | - vim.notify(string.format("[%d/%d] %s — %s", idx - 1, #requests, req.name, |
643 | | - parsed and (parsed.status .. " " .. (parsed.status_text or "")) or "failed"), |
644 | | - vim.log.levels.INFO, { title = "Poste" }) |
645 | | - end) |
646 | | - execute_next() |
647 | | - end, |
648 | | - }) |
| 612 | + local cmd = string.format("%s run %s --line %d --env %s --json --stdin", |
| 613 | + vim.fn.shellescape(binary), |
| 614 | + vim.fn.shellescape(file_path), |
| 615 | + req.line, |
| 616 | + vim.fn.shellescape(state.current_env) |
| 617 | + ) |
| 618 | + |
| 619 | + local stdout_buf = {} |
| 620 | + local stderr_buf = {} |
| 621 | + |
| 622 | + local job_id = vim.fn.jobstart(cmd, { |
| 623 | + stdin = "pipe", |
| 624 | + stdout_buffered = true, |
| 625 | + stderr_buffered = true, |
| 626 | + on_stdout = function(_, data) |
| 627 | + if not data then return end |
| 628 | + for _, line in ipairs(data) do |
| 629 | + if line ~= "" then table.insert(stdout_buf, line) end |
| 630 | + end |
| 631 | + end, |
| 632 | + on_stderr = function(_, data) |
| 633 | + if not data then return end |
| 634 | + for _, line in ipairs(data) do |
| 635 | + if line ~= "" then table.insert(stderr_buf, line) end |
| 636 | + end |
| 637 | + end, |
| 638 | + on_exit = function(_, code) |
| 639 | + local stdout_text = table.concat(stdout_buf, "\n") |
| 640 | + local ok, parsed = pcall(vim.json.decode, stdout_text) |
| 641 | + if ok and type(parsed) == "table" then |
| 642 | + -- Run target block's post-script so client.global.set() persists |
| 643 | + process_target_post_script(parsed, content, req.line, block_end) |
| 644 | + -- Cache the response for cross-request variable resolution |
| 645 | + request_vars.cache_response(req.name, parsed) |
| 646 | + table.insert(results, { name = req.name, response = parsed }) |
| 647 | + else |
| 648 | + table.insert(results, { name = req.name, response = { |
| 649 | + status = code, |
| 650 | + status_text = "Failed", |
| 651 | + body = stdout_text, |
| 652 | + stderr = table.concat(stderr_buf, "\n"), |
| 653 | + }}) |
| 654 | + end |
| 655 | + vim.schedule(function() |
| 656 | + vim.notify(string.format("[%d/%d] %s — %s", idx - 1, #requests, req.name, |
| 657 | + parsed and (parsed.status .. " " .. (parsed.status_text or "")) or "failed"), |
| 658 | + vim.log.levels.INFO, { title = "Poste" }) |
| 659 | + end) |
| 660 | + execute_next() |
| 661 | + end, |
| 662 | + }) |
649 | 663 |
|
650 | | - if job_id > 0 then |
651 | | - vim.fn.chansend(job_id, modified_content) |
652 | | - vim.fn.chanclose(job_id, "stdin") |
653 | | - else |
654 | | - table.insert(results, { name = req.name, response = { |
655 | | - status = 0, status_text = "Job start failed", body = "", |
656 | | - }}) |
657 | | - execute_next() |
658 | | - end |
| 664 | + if job_id > 0 then |
| 665 | + vim.fn.chansend(job_id, modified_content) |
| 666 | + vim.fn.chanclose(job_id, "stdin") |
| 667 | + else |
| 668 | + table.insert(results, { name = req.name, response = { |
| 669 | + status = 0, status_text = "Job start failed", body = "", |
| 670 | + }}) |
| 671 | + execute_next() |
| 672 | + end |
| 673 | + end) |
659 | 674 | end |
660 | 675 |
|
661 | 676 | execute_next() |
|
0 commit comments