Skip to content

feat: parse typed process outputs from the language server#12

Merged
ewels merged 2 commits into
ewels:mainfrom
znorgaard:feat/typed-process-outputs
May 29, 2026
Merged

feat: parse typed process outputs from the language server#12
ewels merged 2 commits into
ewels:mainfrom
znorgaard:feat/typed-process-outputs

Conversation

@znorgaard
Copy link
Copy Markdown
Contributor

Make parse_process_hover extract outputs for processes written in the typed Nextflow, 26.04 (nextflow.enable.types), with or without Records.

Implementation:

  • _extract_output_block (new) replaces the regex-only output-section capture in parse_process_hover. It is brace-aware so a typed Record { ... } is captured in full and multiple output channels are not truncated at the first closing brace. The match is anchored to a line start so an output: appearing mid-line (e.g. inside a script string) is not mistaken for the section label, and any declaration sharing the output: line is included as the first line of the block.
  • _parse_output_declarations is now brace-aware with the record's field shape surfaced in name (e.g. meta: Map, bam: Path). Deeper-nested record lines are not expanded and field lines never become separate outputs.
  • _parse_single_output gains two typed branches: name: Record { ... and the simple typed form name: Type. The simple branch is guarded against _TRADITIONAL_QUALIFIERS so it cannot false-match traditional declarations.
  • _typed_to_qualifier maps "Record" to "record" (lowercase, for consistency with val/path), keeping the type-name-to-label mapping in one place.
  • The legacy _OUTPUT_SECTION_RE is removed: enrich_outputs_from_source now uses the new brace-aware extractor too, so the hover and source paths share one section extractor. This also fixes a latent truncation when a source output glob contains brace expansion such as path "*_{R1,R2}.fastq".

What it looks like:
examples.zip

image

Beyond a general review:
Claude and I did a lot of work coming up with "odd" patterns we might use. Did we catch them all? Did we cover cases that can't exist and we could simplify the code?

Current Tests:

  • Typed record outputs (single channel, multiple channels, mixed with traditional outputs, nested Record { Record { ... } }).
  • Typed simple outputs (Path -> path; Integer -> val).
  • Field-collection edge cases: empty record falls back to emit-as-name; a record-opening { followed by trailing whitespace does not leak the brace into the field text.
  • A declaration sharing the output: line is captured.
  • _extract_output_block ignores an output: appearing mid-line and returns None when no output section is present.
  • enrich_outputs_from_source correctly handles a source whose output glob contains brace expansion (regression for the old truncating regex).

znorgaard added 2 commits May 28, 2026 14:43
Make `parse_process_hover` extract outputs for processes written in the
typed Nextflow DSL (`nextflow.enable.types`). The language server emits
typed outputs as `channel: Record { field: Type ... }` (multi-line,
brace-delimited), which the previous parser did not recognize: each
output line returned `None`, `process.outputs` ended up empty, and the
renderer omitted the Outputs section entirely. Typed inputs already
worked and are unchanged.

Implementation:

* `_extract_output_block` (new) replaces the regex-only output-section
  capture in `parse_process_hover`. It is brace-aware so a typed
  `Record { ... }` is captured in full and multiple output channels are
  not truncated at the first closing brace. The match is anchored to a
  line start so an `output:` appearing mid-line (e.g. inside a script
  string) is not mistaken for the section label, and any declaration
  sharing the `output:` line is included as the first line of the block.
* `_parse_output_declarations` is now brace-aware and uses one-way
  dataflow: when a typed-record line opens at depth 0 it is buffered in
  `pending`; the record's direct field lines (depth 1) are collected;
  the finalized `ParsedOutput` is constructed once on the closing `}`,
  with the record's field shape surfaced in `name` (e.g.
  `meta: Map, bam: Path`). Deeper-nested record lines are not expanded
  and field lines never become separate outputs.
* `_parse_single_output` gains two typed branches: `name: Record { ...`
  and the simple typed form `name: Type`. The simple branch is guarded
  against `_TRADITIONAL_QUALIFIERS` so it cannot false-match traditional
  declarations.
* `_typed_to_qualifier` maps `"Record"` to `"record"` (lowercase, for
  consistency with `val`/`path`), keeping the type-name-to-label mapping
  in one place. `_parse_output_declarations` keys off the parsed type
  via the cached `_typed_to_qualifier("Record")` so the "is this a
  record channel?" test has a single source of truth.
* The legacy `_OUTPUT_SECTION_RE` is removed: `enrich_outputs_from_source`
  now uses the new brace-aware extractor too, so the hover and source
  paths share one section extractor. This also fixes a latent
  truncation when a source output glob contains brace expansion such as
  `path "*_{R1,R2}.fastq"`.

Tests:

* Typed record outputs (single channel, multiple channels, mixed with
  traditional outputs, nested `Record { Record { ... } }`).
* Typed simple outputs (`Path` -> `path`; `Integer` -> `val`).
* Field-collection edge cases: empty record falls back to emit-as-name;
  a record-opening `{` followed by trailing whitespace does not leak
  the brace into the field text.
* A declaration sharing the `output:` line is captured.
* `_extract_output_block` ignores an `output:` appearing mid-line and
  returns `None` when no output section is present.
* `enrich_outputs_from_source` correctly handles a source whose output
  glob contains brace expansion (regression for the old truncating
  regex).
Copy link
Copy Markdown
Owner

@ewels ewels left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really nice, thanks!

@ewels ewels merged commit c0723c4 into ewels:main May 29, 2026
8 checks passed
@ewels
Copy link
Copy Markdown
Owner

ewels commented May 29, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants