';
+ fig.setAttribute('data-c4-estado', 'erro');
+ return false;
+ }
+ var lay = calcularLayout(prep, opcoes);
+ contador += 1;
+ var idBase = 'c4-' + vistaId.replace(/[^a-z0-9-]/gi, '') + '-' + contador;
+ // ajusta à largura quando o texto ainda fica legível (escala >= 62%); senão, tamanho real com rolagem
+ var disponivel = fig.clientWidth || 0;
+ var ajustado = disponivel ? disponivel >= lay.largura * 0.62 : lay.largura <= CFG.larguraAjustavel;
+ var html = '';
+ html += '' + esc(prep.vista.titulo) + 'C4 · ' + esc(NIVEIS[prep.vista.nivel] || prep.vista.nivel) + '';
+ html += '
' +
+ 'Clique (ou Enter) numa caixa para ver a descrição e as fontes.
';
+ html += '
' + gerarSvg(prep, lay, idBase, opcoes) + '
';
+ html += legendaHtml(prep);
+ html += '';
+ html += tabelaHtml(prep);
+ fig.innerHTML = html;
+ fig.setAttribute('data-c4-estado', 'ok');
+ fig.__c4 = { prep: prep, layout: lay };
+ ouvir(fig);
+ return true;
+ }
+
+ /** Acha `figure[data-c4]` em `raiz` e desenha cada vista. Devolve quantas desenhou. */
+ function desenhar(raiz, modelo, opcoes) {
+ raiz = raiz || global.document;
+ if (!raiz || typeof raiz.querySelectorAll !== 'function') return 0;
+ injetarEstilo(raiz.ownerDocument || global.document);
+ ligarImpressao();
+ var figs = raiz.querySelectorAll('figure[data-c4]');
+ var n = 0;
+ for (var i = 0; i < figs.length; i++) if (desenharFigura(figs[i], modelo, opcoes)) n++;
+ return n;
+ }
+
+ var api = {
+ desenhar: desenhar,
+ prepararVista: prepararVista,
+ calcularLayout: calcularLayout,
+ gerarSvg: gerarSvg,
+ tabelaHtml: tabelaHtml,
+ quebrarTexto: quebrarTexto,
+ validarModelo: validarModelo,
+ ESTILO: ESTILO, // folha do diagrama; sob CSP sem estilo inline, sirva-a como .css com id="atm-c4-estilo" (aí não é injetada)
+ TIPOS: TIPOS.slice()
+ };
+ global.ATM_C4 = api;
+ if (typeof module !== 'undefined' && module.exports) module.exports = api;
+ })(typeof window !== 'undefined' ? window : globalThis);
+
+ painel-markdown.js: |
+ /* ===========================================================================
+ markdown.js — renderizador Markdown do visualizador de governança.
+
+ Sem dependências. Funciona no navegador (window.ATMMarkdown) e no Node
+ (module.exports), para os testes em markdown.teste.js.
+
+ SEGURANÇA
+ Todo texto do conteúdo é escapado. HTML cru escrito no Markdown NÃO é
+ interpretado: aparece como texto. As únicas exceções são (comum em
+ célula de tabela), que vira quebra de linha, e comentários , que
+ são descartados. Links e imagens só aceitam http, https, mailto, âncora e
+ caminho relativo; qualquer outro esquema (javascript:, data:, ...) vira "#".
+
+ SUPORTE
+ Títulos ATX (#) e setext (=== / ---), parágrafos, ênfase (* _ ** __ ~~),
+ código inline e em bloco (``` ~~~ e recuo de 4 espaços), listas ordenadas
+ e não ordenadas aninhadas (inclusive de tarefa: - [ ] / - [x]), tabelas
+ GFM com alinhamento, citações aninhadas, links inline, de referência e
+ automáticos ( e URL solta), imagens, regras horizontais e
+ quebras de linha (dois espaços ou barra invertida no fim da linha).
+ Bloco cercado ```c4 vira
,
+ que o c4.js desenha a partir do modelo (ATM_GOV.c4).
+
+ CÓPIA NO PAINEL DO DONO
+ frontend/publico/painel-markdown.js é cópia byte a byte deste arquivo
+ (`python governanca/gerar.py --copiar-para-o-painel`); o gerar.py avisa
+ quando as duas divergem.
+
+ USO
+ ATMMarkdown.render(md, {
+ resolverLink: function (href) { return hrefNovo ou null },
+ resolverImagem: function (src) { return srcNovo ou null },
+ prefixoId: '', // prefixo dos ids dos títulos
+ alinhamentoPorClasse: false // true: alinhamento de tabela por classe, sem style=
+ })
+ -> { html: '...', titulos: [{ nivel, texto, id }] }
+ =========================================================================== */
+ (function (raiz, fabrica) {
+ var api = fabrica();
+ if (typeof module === 'object' && module.exports) module.exports = api;
+ else raiz.ATMMarkdown = api;
+ })(typeof self !== 'undefined' ? self : this, function () {
+ 'use strict';
+
+ /* ---------------------------------------------------------------- util */
+
+ function escapar(s) {
+ return String(s)
+ .replace(/&/g, '&')
+ .replace(//g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, ''');
+ }
+
+ var PONTUACAO = /[!-\/:-@\[-`{-~¡-¿‐-‧‰-⁞]/;
+ var ESPACO = /\s/;
+
+ function ehBranca(linha) { return /^\s*$/.test(linha); }
+
+ function recuo(linha) {
+ var m = /^ */.exec(linha);
+ return m[0].length;
+ }
+
+ /* Slug no estilo do GitHub: minúsculas, mantém letras acentuadas, troca
+ espaço por hífen e descarta o resto da pontuação. Assim uma âncora
+ escrita à mão pelo autor ("#visão-geral") bate com o id gerado. */
+ function slug(texto) {
+ return String(texto)
+ .trim()
+ .toLowerCase()
+ .replace(/[^\p{L}\p{N}\p{M}_\- ]/gu, '')
+ .replace(/ /g, '-');
+ }
+
+ function semAcento(s) {
+ return String(s).normalize('NFD').replace(/[̀-ͯ]/g, '');
+ }
+
+ var ESQUEMA = /^([a-zA-Z][a-zA-Z0-9+.\-]*):/;
+
+ /* Devolve um href seguro, ou "#" se o esquema não for permitido. */
+ function urlSegura(url) {
+ var u = String(url).trim();
+ // Remove caracteres de controle e espaços que navegadores ignoram dentro
+ // do esquema ("java\tscript:").
+ var limpo = u.replace(/[\u0000- \u007F]/g, '');
+ var m = ESQUEMA.exec(limpo);
+ if (m) {
+ var esq = m[1].toLowerCase();
+ if (esq !== 'http' && esq !== 'https' && esq !== 'mailto') return '#';
+ }
+ return u;
+ }
+
+ function textoPuro(html) {
+ return html
+ .replace(/<[^>]*>/g, '')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/"/g, '"')
+ .replace(/'/g, "'")
+ .replace(/&/g, '&');
+ }
+
+ /* -------------------------------------------------------------- inline */
+
+ /* O texto vira uma lista de nós: texto cru, HTML já pronto (código, link)
+ e delimitadores de ênfase. A ênfase é resolvida depois, numa versão
+ simplificada do algoritmo do CommonMark ("process emphasis"). */
+
+ function Inline(ctx) { this.ctx = ctx; }
+
+ Inline.prototype.render = function (texto) {
+ var nos = this.tokenizar(texto);
+ this.enfase(nos);
+ return this.serializar(nos);
+ };
+
+ Inline.prototype.tokenizar = function (s) {
+ var nos = [];
+ var buf = '';
+ var i = 0;
+ var n = s.length;
+ var self = this;
+
+ function despejar() {
+ if (buf) { nos.push({ t: 'txt', v: buf }); buf = ''; }
+ }
+ function html(v) { despejar(); nos.push({ t: 'html', v: v }); }
+
+ while (i < n) {
+ var c = s.charAt(i);
+
+ // Escape com barra invertida.
+ if (c === '\\') {
+ var prox = s.charAt(i + 1);
+ if (prox === '\n') { html(' \n'); i += 2; continue; }
+ if (prox && PONTUACAO.test(prox) && prox.charCodeAt(0) < 128) {
+ buf += prox; i += 2; continue;
+ }
+ buf += c; i++; continue;
+ }
+
+ // Código inline.
+ if (c === '`') {
+ var ini = i;
+ while (i < n && s.charAt(i) === '`') i++;
+ var marca = s.slice(ini, i);
+ var fim = acharCrases(s, i, marca.length);
+ if (fim < 0) { buf += marca; continue; }
+ var cod = s.slice(i, fim).replace(/\n/g, ' ');
+ if (/^ .*[^ ].* $/.test(cod) || /^ [^ ] $/.test(cod)) cod = cod.slice(1, -1);
+ html('' + escapar(cod) + '');
+ i = fim + marca.length;
+ continue;
+ }
+
+ // Quebra dura: dois ou mais espaços antes da quebra de linha.
+ if (c === '\n') {
+ var mb = / {2,}$/.exec(buf);
+ if (mb) { buf = buf.slice(0, mb.index); html(' \n'); }
+ else { buf = buf.replace(/ +$/, ''); buf += '\n'; }
+ i++;
+ while (s.charAt(i) === ' ') i++;
+ continue;
+ }
+
+ // Comentário HTML: descartado.
+ if (c === '<' && s.substr(i, 4) === '', i + 4);
+ if (fc >= 0) { i = fc + 3; continue; }
+ }
+
+ // permitido.
+ if (c === '<') {
+ var mbr = /^ /i.exec(s.slice(i));
+ if (mbr) { html(' '); i += mbr[0].length; continue; }
+ var mal = /^<((?:https?|mailto):[^\s<>]*)>/i.exec(s.slice(i));
+ if (mal) { html(self.link(mal[1], escapar(mal[1]), '')); i += mal[0].length; continue; }
+ var mem = /^<([A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,})>/.exec(s.slice(i));
+ if (mem) { html(self.link('mailto:' + mem[1], escapar(mem[1]), '')); i += mem[0].length; continue; }
+ }
+
+ // Imagem e link.
+ if (c === '!' && s.charAt(i + 1) === '[') {
+ var img = self.lerLink(s, i + 1);
+ if (img) {
+ html(self.imagem(img.dest, textoPuro(self.render(img.texto)), img.titulo));
+ i = img.fim; continue;
+ }
+ }
+ // Link dentro de link não existe em HTML: o "[" interno fica como texto.
+ if (c === '[' && !self.ctx.dentroDeLink) {
+ var lk = self.lerLink(s, i);
+ if (lk) {
+ self.ctx.dentroDeLink = true;
+ var dentro = self.render(lk.texto);
+ self.ctx.dentroDeLink = false;
+ html(self.link(lk.dest, dentro, lk.titulo));
+ i = lk.fim; continue;
+ }
+ }
+
+ // URL solta (extensão GFM).
+ if ((c === 'h' || c === 'H') && !self.ctx.dentroDeLink) {
+ var antes = i > 0 ? s.charAt(i - 1) : ' ';
+ if (!/[A-Za-z0-9]/.test(antes)) {
+ var mu = /^https?:\/\/[^\s<]+/i.exec(s.slice(i));
+ if (mu) {
+ var url = aparaUrl(mu[0]);
+ html(self.link(url, escapar(url), ''));
+ i += url.length; continue;
+ }
+ }
+ }
+
+ // Delimitadores de ênfase.
+ if (c === '*' || c === '_' || c === '~') {
+ var j = i;
+ while (j < n && s.charAt(j) === c) j++;
+ var qtd = j - i;
+ if (c === '~' && qtd !== 2) { buf += s.slice(i, j); i = j; continue; }
+ var ant = i > 0 ? s.charAt(i - 1) : ' ';
+ var dep = j < n ? s.charAt(j) : ' ';
+ var antEsp = ESPACO.test(ant), depEsp = ESPACO.test(dep);
+ var antPont = PONTUACAO.test(ant), depPont = PONTUACAO.test(dep);
+ var esq = !depEsp && (!depPont || antEsp || antPont);
+ var dir = !antEsp && (!antPont || depEsp || depPont);
+ var abre, fecha;
+ if (c === '_') {
+ abre = esq && (!dir || antPont);
+ fecha = dir && (!esq || depPont);
+ } else {
+ abre = esq; fecha = dir;
+ }
+ despejar();
+ nos.push({ t: 'del', c: c, n: qtd, orig: qtd, abre: abre, fecha: fecha });
+ i = j;
+ continue;
+ }
+
+ buf += c;
+ i++;
+ }
+ despejar();
+ return nos;
+ };
+
+ function acharCrases(s, de, tam) {
+ var i = de;
+ while (i < s.length) {
+ var p = s.indexOf('`', i);
+ if (p < 0) return -1;
+ var j = p;
+ while (j < s.length && s.charAt(j) === '`') j++;
+ if (j - p === tam) return p;
+ i = j;
+ }
+ return -1;
+ }
+
+ function aparaUrl(url) {
+ // Pontuação final não faz parte da URL; ")" só fica se estiver casado.
+ for (;;) {
+ var ult = url.charAt(url.length - 1);
+ if (/[.,:;!?*_~'"]/.test(ult)) { url = url.slice(0, -1); continue; }
+ if (ult === ')') {
+ var abre = (url.match(/\(/g) || []).length;
+ var fecha = (url.match(/\)/g) || []).length;
+ if (fecha > abre) { url = url.slice(0, -1); continue; }
+ }
+ return url;
+ }
+ }
+
+ /* Lê [texto](destino "título") ou [texto][ref] / [texto][] / [texto]
+ a partir de s[i] === '['. Devolve null se não for link. */
+ Inline.prototype.lerLink = function (s, i) {
+ var n = s.length;
+ var prof = 0;
+ var j = i;
+ for (; j < n; j++) {
+ var c = s.charAt(j);
+ if (c === '\\') { j++; continue; }
+ if (c === '`') {
+ var k = j; while (k < n && s.charAt(k) === '`') k++;
+ var f = acharCrases(s, k, k - j);
+ if (f >= 0) { j = f + (k - j) - 1; continue; }
+ j = k - 1; continue;
+ }
+ if (c === '[') prof++;
+ else if (c === ']') { prof--; if (prof === 0) break; }
+ }
+ if (j >= n) return null;
+ var texto = s.slice(i + 1, j);
+ var p = j + 1;
+
+ if (s.charAt(p) === '(') {
+ var q = p + 1;
+ while (q < n && /[ \t\n]/.test(s.charAt(q))) q++;
+ var dest = '';
+ if (s.charAt(q) === '<') {
+ var fimA = s.indexOf('>', q);
+ if (fimA < 0) return null;
+ dest = s.slice(q + 1, fimA);
+ q = fimA + 1;
+ } else {
+ var par = 0;
+ var d0 = q;
+ while (q < n) {
+ var ch = s.charAt(q);
+ if (ch === '\\') { q += 2; continue; }
+ if (/\s/.test(ch)) break;
+ if (ch === '(') par++;
+ else if (ch === ')') { if (par === 0) break; par--; }
+ q++;
+ }
+ dest = s.slice(d0, q);
+ }
+ while (q < n && /[ \t\n]/.test(s.charAt(q))) q++;
+ var titulo = '';
+ var ab = s.charAt(q);
+ if (ab === '"' || ab === "'" || ab === '(') {
+ var fe = ab === '(' ? ')' : ab;
+ var ft = s.indexOf(fe, q + 1);
+ if (ft < 0) return null;
+ titulo = s.slice(q + 1, ft);
+ q = ft + 1;
+ while (q < n && /[ \t\n]/.test(s.charAt(q))) q++;
+ }
+ if (s.charAt(q) !== ')') return null;
+ return { texto: texto, dest: dest.replace(/\\([!-\/:-@\[-`{-~])/g, '$1'), titulo: titulo, fim: q + 1 };
+ }
+
+ // Referência.
+ var refs = this.ctx.refs;
+ var rotulo = null;
+ var fim = p;
+ if (s.charAt(p) === '[') {
+ var fr = s.indexOf(']', p + 1);
+ if (fr >= 0) {
+ rotulo = s.slice(p + 1, fr) || texto;
+ fim = fr + 1;
+ }
+ }
+ if (rotulo === null) rotulo = texto;
+ var def = refs[normRotulo(rotulo)];
+ if (!def) return null;
+ return { texto: texto, dest: def.dest, titulo: def.titulo, fim: fim };
+ };
+
+ function normRotulo(r) { return String(r).trim().replace(/\s+/g, ' ').toLowerCase(); }
+
+ Inline.prototype.link = function (dest, htmlTexto, titulo) {
+ var href = dest;
+ var externo = /^(https?:)?\/\//i.test(dest);
+ if (this.ctx.resolverLink && !externo && !/^mailto:/i.test(dest)) {
+ var r = this.ctx.resolverLink(dest);
+ if (r) href = r;
+ }
+ href = urlSegura(href);
+ var attrs = ' href="' + escapar(href) + '"';
+ if (titulo) attrs += ' title="' + escapar(titulo) + '"';
+ if (externo) attrs += ' class="externo" target="_blank" rel="noopener noreferrer"';
+ return '' + htmlTexto + '';
+ };
+
+ Inline.prototype.imagem = function (src, alt, titulo) {
+ var s = src;
+ if (this.ctx.resolverImagem && !/^(https?:)?\/\//i.test(src)) {
+ var r = this.ctx.resolverImagem(src);
+ if (r) s = r;
+ }
+ s = urlSegura(s);
+ if (/^mailto:/i.test(s)) s = '#';
+ var attrs = ' src="' + escapar(s) + '" alt="' + escapar(alt) + '" loading="lazy"';
+ if (titulo) attrs += ' title="' + escapar(titulo) + '"';
+ return '';
+ };
+
+ Inline.prototype.enfase = function (nos) {
+ var k = 0;
+ while (k < nos.length) {
+ var fe = nos[k];
+ if (fe.t !== 'del' || !fe.fecha || fe.n === 0) { k++; continue; }
+ // Procura um abridor compatível para trás.
+ var a = k - 1;
+ var achou = -1;
+ for (; a >= 0; a--) {
+ var ab = nos[a];
+ if (ab.t !== 'del' || ab.c !== fe.c || !ab.abre || ab.n === 0) continue;
+ if (fe.c === '~' && ab.n !== fe.n) continue;
+ // Regra do múltiplo de 3 (CommonMark).
+ if ((ab.fecha || fe.abre) && (ab.orig + fe.orig) % 3 === 0 &&
+ !(ab.orig % 3 === 0 && fe.orig % 3 === 0)) continue;
+ achou = a; break;
+ }
+ if (achou < 0) {
+ if (!fe.abre) fe.fecha = false; // não fecha nada; vira texto
+ k++;
+ continue;
+ }
+ var abr = nos[achou];
+ var usa = fe.c === '~' ? 2 : (abr.n >= 2 && fe.n >= 2 ? 2 : 1);
+ var tag = fe.c === '~' ? 'del' : (usa === 2 ? 'strong' : 'em');
+ var meio = nos.slice(achou + 1, k);
+ var htmlMeio = this.serializar(meio);
+ abr.n -= usa;
+ fe.n -= usa;
+ var novo = { t: 'html', v: '<' + tag + '>' + htmlMeio + '' + tag + '>' };
+ nos.splice(achou + 1, k - achou - 1, novo);
+ k = achou + 2; // posição do fechador
+ if (abr.n === 0) { nos.splice(achou, 1); k--; }
+ if (fe.n === 0) { nos.splice(k, 1); }
+ }
+ };
+
+ Inline.prototype.serializar = function (nos) {
+ var out = '';
+ for (var i = 0; i < nos.length; i++) {
+ var no = nos[i];
+ if (no.t === 'txt') out += escapar(no.v);
+ else if (no.t === 'html') out += no.v;
+ else if (no.t === 'del') out += escapar(new Array(no.n + 1).join(no.c));
+ }
+ return out;
+ };
+
+ /* -------------------------------------------------------------- blocos */
+
+ var RX = {
+ cerca: /^( {0,3})(`{3,}|~{3,})[ \t]*([^\s`]*)[^`]*$/,
+ cercaTil: /^( {0,3})(~{3,})[ \t]*(\S*).*$/,
+ atx: /^ {0,3}(#{1,6})(?:[ \t]+(.*?))?(?:[ \t]+#+)?[ \t]*$/,
+ hr: /^ {0,3}([-*_])(?:[ \t]*\1){2,}[ \t]*$/,
+ citacao: /^ {0,3}> ?/,
+ setext1: /^ {0,3}=+[ \t]*$/,
+ setext2: /^ {0,3}-+[ \t]*$/,
+ comentario: /^ {0,3}') < 0) i++;
+ i++;
+ continue;
+ }
+
+ // Título ATX.
+ var mh = RX.atx.exec(l);
+ if (mh) {
+ out.push({ t: 'titulo', nivel: mh[1].length, texto: (mh[2] || '').trim(), ini: ini, fim: i + 1 });
+ i++;
+ continue;
+ }
+
+ // Regra horizontal.
+ if (RX.hr.test(l)) {
+ out.push({ t: 'hr', ini: ini, fim: i + 1 });
+ i++;
+ continue;
+ }
+
+ // Citação.
+ if (RX.citacao.test(l)) {
+ var cit = [];
+ while (i < n) {
+ var lc = linhas[i];
+ if (RX.citacao.test(lc)) { cit.push(lc.replace(RX.citacao, '')); i++; continue; }
+ // Continuação preguiçosa de parágrafo.
+ if (!ehBranca(lc) && cit.length && !ehBranca(cit[cit.length - 1]) && !interrompe(linhas, i)) {
+ cit.push(lc); i++; continue;
+ }
+ break;
+ }
+ out.push({ t: 'citacao', filhos: this.blocos(cit), ini: ini, fim: i });
+ continue;
+ }
+
+ // Lista.
+ var mk = marcador(l);
+ if (mk) {
+ var lista = this.lista(linhas, i);
+ out.push(lista.bloco);
+ i = lista.prox;
+ continue;
+ }
+
+ // Código por recuo.
+ if (recuo(l) >= 4) {
+ var cod = [];
+ while (i < n && (recuo(linhas[i]) >= 4 || ehBranca(linhas[i]))) {
+ cod.push(linhas[i].slice(Math.min(4, recuo(linhas[i]))));
+ i++;
+ }
+ while (cod.length && ehBranca(cod[cod.length - 1])) { cod.pop(); }
+ // Não consome as linhas em branco do fim.
+ i = ini + cod.length;
+ out.push({ t: 'codigo', lang: '', texto: cod.join('\n'), ini: ini, fim: i });
+ continue;
+ }
+
+ // Tabela.
+ if (ehInicioTabela(linhas, i)) {
+ var cab = celulas(linhas[i]);
+ var alin = celulas(linhas[i + 1]).map(function (d) {
+ var e = d.charAt(0) === ':', r = d.charAt(d.length - 1) === ':';
+ return e && r ? 'center' : r ? 'right' : e ? 'left' : '';
+ });
+ i += 2;
+ var linhasT = [];
+ while (i < n && !ehBranca(linhas[i]) && linhas[i].indexOf('|') >= 0 &&
+ !abreCerca(linhas[i]) && !RX.citacao.test(linhas[i])) {
+ var cs = celulas(linhas[i]);
+ while (cs.length < cab.length) cs.push('');
+ linhasT.push(cs.slice(0, cab.length));
+ i++;
+ }
+ out.push({ t: 'tabela', cab: cab, alin: alin, linhas: linhasT, ini: ini, fim: i });
+ continue;
+ }
+
+ // Parágrafo (ou título setext).
+ var par = [l.replace(/^\s+/, '')];
+ i++;
+ var setext = 0;
+ while (i < n && !ehBranca(linhas[i])) {
+ if (RX.setext1.test(linhas[i])) { setext = 1; i++; break; }
+ if (RX.setext2.test(linhas[i])) { setext = 2; i++; break; }
+ if (interrompe(linhas, i)) break;
+ par.push(linhas[i].replace(/^\s+/, ''));
+ i++;
+ }
+ // Espaços no fim do parágrafo não viram quebra de linha.
+ var txt = par.join('\n').replace(/\s+$/, '');
+ if (setext) out.push({ t: 'titulo', nivel: setext, texto: txt.replace(/\n/g, ' '), ini: ini, fim: i });
+ else out.push({ t: 'par', texto: txt, ini: ini, fim: i });
+ }
+ return out;
+ };
+
+ Analisador.prototype.lista = function (linhas, i) {
+ var n = linhas.length;
+ var primeiro = marcador(linhas[i]);
+ var itens = [];
+ var solta = false;
+ var ini = i;
+
+ while (i < n) {
+ var mk = marcador(linhas[i]);
+ if (!mk || mk.ordenada !== primeiro.ordenada || mk.sinal !== primeiro.sinal) break;
+ if (RX.hr.test(linhas[i])) break;
+ var larg = mk.largura;
+ var conteudo = [mk.conteudo];
+ i++;
+ while (i < n) {
+ var l = linhas[i];
+ if (ehBranca(l)) { conteudo.push(''); i++; continue; }
+ var r = recuo(l);
+ if (r >= larg) { conteudo.push(l.slice(larg)); i++; continue; }
+ var anteriorBranca = ehBranca(conteudo[conteudo.length - 1]);
+ // Tolerância: sublista recuada menos que o exigido (ex.: 2 espaços
+ // sob "1."), comum em texto escrito à mão.
+ var sub = marcador(l);
+ if (sub && r > mk.recuo) { larg = r; conteudo.push(l.slice(r)); i++; continue; }
+ if (anteriorBranca) break;
+ if (!interrompe(linhas, i) && !sub) { conteudo.push(l); i++; continue; }
+ break;
+ }
+ // Linhas em branco no fim do item.
+ var brancas = 0;
+ while (conteudo.length > 1 && ehBranca(conteudo[conteudo.length - 1])) { conteudo.pop(); brancas++; }
+ var proxMk = i < n ? marcador(linhas[i]) : null;
+ var continua = proxMk && proxMk.ordenada === primeiro.ordenada && proxMk.sinal === primeiro.sinal && !RX.hr.test(linhas[i]);
+ if (brancas && continua) solta = true;
+ if (!continua) i -= brancas;
+
+ // Item de tarefa.
+ var tarefa = null;
+ var mt = /^\[([ xX])\][ \t]+/.exec(conteudo[0]);
+ if (mt) { tarefa = mt[1] !== ' '; conteudo[0] = conteudo[0].slice(mt[0].length); }
+
+ var filhos = this.blocos(conteudo);
+ for (var k = 1; k < filhos.length; k++) {
+ if (filhos[k].ini > filhos[k - 1].fim) solta = true;
+ }
+ itens.push({ filhos: filhos, tarefa: tarefa });
+ if (!continua) break;
+ }
+ return {
+ bloco: { t: 'lista', ordenada: primeiro.ordenada, inicio: primeiro.inicio, itens: itens, solta: solta, ini: ini, fim: i },
+ prox: i
+ };
+ };
+
+ /* ------------------------------------------------------------ geração */
+
+ function Gerador(ctx) {
+ this.ctx = ctx;
+ this.inline = new Inline(ctx);
+ }
+
+ Gerador.prototype.blocos = function (blocos, justa) {
+ var out = '';
+ for (var i = 0; i < blocos.length; i++) out += this.bloco(blocos[i], justa);
+ return out;
+ };
+
+ Gerador.prototype.bloco = function (b, justa) {
+ var ctx = this.ctx;
+ switch (b.t) {
+ case 'par':
+ var h = this.inline.render(b.texto);
+ return justa ? h + '\n' : '
' + h + '
\n';
+ case 'titulo':
+ var conteudo = this.inline.render(b.texto);
+ var texto = textoPuro(conteudo).trim();
+ var base = slug(texto) || 'secao';
+ var id = base;
+ if (ctx.slugs[base] !== undefined) {
+ ctx.slugs[base]++;
+ id = base + '-' + ctx.slugs[base];
+ } else {
+ ctx.slugs[base] = 0;
+ }
+ var idFinal = ctx.prefixoId + id;
+ ctx.titulos.push({ nivel: b.nivel, texto: texto, id: idFinal, ancora: id });
+ return '' + conteudo + '\n';
+ case 'hr':
+ return '\n';
+ case 'codigo':
+ // ```c4 -> lugar de um diagrama C4, desenhado depois por
+ // c4.js (window.ATM_C4.desenhar). O id só aceita [a-z0-9-]; sem id
+ // válido, o bloco continua sendo código comum.
+ if (String(b.lang || '').toLowerCase() === 'c4') {
+ var vista = String(b.resto || '').toLowerCase().replace(/[^a-z0-9-]/g, '');
+ if (vista) {
+ return 'Diagrama C4: ' + vista +
+ '\n';
+ }
+ }
+ var lang = String(b.lang || '').replace(/[^\w+#.\-]/g, '');
+ var cls = lang ? ' class="language-' + escapar(lang) + '"' : '';
+ var dl = lang ? ' data-lang="' + escapar(lang) + '"' : '';
+ return '
' + escapar(b.texto) + (b.texto ? '\n' : '') + '
\n';
+ case 'citacao':
+ return '
\n' + this.blocos(b.filhos, false) + '
\n';
+ case 'lista':
+ var tag = b.ordenada ? 'ol' : 'ul';
+ var attrs = b.ordenada && b.inicio !== 1 ? ' start="' + b.inicio + '"' : '';
+ var temTarefa = b.itens.some(function (it) { return it.tarefa !== null; });
+ if (temTarefa) attrs += ' class="tarefas"';
+ var out = '<' + tag + attrs + '>\n';
+ for (var i = 0; i < b.itens.length; i++) {
+ var it = b.itens[i];
+ var caixa = '';
+ if (it.tarefa !== null) {
+ caixa = ' ';
+ }
+ var corpo = this.blocos(it.filhos, !b.solta).replace(/\n$/, '');
+ out += '
' + caixa + corpo + '
\n';
+ }
+ return out + '' + tag + '>\n';
+ case 'tabela':
+ var self = this;
+ function celula(t, v, k) {
+ // Com `alinhamentoPorClasse` (o painel do dono: a CSP recusa style=),
+ // o alinhamento vira a classe `alinha-`.
+ var a = !b.alin[k] ? '' : ctx.alinhamentoPorClasse
+ ? ' class="alinha-' + b.alin[k] + '"' : ' style="text-align:' + b.alin[k] + '"';
+ var sc = t === 'th' ? ' scope="col"' : '';
+ return '<' + t + sc + a + '>' + self.inline.render(v) + '' + t + '>';
+ }
+ var html = '
\n
\n\n
';
+ html += b.cab.map(function (v, k) { return celula('th', v, k); }).join('');
+ html += '
\n\n';
+ if (b.linhas.length) {
+ html += '\n';
+ for (var r = 0; r < b.linhas.length; r++) {
+ html += '