Skip to content

Commit

Permalink
Allows front-matter defined permalinks to use :placeholder patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
webketje committed Dec 12, 2023
1 parent d5d199f commit 053e92e
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 41 deletions.
61 changes: 20 additions & 41 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,33 +171,15 @@ const normalizeOptions = (options) => {
}
}

/**
* Resolve a permalink path string from an existing file `path`.
*
* @param {String} str The path
* @return {String}
*/
const resolve = (str, directoryIndex = 'index.html') => {
const base = path.basename(str, path.extname(str))
let ret = path.dirname(str)
if (base !== path.basename(directoryIndex, path.extname(directoryIndex))) {
ret = path.join(ret, base).replace(/\\/g, '/')
}

return ret
}

/**
* Replace a `pattern` with a file's `data`.
*
* @param {string} pattern (optional)
* @param {Object} data
* @param {Object} options
* @param {Object} data
*
* @return {Mixed} String or Null
*/
const replace = (pattern, data, options) => {
if (!pattern) return null
const replace = ({ pattern, ...options }, data) => {
// regexparam has logic that interprets a dot as start of an extension name
// we don't want this here, so we replace it temporarily with a NUL char
const remapped = pattern.replace(/\./g, '\0')
Expand All @@ -222,8 +204,9 @@ const replace = (pattern, data, options) => {
}
}

const transformed = route.inject(remapped, ret)

let transformed = route.inject(remapped, ret)
if (path.basename(transformed) === path.basename(options.directoryIndex, path.extname(options.directoryIndex)))
transformed = path.dirname(transformed)
// handle absolute paths
if (transformed.startsWith('/')) return transformed.slice(1)
return transformed
Expand Down Expand Up @@ -273,27 +256,28 @@ function permalinks(options) {
.filter((file) => files[file].permalink !== false)
.forEach((file) => {
const data = files[file]
const hasOwnPermalinkDeclaration = !!data.permalink
debug('checking file: %s', file)

const linkset = findLinkset(data, file, metalsmith)
const permalinkTransformContext = { ...normalizedOptions, ...defaultLinkset, ...linkset }
if (hasOwnPermalinkDeclaration) permalinkTransformContext.pattern = data.permalink

debug('applying pattern: %s to file: %s', linkset.pattern, file)

let ppath

// Override the path with `permalink` option. Before the replace call, so placeholders can also be used in front-matter
if (Object.prototype.hasOwnProperty.call(data, 'permalink')) {
ppath = data.permalink
}

try {
ppath =
replace(
linkset.pattern,
{
...data,
basename:
path.basename(file) === normalizedOptions.directoryIndex
? ''
: path.basename(file, path.extname(file)),
dirname: path.dirname(file)
},
{ ...normalizedOptions, ...defaultLinkset, ...linkset }
) || resolve(file, normalizedOptions.directoryIndex)
ppath = replace(permalinkTransformContext, {
...data,
basename: path.basename(file, path.extname(file)),
dirname: path.dirname(file) === '.' ? '' : path.dirname(file)
})
} catch (err) {
return done(new Error(`${err.message} for file '${file}'`))
}
Expand All @@ -305,11 +289,6 @@ function permalinks(options) {
return done(new Error(msg))
}

// Override the path with `permalink` option
if (Object.prototype.hasOwnProperty.call(data, 'permalink')) {
ppath = data.permalink
}

const out = makeUnique(path.normalize(ppath), files, file, normalizedOptions)
if (out instanceof Error) {
return done(out)
Expand All @@ -322,7 +301,7 @@ function permalinks(options) {
}

// contrary to the 2.x "path" property, the permalink property does not override previously set file metadata
if (!data.permalink) {
if (!hasOwnPermalinkDeclaration) {
data.permalink = permalink
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test
7 changes: 7 additions & 0 deletions test/fixtures/permalink-frontmatter-dynamic/src/test.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
collection: services
service: software-development
permalink: :collection/:service
title: test
---
test
5 changes: 5 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ const fixtures = [
folder: 'permalink-override',
options: ':title'
},
{
message: 'should support dynamic permalink from front-matter metadata',
folder: 'permalink-frontmatter-dynamic',
options: undefined
},
{
message: 'should remove/replace invalid path characters by default',
folder: 'permalink-invalid-chars',
Expand Down

0 comments on commit 053e92e

Please sign in to comment.