Skip to content

Metalsmith Plugin for setting default values to file metadata

License

Notifications You must be signed in to change notification settings

metalsmith/default-values

Repository files navigation

@metalsmith/default-values

A Metalsmith plugin for setting default values to file metadata.

metalsmith: core plugin npm: version ci: build code coverage license: LGPL-3.0

Features

  • sets default values for metadata keys and file contents on files matched by pattern
  • does not overwrite or transform key values that are already defined, unless strategy: 'overwrite'.
  • can set computed defaults based on other file keys or metalsmith metadata

Installation

NPM:

npm install @metalsmith/default-values

Yarn:

yarn add @metalsmith/default-values

Usage:

Pass @metalsmith/default-values to metalsmith.use:

import defaultValues from '@metalsmith/default-values'

// single defaults set for all HTML and markdown files
metalsmith.use({
  defaults: {
    pattern: '**/*.md',
    title: 'Lorem ipsum'
  }
})

metalsmith.use(
  defaultValues([
    {
      pattern: 'posts/*.md',
      defaults: {
        layout: 'post.hbs',
        date: function (post) {
          return post.stats.ctime
        }
      }
    },
    {
      pattern: 'diary/*.md',
      defaults: {
        layout: 'diary.hbs',
        private: true
      }
    },
    {
      pattern: ['diary/*.md', 'archive/**/*.md'],
      defaults: {
        no_index: true
      }
    },
    {
      pattern: '**/*.md',
      defaults: {
        layout: 'default.hbs'
      }
    }
  ])
)

Options

@metalsmith/default-values takes an array of defaults sets or a single defaults set. The defaults set has the following properties:

  • pattern (string|string[]): One or more glob patterns to match file paths. Defaults to '**' (all).
  • defaults (Object<string, any>): An object whose key-value pairs will be added to file metadata. You can also specify a function callback(file, metadata) to set dynamic defaults based on existing file or global metadata.
  • strategy ('keep'|'overwrite'): Strategy to handle setting defaults to keys that are aleady defined.

Examples

Setting defaults at a keypath

You can set a default at a file's nested keypath:

metalsmith.use(
  defaultValues({
    pattern: '**/*.md',
    defaults: {
      pubdate(file) { return new Date() }
      'config.scripts.app': '/app.js'
    }
  })
)

Setting default objects

If you assign a default object like this:

metalsmith.use(defaultValues({ defaults: { someObject: { id: 'some' } } }))

All files to which the value was set will refer to the same object (files['index.html'].someObject === files['other.html'].someObject). If the object needs to be unique for each file, use a default setter function or specify each property as a keypath:

// using a function
metalsmith.use(
  defaultValues({
    defaults: {
      someObject: () => ({ id: 'some', other: true })
    }
  })
)

// using keypaths
metalsmith.use(
  defaultValues({
    defaults: {
      'someObject.id': 'some',
      'someObject.other': true
    }
  })
)

Setting default contents

You can set a file's default contents (which is a Node buffer) and any other Buffer properties:

metalsmith.use(
  defaultValues({
    pattern: '**/*.md',
    defaults: {
      strategy: 'overwrite',
      contents: Buffer.from('TO DO')
    }
  })
)

When using a JSON config, a string can be used as default and it will automatically be transformed into a buffer.

Setting dynamic defaults

You can set dynamic defaults based on current file metadata or metalsmith metadata:

metalsmith
  .metadata({
    build: { timestamp: Date.now() }
  })
  .use(
    defaultValues([
      {
        strategy: 'overwrite',
        defaults: {
          buildInfo(file, metadata) {
            return metadata.build
          },
          excerpt(file) {
            return file.contents.toString().slice(0, 200)
          }
        }
      }
    ])
  )

Combining with other plugins

@metalsmith/default-values works great with other @metalsmith plugins. The example below attaches a collection and layout matching the parent directory for all files in the directories services,products, and articles:

import slugify from 'slugify'
const contentTypes = ['product', 'service', 'article']

metalsmith
  .use(
    defaultValues(
      contentTypes.map((contentType) => ({
        pattern: `${contentType}s/*.md`, // pluralized
        defaults: {
          collection: `${contentType}s`, // pluralized
          bodyClass: contentType,
          layout: `${contentType}.njk`, // using jstransformer-nunjucks
          contentLength(file) {
            if (file.contents) return file.contents.toString().length
            return 0
          }
        }
      }))
    )
  )
  .use(markdown()) // @metalsmith/markdown
  .use(collections()) // @metalsmith/collections
  .use(
    layouts({
      // @metalsmith/layouts
      pattern: '**/*.html'
    })
  )

Debug

To enable debug logs, set the DEBUG environment variable to @metalsmith/default-values*:

metalsmith.env('DEBUG', '@metalsmith/default-values*')

Alternatively you can set DEBUG to @metalsmith/* to debug all Metalsmith core plugins.

CLI usage

To use this plugin with the Metalsmith CLI, add @metalsmith/default-values to the plugins key in your metalsmith.json file:

{
  "plugins": [
    {
      "@metalsmith/default-values": [
        {
          "pattern": "diary/*.md",
          "defaults": {
            "layout": "diary.hbs",
            "private": true
          }
        }
      ]
    }
  ]
}

License

LGPL-3.0 or later