Skip to content

Commit 2b95606

Browse files
committed
Resolves #68: adds ability to render targets in metalsmith.metadata()
1 parent e104d3b commit 2b95606

File tree

4 files changed

+89
-28
lines changed

4 files changed

+89
-28
lines changed

README.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ A Metalsmith plugin to render markdown files to HTML, using [Marked](https://git
1111
## Features
1212

1313
- Compiles `.md` and `.markdown` files in `metalsmith.source()` to HTML.
14-
- Enables rendering file metadata keys to HTML through the [keys option](#rendering-file-metadata)
14+
- Enables rendering file or metalsmith metadata keys to HTML through the [keys option](#rendering-metadata)
1515
- Define a dictionary of markdown globalRefs (for links, images) available to all render targets
1616
- Supports using the markdown library of your choice through the [render option](#using-another-markdown-library)
1717

@@ -75,17 +75,28 @@ metalsmith.use(
7575
- `render` - Specify a custom render function with the signature `(source, engineOptions, context) => string`. `context` is an object with the signature `{ path:string, key:string }` where the `path` key contains the current file path, and `key` contains the target metadata key.
7676
- `engineOptions` Options to pass to the markdown engine (default [marked](https://github.com/markedjs/marked))
7777

78-
### Rendering file metadata
78+
### Rendering metadata
7979

80-
You can render markdown to HTML in file metadata keys by specifying the `keys` option.
81-
The `keys` option also supports dot-delimited key-paths.
80+
You can render markdown to HTML in file or metalsmith metadata keys by specifying the `keys` option.
81+
The `keys` option also supports dot-delimited key-paths. You can also use [globalRefs within them](#defining-a-dictionary-of-markdown-globalrefs)
8282

8383
```js
84-
metalsmith.use(
85-
markdown({
86-
keys: ['html_desc', 'nested.data']
84+
metalsmith
85+
.metadata({
86+
from_metalsmith_metadata: 'I _shall_ become **markdown** and can even use a [globalref][globalref_link]',
87+
markdownRefs: {
88+
globalref_link: 'https://johndoe.com'
89+
}
8790
})
88-
)
91+
.use(
92+
markdown({
93+
keys: {
94+
files: ['html_desc', 'nested.data'],
95+
global: ['from_metalsmith_metadata']
96+
},
97+
globalRefs: 'markdownRefs'
98+
})
99+
)
89100
```
90101

91102
You can even render all keys at a certain path by setting the `wildcard` option and using a globstar `*` in the keypaths.
@@ -170,7 +181,7 @@ metalsith
170181
// eg in a markdown file: [My Twitter profile][twitter]
171182
.use(markdown({ globalRefs: 'global.links' }))
172183
// eg in a handlebars layout: {{ global.links.twitter }}
173-
.use(layouts())
184+
.use(layouts({ pattern: '**/*.html' }))
174185
```
175186

176187
### Custom markdown rendering

lib/index.d.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,15 @@ export type Render<E> = (source: string, engineOptions: EngineOptions<E>, contex
1010

1111
export type Options<E = marked.MarkedOptions> = {
1212
/**
13-
* - Key names of file metadata to render to HTML - can be nested
13+
* - Array of file metadata key names or object with arrays of key names of file or global metadata key names to render to HTML - can be nested keypaths
1414
*/
15-
keys?: string[];
15+
keys?: string[] | {
16+
files: string[]
17+
global: string[]
18+
};
1619
/**
1720
* - Expand `*` wildcards in keypaths
21+
* @default false
1822
*/
1923
wildcard?: boolean;
2024
/**

src/index.js

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function refsObjectToMarkdown(refsObject) {
2323

2424
/**
2525
* @typedef Options
26-
* @property {string[]} [keys] - Key names of file metadata to render to HTML - can be nested
26+
* @property {string[]|{files: string[], global: string[]}} [keys] - Key names of file metadata to render to HTML - can be nested
2727
* @property {boolean} [wildcard=false] - Expand `*` wildcards in keypaths
2828
* @property {string|Object<string, string>} [globalRefs] An object of `{ refname: 'link' }` pairs that will be made available for all markdown files and keys,
2929
* or a `metalsmith.metadata()` keypath containing such object
@@ -33,7 +33,7 @@ function refsObjectToMarkdown(refsObject) {
3333
**/
3434

3535
const defaultOptions = {
36-
keys: [],
36+
keys: {},
3737
wildcard: false,
3838
render: defaultRender,
3939
engineOptions: {},
@@ -52,10 +52,31 @@ function markdown(options = defaultOptions) {
5252
options = Object.assign({}, defaultOptions, options)
5353
}
5454

55+
if (Array.isArray(options.keys)) {
56+
options.keys = { files: options.keys }
57+
}
58+
5559
return function markdown(files, metalsmith, done) {
5660
const debug = metalsmith.debug('@metalsmith/markdown')
5761
const matches = metalsmith.match('**/*.{md,markdown}', Object.keys(files))
5862

63+
function renderKeys(keys, prepend, target, path) {
64+
if (options.wildcard) {
65+
keys = expandWildcardKeypaths(target, keys, '*')
66+
}
67+
68+
keys.forEach((key) => {
69+
const value = get(target, key)
70+
if (typeof value === 'string') {
71+
const context = path === 'metalsmith.metadata()' ? { key } : { path, key }
72+
debug.info('Rendering key "%s" of target "%s"', key.join ? key.join('.') : key, path)
73+
set(target, key, options.render(prepend + value, options.engineOptions, context))
74+
} else if (typeof value !== 'undefined') {
75+
debug.warn('Couldn\'t render key "%s" of target "%s": not a string', key.join ? key.join('.') : key, path)
76+
}
77+
})
78+
}
79+
5980
const legacyEngineOptions = Object.keys(options).filter((opt) => !Object.keys(defaultOptions).includes(opt))
6081
if (legacyEngineOptions.length) {
6182
debug.warn('Starting from version 2.0 marked engine options will need to be specified as options.engineOptions')
@@ -101,25 +122,19 @@ function markdown(options = defaultOptions) {
101122
})
102123
data.contents = Buffer.from(str)
103124

104-
let keys = options.keys
105-
if (options.wildcard) {
106-
keys = expandWildcardKeypaths(data, options.keys, '*')
107-
}
108-
keys.forEach((key) => {
109-
const value = get(data, key)
110-
if (typeof value === 'string') {
111-
debug.info('Rendering key "%s" of file "%s"', key.join ? key.join('.') : key, file)
112-
set(data, key, options.render(globalRefsMarkdown + value, options.engineOptions, { path: file, key }))
113-
// log a warning if the key is defined and of an unexpected type, but not if the property simply is not defined
114-
} else if (typeof value !== 'undefined') {
115-
debug.warn('Couldn\'t render key "%s" of file "%s": not a string', key.join ? key.join('.') : key, file)
116-
}
117-
})
125+
const keys = options.keys && options.keys.files ? options.keys.files : []
126+
renderKeys(keys, globalRefsMarkdown, data, file)
118127

119128
delete files[file]
120129
files[html] = data
121130
})
122131

132+
if (options.keys && options.keys.global) {
133+
debug.info('Processing metalsmith.metadata()')
134+
const meta = metalsmith.metadata()
135+
renderKeys(options.keys.global, globalRefsMarkdown, meta, 'metalsmith.metadata()')
136+
}
137+
123138
done()
124139
}
125140
}

test/index.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ describe('@metalsmith/markdown', function () {
272272
if (err) done(err)
273273
try {
274274
assert.deepStrictEqual(output.slice(0, 1), [
275-
['warn', 'Couldn\'t render key "%s" of file "%s": not a string', 'not_a_string', 'index.md']
275+
['warn', 'Couldn\'t render key "%s" of target "%s": not a string', 'not_a_string', 'index.md']
276276
])
277277
done()
278278
} catch (err) {
@@ -326,6 +326,37 @@ describe('@metalsmith/markdown', function () {
326326
})
327327
})
328328

329+
it('should render keys in metalsmith.metadata()', function (done) {
330+
const ms = msCommon('test/fixtures/basic')
331+
ms.env('DEBUG', '@metalsmith/mardown*')
332+
.metadata({
333+
markdownRefs: {
334+
defined_link: 'https://globalref.io'
335+
},
336+
has_markdown: '**[globalref_link][defined_link]**'
337+
})
338+
.use(
339+
markdown({
340+
keys: {
341+
global: ['has_markdown']
342+
},
343+
globalRefs: 'markdownRefs'
344+
})
345+
)
346+
.process((err) => {
347+
if (err) done(err)
348+
try {
349+
assert.strictEqual(
350+
ms.metadata().has_markdown,
351+
'<p><strong><a href="https://globalref.io">globalref_link</a></strong></p>\n'
352+
)
353+
done()
354+
} catch (err) {
355+
done(err)
356+
}
357+
})
358+
})
359+
329360
it('expandWildCardKeyPath should throw if root is not an object', function () {
330361
try {
331362
expandWildcardKeypath(null, [], '*')

0 commit comments

Comments
 (0)