npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ngx-docs-markdown-kit/parser-md-converter

v0.1.0

Published

Genera README.md multi-flavor (GitHub/npmjs/NuGet) a partir del manifiesto de contenido de un sitio create-ngx-docs-site -- nucleo agnostico de framework (sin dependencias de Angular): marcadores de splice, deteccion de badges, downgrade de las extensione

Readme

@ngx-docs-markdown-kit/parser-md-converter

Nucleo agnostico de framework para generar README.md multi-flavor (GitHub/npmjs/NuGet) a partir del manifiesto de contenido de un sitio create-ngx-docs-site. No escanea el filesystem por su cuenta -- el llamador (generate-readme.mjs en cada sitio) le pasa las paginas ya resueltas.

Expone:

  • markersFor/wrapFullDocument/spliceGranular/spliceFullBlock/extractFullBlock/extractHeaderAndBody -- marcadores <!-- {proyecto}:doc_start --> etc., y las 2 semanticas de insercion (granular para el README del proyecto, bloque completo para el README de la raiz del repo).
  • detectAutoBadges/manualBadges/renderBadgesMarkdown -- badges de version/tecnologia detectados del package.json, mas los bien conocidos (stars/issues/docker/deepwiki) activados a mano.
  • listDependencies/renderDependenciesMarkdown -- lista de dependencias reales.
  • downgradeToMarkdown -- baja fences enriquecidos (image/code-block/card-code-block/content-card/cards) a Markdown compatible.
  • generateFlavorDocument/buildLanguageStub -- arma el documento completo de un flavor.
  • writeWithSizeGuard/ReadmeTooLargeError -- escritura con resguardo de tamano (copia .bak, restaura si se excede el limite).
  • spliceProjectReadme/spliceRepoReadme -- aplica el splice sobre los 2 destinos reales.

Documentacion de uso completa (sintaxis de [readme_ignored], flujo de 2 pasos, config de un sitio) en el propio sitio de docs de create-ngx-docs-site.

parser-md-converter

parser-md-converter

version node npm

Dependencias:

  • @angular/animations: ^22.1.0
  • @angular/cdk: ^22.1.0
  • @angular/common: ^22.1.0
  • @angular/compiler: ^22.1.0
  • @angular/core: ^22.1.0
  • @angular/forms: ^22.1.0
  • @angular/material: ^22.1.0
  • @angular/platform-browser: ^22.1.0
  • @angular/platform-server: ^22.1.0
  • @angular/router: ^22.1.0
  • @angular/ssr: ^22.1.3
  • @ngx-docs-markdown-kit/parser-md: file:./vendor/parser-md/ngx-docs-markdown-kit-parser-md-0.1.0.tgz
  • @ngx-docs-markdown-kit/parser-md-seo: file:./vendor/parser-md-seo/ngx-docs-markdown-kit-parser-md-seo-0.1.0.tgz
  • @ngx-docs-markdown-kit/parser-md-code-block: file:./vendor/parser-md-code-block/ngx-docs-markdown-kit-parser-md-code-block-0.1.0.tgz
  • @ngx-docs-markdown-kit/parser-md-code-block-themes: file:./vendor/parser-md-code-block-themes/ngx-docs-markdown-kit-parser-md-code-block-themes-0.1.0.tgz
  • @ngx-docs-markdown-kit/parser-md-image: file:./vendor/parser-md-image/ngx-docs-markdown-kit-parser-md-image-0.1.0.tgz
  • @ngx-docs-markdown-kit/parser-md-card: file:./vendor/parser-md-card/ngx-docs-markdown-kit-parser-md-card-0.1.0.tgz
  • @ngx-docs-markdown-kit/parser-md-converter: file:./vendor/parser-md-converter/ngx-docs-markdown-kit-parser-md-converter-0.1.0.tgz
  • @ngx-docs-markdown-kit/ui: file:./vendor/ui/ngx-docs-markdown-kit-ui-0.1.0.tgz
  • rxjs: ~7.8.0
  • tslib: ^2.3.0

Apartados de parser-md-converter

  • Docs -- Documentación de @ngx-docs-markdown-kit/parser-md-converter -- genera README.md multi-flavor desde el manifiesto de contenido.
  • Parser MD Converter -- Genera README.md multi-flavor (GitHub/npmjs/NuGet) desde el manifiesto de contenido de un sitio @ngx-docs-markdown-kit.

Docs de parser-md-converter

REGRESAR A APARTADOS DE parser-md-converter


Índice Docs de parser-md-converter

  • Primeros pasos -- Qué genera, y cómo correrlo sobre un sitio create-ngx-docs-site real.
    • Instalación -- Ya viene conectado en cualquier sitio create-ngx-docs-site -- npm run readme.
  • Uso -- El flujo de 2 pasos, el resguardo de tamaño, el config, badges y [readme_ignored].
    • Cómo funciona -- El flujo de 2 pasos -- generar por flavor, después insertar con marcadores en los README reales.
    • CONVERTER_CONFIG -- El config real de un sitio -- projectRoot/repoRoot calculados solos, badges, idiomas.
    • Resguardo de tamaño -- Por qué toda escritura falla duro y restaura el original en vez de dejar un README a medio escribir.
    • "[readme_ignored]" -- Excluir una página puntual del README generado.
  • Ecosistema -- Qué depende realmente de parser-md-converter, y qué reimplementa a propósito en vez de importar.
    • Relación con el ecosistema -- Depende de parser-md, reimplementa a propósito los fences de las demás librerías Angular, y comparte el manifiesto con parser-md-seo.

Primeros pasos de parser-md-converter

< Índice Docs de parser-md-converter


Instalación de parser-md-converter

< Primeros pasos de parser-md-converter


npm install @ngx-docs-markdown-kit/parser-md-converter

Núcleo agnóstico de framework (sin dependencias de Angular) -- pensado para correr con Node plano, en un script de build, NO dentro del bundle del navegador.

Cualquier sitio generado con create-ngx-docs-site ya lo trae conectado por default (no es una extensión --no-<id> -- es infraestructura de publicación, siempre presente): el script frugocorp_modules/parser-md-converter/scripts/generate-readme.mjs y el config frugocorp_modules/parser-md-converter/config/converter.config.ts ya están en la plantilla.

Generar el README real

npm run readme -- --github

Sin flavor explícito, genera los 3 (--github/--npmjs/--nuget). No corre automáticamente como parte de npm run build/npm start -- es un paso deliberado, se corre a mano cuando querés publicar (ver Cómo funciona para el motivo).

Reusa el CONTENT_MANIFEST YA GENERADO por parser-md -- nunca vuelve a escanear el filesystem por su cuenta. Si todavía no corriste npm start/npm run build al menos una vez, no hay manifiesto que leer.

Fuera de un sitio create-ngx-docs-site, es un paquete instalable como cualquier otro de npm (dependencia real de @ngx-docs-markdown-kit/parser-md, no un peer) -- ver Relación con el ecosistema para el detalle de qué asume del resto del kit y qué no.

Uso de parser-md-converter

< Índice Docs de parser-md-converter


Cómo funciona de parser-md-converter

< Uso de parser-md-converter


Paso 1 -- generar un documento por flavor

Por cada flavor pedido (github/npmjs/nuget), arma un documento completo a partir del árbol real de páginas del manifiesto (mismo árbol grupo/orden que usa la navegación del sitio -- ver buildContentManifest de parser-md) y lo guarda en frugocorp_modules/parser-md-converter/generated/README.<flavor>.md (gitignored -- documento intermedio, nunca el destino final).

Ese documento queda envuelto de punta a punta en marcadores, únicos por proyecto (para que 2 proyectos nunca se pisen si comparten un mismo README, ej. la raíz de un monorepo):

<!-- {proyecto}:doc_start -->
<!-- {proyecto}:doc_header_start -->
{título, logo, badges, dependencias}
<!-- {proyecto}:doc_header_end -->
<!-- {proyecto}:doc_body_start -->
{"Apartados de {título}" + un bloque por cada sección de nivel superior}
<!-- {proyecto}:doc_body_end -->
<!-- {proyecto}:doc_end -->

El body está organizado en bloques: cada sección de nivel superior del contenido (profundidad 0 en el manifiesto) es su propio bloque, con su título en ##, un link de vuelta a "Apartados de {título}", y -- si tiene páginas hijas -- su propio sub-índice recursivo (## Índice {título del bloque}) antes de las secciones reales. Un bloque sin hijos (ej. una página de licencia suelta) va directo a su contenido. Los niveles de heading DENTRO de un bloque arrancan en ## para el bloque Y sus hijos directos (no se anida un nivel extra solo por "estar dentro" del bloque), y de ahí para adentro bajan uno por nivel real, tope ######.

Páginas cuyo frontmatter declara [readme_ignored] quedan afuera (ver readme_ignored). Los links internos del sitio (/docs/...) se resuelven al anchor real dentro del mismo documento si la página de destino está incluida, o se sacan por completo ([texto], sin URL) si no -- nunca queda un link roto apuntando a una ruta que no sirve de nada en un README.

Anchors reales de GitHub, no los del sitio

Los links de "Apartados de {título}" y de cada "volver" apuntan a un anchor (#mi-titulo) que tiene que coincidir EXACTO con el que arma GitHub al renderizar un heading -- distinto del slugify que usa @ngx-docs-markdown-kit/parser-md para los anchors internos del sitio corriendo. parser-md saca acentos/letras unicode (pensado para URLs limpias); GitHub NO -- solo baja a minúsculas, saca puntuación ASCII y cambia espacios por guiones, dejando la letra unicode tal cual ("Cómo funciona"cómo-funciona, no como-funciona). Por eso este paquete trae su propia función (github-anchor.ts), que replica ese algoritmo real (mismo criterio que usa remark/ github-slugger por dentro) en vez de reusar slugify -- resuelven 2 problemas distintos para 2 audiencias distintas, mezclarlos habría generado anchors que se ven bien en el sitio pero no funcionan al hacer clic en GitHub. Títulos duplicados dentro del mismo documento se desambiguan con un sufijo (-1, -2, ...) llevando la cuenta por documento generado.

Paso 2 -- insertar en los README reales, NUNCA sobreescribir por completo

Dos destinos, con 2 semánticas de reemplazo distintas:

  1. README de la raíz del PROYECTO (el sitio en sí) -- reemplazo GRANULAR: el header y el body se reemplazan cada uno POR SEPARADO -- todo lo demás (antes del header, entre header y body, después del body) queda intacto. Tu equipo puede escribir contenido propio en cualquiera de esos huecos sin que la próxima corrida lo borre. Solo el flavor github alimenta este destino y el siguiente (es el que tanto GitHub como npmjs terminan leyendo de un solo archivo real).
  2. README de la raíz del repo git que lo contiene (si es una carpeta DISTINTA a la del proyecto -- ej. la raíz de un monorepo) -- reemplazo COMPLETO del bloque doc_start/doc_end, copiando tal cual lo que quedó en el README del proyecto (header + body + lo que tu equipo haya agregado adentro, del paso anterior).

Si el destino todavía no tiene marcadores (primera corrida), el bloque se agrega AL FINAL del archivo, sin asumir ninguna posición "correcta".

Las rutas de imagen del contenido (/images/..., absolutas para el navegador del sitio real) se reescriben distinto según el destino -- public/images/... en el README del proyecto, {ruta relativa real}/public/images/... en el de la raíz del repo -- para que funcionen como archivo real en disco al ver el README en GitHub/npmjs, no solo en el sitio corriendo.

npmjs/nuget quedan como documentos alternativos en generated/, sin destino automático -- listos para copiar a mano donde haga falta (ej. junto a un .csproj real de NuGet).

Toda escritura de este paso (los 3 generated/README.<flavor>.md y los 2 destinos reales) pasa por el mismo resguardo de tamaño -- ver Resguardo de tamaño.

Paso 3 -- actualizar SOLO la propia entrada del índice del repo

No confundir con el sub-índice interno del Paso 1 (## Índice {título del bloque}, dentro del propio documento de un proyecto) -- este es un mecanismo distinto, para un problema distinto: un LISTADO de proyectos, no un índice de páginas dentro de uno.

Cuando el README de la raíz del repo reúne a VARIOS proyectos (ej. un monorepo con un paquete por carpeta), cada uno necesita aparecer como 1 línea en ese listado común, sin que la corrida de un proyecto pise las entradas que ya escribieron los demás. Mecanismo aparte del Paso 2 (que solo mueve el bloque completo de UN proyecto) -- 2 niveles de marcador, anidados:

<!-- indice_auto:start -->
<!-- indice_auto_section_{proyecto-a}:start -->
- [Título A](#título-a) -- descripción de A
<!-- indice_auto_section_{proyecto-a}:end -->
<!-- indice_auto_section_{proyecto-b}:start -->
- [Título B](#título-b) -- descripción de B
<!-- indice_auto_section_{proyecto-b}:end -->
<!-- indice_auto:end -->
  • El contenedor indice_auto:start/end nunca se crea solo -- su posición "correcta" (normalmente debajo del logo, antes de cualquier bloque de proyecto) es una decisión de diseño, no algo que este paquete pueda adivinar. Si no existe todavía, la corrida no hace nada -- se bootstrapea a mano 1 sola vez; de ahí en adelante cada corrida solo actualiza lo que ya está.
  • Dentro del contenedor, cada proyecto tiene su propio par indice_auto_section_{proyecto}:start/ end: si ya existe, la línea se reemplaza en el lugar (el orden entre proyectos se preserva); si no existe, se agrega al final del contenedor (orden de inserción -- reordenable a mano después, sin que la próxima corrida lo pierda).
  • La línea sale de home.md: [Título](#anchor) -- [description] del frontmatter de la página home del proyecto -- mismo githubAnchor() que el Paso 1 (arriba), para que el link funcione clickeado en GitHub. Sin descripción en el frontmatter, la línea queda sin el -- final.
  • Solo corre si el destino existe en disco -- el mismo README de la raíz del repo que alimenta el Paso 2 (o el propio README del proyecto, si projectRoot YA ES la raíz del repo -- caso de un proyecto que documenta el repo completo, no una carpeta particular de un monorepo).

CONVERTER_CONFIG de parser-md-converter

< Uso de parser-md-converter


Vive en frugocorp_modules/parser-md-converter/config/converter.config.ts de cada sitio -- TS fuente, no JSON en runtime (mismo criterio que el resto del config del ecosistema).

export const CONVERTER_CONFIG = {
  title: 'MiProyecto',
  logo: '/images/mi-logo-300x300.jpg',
  projectRoot: { outputPath: 'README.md', path: '.', maxBytes: null },
  repoRoot: { outputPath: 'README.md', path: '../../..', enabled: true, maxBytes: null },
  nuget: { maxBytes: 1_000_000 },
  badges: { stars: null, issues: null, docker: null, deepwiki: null },
  languages: [{ code: 'es', label: 'Español', file: 'README.md' }],
} satisfies ConverterConfig;

projectRoot/repoRoot

Calculados automáticamente por scaffoldSite() UNA SOLA VEZ, al crear el sitio -- detección automática, NO una garantía: revisá/corregí repoRoot.path si tu convención de carpetas es distinta (ej. moviste el sitio a otro lugar después de crearlo). repoRoot.path es la ruta relativa real (calculada subiendo desde la carpeta del sitio hasta el .git más cercano) hasta la raíz del repo que lo contiene -- si no encuentra ninguno, o coincide con la carpeta del propio proyecto, cae a "." (mismo valor que projectRoot.path), lo que auto-anula el splice del repo-root (ver Cómo funciona) sin necesitar un if aparte.

maxBytes: null = sin límite -- nuget.maxBytes sí trae un default real (1_000_000, ~1MB, límite real de NuGet) porque ese flavor SIEMPRE necesita uno.

badges

Bien conocidos por su nombre oficial -- null = no aparece (nunca un badge roto/vacío). El equipo pone el link real cuando quiere activar uno:

| Clave | Valor esperado | Genera | | --- | --- | --- | | stars | URL del repo de GitHub | Badge de estrellas (shields.io), link a /stargazers. | | issues | URL del repo de GitHub | Badge de issues abiertos, link a /issues. | | docker | URL de Docker Hub | Badge fijo "docker-pull", link directo. | | deepwiki | URL de deepwiki | Badge fijo "deepwiki-view", link directo. |

Además de estos, el header SIEMPRE detecta automáticamente badges de versión/tecnología desde el package.json real del proyecto (versión, engines.node, link a npmjs) -- sin config.

languages

Hoy solo un idioma por default (es). Si agregás un segundo, la corrida crea (una vez, si no existe) un stub README.<idioma>.md con un placeholder "🚧 En construcción" + link de vuelta al primero -- nunca traducción automática.

Resguardo de tamaño de parser-md-converter

< Uso de parser-md-converter


Cada archivo que este paquete escribe -- los 3 generated/README.<flavor>.md intermedios, y los 2 destinos reales del paso 2 (README del proyecto, README de la raíz del repo) -- pasa por la misma función de escritura protegida, no un writeFileSync directo.

Qué hace

  1. Si el destino ya existe, lo copia primero a <destino>.bak.
  2. Escribe el contenido nuevo en el destino real.
  3. Mide el archivo ya en disco (no el string en memoria -- el tamaño real que va a pesar en GitHub/npmjs/NuGet).
  4. Si no hay límite configurado (maxBytes: null), listo -- borra el .bak y termina.
  5. Si hay límite y el archivo mide menos, también listo -- borra el .bak.
  6. Si hay límite y el archivo lo supera, borra lo que acaba de escribir, restaura el .bak (o borra el destino directamente si no existía antes) y corta la ejecución lanzando ReadmeTooLargeError.

Por qué falla duro en vez de avisar y seguir

Un README real fuera de límite no es un detalle cosmético -- en NuGet, un paquete con PackageReadmeFile que supera el límite del feed directamente no publica (o el feed lo rechaza según el caso). Preferible cortar la corrida con un error claro que diga cuántos bytes se pasó y de cuánto, que dejar un archivo roto a mitad de escritura o -- peor -- un README que "funciona" en local pero rompe recién en el momento de publicar. Restaurar el .bak automáticamente evita además el peor escenario posible: perder el contenido bueno que ya estaba en el destino porque la corrida nueva falló a mitad de camino.

Dónde aplica un límite real hoy

Solo nuget.maxBytes trae un default real (1_000_000, ~1 MB) en CONVERTER_CONFIG -- ver CONVERTER_CONFIG -- porque ese flavor siempre corre contra un límite real del ecosistema NuGet. projectRoot/repoRoot quedan en maxBytes: null por default (GitHub y npmjs no imponen un límite estricto comparable) -- el equipo puede poner un número ahí igual si quiere protegerse de un README que creció demasiado.

"[readme_ignored]" de parser-md-converter

< Uso de parser-md-converter


Una página que declara este campo en su frontmatter queda AFUERA del README generado -- sigue apareciendo normal en el sitio (navegación, sitemap, todo lo demás), solo se excluye de este mecanismo puntual:

---
[slug]: notas-internas
[title]: Notas internas del equipo
[readme_ignored]: no aplica a un lector externo del paquete
---

El valor es libre -- un motivo, para quien lea el .md fuente más adelante y se pregunte por qué no aparece en el README. Ese texto NUNCA viaja al README -- solo importa que la clave exista.

No requiere ningún cambio en parser-md/content-manifest.ts -- el frontmatter completo de cada página ya viaja genérico en GeneratedPage.meta, este paquete solo lee page.meta['readme_ignored'] al armar la lista de páginas a incluir.

Ecosistema de parser-md-converter

< Índice Docs de parser-md-converter


Relación con el ecosistema de parser-md-converter

< Ecosistema de parser-md-converter


@ngx-docs-markdown-kit/parser-md-converter es, a propósito, el único paquete del kit pensado para correr fuera del navegador -- Node plano, en un script de build, nunca dentro del bundle de Angular. Eso condiciona toda su relación con el resto del ecosistema: depende de una sola librería en serio, y del resto solo conoce una convención de texto, nunca el código.

Lo único de lo que depende de verdad

@ngx-docs-markdown-kit/parser-md es una dependencia real en su package.json (no un peer, no algo opcional) -- reusa directo su parseKeyValueLines() para leer los campos @campo[<Etiqueta>] [lang] de los fences enriquecidos (card-code-block, content-card) al bajarlos a Markdown plano. Nada más del kit se importa en código.

Por qué REIMPLEMENTA en vez de importar el resto

Este paquete reconoce los mismos nombres de fence que declaran @ngx-docs-markdown-kit/parser-md-code-block (code-block), @ngx-docs-markdown-kit/parser-md-image (image) y @ngx-docs-markdown-kit/parser-md-card (content-card, cards, card-code-block) -- pero no depende de NINGUNO de esos 3 paquetes. Los nombres están hardcodeados en fence-downgraders.ts, a propósito duplicados en vez de importados: esas 3 librerías son extensiones de Angular (.use() sobre MarkdownExtensionRegistry, con componentes standalone reales) -- traerlas como dependencia habría arrastrado Angular entero a un paquete que necesita poder correr en cualquier script de Node, sin bundler, sin zone.js, sin @angular/core instalado siquiera. El acoplamiento real es más barato de mantener (una constante de string por fence, ver Cómo funciona) que la alternativa de depender de 3 librerías de UI para leer 5 nombres.

El manifiesto que comparte con parser-md-seo

generate-readme.mjs (el script que corre en cada sitio, no este paquete en sí) lee el mismo CONTENT_MANIFEST que también consume generate-seo-files.mjs de @ngx-docs-markdown-kit/parser-md-seo -- ambos scripts parten del mismo árbol de páginas ya escaneado por parser-md, cada uno lo proyecta a un formato de salida distinto (sitemap/BreadcrumbList/JSON-LD uno, README multi-flavor el otro). Ninguno de los 2 vuelve a tocar el filesystem de contenido por su cuenta ni conoce al otro -- convergen en el mismo dato, generado una sola vez.

Quién lo consume

create-ngx-docs-site es el único consumidor real hoy: lo instala por default en la plantilla de cualquier sitio nuevo (no es una extensión --no-<id> opcional -- es infraestructura de publicación, siempre presente), junto con el script generate-readme.mjs y el config converter.config.ts que lo invocan. Nada le impide correr fuera de ese CLI -- el núcleo (generateFlavorDocument(), spliceProjectReadme(), etc.) solo pide un array de ConverterPage[] ya resuelto, sin asumir de dónde salió.

Parser MD Converter de parser-md-converter

REGRESAR A APARTADOS DE parser-md-converter


GitHub | Sitio | FrugoCorp

parser-md-converter genera un README.md multi-flavor (GitHub/npmjs/NuGet) a partir del mismo manifiesto de contenido que ya arma parser-md -- nucleo agnostico de framework, sin ninguna dependencia de Angular, para poder correr en cualquier pipeline de build o publish.

Por que un README generado y no escrito a mano

Un README a mano se desincroniza del contenido real apenas el sitio crece -- este paquete lo resuelve al reves: splice granular por marcadores unicos (nunca colisionan entre proyectos que comparten un mismo README raiz de monorepo), deteccion de badges, y downgrade automatico de las extensiones de Markdown de este ecosistema (fences enriquecidos) al formato mas simple que cada flavor de destino soporta.

Que trae de base

Indice en "bloques" de 2 niveles (cada raiz del arbol de contenido es un bloque con su propio sub-indice, sin recursion global), y resguardo de tamano para no generar un README inmanejable en sitios con mucho contenido.