Tips & Tricks (Atualizado: 02/06/2026)

Processamento seguro de Markdown e MDX com Claude Code

Processe Markdown/MDX com Claude Code: AST, frontmatter, XSS, links e QA de locales.

Processamento seguro de Markdown e MDX com Claude Code

Markdown não é apenas texto

Um artigo publicado em Markdown ou MDX não é só um bloco de parágrafos. Ele carrega frontmatter, description para SEO, hierarquia de títulos, âncoras geradas, blocos de código, links internos, fontes oficiais, rotas por idioma e às vezes HTML cru. Se você pedir ao Claude Code “melhore este artigo” sem um contrato técnico, o texto pode ficar melhor, mas o slug pode mudar, o CTA pode sumir, a imagem hero pode ser alterada ou uma locale pode virar um resumo fino.

A regra prática é separar escrita e verificação. Claude Code pode reescrever, localizar e expandir. A estrutura precisa ser checada por scripts. Markdown e MDX devem ser lidos com AST, ou árvore de sintaxe abstrata. Frontmatter deve ser validado como dado. HTML precisa de uma fronteira explícita de sanitização. E as dez locales precisam ser vistas como um conjunto.

As fontes principais foram verificadas em 2 de junho de 2026. O guia de unified explica o pipeline de parse, transform e stringify. A página de syntax trees mostra por que AST é mais seguro que regex de linha. Para Markdown, use remark e remark-parse. Para MDX, veja a documentação oficial do MDX. Para frontmatter, gray-matter é direto. Para HTML e XSS, compare rehype-sanitize com o OWASP XSS Prevention Cheat Sheet. Para limitar o agente, leia Claude Code overview e settings.

flowchart LR
  A["Arquivo MDX"] --> B["frontmatter"]
  B --> C["schema validation"]
  A --> D["remark / MDX AST"]
  D --> E["títulos, fences, links"]
  D --> F["pipeline rehype"]
  F --> G["sanitize"]
  C --> H["locale e build checks"]
  E --> H
  G --> H

Escolha o parser antes de editar

A primeira instrução ao Claude Code deve nomear a toolchain. “Parse Markdown” é amplo demais. Para um arquivo pequeno, uma regex parece boa; para conteúdo publicado, ela falha em casos comuns.

NecessidadeMelhor escolhaAtalho arriscado
Ler títulos, links e code fencesremark-parse com AST traversalRegex ^## no texto
Suportar JSX em .mdxremark-mdx ou compiler MDXParser só de Markdown
Gerar HTMLremark-rehype para rehypeConcatenar strings HTML
Permitir raw HTMLrehype-raw e rehype-sanitizeallowDangerousHtml
Ler frontmattergray-matter com schema checksSplit manual de YAML

AST separa significado. Um ## título falso dentro de bloco de código não pode entrar no índice. Uma URL dentro de props MDX pode não ser um link editorial. tags: Claude Code, Markdown é string, não array. Parser e schema pegam esse tipo de erro antes da revisão humana.

Quatro casos de uso práticos

O primeiro caso é atualizar um artigo já publicado. Title, description, updatedDate, links oficiais, links internos, exemplos de código e CTA precisam caminhar juntos. No ClaudeCodeLab, isso se conecta a boas práticas de CLAUDE.md e web scraping com Claude Code, sem tocar em outros slugs.

O segundo caso é documentação com componentes MDX. Callouts, abas, cards de preço, FAQ e exemplos vivos são úteis, mas misturam Markdown e JSX. Um checker que não entende MDX pode quebrar componentes ou ignorar links relevantes.

O terceiro caso é publicação multilíngue. Um canonical japonês forte não resolve se português, espanhol, francês ou indonésio viram resumos. Cada locale precisa ter exemplos, armadilhas, snippets executáveis, links oficiais, links internos, CTA e nota de verificação.

O quarto caso é operação comercial de conteúdo. Páginas de Gumroad, training, recursos gratuitos e emails frequentemente reaproveitam Markdown. Quanto mais perto de compra ou consultoria, mais importante é verificar code fences, links e HTML.

Setup mínimo para copiar

Os exemplos usam Node.js 18 ou superior e ESM. Comece em uma pasta de teste antes de levar para o repositório.

mkdir mdx-audit-demo
cd mdx-audit-demo
npm init -y
npm pkg set type=module
npm install unified remark-parse remark-mdx remark-gfm gray-matter
npm install unist-util-visit github-slugger
npm install remark-rehype rehype-raw rehype-sanitize rehype-stringify
mkdir tools

Este script lê frontmatter com gray-matter, faz parse do body com remark e suporte MDX, e falha se campos obrigatórios faltarem, se description passar de 120 caracteres, se um code fence não tiver linguagem ou se faltarem links internos e externos.

// tools/audit-mdx.mjs
import fs from "node:fs/promises";
import matter from "gray-matter";
import GithubSlugger from "github-slugger";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkMdx from "remark-mdx";
import remarkGfm from "remark-gfm";
import { visit } from "unist-util-visit";

const file = process.argv[2];
if (!file) {
  throw new Error("Usage: node tools/audit-mdx.mjs article.mdx");
}

const source = await fs.readFile(file, "utf8");
const { data, content } = matter(source);
const errors = [];
const links = { internal: [], external: [] };
const headings = [];
const codeBlocks = [];

for (const key of ["title", "description", "pubDate", "heroImage", "lang"]) {
  if (typeof data[key] !== "string" || data[key].trim() === "") {
    errors.push(`frontmatter.${key} is required`);
  }
}

if ([...String(data.description ?? "")].length > 120) {
  errors.push("description must be 120 characters or fewer");
}

if (!Array.isArray(data.tags) || data.tags.length === 0) {
  errors.push("frontmatter.tags must be a non-empty array");
}

const tree = unified()
  .use(remarkParse)
  .use(remarkMdx)
  .use(remarkGfm)
  .parse(content);

const slugger = new GithubSlugger();

visit(tree, (node) => {
  if (node.type === "heading") {
    const text = plainText(node);
    headings.push({ depth: node.depth, text, slug: slugger.slug(text) });
  }

  if (node.type === "code") {
    codeBlocks.push({ lang: node.lang || "", meta: node.meta || "" });
    if (!node.lang) errors.push("code fence is missing a language");
  }

  if (node.type === "link") {
    const url = String(node.url || "");
    if (url.startsWith("http")) links.external.push(url);
    if (url.startsWith("/")) links.internal.push(url);
  }
});

if (links.internal.length === 0) errors.push("missing internal link");
if (links.external.length === 0) errors.push("missing external link");

if (errors.length > 0) {
  console.error(errors.map((error) => `- ${error}`).join("\n"));
  process.exit(1);
}

console.log(JSON.stringify({ headings, codeBlocks, links }, null, 2));

function plainText(node) {
  if (typeof node.value === "string") return node.value;
  if (!Array.isArray(node.children)) return "";
  return node.children.map(plainText).join("");
}
node tools/audit-mdx.mjs site/src/content/blog-pt/example.mdx

Exemplo 2: converter Markdown para HTML seguro

Se você não precisa de raw HTML, não habilite. Se precisa, faça parse e sanitize logo depois. allowDangerousHtml sozinho não é defesa.

// tools/markdown-to-safe-html.mjs
import fs from "node:fs/promises";
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkGfm from "remark-gfm";
import remarkRehype from "remark-rehype";
import rehypeRaw from "rehype-raw";
import rehypeSanitize, { defaultSchema } from "rehype-sanitize";
import rehypeStringify from "rehype-stringify";

const file = process.argv[2];
const markdown = await fs.readFile(file, "utf8");
const schema = {
  ...defaultSchema,
  attributes: {
    ...defaultSchema.attributes,
    code: [["className", /^language-/]],
  },
};

const html = await unified()
  .use(remarkParse)
  .use(remarkGfm)
  .use(remarkRehype, { allowDangerousHtml: true })
  .use(rehypeRaw)
  .use(rehypeSanitize, schema)
  .use(rehypeStringify)
  .process(markdown);

console.log(String(html));

A ordem importa. rehype-raw devolve HTML cru para a árvore HTML; rehype-sanitize remove tags e atributos não permitidos. Sem a segunda etapa, conteúdo perigoso pode chegar ao DOM renderizado.

Exemplo 3: verificar as dez locales

Este script confirma que o mesmo slug existe em todos os idiomas, que heroImage foi preservado, que updatedDate está correto e que cada body contém link interno e externo.

// tools/check-locales.mjs
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";

const slug = "claude-code-markdown-processing.mdx";
const expectedHero = "/images/hero/hero-077.png";
const locales = [
  ["ja", "site/src/content/blog"],
  ["en", "site/src/content/blog-en"],
  ["zh", "site/src/content/blog-zh"],
  ["ko", "site/src/content/blog-ko"],
  ["es", "site/src/content/blog-es"],
  ["fr", "site/src/content/blog-fr"],
  ["de", "site/src/content/blog-de"],
  ["pt", "site/src/content/blog-pt"],
  ["hi", "site/src/content/blog-hi"],
  ["id", "site/src/content/blog-id"],
];

const errors = [];

for (const [lang, dir] of locales) {
  const file = path.join(dir, slug);
  const source = fs.readFileSync(file, "utf8");
  const { data, content } = matter(source);
  if (data.lang !== lang) errors.push(`${lang}: lang mismatch`);
  if (data.heroImage !== expectedHero) errors.push(`${lang}: hero changed`);
  if (data.updatedDate !== "2026-06-02") {
    errors.push(`${lang}: updatedDate mismatch`);
  }
  if ([...String(data.description ?? "")].length > 120) {
    errors.push(`${lang}: description too long`);
  }
  if (!content.includes("https://")) errors.push(`${lang}: no external link`);
  if (!content.includes("](/")) errors.push(`${lang}: no internal link`);
}

if (errors.length > 0) {
  console.error(errors.map((error) => `- ${error}`).join("\n"));
  process.exit(1);
}

console.log("locale set is consistent");

Falhas concretas

FalhaResultadoProteção
Ler títulos com regexFalso título dentro de código entra no índicePercorrer nós heading
tags vira stringFiltros e posts relacionados quebramValidar tipos do frontmatter
Slug inconsistenteÂncoras quebram por idiomaUsar o mesmo slugger
Confiar em raw HTMLRisco XSS por tags ou atributosSanitizar com schema
Não checar links externosDocs oficiais mudam sem alertaTestar antes de publicar
Prompt amplo demaisArquivos de outros workers são alteradosFixar owned_files

Essas falhas devem estar no prompt. Claude Code responde melhor a restrições verificáveis do que a uma frase vaga como “deixe mais profissional”.

Prompt seguro para Claude Code

task: "Refresh one published MDX article"
owned_files:
  - "site/src/content/blog-pt/claude-code-markdown-processing.mdx"
preserve:
  - "slug path"
  - "heroImage"
  - "unrelated dirty files"
required:
  - "updatedDate: 2026-06-02"
  - "description <= 120 characters"
  - "AST-based Markdown checks"
  - "official external links"
  - "internal links and monetization CTA"
forbidden:
  - "regex-only heading parsing"
  - "raw HTML without sanitization"
  - "thin locale summaries"
verification:
  - "node scripts/check-code-fences.mjs"
  - "node scripts/check-updated-article-quality.mjs"

Checagem antes de publicar e CTA

Antes de publicar, combine scripts e revisão humana. Scripts checam estrutura, metadata, fences, links e profundidade. A pessoa revisa naturalidade, intenção de busca, leitura mobile e CTA.

node tools/audit-mdx.mjs site/src/content/blog-pt/claude-code-markdown-processing.mdx
node tools/check-locales.mjs
node scripts/check-code-fences.mjs
node scripts/check-updated-article-quality.mjs

Para uso individual, comece pela cheatsheet gratuita de Claude Code. Para prompts reutilizáveis de review e escrita, use os Claude Code prompt templates. Para equipes que precisam de permissões, CI, fluxo multilíngue e revisão editorial, veja treinamento e consultoria Claude Code.

Resultado do teste prático

Nesta atualização, Masa tratou o artigo como pipeline real de conteúdo: description curta, updatedDate, heroImage preservado, linguagens em code fences, links oficiais, locales completos e CTA. A auditoria baseada em AST cobre erros que regex não vê, principalmente títulos dentro de blocos de código e sintaxe MDX perto de componentes. No final, os comandos usados foram node scripts/check-code-fences.mjs e node scripts/check-updated-article-quality.mjs. A lição é que Claude Code fica confiável quando o contrato do artigo é executável, não apenas quando o prompt pede “mais qualidade”.

#Claude Code #Markdown #MDX #remark #operações de conteúdo
Grátis

PDF grátis: cheatsheet do Claude Code

Informe seu e-mail e baixe uma página com comandos, hábitos de revisão e workflows seguros.

Cuidamos dos seus dados e não enviamos spam.

Masa

Sobre o autor

Masa

Engenheiro focado em workflows práticos com Claude Code.