diff --git a/app/locations/trailing-history.js b/app/locations/trailing-history.js index ef2eadeb..90a54536 100644 --- a/app/locations/trailing-history.js +++ b/app/locations/trailing-history.js @@ -1,16 +1,18 @@ import HistoryLocation from '@ember/routing/history-location'; -/* When using this location type with ember-cli dev server, be sure to +/* When using this location type with ember-cli dev server, be sure to set historySupportMiddleware: true in config/environment.js */ -export default class extends HistoryLocation { +export default class TrailingHistoryLocation extends HistoryLocation { formatURL() { - let url = super.formatURL(...arguments); + return formatURL(super.formatURL(...arguments)); + } +} - if (url.includes('#')) { - return url.replace(/([^/])#(.*)/, '$1/#$2'); - } else { - return url.replace(/\/?$/, '/'); - } +export function formatURL(url) { + let parsed = new URL(url, 'http://example.com'); + if (!parsed.pathname.endsWith('/')) { + parsed.pathname += '/'; } + return `${parsed.pathname}${parsed.search}${parsed.hash}`; } diff --git a/tests/unit/locations/trailing-history-test.js b/tests/unit/locations/trailing-history-test.js new file mode 100644 index 00000000..460573ec --- /dev/null +++ b/tests/unit/locations/trailing-history-test.js @@ -0,0 +1,46 @@ +import { module, test } from 'qunit'; +import { formatURL } from 'ember-api-docs/locations/trailing-history'; + +module('Unit | Location | trailing-history | formatURL', function () { + const cases = [ + { + input: '/ember/6.8/classes/Ember.Controller', + output: '/ember/6.8/classes/Ember.Controller/', + label: 'adds trailing slash to bare path', + }, + { + input: '/ember/6.8/classes/Ember.Controller/', + output: '/ember/6.8/classes/Ember.Controller/', + label: 'leaves already-trailing-slashed path unchanged', + }, + { + input: '/ember/6.8/classes/Ember.Controller?show=deprecated', + output: '/ember/6.8/classes/Ember.Controller/?show=deprecated', + label: 'adds trailing slash before query string', + }, + { + input: '/ember/6.8/classes/Ember.Controller?show=deprecated#addObserver', + output: + '/ember/6.8/classes/Ember.Controller/?show=deprecated#addObserver', + label: 'adds trailing slash before query string, preserving hash', + }, + { + input: '/ember/6.8/classes/Ember.Controller#addObserver', + output: '/ember/6.8/classes/Ember.Controller/#addObserver', + label: 'adds trailing slash before hash when no query string', + }, + { + input: '/ember/6.8/classes/Ember.Controller/?show=deprecated#addObserver', + output: + '/ember/6.8/classes/Ember.Controller/?show=deprecated#addObserver', + label: + 'leaves already-trailing-slashed path with query and hash unchanged', + }, + ]; + + for (let { input, output, label } of cases) { + test(label, function (assert) { + assert.strictEqual(formatURL(input), output); + }); + } +});