test: improve test coverage; multiple internal refactors (#6912)

This commit is contained in:
Joshua Chen 2022-03-14 21:53:57 +08:00 committed by GitHub
parent 12a7305238
commit ad88f5cc87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
78 changed files with 1613 additions and 1149 deletions

View file

@ -10,7 +10,8 @@ import {
parseMarkdownContentTitle,
parseMarkdownString,
parseMarkdownHeadingId,
} from '../markdownParser';
writeMarkdownHeadingId,
} from '../markdownUtils';
import dedent from 'dedent';
describe('createExcerpt', () => {
@ -801,3 +802,108 @@ describe('parseMarkdownHeadingId', () => {
});
});
});
describe('writeMarkdownHeadingId', () => {
it('works for simple level-2 heading', () => {
expect(writeMarkdownHeadingId('## ABC')).toBe('## ABC {#abc}');
});
it('works for simple level-3 heading', () => {
expect(writeMarkdownHeadingId('### ABC')).toBe('### ABC {#abc}');
});
it('works for simple level-4 heading', () => {
expect(writeMarkdownHeadingId('#### ABC')).toBe('#### ABC {#abc}');
});
it('unwraps markdown links', () => {
const input = `## hello [facebook](https://facebook.com) [crowdin](https://crowdin.com/translate/docusaurus-v2/126/en-fr?filter=basic&value=0)`;
expect(writeMarkdownHeadingId(input)).toBe(
`${input} {#hello-facebook-crowdin}`,
);
});
it('can slugify complex headings', () => {
const input = '## abc [Hello] How are you %Sébastien_-_$)( ## -56756';
expect(writeMarkdownHeadingId(input)).toBe(
// cSpell:ignore ébastien
`${input} {#abc-hello-how-are-you-sébastien_-_---56756}`,
);
});
it('does not duplicate duplicate id', () => {
expect(writeMarkdownHeadingId('## hello world {#hello-world}')).toBe(
'## hello world {#hello-world}',
);
});
it('respects existing heading', () => {
expect(writeMarkdownHeadingId('## New heading {#old-heading}')).toBe(
'## New heading {#old-heading}',
);
});
it('overwrites heading ID when asked to', () => {
expect(
writeMarkdownHeadingId('## New heading {#old-heading}', {
overwrite: true,
}),
).toBe('## New heading {#new-heading}');
});
it('maintains casing when asked to', () => {
expect(
writeMarkdownHeadingId('## getDataFromAPI()', {
maintainCase: true,
}),
).toBe('## getDataFromAPI() {#getDataFromAPI}');
});
it('transform the headings', () => {
const input = `
# Ignored title
## abc
### Hello world
\`\`\`
# Heading in code block
\`\`\`
## Hello world
\`\`\`
# Heading in escaped code block
\`\`\`
### abc {#abc}
`;
const expected = `
# Ignored title
## abc {#abc-1}
### Hello world {#hello-world}
\`\`\`
# Heading in code block
\`\`\`
## Hello world {#hello-world-1}
\`\`\`
# Heading in escaped code block
\`\`\`
### abc {#abc}
`;
expect(writeMarkdownHeadingId(input)).toEqual(expected);
});
});

View file

@ -15,11 +15,18 @@ import {
removeTrailingSlash,
resolvePathname,
encodePath,
buildSshUrl,
buildHttpsUrl,
hasSSHProtocol,
} from '../urlUtils';
describe('normalizeUrl', () => {
it('normalizes urls correctly', () => {
const asserts = [
{
input: [],
output: '',
},
{
input: ['/', ''],
output: '/',
@ -248,3 +255,60 @@ describe('encodePath', () => {
expect(encodePath('a/你好/')).toBe('a/%E4%BD%A0%E5%A5%BD/');
});
});
describe('buildSshUrl', () => {
it('builds a normal ssh url', () => {
const url = buildSshUrl('github.com', 'facebook', 'docusaurus');
expect(url).toBe('git@github.com:facebook/docusaurus.git');
});
it('builds a ssh url with port', () => {
const url = buildSshUrl('github.com', 'facebook', 'docusaurus', '422');
expect(url).toBe('ssh://git@github.com:422/facebook/docusaurus.git');
});
});
describe('buildHttpsUrl', () => {
it('builds a normal http url', () => {
const url = buildHttpsUrl(
'user:pass',
'github.com',
'facebook',
'docusaurus',
);
expect(url).toBe('https://user:pass@github.com/facebook/docusaurus.git');
});
it('builds a normal http url with port', () => {
const url = buildHttpsUrl(
'user:pass',
'github.com',
'facebook',
'docusaurus',
'5433',
);
expect(url).toBe(
'https://user:pass@github.com:5433/facebook/docusaurus.git',
);
});
});
describe('hasSSHProtocol', () => {
it('recognizes explicit SSH protocol', () => {
const url = 'ssh://git@github.com:422/facebook/docusaurus.git';
expect(hasSSHProtocol(url)).toBe(true);
});
it('recognizes implied SSH protocol', () => {
const url = 'git@github.com:facebook/docusaurus.git';
expect(hasSSHProtocol(url)).toBe(true);
});
it('does not recognize HTTPS with credentials', () => {
const url = 'https://user:pass@github.com/facebook/docusaurus.git';
expect(hasSSHProtocol(url)).toBe(false);
});
it('does not recognize plain HTTPS URL', () => {
const url = 'https://github.com:5433/facebook/docusaurus.git';
expect(hasSSHProtocol(url)).toBe(false);
});
});

View file

@ -45,6 +45,9 @@ export {
addLeadingSlash,
addTrailingSlash,
removeTrailingSlash,
hasSSHProtocol,
buildHttpsUrl,
buildSshUrl,
} from './urlUtils';
export {
type Tag,
@ -60,7 +63,9 @@ export {
parseFrontMatter,
parseMarkdownContentTitle,
parseMarkdownString,
} from './markdownParser';
writeMarkdownHeadingId,
type WriteHeadingIDOptions,
} from './markdownUtils';
export {
type ContentPaths,
type BrokenMarkdownLink,

View file

@ -7,6 +7,7 @@
import logger from '@docusaurus/logger';
import matter from 'gray-matter';
import {createSlugger, type Slugger} from './slugger';
// Input: ## Some heading {#some-heading}
// Output: {text: "## Some heading", id: "some-heading"}
@ -205,3 +206,72 @@ This can happen if you use special characters in front matter values (try using
throw err;
}
}
function unwrapMarkdownLinks(line: string): string {
return line.replace(/\[(?<alt>[^\]]+)\]\([^)]+\)/g, (match, p1) => p1);
}
function addHeadingId(
line: string,
slugger: Slugger,
maintainCase: boolean,
): string {
let headingLevel = 0;
while (line.charAt(headingLevel) === '#') {
headingLevel += 1;
}
const headingText = line.slice(headingLevel).trimEnd();
const headingHashes = line.slice(0, headingLevel);
const slug = slugger.slug(unwrapMarkdownLinks(headingText).trim(), {
maintainCase,
});
return `${headingHashes}${headingText} {#${slug}}`;
}
export type WriteHeadingIDOptions = {
maintainCase?: boolean;
overwrite?: boolean;
};
export function writeMarkdownHeadingId(
content: string,
options: WriteHeadingIDOptions = {maintainCase: false, overwrite: false},
): string {
const {maintainCase = false, overwrite = false} = options;
const lines = content.split('\n');
const slugger = createSlugger();
// If we can't overwrite existing slugs, make sure other headings don't
// generate colliding slugs by first marking these slugs as occupied
if (!overwrite) {
lines.forEach((line) => {
const parsedHeading = parseMarkdownHeadingId(line);
if (parsedHeading.id) {
slugger.slug(parsedHeading.id);
}
});
}
let inCode = false;
return lines
.map((line) => {
if (line.startsWith('```')) {
inCode = !inCode;
return line;
}
// Ignore h1 headings, as we don't create anchor links for those
if (inCode || !line.startsWith('##')) {
return line;
}
const parsedHeading = parseMarkdownHeadingId(line);
// Do not process if id is already there
if (parsedHeading.id && !overwrite) {
return line;
}
return addHeadingId(parsedHeading.text, slugger, maintainCase);
})
.join('\n');
}

View file

@ -154,3 +154,40 @@ export function addTrailingSlash(str: string): string {
export function removeTrailingSlash(str: string): string {
return removeSuffix(str, '/');
}
export function buildSshUrl(
githubHost: string,
organizationName: string,
projectName: string,
githubPort?: string,
): string {
if (githubPort) {
return `ssh://git@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
}
return `git@${githubHost}:${organizationName}/${projectName}.git`;
}
export function buildHttpsUrl(
gitCredentials: string,
githubHost: string,
organizationName: string,
projectName: string,
githubPort?: string,
): string {
if (githubPort) {
return `https://${gitCredentials}@${githubHost}:${githubPort}/${organizationName}/${projectName}.git`;
}
return `https://${gitCredentials}@${githubHost}/${organizationName}/${projectName}.git`;
}
export function hasSSHProtocol(sourceRepoUrl: string): boolean {
try {
if (new URL(sourceRepoUrl).protocol === 'ssh:') {
return true;
}
return false;
} catch {
// Fails when there isn't a protocol
return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl); // git@github.com:facebook/docusaurus.git
}
}