Skip to content

Commit

Permalink
BREAKING: Resolves #132, removes deprecated options 'relative','dupli…
Browse files Browse the repository at this point in the history
…catesFail','unique' and 'indexFile' and related bloat
  • Loading branch information
webketje committed Oct 1, 2023
1 parent 3892e08 commit f435b0c
Show file tree
Hide file tree
Showing 27 changed files with 16 additions and 277 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
- test: add test case for array matches & cheat coverage [`5f7734c`](https://github.com/metalsmith/permalinks/commit/5f7734c0c0c2e63bb613572a4ce2412b721dcc66)
- docs: correct typo's & omissions in README.md [`94816a2`](https://github.com/metalsmith/permalinks/commit/94816a2ce45696a24b750265bd0013be9294eeee)
- Deprecates the 'relative' option, cfr. #132 [`ffb7fcb`](https://github.com/metalsmith/permalinks/commit/ffb7fcb41a41259b47856959d73c8e705ae6679f)
- fix: ESM build export * instead of default from regexparam [`e1a9fe6`](https://github.com/metalsmith/permalinks/commit/e1a9fe6684743429741c15148345eb7a43bf7105)
- fix: ESM build export \* instead of default from regexparam [`e1a9fe6`](https://github.com/metalsmith/permalinks/commit/e1a9fe6684743429741c15148345eb7a43bf7105)

#### [v2.4.1](https://github.com/metalsmith/permalinks/compare/v2.4.0...v2.4.1)

Expand Down
44 changes: 0 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,50 +176,6 @@ metalsmith.use(
There are plenty of other options on npm for transliteration and slugs. <https://www.npmjs.com/browse/keyword/transliteration>.
### Relative Files
When this plugin rewrites your files to be permalinked properly, it will also duplicate sibling files so that relative links like `css/style.css` will be preserved nicely. You can turn this feature off by setting the `relative` option to `false`.
For example for this source directory:
src/
css/
style.css
post.html
Here's what the build directory would look like with `relative` on:
build/
post/
index.html
css/
style.css
css/
style.css
And here's with `relative` off:
build/
post/
index.html
css/
style.css
`relative` can also be set to `folder`, which uses a strategy that considers files in folder as siblings if the folder is named after the html file.
For example using the `folder` strategy with this source directory:
src/
post.html
post/
image.jpg
Here's what the build directory would look like with `relative` set to `folder`:
build/
index.html
image.jpg
### Skipping Permalinks for a file
A file can be ignored by the permalinks plugin if you pass the `permalink: false` option to the yaml metadata of a file.
Expand Down
16 changes: 0 additions & 16 deletions lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,6 @@ export type Options = {
* [Moment.js format string](https://momentjs.com/docs/#/displaying/format/) to transform Date link parts into, defaults to `YYYY/MM/DD`.
*/
date?: string;
/**
* **[DEPRECATED]** - _will be defaulted to false and removed in the next major version_. When `true` (by default), will duplicate sibling files so relative links keep working in resulting structure. Turn off by setting `false`. Can also be set to `folder`, which uses a strategy that considers files in folder as siblings if the folder is named after the html file.
*/
relative?: boolean | 'folder';
/**
* **[DEPRECATED]** - _renamed to directoryIndex_. Basename of the permalinked file (default: `index.html`)
*/
indexFile?: string;
/**
* Basename of the permalinked file (default: `index.html`)
*/
Expand All @@ -90,14 +82,6 @@ export type Options = {
* Whether a trailing `/` should be added to the `file.permalink` property. Useful to avoid redirects on servers which do not have a built-in rewrite module enabled.
*/
trailingSlash?: boolean;
/**
* **[DEPRECATED]** - _use `duplicates` option instead_. Set to `true` to add a number to duplicate permalinks (default: `false`), or specify a custom duplicate handling callback of the form `(permalink, files, file, options) => string`
*/
unique?: boolean | Function;
/**
* **[DEPRECATED]** - _use `duplicates` option instead_. Set to `true` to throw an error if multiple file path transforms result in the same permalink. `false` by default
*/
duplicatesFail?: boolean;
/**
* How to handle duplicate target URI's.
*/
Expand Down
170 changes: 8 additions & 162 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,9 @@ const dupeHandlers = {
* @typedef {Object} Options
* @property {string} [pattern] A permalink pattern to transform file paths into, e.g. `blog/:date/:title`
* @property {string} [date='YYYY/MM/DD'] [Moment.js format string](https://momentjs.com/docs/#/displaying/format/) to transform Date link parts into, defaults to `YYYY/MM/DD`.
* @property {boolean|'folder'} [relative=true] _**[DEPRECATED]** - _will be defaulted to false and removed in the next major version_. When `true` (by default), will duplicate sibling files so relative links keep working in resulting structure. Turn off by setting `false`. Can also be set to `folder`, which uses a strategy that considers files in folder as siblings if the folder is named after the html file.
* @property {string} [indexFile='index.html'] _**[DEPRECATED]** - _renamed to directoryIndex_. Basename of the permalinked file (default: `index.html`)
* @property {string} [directoryIndex='index.html'] Basename of the permalinked file (default: `index.html`)
* @property {boolean} [trailingSlash=false] Whether a trailing `/` should be added to the `file.permalink` property. Useful to avoid redirects on servers which do not have a built-in rewrite module enabled.
* @property {boolean|Function} [unique] **[DEPRECATED]** - _use `duplicates` option instead_. Set to `true` to add a number to duplicate permalinks (default: `false`), or specify a custom duplicate handling callback of the form `(permalink, files, file, options) => string`
* @property {boolean} [duplicatesFail=false] **[DEPRECATED]** - _use `duplicates` option instead_. Set to `true` to throw an error if multiple file path transforms result in the same permalink. `false` by default
* @property {'error'|'index'|'overwrite'|Function} [duplicates] How to handle duplicate target URI's.
* @property {'error'|'index'|'overwrite'|Function} [duplicates='error'] How to handle duplicate target URI's.
* @property {Linkset[]} [linksets] An array of additional linksets
* @property {SlugifyOptions|slugFunction} [slug] {@link SlugifyOptions} or a custom slug function of the form `(pathpart) => string`
*/
Expand All @@ -79,9 +75,10 @@ const dupeHandlers = {
const defaultOptions = {
date: 'YYYY/MM/DD',
slug: { lower: true },
relative: true,
trailingSlash: false,
linksets: []
linksets: [],
duplicates: 'error',
directoryIndex: 'index.html'
}

/**
Expand All @@ -102,23 +99,6 @@ function slugFn(options = defaultOptions.slug) {
}
}

/**
* Re-links content
*
* @param {import('metalsmith').File} data
* @param {Object} moved
*
* @return {Void}
*/
const relink = (data, moved) => {
let content = data.contents.toString()
Object.keys(moved).forEach((to) => {
const from = moved[to]
content = content.replace(from, to)
})
data.contents = Buffer.from(content)
}

/**
* Check whether a file is an HTML file.
*
Expand Down Expand Up @@ -147,97 +127,16 @@ const normalizeOptions = (options) => {
}
options = Object.assign({}, defaultOptions, options)

if (!options.duplicates) {
if (options.duplicatesFail) {
options.duplicates = dupeHandlers.error
} else if (options.unique === true) {
options.duplicates = dupeHandlers.index
} else if (typeof options.unique === 'function') {
options.duplicates = options.unique
} else {
options.duplicates = dupeHandlers.overwrite
}
} else if (Object.keys(dupeHandlers).includes(options.duplicates)) {
if (options.duplicates && Object.keys(dupeHandlers).includes(options.duplicates)) {
options.duplicates = dupeHandlers[options.duplicates]
}

if (!options.directoryIndex) {
if (options.indexFile) {
options.directoryIndex = options.indexFile
} else {
options.directoryIndex = 'index.html'
}
}

options.slug = typeof options.slug === 'function' ? options.slug : slugFn(options.slug)
options.date = format(options.date)

return options
}

/**
* Get a list of sibling and children files for a given `file` in `files`.
*
* @param {string} file
* @param {Object} files
* @return {Object}
*/
const family = (file, files) => {
const ret = {}
let dir = path.dirname(file)

if (dir === '.') {
dir = ''
}

for (const key in files) {
/* istanbul ignore next */
if (key === file) continue
/* istanbul ignore next */
if (key.indexOf(dir) !== 0) continue
/* istanbul ignore next */
if (html(key)) continue

const rel = key.slice(dir.length)
ret[rel] = files[key]
}

return ret
}

/**
* Get a list of files that exists in a folder named after `file` for a given `file` in `files`.
*
* @param {string} file
* @param {Object} files
* @return {Object}
*/
const folder = (file, files) => {
const bn = path.basename(file, path.extname(file))
const family = {}
let dir = path.dirname(file)

if (dir === '.') {
dir = ''
}

const sharedPath = path.join(dir, bn, '/')

for (const otherFile in files) {
/* istanbul ignore next */
if (otherFile === file) continue
/* istanbul ignore next */
if (otherFile.indexOf(sharedPath) !== 0) continue
/* istanbul ignore next */
if (html(otherFile)) continue

const remainder = otherFile.slice(sharedPath.length)
family[remainder] = files[otherFile]
}

return family
}

/**
* Resolve a permalink path string from an existing file `path`.
*
Expand Down Expand Up @@ -301,13 +200,11 @@ const replace = (pattern, data, options) => {
*/
function permalinks(options) {
const normalizedOptions = normalizeOptions(options)

let primaryLinkset = normalizedOptions.linksets.find((ls) => Boolean(ls.isDefault))
if (!primaryLinkset) {
primaryLinkset = normalizedOptions
}

const dupes = {}
const findLinkset = (file) => {
const set = normalizedOptions.linksets.find((ls) =>
Object.keys(ls.match).some((key) => {
Expand All @@ -327,13 +224,8 @@ function permalinks(options) {
const debug = metalsmith.debug('@metalsmith/permalinks')
debug.info('Running with options: %O', normalizedOptions)

if (normalizedOptions.relative || normalizedOptions.linksets.find((ls) => ls.relative)) {
debug.warn(
'The relative option is deprecated and its default value will be changed to false before being removed in the next major versions.'
)
debug.warn(
"To prepare for this change, use root-relative URL's in file contents or use a custom markdown renderer to prefix relative URI's."
)
if (normalizedOptions.relative || normalizedOptions.linksets.find((ls) => ls && ls.relative)) {
return done(new Error('The "relative" option is no longer supported.'))
}

const makeUnique = normalizedOptions.duplicates
Expand Down Expand Up @@ -371,18 +263,6 @@ function permalinks(options) {
}
let ppath = replace(linkset.pattern, data, opts) || resolve(file, normalizedOptions.directoryIndex)

let fam
switch (linkset.relative) {
case true:
fam = family(file, files)
break
case 'folder':
fam = folder(file, files)
break
default:
// nothing
}

// Override the path with `permalink` option
if (Object.prototype.hasOwnProperty.call(data, 'permalink') && data.permalink !== false) {
ppath = data.permalink
Expand All @@ -393,57 +273,23 @@ function permalinks(options) {
return done(out)
}

// track duplicates for relative files to maintain references
const moved = {}
if (fam) {
for (const key in fam) {
if (Object.prototype.hasOwnProperty.call(fam, key)) {
const rel = path.posix.join(ppath, key)
dupes[rel] = fam[key]
moved[key] = rel
}
}
}

// add to permalink data for use in links in templates
let permalink = ppath === '.' ? '' : ppath.replace(/\\/g, '/')
if (normalizedOptions.trailingSlash) {
permalink = path.posix.join(permalink, './')
}

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

// this is only to ensure backwards-compat with 2.x, will be removed in 3.x
const descriptor = Object.getOwnPropertyDescriptor(data, 'path')
/* istanbul ignore next */
if (!descriptor || descriptor.configurable) {
Object.defineProperty(data, 'path', {
get() {
debug.warn('Accessing the permalink at "file.path" is deprecated, use "file.permalink" instead.')
return permalink
},
set(value) {
permalink = value
}
})
}

relink(data, moved)

delete files[file]
files[out] = data
})

// add duplicates for relative files after processing to avoid double-dipping
// note: `dupes` will be empty if `options.relative` is false
Object.keys(dupes).forEach((dupe) => {
files[dupe] = dupes[dupe]
})
done()
}
}

// Expose `plugin`
export default permalinks
Empty file.
1 change: 0 additions & 1 deletion test/fixtures/relative-folder/expected/post/index.html

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/relative-folder/src/post.html

This file was deleted.

Empty file.
Empty file.
Empty file.
1 change: 0 additions & 1 deletion test/fixtures/relative-multiple/expected/post/index.html

This file was deleted.

Empty file.
1 change: 0 additions & 1 deletion test/fixtures/relative-multiple/expected/post2/index.html

This file was deleted.

Empty file.
1 change: 0 additions & 1 deletion test/fixtures/relative-multiple/src/post.html

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/relative-multiple/src/post2.html

This file was deleted.

Empty file.
Empty file.

This file was deleted.

Empty file.
5 changes: 0 additions & 5 deletions test/fixtures/relative-pattern/src/post.html

This file was deleted.

Empty file.
Empty file.
1 change: 0 additions & 1 deletion test/fixtures/relative/expected/post/index.html

This file was deleted.

Empty file.
1 change: 0 additions & 1 deletion test/fixtures/relative/src/post.html

This file was deleted.

Loading

0 comments on commit f435b0c

Please sign in to comment.