Skip to content

Commit a8f151e

Browse files
authored
fix: avoid quadratic slugify cache lookup (docsifyjs#2783)
1 parent 030652c commit a8f151e

2 files changed

Lines changed: 19 additions & 1 deletion

File tree

src/core/render/slugify.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function slugify(str) {
2323
.replace(/^(\d)/, '_$1');
2424
let count = cache[slug];
2525

26-
count = Object.keys(cache).includes(slug) ? count + 1 : 0;
26+
count = Object.prototype.hasOwnProperty.call(cache, slug) ? count + 1 : 0;
2727
cache[slug] = count;
2828

2929
if (count) {

test/unit/render-util.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ describe('core/render/tpl', () => {
167167
});
168168

169169
describe('core/render/slugify', () => {
170+
beforeEach(() => {
171+
slugify.clear();
172+
});
173+
170174
test('slugify()', () => {
171175
const htmlStrippedSlug = slugify(
172176
'Bla bla bla <svg aria-label="broken" class="broken" viewPort="0 0 1 1"><circle cx="0.5" cy="0.5"/></svg>',
@@ -218,4 +222,18 @@ describe('core/render/slugify', () => {
218222
);
219223
expect(markdownLinkSlug).toBe('_500-rc4-2026-03-11');
220224
});
225+
226+
test('slugify.clear() resets duplicate tracking', () => {
227+
expect(slugify('duplicate')).toBe('duplicate');
228+
expect(slugify('duplicate')).toBe('duplicate-1');
229+
230+
slugify.clear();
231+
232+
expect(slugify('duplicate')).toBe('duplicate');
233+
});
234+
235+
test('slugify() handles inherited property names as new slugs', () => {
236+
expect(slugify('constructor')).toBe('constructor');
237+
expect(slugify('constructor')).toBe('constructor-1');
238+
});
221239
});

0 commit comments

Comments
 (0)