STXT, prosa dentro de la estructura

Frontmatter, MDX y Markdoc insertan la estructura en la prosa. STXT inserta la prosa en la estructura, y así se puede validar el documento completo.

El problema

Markdown es prosa. Un fichero Markdown no tiene campos.

Cuando una página necesita datos, los datos van en un Frontmatter: un bloque YAML antes de la prosa. Eso cubre un título, un autor y una fecha.

El problema empieza cuando la estructura está dentro de la prosa. Una pregunta en medio de una lección. Un cuestionario al final, con sus preguntas y respuestas. Markdown no tiene sintaxis para eso, así que cada herramienta añade la suya: componentes en MDX, etiquetas en Markdoc. La estructura queda incrustada en la prosa, y ningún esquema cubre el fichero entero.

STXT va al revés. La estructura es el documento: nodos con nombre, cardinalidad y tipo. La prosa va dentro, como Markdown, en nodos block. Una plantilla valida el fichero entero.

La lección siguiente tiene varios autores, una pregunta intercalada en el contenido y un cuestionario final.

Una Lección en STXT

Los datos son nodos, y la prosa es Markdown dentro de nodos block:

Lección (com.example.school.es): ¿Qué es STXT?
	Autores:
		Autor: Joan Costa
		Autor: James Smith
	Docente: Sheila Jones
	Dificultad: fácil
	Introducción >>
		STXT es un **formato de texto jerárquico**: fácil de leer
		para las personas y trivial de parsear para las máquinas.
	Contenido >>
		Un documento es un árbol de nodos. Solo hay dos tipos:

		- `Nombre: valor`, para valores cortos en línea.
		- `Nombre >>`, para un bloque de texto literal, como este.

		La indentación *es* la estructura: sin etiquetas de cierre,
		sin comillas y sin caracteres de escape.
	Pregunta: ¿Qué otro formato es parecido?
		Respuesta: XML, por ejemplo
	Contenido >>
		Los comentarios son las líneas que empiezan por `#`.

		Los documentos pueden tener namespaces. Se declaran
		con `Nombre (namespace.nombre)`.
	Conclusión >>
		Con dos tipos de nodo y la indentación se puede describir cualquier documento.
		Una plantilla añade **validación**, sin cambiar la sintaxis.
	Cuestionario:
		Pregunta: ¿Cómo se expresa la estructura de un documento?
			Respuesta >>
				Con la indentación: un nodo es hijo del nodo anterior
				más cercano que tiene un nivel menos.
		Pregunta: ¿Qué pasa con el texto de un bloque `>>`?
			Respuesta >>
				Se conserva literalmente. No se interpreta nada de su interior.
				Puede ser Markdown, código o cualquier otro texto.

Y la plantilla que valida estructura y cardinalidad:

Template (@stxt.template): com.example.school.es
	Structure >>
		Lección:
			Autores: (1)
				Autor: (+)
			Docente: (1)
			Dificultad: (?) ENUM [fácil, media, difícil]
			Introducción: (?) MARKDOWN
			Contenido: (*) MARKDOWN
			Pregunta: (*)
				Respuesta: (1) MARKDOWN
			Conclusión: (?) MARKDOWN
			Cuestionario: (?) GROUP
				Pregunta: (+) @Pregunta

Contenido aparece dos veces, con una Pregunta entre ambos, y el árbol conserva ese orden. El validador comprueba el resto: al menos un autor, un docente, una dificultad de la lista y un cuestionario con una o más preguntas, cada una con su respuesta.

Markdown con Frontmatter

Los metadatos van en el Frontmatter, escrito en YAML. El resto son títulos y párrafos:

---
tipo: lección
título: ¿Qué es STXT?
autores:
  - Joan Costa
  - James Smith
docente: Sheila Jones
dificultad: fácil
---

# Introducción

STXT es un **formato de texto jerárquico**: fácil de leer
para las personas y trivial de parsear para las máquinas.

# Contenido

Un documento es un árbol de nodos. Solo hay dos tipos:

- `Nombre: valor`, para valores cortos en línea.
- `Nombre >>`, para un bloque de texto literal, como este.

La indentación *es* la estructura: sin etiquetas de cierre,
sin comillas y sin caracteres de escape.

**Pregunta**: ¿Qué otro formato es parecido?

**Respuesta**: XML, por ejemplo

# Contenido

Los comentarios son las líneas que empiezan por `#`.

Los documentos pueden tener namespaces. Se declaran
con `Nombre (namespace.nombre)`.

# Conclusión

Con dos tipos de nodo y la indentación se puede describir cualquier documento.
Una plantilla añade **validación**, sin cambiar la sintaxis.

# Cuestionario

## ¿Cómo se expresa la estructura de un documento?

Con la indentación: un nodo es hijo del nodo anterior
más cercano que tiene un nivel menos.

## ¿Qué pasa con el texto de un bloque `>>`?

Se conserva literalmente. No se interpreta nada de su interior.
Puede ser Markdown, código o cualquier otro texto.

La pregunta, las respuestas y el cuestionario son una convención de negritas y títulos. Para Markdown solo son párrafos. Nada comprueba que el cuestionario tenga preguntas ni que cada pregunta tenga respuesta.

El Frontmatter se puede validar con un esquema externo: JSON Schema, o un esquema Zod en las colecciones de contenido de Astro. El cuerpo, no.

El cuestionario se puede trasladar al Frontmatter. Así queda validado, pero las respuestas pasan a ser cadenas, y la plantilla del sitio tiene que convertirlas a HTML como Markdown por su cuenta.

MDX

MDX añade JSX a Markdown. La pregunta y el cuestionario se convierten en componentes:

---
tipo: lección
título: ¿Qué es STXT?
autores:
  - Joan Costa
  - James Smith
docente: Sheila Jones
dificultad: fácil
---

import { Pregunta, Cuestionario } from '../components/Leccion'

# Introducción

STXT es un **formato de texto jerárquico**: fácil de leer
para las personas y trivial de parsear para las máquinas.

# Contenido

Un documento es un árbol de nodos. Solo hay dos tipos:

- `Nombre: valor`, para valores cortos en línea.
- `Nombre >>`, para un bloque de texto literal, como este.

La indentación *es* la estructura: sin etiquetas de cierre,
sin comillas y sin caracteres de escape.

<Pregunta texto="¿Qué otro formato es parecido?">
  XML, por ejemplo
</Pregunta>

# Contenido

Los comentarios son las líneas que empiezan por `#`.

Los documentos pueden tener namespaces. Se declaran
con `Nombre (namespace.nombre)`.

# Conclusión

Con dos tipos de nodo y la indentación se puede describir cualquier documento.
Una plantilla añade **validación**, sin cambiar la sintaxis.

<Cuestionario>
  <Pregunta texto="¿Cómo se expresa la estructura de un documento?">
    Con la indentación: un nodo es hijo del nodo anterior
    más cercano que tiene un nivel menos.
  </Pregunta>
  <Pregunta texto="¿Qué pasa con el texto de un bloque `>>`?">
    Se conserva literalmente. No se interpreta nada de su interior.
    Puede ser Markdown, código o cualquier otro texto.
  </Pregunta>
</Cuestionario>

Pregunta y Cuestionario son componentes JavaScript definidos en otro fichero. El documento se compila a un módulo JavaScript, y el import se ejecuta. El documento es código.

El Frontmatter no forma parte de MDX: lo procesa el framework o un plugin de remark.

No hay esquema. Un componente inexistente provoca un error al generar la página. Si falta el atributo texto, solo lo detecta el propio componente, y únicamente si está programado para ello. Nada cuenta las preguntas de un Cuestionario. Los títulos siguen siendo una convención.

En la prosa, < y { abren JSX y expresiones, así que hay que escaparlos.

Markdoc

Markdoc añade etiquetas a Markdown y valida el documento contra un esquema definido en la aplicación:

---
tipo: lección
título: ¿Qué es STXT?
autores:
  - Joan Costa
  - James Smith
docente: Sheila Jones
dificultad: fácil
---

# Introducción

STXT es un **formato de texto jerárquico**: fácil de leer
para las personas y trivial de parsear para las máquinas.

# Contenido

Un documento es un árbol de nodos. Solo hay dos tipos:

- `Nombre: valor`, para valores cortos en línea.
- `Nombre >>`, para un bloque de texto literal, como este.

La indentación *es* la estructura: sin etiquetas de cierre,
sin comillas y sin caracteres de escape.

{% pregunta texto="¿Qué otro formato es parecido?" %}
XML, por ejemplo
{% /pregunta %}

# Contenido

Los comentarios son las líneas que empiezan por `#`.

Los documentos pueden tener namespaces. Se declaran
con `Nombre (namespace.nombre)`.

# Conclusión

Con dos tipos de nodo y la indentación se puede describir cualquier documento.
Una plantilla añade **validación**, sin cambiar la sintaxis.

{% cuestionario %}
{% pregunta texto="¿Cómo se expresa la estructura de un documento?" %}
Con la indentación: un nodo es hijo del nodo anterior
más cercano que tiene un nivel menos.
{% /pregunta %}
{% pregunta texto="¿Qué pasa con el texto de un bloque `>>`?" %}
Se conserva literalmente. No se interpreta nada de su interior.
Puede ser Markdown, código o cualquier otro texto.
{% /pregunta %}
{% /cuestionario %}

El esquema es un objeto JavaScript. Declara las etiquetas, sus atributos y qué hijos aceptan:

const config = {
  tags: {
    pregunta: {
      render: 'Pregunta',
      attributes: {
        texto: { type: String, required: true },
      },
    },
    cuestionario: {
      render: 'Cuestionario',
      children: ['tag'],
    },
  },
};

const ast = Markdoc.parse(source);
const errors = Markdoc.validate(ast, config);

Markdoc.validate detecta una etiqueta desconocida, un texto ausente y un hijo que la etiqueta no admite. Los valores permitidos de un atributo se declaran con matches. El documento no se ejecuta.

La cardinalidad no es declarativa. «Al menos una pregunta en el cuestionario» exige escribir una función validate para la etiqueta cuestionario, en JavaScript. Markdoc entrega el Frontmatter como texto sin procesar: la aplicación lo parsea y lo valida por separado. Los títulos siguen siendo una convención.

YAML con Markdown dentro

La lección completa en YAML, con la prosa en escalares de bloque:

tipo: lección
título: ¿Qué es STXT?
autores:
  - Joan Costa
  - James Smith
docente: Sheila Jones
dificultad: fácil
introducción: |
  STXT es un **formato de texto jerárquico**: fácil de leer
  para las personas y trivial de parsear para las máquinas.
cuerpo:
  - contenido: |
      Un documento es un árbol de nodos. Solo hay dos tipos:

      - `Nombre: valor`, para valores cortos en línea.
      - `Nombre >>`, para un bloque de texto literal, como este.

      La indentación *es* la estructura: sin etiquetas de cierre,
      sin comillas y sin caracteres de escape.
  - pregunta: ¿Qué otro formato es parecido?
    respuesta: XML, por ejemplo
  - contenido: |
      Los comentarios son las líneas que empiezan por `#`.

      Los documentos pueden tener namespaces. Se declaran
      con `Nombre (namespace.nombre)`.
conclusión: |
  Con dos tipos de nodo y la indentación se puede describir cualquier documento.
  Una plantilla añade **validación**, sin cambiar la sintaxis.
cuestionario:
  - pregunta: ¿Cómo se expresa la estructura de un documento?
    respuesta: |
      Con la indentación: un nodo es hijo del nodo anterior
      más cercano que tiene un nivel menos.
  - pregunta: ¿Qué pasa con el texto de un bloque `>>`?
    respuesta: |
      Se conserva literalmente. No se interpreta nada de su interior.
      Puede ser Markdown, código o cualquier otro texto.

Aquí la prosa está dentro de la estructura, como en STXT. Hay dos diferencias:

  • Repetición y orden. Las claves de un mapa YAML son únicas. contenido no puede aparecer dos veces con una pregunta intercalada, así que los tres elementos pasan a una lista, cuerpo, con una clave cada uno. En STXT un hijo repetido ya es la lista, y el árbol conserva el orden.
  • La prosa es una cadena. Nada en el fichero indica que introducción sea Markdown: lo decide quien la muestra. En STXT lo indica la plantilla, con Introducción: (?) MARKDOWN.

Un JSON Schema valida la estructura, las cardinalidades y la enumeración. Es un tercer lenguaje, y se aplica a los datos ya cargados. Los indicadores de los escalares de bloque se explican en STXT frente a YAML.

Resumen

Frontmatter MDX Markdoc YAML STXT
Metadatos Bloque YAML Bloque YAML, lo procesa el framework Bloque YAML, lo procesa la aplicación Claves Nodos
Estructura en la prosa Títulos, por convención Componentes JSX Etiquetas Claves y listas Nodos, con la prosa en nodos block
Validación de la estructura Solo el Frontmatter, externa Ninguna: los componentes se ejecutan Etiquetas y atributos, con un esquema JS Externa, con JSON Schema Plantilla, en STXT
Cardinalidad No No Una función validate en JS JSON Schema Plantilla
Partes repetidas, en orden Títulos, por convención Componentes Etiquetas Lista de elementos de una clave Hijos repetidos
Qué texto es Markdown El cuerpo El cuerpo El cuerpo El fichero no lo indica Los nodos de tipo MARKDOWN
El fichero es código No Sí, un módulo JavaScript No No No