From c7a56f145e18d7c49885fd42a34ee14760417ed2 Mon Sep 17 00:00:00 2001 From: Kevin Van Lierde Date: Tue, 3 Jan 2023 23:37:21 +0100 Subject: [PATCH] Deprecates file.path in favor of file.permalink and adds better testing --- lib/index.d.ts | 6 ++- src/index.js | 9 ++++- test/index.cjs | 101 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 90 insertions(+), 26 deletions(-) diff --git a/lib/index.d.ts b/lib/index.d.ts index 27e8d32..d98d165 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -75,7 +75,7 @@ export type Options = { */ 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. + * **[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'; /** @@ -86,6 +86,10 @@ export type Options = { * Basename of the permalinked file (default: `index.html`) */ directoryIndex?: string; + /** + * 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` */ diff --git a/src/index.js b/src/index.js index f6e8bdd..8c58f2a 100644 --- a/src/index.js +++ b/src/index.js @@ -67,6 +67,7 @@ const dupeHandlers = { * @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. @@ -81,6 +82,7 @@ const defaultOptions = { slug: { lower: true }, relative: true, indexFile: 'index.html', + trailingSlash: false, unique: false, duplicatesFail: false, linksets: [] @@ -180,8 +182,6 @@ const normalizeOptions = (options) => { } } else if (Object.keys(dupeHandlers).includes(options.duplicates)) { options.duplicates = dupeHandlers[options.duplicates] - } else { - options.duplicates = dupeHandlers.overwrite } if (options.indexFile && !options.directoryIndex) { @@ -406,6 +406,10 @@ function permalinks(options) { // add to permalink data for use in links in templates let permalink = ppath === '.' ? '' : ppath.replace(/\\/g, '/') + if (options.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 } @@ -419,6 +423,7 @@ function permalinks(options) { return permalink }, set(value) { + /* istanbul ignore next */ permalink = value } }) diff --git a/test/index.cjs b/test/index.cjs index 1595827..72094df 100644 --- a/test/index.cjs +++ b/test/index.cjs @@ -317,32 +317,87 @@ describe('@metalsmith/permalinks', () => { }) }) - it('should set a permalink property on each processed file', done => { - const ms = Metalsmith(path.join(fixturesBase, 'no-relative')) - .env('DEBUG', process.env.DEBUG) - .ignore('**') + describe('sets a file.permalink property', () => { + let ms + beforeEach(() => { + ms = Metalsmith(path.join(fixturesBase, 'no-relative')) + .env('DEBUG', process.env.DEBUG) + .ignore('**') + }) - const files = { - 'test.html': { - contents: Buffer.from('Test'), - path: 'test.html' - }, - [path.join('nested', 'test.html')]: { - contents: Buffer.from('Nested test') + it('on each processed file', done => { + const files = { + 'test.html': { + contents: Buffer.from('Test'), + path: 'test.html' + }, + [path.join('nested', 'test.html')]: { + contents: Buffer.from('Nested test') + } } - } - permalinks()(files, ms, (err) => { - if (err) done(err) - assert.deepStrictEqual(Object.values(files).map(f => f.permalink).sort(), [ - 'nested/test', - 'test', - ]) - assert.deepStrictEqual(Object.keys(files).sort(), [ - 'nested/test/index.html', - 'test/index.html', - ].map(path.normalize)) - done() + permalinks()(files, ms, (err) => { + if (err) done(err) + assert.deepStrictEqual(Object.values(files).map(f => f.permalink).sort(), [ + 'nested/test', + 'test', + ]) + assert.deepStrictEqual(Object.keys(files).sort(), [ + 'nested/test/index.html', + 'test/index.html', + ].map(path.normalize)) + done() + }) + }) + + it('that supports adding a trailing slash to the permalink property', done => { + const ms = Metalsmith(path.join(fixturesBase, 'no-relative')) + .env('DEBUG', process.env.DEBUG) + .ignore('**') + + const files = { + 'test.html': { + contents: Buffer.from('Test'), + }, + [path.join('nested', 'test.html')]: { + contents: Buffer.from('Nested test') + } + } + + permalinks({ + trailingSlash: true + })(files, ms, (err) => { + if (err) done(err) + assert.deepStrictEqual(Object.values(files).map(f => f.permalink).sort(), [ + 'nested/test/', + 'test/', + ]) + assert.deepStrictEqual(Object.keys(files).sort(), [ + 'nested/test/index.html', + 'test/index.html', + ].map(path.normalize)) + done() + }) + }) + + it('but without overriding explicitly defined permalinks', done => { + const files = { + 'test.html': { + contents: Buffer.from('Test'), + title: 'HelloWorld', + permalink: 'new/permalink/hehe' + } + } + + permalinks({ + trailingSlash: true, + pattern: ':title' + })(files, ms, (err) => { + if (err) done(err) + assert.strictEqual(Object.values(files)[0].permalink, 'new/permalink/hehe') + assert.strictEqual(Object.keys(files)[0], path.normalize('new/permalink/hehe/index.html')) + done() + }) }) }) }) \ No newline at end of file