Skip to content

Commit

Permalink
Provides access to metalsmith.metadata() within default setter functions
Browse files Browse the repository at this point in the history
  • Loading branch information
webketje committed Feb 26, 2023
1 parent 9dd6a84 commit d4a5723
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 13 deletions.
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ A Metalsmith plugin for setting default values to file metadata.

- 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 metadata
- can set computed defaults based on other file keys or metalsmith metadata

## Installation

Expand Down Expand Up @@ -82,7 +82,7 @@ metalsmith.use(
`@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)` to set dynamic defaults based on other, existing file metadata.
- `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
Expand All @@ -100,6 +100,32 @@ metalsmith.use(
)
```

#### Setting dynamic defaults

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

```js
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`:
Expand Down
5 changes: 2 additions & 3 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Plugin } from 'metalsmith';
import defaultValues from '.';
import { Plugin, File } from 'metalsmith';

export default defaultValues;
export interface DefaultsSet {
/** 1 or more glob patterns to match files. Defaults to `'**'` (all). */
pattern?: string;
/** an object whose keys will be set as file metadata keys */
defaults: {
[key:string]: string;
[key:string]: ((data:File, metadata: {[key:string]:any}) => any)|string|boolean|number|Object;
}
/** Strategy to handle setting defaults to keys that are aleady defined. */
strategy: 'keep'|'overwrite'
Expand Down
10 changes: 8 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import getDefaultsSetter from './set_defaults.js'

/**
* @callback DefaultSetter
* @param {import('metalsmith').File} file
* @param {Object<string, *>} metadata
*/

/**
* @typedef {Object} DefaultsSet
* @property {string|string[]} [pattern="**"] 1 or more glob patterns to match files. Defaults to `'**'` (all).
* @property {Object} [defaults={}] an object whose keys will be set as file metadata keys
* @property {Object<string, *>} [defaults={}] an object whose keys will be set as file metadata keys
* @property {'keep'|'overwrite'} strategy Strategy to handle setting defaults to keys that are aleady defined.
*/

Expand Down Expand Up @@ -50,7 +56,7 @@ function defaultValues(options) {
if (matches.length) {
const setDefaults = getDefaultsSetter(defaultsEntries, strategy)
matches.forEach((file) => {
setDefaults(files[file])
setDefaults(files[file], metalsmith.metadata())
debug.info(
'Defaults set for file "%s", the resulting metadata is: %O',
file,
Expand Down
6 changes: 3 additions & 3 deletions src/set_defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { dset as set } from 'dset'
* Sets defaults for object values
* @param {Array<Array<*>>} defaults
* @param {'keep'|'overwrite'} strategy
* @return {function} Takes an object and sets defaults
* @return {import('.').DefaultSetter} Takes an object and sets defaults
*/
function set_defaults(defaults, strategy) {
return (item) => {
return (item, context) => {
defaults.forEach(([key, defaultValue]) => {
const value = get(item, key)
if (
Expand All @@ -17,7 +17,7 @@ function set_defaults(defaults, strategy) {
value === null ||
(key === 'contents' && item.contents.toString().trim().length === 0)
) {
if (typeof defaultValue === 'function') defaultValue = defaultValue(item)
if (typeof defaultValue === 'function') defaultValue = defaultValue(item, context)
set(item, key, defaultValue)
}
})
Expand Down
23 changes: 20 additions & 3 deletions test/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function relevantProps(expected, files) {
}

describe('@metalsmith/default-values', function () {
before(function(done) {
before(function (done) {
// eslint-disable-next-line import/no-internal-modules
import('../src/set_defaults.js').then(imported => {
set_defaults_lib = imported.default
Expand Down Expand Up @@ -85,11 +85,11 @@ describe('@metalsmith/default-values', function () {

it('logs a warning when no files match a pattern', function (done) {
let warning
function Debugger() {}
function Debugger() { }
Debugger.warn = (msg) => {
warning = msg
}
Debugger.info = () => {}
Debugger.info = () => { }

const msStub = {
match() {
Expand Down Expand Up @@ -245,5 +245,22 @@ describe('@metalsmith/default-values', function () {

assert.deepStrictEqual(actual, expected)
})

it('sets a default computed from additional metadata', function () {
const defaults = {
default_val: true, buildVersion(file, globalMeta) {
return globalMeta.buildVersion
}
}
const set_defaults = set_defaults_lib(Object.entries(defaults))
const actual = set_defaults({ initial: 'yes' }, { buildVersion: '1.0.0' })
const expected = {
initial: 'yes',
default_val: true,
buildVersion: '1.0.0'
}

assert.deepStrictEqual(actual, expected)
})
})
})

0 comments on commit d4a5723

Please sign in to comment.