提交 281f242c 编写于 作者: M Matt Bierner

Don't strip special characters in slugify

Fixes #48482
上级 feeefd10
......@@ -17,7 +17,7 @@ import { MarkdownEngine } from './markdownEngine';
import { getMarkdownExtensionContributions } from './markdownExtensions';
import { ExtensionContentSecurityPolicyArbiter, PreviewSecuritySelector } from './security';
import { loadDefaultTelemetryReporter } from './telemetryReporter';
import { stripSlugifier } from './slugify';
import { githubSlugifier } from './slugify';
export function activate(context: vscode.ExtensionContext) {
......@@ -27,7 +27,7 @@ export function activate(context: vscode.ExtensionContext) {
const contributions = getMarkdownExtensionContributions();
const cspArbiter = new ExtensionContentSecurityPolicyArbiter(context.globalState, context.workspaceState);
const engine = new MarkdownEngine(contributions, stripSlugifier);
const engine = new MarkdownEngine(contributions, githubSlugifier);
const logger = new Logger();
const selector: vscode.DocumentSelector = [
......
......@@ -17,19 +17,16 @@ export interface Slugifier {
fromHeading(heading: string): Slug;
}
export const stripSlugifier: Slugifier = new class implements Slugifier {
private readonly specialChars: any = { 'à': 'a', 'ä': 'a', 'ã': 'a', 'á': 'a', 'â': 'a', 'æ': 'a', 'å': 'a', 'ë': 'e', 'è': 'e', 'é': 'e', 'ê': 'e', 'î': 'i', 'ï': 'i', 'ì': 'i', 'í': 'i', 'ò': 'o', 'ó': 'o', 'ö': 'o', 'ô': 'o', 'ø': 'o', 'ù': 'o', 'ú': 'u', 'ü': 'u', 'û': 'u', 'ñ': 'n', 'ç': 'c', 'ß': 's', 'ÿ': 'y', 'œ': 'o', 'ŕ': 'r', 'ś': 's', 'ń': 'n', '': 'p', '': 'w', 'ǵ': 'g', 'ǹ': 'n', 'ḿ': 'm', 'ǘ': 'u', '': 'x', 'ź': 'z', '': 'h', '·': '-', '/': '-', '_': '-', ',': '-', ':': '-', ';': '-', 'З': '3', 'з': '3' };
public fromHeading(heading: string): Slug {
const slugifiedHeading = encodeURI(heading.trim()
.toLowerCase()
.replace(/./g, c => this.specialChars[c] || c)
.replace(/[\]\[\!\'\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~\`]/g, '')
.replace(/\s+/g, '-') // Replace whitespace with -
.replace(/[^\w\-]+/g, '') // Remove remaining non-word chars
.replace(/^\-+/, '') // Remove leading -
.replace(/\-+$/, '') // Remove trailing -
export const githubSlugifier: Slugifier = new class implements Slugifier {
fromHeading(heading: string): Slug {
const slugifiedHeading = encodeURI(
heading.trim()
.toLowerCase()
.replace(/\s+/g, '-') // Replace whitespace with -
.replace(/[^\w\-]+/gu, '') // Remove non-word chars
.replace(/^\-+/, '') // Remove leading -
.replace(/\-+$/, '') // Remove trailing -
);
return new Slug(slugifiedHeading);
}
};
\ No newline at end of file
};
......@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { MarkdownEngine } from './markdownEngine';
import { Slug, stripSlugifier } from './slugify';
import { Slug, githubSlugifier } from './slugify';
export interface TocEntry {
readonly slug: Slug;
......@@ -36,7 +36,7 @@ export class TableOfContentsProvider {
public async lookup(fragment: string): Promise<TocEntry | undefined> {
const toc = await this.getToc();
const slug = stripSlugifier.fromHeading(fragment);
const slug = githubSlugifier.fromHeading(fragment);
return toc.find(entry => entry.slug.equals(slug));
}
......@@ -48,7 +48,7 @@ export class TableOfContentsProvider {
const lineNumber = heading.map[0];
const line = document.lineAt(lineNumber);
toc.push({
slug: stripSlugifier.fromHeading(line.text),
slug: githubSlugifier.fromHeading(line.text),
text: TableOfContentsProvider.getHeaderText(line.text),
level: TableOfContentsProvider.getHeaderLevel(heading.markup),
line: lineNumber,
......
......@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import { MarkdownEngine } from '../markdownEngine';
import { MarkdownContributions } from '../markdownExtensions';
import { stripSlugifier } from '../slugify';
import { githubSlugifier } from '../slugify';
const emptyContributions = new class implements MarkdownContributions {
readonly previewScripts: vscode.Uri[] = [];
......@@ -16,5 +16,5 @@ const emptyContributions = new class implements MarkdownContributions {
};
export function createNewMarkdownEngine(): MarkdownEngine {
return new MarkdownEngine(emptyContributions, stripSlugifier);
return new MarkdownEngine(emptyContributions, githubSlugifier);
}
......@@ -75,18 +75,17 @@ suite('markdown.TableOfContentsProvider', () => {
assert.strictEqual(await provider.lookup('fo o'), undefined);
});
test('should normalize special characters #44779', async () => {
test('should handle special characters #44779', async () => {
const doc = new InMemoryDocument(testFileName, `# Indentação\n`);
const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc);
assert.strictEqual((await provider.lookup('indentacao'))!.line, 0);
assert.strictEqual((await provider.lookup('indentação'))!.line, 0);
});
test('should map special З, #37079', async () => {
const doc = new InMemoryDocument(testFileName, `### Заголовок Header 3`);
test('should handle special characters 2, #48482', async () => {
const doc = new InMemoryDocument(testFileName, `# Инструкция - Делай Раз, Делай Два\n`);
const provider = new TableOfContentsProvider(createNewMarkdownEngine(), doc);
assert.strictEqual((await provider.lookup('Заголовок-header-3'))!.line, 0);
assert.strictEqual((await provider.lookup('3аголовок-header-3'))!.line, 0);
assert.strictEqual((await provider.lookup('инструкция---делай-раз-делай-два'))!.line, 0);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册