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
- Variables
- func ExtCodeExpand(formatter *chromahtml.Formatter, style *chroma.Style) goldmark.Extender
- func ExtractAttr(attrs []html.Attribute, key string) (val string, ok bool)
- func Get(pc parser.Context) int
- func GetWordArticle(word string) string
- func HTMLEscapeString(s string) string
- func NewAlertHTMLRenderer(opts ...html.Option) renderer.NodeRenderer
- func NewAlertHeaderHTMLRenderer(opts ...html.Option) renderer.NodeRenderer
- func NewAlertHeaderParser() parser.BlockParser
- func NewAlertParser() parser.BlockParser
- func NewGnoParserContext(mdctx GnoContext) parser.Context
- func NewMentionParser() parser.InlineParser
- func ParseHTMLTokens(r io.Reader) ([]html.Token, error)
- func Pop(pc parser.Context)
- func Push(pc parser.Context) bool
- func Seed(pc parser.Context, depth int)
- type Alert
- type AlertHTMLRenderer
- type AlertHeader
- type AlertHeaderHTMLRenderer
- type AlertType
- type ForeignNode
- type FormElement
- type FormExtension
- type FormInput
- type FormNode
- type FormParser
- func (p *FormParser) CanAcceptIndentedLine() bool
- func (p *FormParser) CanInterruptParagraph() bool
- func (p *FormParser) Close(node ast.Node, reader text.Reader, pc parser.Context)
- func (p *FormParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State
- func (p *FormParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State)
- func (p *FormParser) Trigger() []byte
- type FormRenderer
- type FormSelect
- type FormTextarea
- type GenFunc
- type GnoColumnNode
- type GnoColumnTag
- type GnoContext
- type GnoExtension
- type GnoLink
- type GnoLinkType
- type GoldenTests
- type ImageValidatorFunc
- type Option
- type Toc
- type TocOptions
Constants ¶
const MaxDepth = 6
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 ¶
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
var ErrLinkInvalidURL = errors.New("invalid URL format")
Error messages for invalid link formats
var ExtAlerts = &alertExtension{}
ExtAlerts is the global instance of the alert extension
var ExtColumns = &columns{}
ExtColumns instance for extending markdown with column functionality.
var ExtForeign = &foreignExtension{}
ExtForeign is the singleton Extender for `<gno-foreign>`. Pass the outer goldmark's image validator so the inner instance inherits it.
var ExtForms = &FormExtension{}
ExtForms is the public form extension instance
var ExtImageValidator = &imgValidatorExtension{}
ExtImageValidator is a Goldmark extension that pre validation on image URLs.
var ExtLinks = &linkExtension{}
ExtLinks instance for extending markdown with link functionality
var ExtMention = &mentionExtension{}
ExtMention is the exported extension instance.
var (
FormKind = ast.NewNodeKind("Form")
)
var KindAlert = ast.NewNodeKind("Alert")
KindAlert is the node kind identifier for Alert nodes
var KindAlertHeader = ast.NewNodeKind("AlertHeader")
KindAlertHeader is the node kind identifier for AlertHeader nodes
var (
KindGnoColumn = ast.NewNodeKind("GnoColumn")
)
var KindGnoForeign = ast.NewNodeKind("GnoForeign")
KindGnoForeign is the node kind for ForeignNode.
var KindGnoLink = ast.NewNodeKind("GnoLink")
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 ¶
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 Get ¶
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 ¶
GetWordArticle returns "a" or "an" based on the first letter of the word
func HTMLEscapeString ¶
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 ¶
ParseHTMLTokens parses an HTML stream and returns a slice of html.Token. It stops at EOF or on error.
func Pop ¶
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 ¶
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 ¶
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 ¶
Alert represents a block-level alert element in markdown It can contain a header and content, and supports different alert types
type AlertHTMLRenderer ¶
AlertHTMLRenderer implements the HTML renderer for Alert nodes
func (*AlertHTMLRenderer) RegisterFuncs ¶
func (r *AlertHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)
RegisterFuncs registers the render functions
type AlertHeader ¶
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 ¶
AlertHeaderHTMLRenderer implements the HTML renderer for AlertHeader nodes
func (*AlertHeaderHTMLRenderer) RegisterFuncs ¶
func (r *AlertHeaderHTMLRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)
RegisterFuncs registers the render functions
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.
type FormElement ¶
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
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
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) 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 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) 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 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 ¶
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
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
type ImageValidatorFunc ¶
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 TocOptions ¶
type TocOptions struct {
MinDepth, MaxDepth int
}