markdown

package
v0.0.0 Latest Latest
Warning

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

Go to latest
Published: Jun 24, 2026 License: UNKNOWN not legal advice Imports: 0 Imported by: 0

Documentation

Overview

Package markdown — gno-foreign extension.

`<gno-foreign>` is a render-time sandbox primitive for foreign-built markdown (markdown returned by an interface method, fetched from a foreign realm, etc.). The body is collected verbatim by the outer parser (opaque to all other block parsers thanks to the load-bearing `parser.Continue` (no HasChildren) invariant) and rendered inside its own goldmark instance with structural extensions selectively loaded.

IMPORTANT — realms MUST emit this block via the p/nt/markdown/foreign helper (foreign.Foreign / ForeignWithLabel), never by hand-assembling the `<gno-foreign>`…`</gno-foreign>` envelope. The body scan here is line-based and CommonMark-structure- blind: it does not skip fenced/indented code or HTML blocks, so a `</gno-foreign>` line inside body code would close the block early, and a foreign opener emitted without a preceding blank line can be absorbed into an adjacent block (e.g. a `<gno-columns>`). The helper neutralizes every body sentinel and blank-line-frames the opener, which is what makes the sandbox safe; hand-built envelopes do not.

Package markdown — nestdepth helper.

nestdepth tracks the global gno-* nesting depth on goldmark's parser.Context, providing a shared cap (4 levels) enforced uniformly across every participating gno-* extension. The cap applies cross-family — a chain like

<gno-foreign> > <gno-foreign> > <gno-columns> > <gno-columns>

reaches depth 4 (the deepest <gno-columns> is allowed); a 5th nested gno-* opener anywhere underneath is refused and falls through to raw HTML, which goldmark safe-mode then strips.

The depth counter is a stack: every participating Open calls Push, every Close (and the AST-transformer synth-close path) calls Pop. Push returns false at cap without incrementing, so the caller can refuse cleanly. Pop clamps at 0 to avoid underflow in the face of unbalanced transformer Pops.

The foreign-specific monotonic block-count counter is NOT here — it is not stack-shaped, so it lives with the foreign parser in ext_foreign.go (see MaxGnoForeignBlocksPerConvert / gnoForeignBlockKey).

Index

Constants

View Source
const MaxDepth = 6
View Source
const MaxGnoNestDepth = 4

MaxGnoNestDepth is the hard cap on nested gno-* blocks across the family. Reached when a 4th-level opener has Push'd; a 5th opener's Push returns false.

Variables

View Source
var (
	ErrFormInvalidTag       = errors.New("unexpected or invalid tag")
	ErrFormMissingName      = errors.New("missing 'name' attribute")
	ErrFormInvalidInputType = errors.New("invalid input type")
	ErrFormDuplicateName    = errors.New("name already used")
	ErrFormInvalidAttribute = errors.New("invalid attribute for input type")
	ErrFormMissingValue     = errors.New("missing 'value' attribute")
)

Form-specific errors

View Source
var ErrLinkInvalidURL = errors.New("invalid URL format")

Error messages for invalid link formats

View Source
var ExtAlerts = &alertExtension{}

ExtAlerts is the global instance of the alert extension

View Source
var ExtColumns = &columns{}

ExtColumns instance for extending markdown with column functionality.

View Source
var ExtForeign = &foreignExtension{}

ExtForeign is the singleton Extender for `<gno-foreign>`. Pass the outer goldmark's image validator so the inner instance inherits it.

View Source
var ExtForms = &FormExtension{}

ExtForms is the public form extension instance

View Source
var ExtImageValidator = &imgValidatorExtension{}

ExtImageValidator is a Goldmark extension that pre validation on image URLs.

View Source
var ExtLinks = &linkExtension{}

ExtLinks instance for extending markdown with link functionality

View Source
var ExtMention = &mentionExtension{}

ExtMention is the exported extension instance.

View Source
var (
	FormKind = ast.NewNodeKind("Form")
)
View Source
var KindAlert = ast.NewNodeKind("Alert")

KindAlert is the node kind identifier for Alert nodes

View Source
var KindAlertHeader = ast.NewNodeKind("AlertHeader")

KindAlertHeader is the node kind identifier for AlertHeader nodes

View Source
var (
	KindGnoColumn = ast.NewNodeKind("GnoColumn")
)
View Source
var KindGnoForeign = ast.NewNodeKind("GnoForeign")

KindGnoForeign is the node kind for ForeignNode.

View Source
var KindGnoLink = ast.NewNodeKind("GnoLink")
View Source
var MaxGnoForeignBlocksPerConvert = chainmd.MaxForeignBlocksPerConvert()

MaxGnoForeignBlocksPerConvert caps the number of <gno-foreign> blocks one Convert call will admit. Beyond this count, foreign openers fall through to raw HTML (safe-mode strips them). It is a foreign-specific MONOTONIC per-Convert total — never decremented — distinct from the cross-family nesting depth (nestdepth.go).

Sourced from the chain/markdown native (the single source of truth) so this enforcement and the realm-facing value realms read via markdown.MaxForeignBlocksPerConvert() cannot drift apart.

Functions

func ExtCodeExpand

func ExtCodeExpand(formatter *chromahtml.Formatter, style *chroma.Style) goldmark.Extender

ExtCodeExpand returns a Goldmark extension that renders fenced and indented code blocks as collapsible <details class="doc-example"> disclosures with Chroma syntax highlighting applied to the code content. The formatter and style are injected by the caller.

func ExtractAttr

func ExtractAttr(attrs []html.Attribute, key string) (val string, ok bool)

func Get

func Get(pc parser.Context) int

Get returns the current gno-* nesting depth on pc. Returns 0 when the key is absent (a freshly-created parser.Context starts at depth 0 without any explicit initialization). Returns 0 if the key is present with a non-int value (defensive guard against hypothetical misuse — only this package sets the key).

func GetWordArticle

func GetWordArticle(word string) string

GetWordArticle returns "a" or "an" based on the first letter of the word

func HTMLEscapeString

func HTMLEscapeString(s string) string

HTMLEscapeString escapes special characters in HTML content

func NewAlertHTMLRenderer

func NewAlertHTMLRenderer(opts ...html.Option) renderer.NodeRenderer

NewAlertHTMLRenderer creates a new alert HTML renderer

func NewAlertHeaderHTMLRenderer

func NewAlertHeaderHTMLRenderer(opts ...html.Option) renderer.NodeRenderer

NewAlertHeaderHTMLRenderer creates a new alert header HTML renderer

func NewAlertHeaderParser

func NewAlertHeaderParser() parser.BlockParser

NewAlertHeaderParser creates a new alert header parser

func NewAlertParser

func NewAlertParser() parser.BlockParser

NewAlertParser creates a new alert parser

func NewGnoParserContext

func NewGnoParserContext(mdctx GnoContext) parser.Context

NewGnoParserContext creates a new parser context with GnoURL

func NewMentionParser

func NewMentionParser() parser.InlineParser

NewMentionParser creates a new parser for @ mentions and g1 addresses

func ParseHTMLTokens

func ParseHTMLTokens(r io.Reader) ([]html.Token, error)

ParseHTMLTokens parses an HTML stream and returns a slice of html.Token. It stops at EOF or on error.

func Pop

func Pop(pc parser.Context)

Pop decrements the depth counter, clamped at 0. Callers in Close and the AST transformer's synth-close path should call Pop exactly once per successful Push.

func Push

func Push(pc parser.Context) bool

Push increments the depth counter if below the cap. Returns true on success (depth incremented), false if already at the cap (no change made). Callers should refuse to open their block when Push returns false; goldmark will then try the next block parser (typically Type-7 HTML block at priority 900), which safe-mode strips.

func Seed

func Seed(pc parser.Context, depth int)

Seed pre-seeds the depth on a fresh inner-instance context. Opaque-body extensions (currently <gno-foreign>; <gno-card> body when CARD.md ships) read the parse-time depth from their AST node (stashed during Open) and call Seed when invoking the inner goldmark instance, so the cap stays global across the inner/outer boundary.

Types

type Alert

type Alert struct {
	ast.BaseBlock
}

Alert represents a block-level alert element in markdown It can contain a header and content, and supports different alert types

func NewAlert

func NewAlert() *Alert

NewAlert creates a new Alert node

func (*Alert) Dump

func (n *Alert) Dump(source []byte, level int)

Dump prints the AST structure for debugging purposes

func (*Alert) Kind

func (n *Alert) Kind() ast.NodeKind

Kind returns the node kind identifier

type AlertHTMLRenderer

type AlertHTMLRenderer struct {
	html.Config
}

AlertHTMLRenderer implements the HTML renderer for Alert nodes

func (*AlertHTMLRenderer) RegisterFuncs

RegisterFuncs registers the render functions

type AlertHeader

type AlertHeader struct {
	ast.BaseBlock
}

AlertHeader represents the header part of an alert It contains the alert type and title

func NewAlertHeader

func NewAlertHeader() *AlertHeader

NewAlertHeader creates a new AlertHeader node

func (*AlertHeader) Dump

func (n *AlertHeader) Dump(source []byte, level int)

Dump prints the AST structure for debugging purposes

func (*AlertHeader) Kind

func (n *AlertHeader) Kind() ast.NodeKind

Kind returns the node kind identifier

type AlertHeaderHTMLRenderer

type AlertHeaderHTMLRenderer struct {
	html.Config
}

AlertHeaderHTMLRenderer implements the HTML renderer for AlertHeader nodes

func (*AlertHeaderHTMLRenderer) RegisterFuncs

RegisterFuncs registers the render functions

type AlertType

type AlertType int
const (
	AlertTypeNote AlertType = iota
	AlertTypeTip
	AlertTypeCaution
	AlertTypeWarning
	AlertTypeSuccess
	AlertTypeInfo
)

type ForeignNode

type ForeignNode struct {
	ast.BaseBlock
	// Body is the accumulated verbatim bytes between the opener and
	// the matching close tag (inclusive of any line terminators).
	Body []byte
	// Label is the optional label string (v1: always "external
	// content"; attribute parsing deferred to a future PR).
	Label string
	// DepthAtParse is the gnoNestDepth value AFTER this block's Push
	// fired during Open. The renderer reads it back to seed the
	// inner instance's parser.Context — goldmark's renderer signature
	// does not carry parser.Context, so the value travels via this
	// AST-node field.
	DepthAtParse int
	// GnoCtx is the render context (GnoURL, chain id, …) captured at
	// parse time. The renderer rebuilds the inner instance's
	// parser.Context from it so links inside the sandbox get the same
	// URL-aware, dangerous-URL-guarded treatment as top-level content
	// (an empty context makes the link transformer no-op, leaving
	// autolinks like `<javascript:…>` unsanitized). Travels via the
	// node for the same reason as DepthAtParse.
	GnoCtx GnoContext
	// Closed is true if the outer parser saw a matching close tag
	// before EOF. False if the AST transformer had to synth-close
	// the node. The renderer treats both the same way.
	Closed bool
	// contains filtered or unexported fields
}

ForeignNode is the AST node for a `<gno-foreign>` block. The body bytes are collected verbatim by the outer parser and handed to an inner goldmark instance at render time.

func (*ForeignNode) Dump

func (n *ForeignNode) Dump(source []byte, level int)

Dump implements ast.Node.

func (*ForeignNode) Kind

func (*ForeignNode) Kind() ast.NodeKind

Kind implements ast.Node.

type FormElement

type FormElement interface {
	GetName() string
	GetError() error
	String() string
}

FormElement represents any form element

type FormExtension

type FormExtension struct{}

FormExtension integrates forms into goldmark

func (*FormExtension) Extend

func (e *FormExtension) Extend(m goldmark.Markdown)

type FormInput

type FormInput struct {
	Name        string
	Type        string
	Placeholder string
	Value       string
	Checked     bool
	Readonly    bool
	Required    bool
	Description string
	Error       error
}

FormInput represents an input element

func (FormInput) GetError

func (e FormInput) GetError() error

func (FormInput) GetName

func (e FormInput) GetName() string

func (FormInput) String

func (e FormInput) String() string

type FormNode

type FormNode struct {
	ast.BaseBlock
	Elements   []FormElement
	ExecFunc   string // Function name for exec attribute
	RenderPath string
	RealmName  string
	Domain     string
	ChainId    string
	Remote     string
	Error      error
	// contains filtered or unexported fields
}

FormNode represents a form in the AST

func (*FormNode) Dump

func (n *FormNode) Dump(source []byte, level int)

func (*FormNode) Kind

func (n *FormNode) Kind() ast.NodeKind

type FormParser

type FormParser struct{}

FormParser handles parsing of form blocks

func NewFormParser

func NewFormParser() *FormParser

func (*FormParser) CanAcceptIndentedLine

func (p *FormParser) CanAcceptIndentedLine() bool

func (*FormParser) CanInterruptParagraph

func (p *FormParser) CanInterruptParagraph() bool

func (*FormParser) Close

func (p *FormParser) Close(node ast.Node, reader text.Reader, pc parser.Context)

func (*FormParser) Continue

func (p *FormParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State

func (*FormParser) Open

func (p *FormParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State)

func (*FormParser) Trigger

func (p *FormParser) Trigger() []byte

type FormRenderer

type FormRenderer struct{}

FormRenderer handles rendering of form nodes

func NewFormRenderer

func NewFormRenderer() *FormRenderer

func (*FormRenderer) RegisterFuncs

func (r *FormRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)

type FormSelect

type FormSelect struct {
	Name        string
	Value       string
	Selected    bool
	Readonly    bool
	Required    bool
	Description string
	Error       error
}

FormSelect represents a select option

func (FormSelect) GetError

func (e FormSelect) GetError() error

func (FormSelect) GetName

func (e FormSelect) GetName() string

func (FormSelect) String

func (e FormSelect) String() string

type FormTextarea

type FormTextarea struct {
	Name        string
	Placeholder string
	Rows        int
	Value       string
	Readonly    bool
	Required    bool
	Description string
	Error       error
}

FormTextarea represents a textarea element

func (FormTextarea) GetError

func (e FormTextarea) GetError() error

func (FormTextarea) GetName

func (e FormTextarea) GetName() string

func (FormTextarea) String

func (e FormTextarea) String() string

type GenFunc

type GenFunc func(t *testing.T, nameIn string, input []byte) (nameOut string, output []byte)

type GnoColumnNode

type GnoColumnNode struct {
	ast.BaseBlock
	Index int          // Index of the column associated with the node.
	Tag   GnoColumnTag // Current Column Tag for this node.
	// contains filtered or unexported fields
}

GnoColumnNode represents a semantic tree for a "column".

func NewColumn

func NewColumn(ctx *columnsContext, tag GnoColumnTag) *GnoColumnNode

NewColumn initializes a ColumnNode object.

func UndefinedGnoColumnNode

func UndefinedGnoColumnNode() *GnoColumnNode

func (*GnoColumnNode) Dump

func (n *GnoColumnNode) Dump(source []byte, level int)

Dump implements Node.Dump for debug representation.

func (*GnoColumnNode) IsEmptyColumns

func (n *GnoColumnNode) IsEmptyColumns() bool

func (*GnoColumnNode) Kind

func (*GnoColumnNode) Kind() ast.NodeKind

Kind implements Node.Kind.

func (*GnoColumnNode) String

func (n *GnoColumnNode) String() string

type GnoColumnTag

type GnoColumnTag int

GnoColumnTag represents the type of tag in a column block.

const (
	GnoColumnTagUndefined GnoColumnTag = iota

	GnoColumnTagOpen
	GnoColumnTagClose

	GnoColumnTagSep
)

type GnoContext

type GnoContext struct {
	GnoURL  *weburl.GnoURL
	ChainId string
	Remote  string
	Domain  string
}

type GnoExtension

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

func NewGnoExtension

func NewGnoExtension(opts ...Option) *GnoExtension

func (*GnoExtension) Extend

func (e *GnoExtension) Extend(m goldmark.Markdown)

Extend adds the Gno extension to the provided Goldmark markdown processor.

type GnoLink struct {
	*ast.Link
	LinkType GnoLinkType
	GnoURL   *weburl.GnoURL
	// Untrusted marks a link parsed from a <gno-foreign> sandbox (the
	// inner instance's context is flagged via markForeignOrigin). Such
	// links render as user-generated content — rel="noopener nofollow
	// ugc" and no first-party tx/internal trust icons — so foreign
	// markdown cannot wear the host realm's link chrome. The href is
	// still resolved normally; only the trust signals are stripped.
	Untrusted bool
}

GnoLink represents a link with Gno-specific metadata

func (*GnoLink) Dump

func (n *GnoLink) Dump(source []byte, level int)

func (*GnoLink) Kind

func (*GnoLink) Kind() ast.NodeKind

Kind implements Node.Kind.

type GnoLinkType

type GnoLinkType int

GnoLinkType represents the type of a link

const (
	GnoLinkTypeInvalid GnoLinkType = iota
	GnoLinkTypeExternal
	GnoLinkTypePackage
	GnoLinkTypeInternal
	GnoLinkTypeUser
)

func (GnoLinkType) String

func (t GnoLinkType) String() string

type GoldenTests

type GoldenTests struct {
	Recurse      bool
	Update       bool
	GenerateFunc GenFunc
	// SkipDirs are subdirectory paths (relative to the walk root) that
	// should be skipped entirely — used to keep this runner out of
	// directories that use a different txtar layout (e.g. golden/sanitize,
	// which has its own driver in sanitize_integration_test.go).
	SkipDirs []string
}

func NewGoldentTests

func NewGoldentTests(exec GenFunc) *GoldenTests

func (*GoldenTests) Run

func (g *GoldenTests) Run(t *testing.T, dir string)

type ImageValidatorFunc

type ImageValidatorFunc func(uri string) (ok bool)

ImageValidatorFunc validates image URLs. It should return `true` for any valid image URL.

type Option

type Option func(cfg *config)

func WithImageValidator

func WithImageValidator(valFunc ImageValidatorFunc) Option

type Toc

type Toc struct {
	Items []*components.TocItem
}

func TocInspect

func TocInspect(n ast.Node, src []byte, opts TocOptions) (Toc, error)

type TocOptions

type TocOptions struct {
	MinDepth, MaxDepth int
}

Jump to

Keyboard shortcuts

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