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

metalsmith-section-pages

v0.1.3

Published

Generate structured-content pages composed of validated library sections from data records

Downloads

267

Readme

metalsmith-section-pages

metalsmith:plugin npm: version license: MIT test coverage ESM Known Vulnerabilities

Generate structured-content pages composed of validated library sections from data records

This plugin is a fully functional proof-of-concept. However, it is not yet fully tested and may contain bugs. Use with caution.

Turns data records (from a spreadsheet API, a headless CMS, a JSON file, anything that produces an array) into pages built from a component library's sections, the structured-content format used by nunjucks-components and the Metalsmith2025 structured-content starter. Generated pages flow through the normal pipeline: layouts, permalinks, and the component bundler treat them exactly like hand-written pages.

The heart of the plugin is a manifest-aware section builder. Your mapping function writes

section('hero', { text: { title: record.title, titleTag: 'h1' } })

and the builder materializes every other property from the component's own manifest.json fields block (including $use and $extends composition), merges your overrides, and validates the result against the manifest's validation block. The plugin does not know what a hero is; it reads the manifests. A new section in the library is constructible the moment its manifest lands, and a bad record fails the build with a path-precise error instead of rendering wrong.

Installation

npm install metalsmith-section-pages

Requires metalsmith-bundled-components >= 1.3.0 as a peer dependency (its schema and validation utilities are the single source of truth for what sections accept; any site using a section component library already has it).

Usage

Records are loaded into metadata by any earlier step (a fetch plugin, a data file loader, inline code), then this plugin maps each record to a page:

import Metalsmith from 'metalsmith';
import sectionPages from 'metalsmith-section-pages';

Metalsmith(import.meta.dirname)
  .use(loadClassData()) // puts an array at metadata.classes
  .use(
    sectionPages({
      source: 'classes',
      path: (record) => `classes/${record.id}.md`,
      page: (record, { section }) => ({
        seo: { title: record.title, description: record.summary },
        card: { title: record.title, date: record.firstDate },
        sections: [
          section('hero', {
            text: { title: record.title, titleTag: 'h1', prose: record.summary }
          }),
          section('multi-media', {
            mediaType: 'iframe',
            isReverse: true,
            iframe: { src: record.registrationUrl, title: 'Registration form', allow: 'payment' },
            text: { title: 'What to expect', prose: record.whatToExpect },
            disclosures: [
              { title: 'Cancellation policy', prose: record.cancellationPolicy }
            ]
          })
        ]
      })
    })
  )
  .build((err) => {
    if (err) throw err;
  });

Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | source | string \| function | 'records' | Metadata key holding the records array, or an async function (metalsmith) => records | | path | function | (required) | (record, index) => string: repo-relative file path for the generated page | | page | function | (required) | (record, helpers) => page object with a sections array; may be async. helpers is { section } | | componentsPath | string | 'lib/layouts/components' | Directory holding _partials/ and sections/ with their manifest.json files | | layout | string | 'pages/sections.njk' | Layout for generated pages; a page object may override it per page |

The section builder

section(type, overrides):

  1. Loads the component's manifest and resolves its fields block with the bundler's own resolver ($use pulls in a partial's fields, $extends merges shared blocks like commons).
  2. Materializes defaults: the data a fresh authoring form would emit.
  3. Deep-merges your overrides (objects merge, arrays and scalars replace).
  4. Validates the merged section with the bundler's own validateSection, the same code the build runs. Failures throw with the component's error message, naming the exact property.

Hand-assembled section objects in the sections array are validated too, so every generated page is held to the manifests no matter how it was constructed.

Errors are the API

Everything about a data-driven site build that can go quietly wrong is turned into a build failure with a specific message: a missing records array, an unknown section type (listing the known ones), an invalid property value (with its dotted path), duplicate record ids, a generated path colliding with a real source file.

Writing a data provider

If you are building the API that feeds this plugin, read docs/data-provider-contract.md. It covers stable ids, ISO dates as text, publication gating, determinism, failure semantics, and the content/presentation boundary, each learned from a production sheet-driven site.

Debug

DEBUG=metalsmith-section-pages metalsmith

License

MIT © Werner Glinka