preproc

package
v1.26.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 13, 2026 License: Apache-2.0 Imports: 1 Imported by: 0

Documentation

Overview

Package preproc extracts TypeScript-ish code blocks from preprocessor-language files (Svelte, Astro) into a "virtual source" buffer that can be fed to a tree-sitter TypeScript/TSX parser. The companion Builder type and per-extractor functions (ExtractSvelte, ExtractAstro) live in the same package.

Import cycle note: this package does NOT import internal/parser. The RemapSymbolLines helper that rewrites parse results lives in internal/parser/preproc_remap.go (parser package) to avoid a cycle.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ExtractAstroWithRefs

func ExtractAstroWithRefs(src []byte) (*VirtualSource, []TemplateRef)

ExtractAstroWithRefs is the primary extractor. It returns both the virtual TypeScript/JS source (frontmatter + <script> blocks) and a list of capitalised JSX-style component tag references found in the template body.

TemplateRefs are emitted for each opening tag whose name starts with an uppercase ASCII letter. Closing tags, HTML-lowercase tags, and namespace-prefixed tags (<astro:fragment>, <svelte:head>) are skipped. Contents of <!-- comments -->, <script>, and <style> blocks are also skipped. Each usage occurrence is recorded (no deduplication — callers may deduplicate per their own requirements).

Resolution of tag names to file paths is NOT performed here — callers should join TemplateRefs against ParseResult.Imports for that purpose.

func ExtractSvelteWithRefs added in v1.22.0

func ExtractSvelteWithRefs(src []byte) (*VirtualSource, []TemplateRef)

ExtractSvelteWithRefs returns both the virtual TypeScript source (from the component's <script> blocks) and the capitalised JSX-style component tag references found in the template markup — the Svelte analogue of ExtractAstroWithRefs.

scanTemplateRefs is template-syntax agnostic: a Svelte component has no --- frontmatter, so findTemplateStart returns 0 and the whole file is walked. <script>/<style> blocks and HTML comments are skipped; every opening tag whose name starts with an uppercase ASCII letter is recorded. Closing tags and namespace-prefixed tags (<svelte:head>, <svelte:component>, …) are skipped, so Svelte's own special elements do not produce spurious refs.

Resolution of tag names to file paths is NOT performed here — callers should join TemplateRefs against the component's <script> imports for that purpose (see callgraph.ResolveTemplateRefs).

Types

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder accumulates virtual code and a line-map from multiple source-block spans.

func NewBuilder

func NewBuilder(lang string) *Builder

NewBuilder creates a Builder for the given language label.

func (*Builder) AppendBlankLine

func (b *Builder) AppendBlankLine()

AppendBlankLine appends a single "\n" with LineMap entry 0 (padding — maps to no original line). Use between blocks to keep virtual symbols separate.

func (*Builder) AppendBlock

func (b *Builder) AppendBlock(fullSrc []byte, blockStart, blockEnd int)

AppendBlock copies fullSrc[blockStart:blockEnd] into the virtual buffer and records line offsets so every virtual line in this block maps to the corresponding original 1-based line number in the full source.

Parameters:

  • fullSrc: the entire original source file bytes
  • blockStart: byte offset in fullSrc where the content begins (inclusive)
  • blockEnd: byte offset in fullSrc where the content ends (exclusive)

Panics if blockEnd < blockStart or offsets are out of range.

func (*Builder) Build

func (b *Builder) Build() *VirtualSource

Build finalises and returns the VirtualSource. The Builder must not be used after Build is called.

type GoTemplateDefine added in v1.20.0

type GoTemplateDefine struct {
	Name      string
	StartLine int
	EndLine   int
}

GoTemplateDefine records a {{define "Name"}} ... {{end}} block found at the top level of a Go html/template file. StartLine and EndLine are 1-based.

func StripGoTemplate added in v1.20.0

func StripGoTemplate(src []byte) (cleaned []byte, defines []GoTemplateDefine)

StripGoTemplate scans src for Go html/template actions ({{...}}) and returns:

  • cleaned: a copy of src where every {{...}} action span is replaced with an equal number of space bytes. This preserves line/column positions for any downstream byte-level scanners (htmx attribute walker, etc.).

  • defines: the list of top-level {{define "Name"}} ... {{end}} blocks, with 1-based start/end line numbers derived from the original src.

Strategy: balanced-brace byte scanner.

  • "{{" opens an action; find matching "}}". Account for trim markers "{{-" and "-}}".
  • "{{/*" ... "*/}}" is a comment block; scan content without nesting.
  • Block actions (define, range, if, with, block) push onto a stack; the matching "{{end}}" pops the stack.
  • Top-level "{{define}}" blocks (depth 0 before pushing) are recorded.

Limitations (sufficient for Wave 1):

  • Strings inside actions (e.g. `{{ printf "%s" "fmt" }}`) are skipped as part of the action span — their content does not affect brace counting because the outer {{...}} scanner does not recurse into Go expressions.
  • Nested pipeline braces `{{ if eq .X "{" }}` are NOT handled; in practice Go template action bodies rarely contain literal braces and the scanner falls back to consuming until the next "}}" at the same depth.

type HtmxRef added in v1.20.0

type HtmxRef struct {
	Method            string // "GET", "POST", "PUT", "DELETE", or "PATCH"
	URL               string // raw attribute value including any {{...}} actions
	StartLine         int    // 1-based line of the opening tag
	EndLine           int    // 1-based line of the attribute value end (same as StartLine for single-line)
	EnclosingTemplate string // name from the nearest enclosing {{define "X"}} block; "" if at top level
}

HtmxRef records a single URL-emitting hx-* attribute found in an HTML file. The URL field contains the ORIGINAL bytes from src (Go template actions such as {{.ID}} are preserved for downstream normalisation by the routes layer).

func ScanHtmxRefs added in v1.20.0

func ScanHtmxRefs(src []byte) []HtmxRef

ScanHtmxRefs scans src for htmx URL-emitting attributes (hx-get, hx-post, hx-put, hx-delete, hx-patch) and returns one HtmxRef per occurrence.

Contract:

  • src MUST be the original file bytes, NOT the cleaned output of StripGoTemplate. The walker needs raw bytes so that Go template actions ({{.ID}}, {{add .Page 1}}) inside attribute values are preserved for the route normaliser in the routes layer.
  • <script> and <style> block contents are skipped (same as scanTemplateRefs).
  • HTML comments <!-- ... --> are skipped.
  • hx-on:* / hx-on::* attributes are not URL-emitting and are ignored.
  • Both double-quoted and single-quoted attribute values are handled.

type TemplateRef

type TemplateRef struct {
	Name string
	Line uint32
	Col  uint32
}

TemplateRef records a single usage of a capitalised JSX-style component tag found in an Astro (or similar) template body.

Name is the bare tag name (e.g. "Breadcrumbs"), Line and Col are 1-based positions in the original source file. Closing tags (</Foo>) are not recorded — only opening tags.

type VirtualSource

type VirtualSource struct {
	// Code is the synthetic TypeScript buffer passed to the tree-sitter parser.
	Code []byte

	// Lang is the effective language label for Symbol.Language ("svelte", "astro", …).
	Lang string

	// LineMap[i] is the 1-based line number in the ORIGINAL source that corresponds
	// to line (i+1) in Code. Length == number of \n in Code + 1. Lines that exist
	// only in Code (blank padding between script blocks) map to 0.
	LineMap []uint32
}

VirtualSource is TypeScript code extracted from a preprocessor-language file (Svelte, Astro, Vue) together with a per-virtual-line mapping back to the original source line numbers.

func ExtractAstro

func ExtractAstro(src []byte) *VirtualSource

ExtractAstro extracts the Astro frontmatter block (between leading ---) and all <script> blocks (page-level <script> tags). Returns VirtualSource with lang="astro".

Handles:

  • Leading frontmatter: starts with optional whitespace then ---\n, ends at next line starting with ---
  • Frontmatter may be absent — just <script> blocks processed
  • Multiple <script> blocks with blank-line padding

Does NOT handle:

  • Template expressions {foo} in the HTML body
  • Style tags
  • Template literal strings containing <script> (backtick-quoted JS strings with embedded <script> markers may be misidentified as real script blocks)

func ExtractMarkupExprs added in v1.22.0

func ExtractMarkupExprs(src []byte) *VirtualSource

ExtractMarkupExprs batches the inner content of ALL top-level {expr} ranges in the Astro template body into ONE virtual source (see buildExprVirtualSource), offset-mapped back to original coordinates, so a downstream reparse pays a single tree-sitter invocation per file rather than one per expression.

The returned VirtualSource carries lang="astro"; it is meant to be reparsed with the TSX grammar (a superset that parses the JSX legally embedded in template expressions), not the plain-TypeScript grammar.

func ExtractSvelte

func ExtractSvelte(src []byte) *VirtualSource

ExtractSvelte extracts all <script> and <script context="module"> / <script module> blocks from a Svelte component and returns a VirtualSource with lang="svelte".

Handles:

  • <script> … </script>
  • <script lang="ts"> … </script>
  • <script context="module"> … </script> (Svelte 4)
  • <script module> … </script> (Svelte 5)
  • Multiple script tags — concatenated with blank-line padding
  • CRLF and LF line endings
  • Missing closing tag — treat as extending to EOF (best-effort)

Does NOT handle:

  • Script content inside HTML comments
  • <style> blocks
  • Template markup
  • Escaped &lt;script&gt; in string literals
  • Template literal strings containing <script> (backtick-quoted JS strings with embedded <script> markers may be misidentified as real script blocks)

func ExtractSvelteMarkupExprs added in v1.22.0

func ExtractSvelteMarkupExprs(src []byte) *VirtualSource

ExtractSvelteMarkupExprs batches every Svelte template EXPR — plain mustaches and sigil-aware block-header expressions — into ONE reparsable virtual source (buildExprVirtualSource), reusing the same batching + line-map core as the Astro path. The result carries lang="svelte" and is reparsed with the TSX grammar by markupExprReparse.

func ExtractVue added in v1.22.0

func ExtractVue(src []byte) *VirtualSource

ExtractVue extracts <script setup> and <script> blocks from a Vue single-file component (SFC) and returns a VirtualSource with lang="vue".

Handles:

  • <script setup> … </script>
  • <script setup lang="ts"> … </script>
  • <script> … </script>
  • <script lang="ts"> … </script>
  • Both blocks in the same SFC — concatenated with blank-line padding
  • CRLF and LF line endings
  • Missing </script> — treats content as extending to EOF (best-effort)

Does NOT handle:

  • <template> block expressions or component references
  • <style> blocks
  • Script content inside HTML comments
  • Escaped &lt;script&gt; inside string literals

Both blocks are appended in document (source) order: <script setup> first because appendScriptBlocks starts scanning from offset 0, so the earlier block in the file appears first in the virtual buffer. In practice Vue SFCs place <script setup> before <script>, which matches this behaviour.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL