Skip to content

Commit d999140

Browse files
authored
Merge pull request #345 from HaaLeo/master
Support GitHub Issue Links
2 parents e8d8304 + bf41e29 commit d999140

File tree

4 files changed

+122
-4
lines changed

4 files changed

+122
-4
lines changed

src/package.ts

+40-4
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,10 @@ function isHostTrusted(host: string): boolean {
179179
return TrustedSVGSources.indexOf(host.toLowerCase()) > -1;
180180
}
181181

182+
function isGitHubRepository(repository: string): boolean {
183+
return /^https:\/\/github\.com\/|^git@github\.com:/.test(repository || '');
184+
}
185+
182186
class ManifestProcessor extends BaseProcessor {
183187

184188
constructor(manifest: Manifest) {
@@ -191,7 +195,7 @@ class ManifestProcessor extends BaseProcessor {
191195
}
192196

193197
const repository = getRepositoryUrl(manifest.repository);
194-
const isGitHub = /^https:\/\/github\.com\/|^git@github\.com:/.test(repository || '');
198+
const isGitHub = isGitHubRepository(repository);
195199

196200
let enableMarketplaceQnA: boolean | undefined;
197201
let customerQnALink: string | undefined;
@@ -350,6 +354,8 @@ export class MarkdownProcessor extends BaseProcessor {
350354

351355
private baseContentUrl: string;
352356
private baseImagesUrl: string;
357+
private isGitHub: boolean;
358+
private repositoryUrl: string;
353359

354360
constructor(manifest: Manifest, private name: string, private regexp: RegExp, private assetType: string, options: IPackageOptions = {}) {
355361
super(manifest);
@@ -358,6 +364,8 @@ export class MarkdownProcessor extends BaseProcessor {
358364

359365
this.baseContentUrl = options.baseContentUrl || (guess && guess.content);
360366
this.baseImagesUrl = options.baseImagesUrl || options.baseContentUrl || (guess && guess.images);
367+
this.repositoryUrl = (guess && guess.repository);
368+
this.isGitHub = isGitHubRepository(this.repositoryUrl);
361369
}
362370

363371
async onFile(file: IFile): Promise<IFile> {
@@ -396,9 +404,36 @@ export class MarkdownProcessor extends BaseProcessor {
396404

397405
return `${isImage}[${title}](${urljoin(prefix, link)})`;
398406
};
399-
407+
// Replace Markdown links with urls
400408
contents = contents.replace(markdownPathRegex, urlReplace);
401409

410+
const markdownIssueRegex = /(\s|\n)([\w\d_-]+\/[\w\d_-]+)?#(\d+)\b/g
411+
const issueReplace = (all: string, prefix: string, ownerAndRepositoryName: string, issueNumber: string): string => {
412+
let result = all;
413+
let owner: string;
414+
let repositoryName: string;
415+
416+
if (ownerAndRepositoryName) {
417+
[owner, repositoryName] = ownerAndRepositoryName.split('/', 2);
418+
}
419+
420+
if (this.isGitHub){
421+
if (owner && repositoryName && issueNumber) {
422+
// Issue in external repository
423+
const issueUrl = urljoin('https://github.com', owner, repositoryName, 'issues', issueNumber);
424+
result = prefix + `[${owner}/${repositoryName}#${issueNumber}](${issueUrl})`;
425+
426+
} else if (!owner && !repositoryName && issueNumber) {
427+
// Issue in own repository
428+
result = prefix + `[#${issueNumber}](${urljoin(this.repositoryUrl, 'issues', issueNumber)})`;
429+
}
430+
}
431+
432+
return result;
433+
}
434+
// Replace Markdown issue references with urls
435+
contents = contents.replace(markdownIssueRegex, issueReplace);
436+
402437
const html = markdownit({ html: true }).render(contents);
403438
const $ = cheerio.load(html);
404439

@@ -430,7 +465,7 @@ export class MarkdownProcessor extends BaseProcessor {
430465
}
431466

432467
// GitHub heuristics
433-
private guessBaseUrls(): { content: string; images: string; } {
468+
private guessBaseUrls(): { content: string; images: string; repository: string} {
434469
let repository = null;
435470

436471
if (typeof this.manifest.repository === 'string') {
@@ -455,7 +490,8 @@ export class MarkdownProcessor extends BaseProcessor {
455490

456491
return {
457492
content: `https://github.com/${account}/${repositoryName}/blob/master`,
458-
images: `https://github.com/${account}/${repositoryName}/raw/master`
493+
images: `https://github.com/${account}/${repositoryName}/raw/master`,
494+
repository: `https://github.com/${account}/${repositoryName}`
459495
};
460496
}
461497
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Replace
2+
3+
[#8](https://github.com/username/repository/issues/8)
4+
5+
* Some issue in same repository: [#7](https://github.com/username/repository/issues/7)
6+
* Some issue in other repository: [other/repositoryName#8](https://github.com/other/repositoryName/issues/8)
7+
* Some issue in other repository with fancy name: [my_user-name/my-rep_o12#6](https://github.com/my_user-name/my-rep_o12/issues/6)
8+
9+
# Do not touch this:
10+
* username#4 (no valid github link)
11+
* /#7
12+
* foo/$234/#7
13+
* [#7](http://shouldnottouchthis/)
14+
* [other/repositoryName#8](http://shouldnottouchthis/)
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Replace
2+
3+
#8
4+
5+
* Some issue in same repository: #7
6+
* Some issue in other repository: other/repositoryName#8
7+
* Some issue in other repository with fancy name: my_user-name/my-rep_o12#6
8+
9+
# Do not touch this:
10+
* username#4 (no valid github link)
11+
* /#7
12+
* foo/$234/#7
13+
* [#7](http://shouldnottouchthis/)
14+
* [other/repositoryName#8](http://shouldnottouchthis/)

src/test/package.test.ts

+54
Original file line numberDiff line numberDiff line change
@@ -1500,6 +1500,60 @@ describe('MarkdownProcessor', () => {
15001500
});
15011501
});
15021502

1503+
it('should replace issue links with urls if its a github repo.', () => {
1504+
const manifest = {
1505+
name: 'test',
1506+
publisher: 'mocha',
1507+
version: '0.0.1',
1508+
description: 'test extension',
1509+
engines: Object.create(null),
1510+
repository: 'https://github.com/username/repository.git'
1511+
};
1512+
1513+
const root = fixture('readme');
1514+
const processor = new ReadmeProcessor(manifest, {});
1515+
const readme = {
1516+
path: 'extension/readme.md',
1517+
localPath: path.join(root, 'readme.github.md')
1518+
};
1519+
1520+
return processor.onFile(readme)
1521+
.then(file => read(file))
1522+
.then(actual => {
1523+
return readFile(path.join(root, 'readme.github.expected.md'), 'utf8')
1524+
.then(expected => {
1525+
assert.equal(actual, expected);
1526+
});
1527+
});
1528+
});
1529+
1530+
it('should not replace issue links with urls if its not a github repo.', () => {
1531+
const manifest = {
1532+
name: 'test',
1533+
publisher: 'mocha',
1534+
version: '0.0.1',
1535+
description: 'test extension',
1536+
engines: Object.create(null),
1537+
repository: 'https://some-other-provider.com/username/repository.git'
1538+
};
1539+
1540+
const root = fixture('readme');
1541+
const processor = new ReadmeProcessor(manifest, {});
1542+
const readme = {
1543+
path: 'extension/readme.md',
1544+
localPath: path.join(root, 'readme.github.md')
1545+
};
1546+
1547+
return processor.onFile(readme)
1548+
.then(file => read(file))
1549+
.then(actual => {
1550+
return readFile(path.join(root, 'readme.github.md'), 'utf8')
1551+
.then(expected => {
1552+
assert.equal(actual, expected);
1553+
});
1554+
});
1555+
});
1556+
15031557
it('should prevent non-HTTPS images', async () => {
15041558
const manifest = { name: 'test', publisher: 'mocha', version: '0.0.1', engines: Object.create(null), repository: 'https://github.com/username/repository' };
15051559
const contents = `![title](http://foo.png)`;

0 commit comments

Comments
 (0)