Skip to content

Namespace Markdown props under the props binding #305

Description

@taras

Motivation

Markdown already presents component and root properties as a namespace in text:

Hello, {props.name}

The evaluation environment currently does something different: it spreads validated props into env.values, so eval blocks and executable code blocks read a prop as the bare binding name. That makes a declared prop indistinguishable from a local eval binding, creates avoidable collisions, and forces documents to use different syntax depending on where the value is read.

Props should remain namespaced everywhere.

Contract

  • A root or Markdown component installs its validated, defaulted property object as the props binding in its evaluation environment.
  • Eval code and expression props read properties as props.name or props.nested.value.
  • Executable code-block interpolation reads them as {props.name}.
  • Text interpolation continues to use {props.name}.
  • A bare reference such as {name} reads only an ordinary eval/capture/return binding. Merely declaring a prop named name does not create that bare binding.
  • Function components continue receiving their validated props object as their generator argument; this story does not change that API.
  • Prop validation, defaults, nested values, reference identity, projection anchoring, and binding lifetime do not otherwise change.

This is a breaking language change. The implementation and PR title must signal it.

Current state

  • documentWorkflow() seeds the root environment with { ...validatedProps }.
  • Markdown component expansion likewise seeds its evaluation environment with individual validated props.
  • interpolateEvalBindings() already traverses dotted binding paths, but the current environment has no props object for executable code blocks.
  • The executable-MDX and root-props specifications explicitly describe bare prop bindings today.

Issue #276 may proceed first using the current {package} spelling. Once this story lands, migrate that bootstrap document to {props.package}.

Scope

  • Change root and Markdown-component evaluation environments to expose one props namespace.
  • Preserve the caller/component anchoring rule: component-authored content sees that component's props; projected caller content sees the caller's props.
  • Update code-block interpolation documentation and remove the rationale that props must be bare.
  • Audit executable Markdown, examples, fixtures, and scripts for bare references that are actually props, and migrate them.
  • Update the executable-MDX and root-document-props specifications and their decision/conformance rows.
  • Do not namespace ordinary eval, capture, loop, component-return, or other user-created bindings.

Acceptance criteria

  • Root eval code can read props.name.
  • A Markdown component's eval code can read its own props.name.
  • Root and component executable code blocks interpolate {props.name}, including nested paths.
  • Expression-valued component props can read props.name.
  • Projected content observes its lexical caller's props namespace.
  • Bare {name} no longer resolves merely because name is a declared prop.
  • An unrelated bare binding named name continues to work and does not mutate props.name.
  • Defaults and validation still happen before any body effect.
  • Tests discriminate root, component, projection, code-block, eval, expression-prop, and collision behavior across Deno, Node, and Bun.
  • All repository verification gates pass.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions