Skip to content

Commit 16184e0

Browse files
authored
feat: find and replace relative paths (#14)
* feat: replace relative paths in article content * feat: use file raw url to get base url * refactor: update build * docs: update docs
1 parent a2292cd commit 16184e0

File tree

6 files changed

+49
-88
lines changed

6 files changed

+49
-88
lines changed

README.md

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,9 @@ license: public-domain
7070
7171
In this article we will learn how to setup with `blogpub`
7272

73-
## Relative images from the repository
73+
## Relative paths from the repository
7474

75-
![ci-meme.jpg](@/assets/meme.jpg)
76-
77-
## External Images
78-
79-
![meme.jpg](https://sources.com/meme.jpg)
75+
![ci-meme.jpg](./assets/meme.jpg)
8076

8177
## Requirements
8278

@@ -117,21 +113,22 @@ This is only for Medium
117113
{{/if}}
118114
```
119115

120-
## Relative Images
116+
## Relative Paths
121117

122-
To use images contained in the same folder of the blog articles use `@/<image_path>`.
123-
`@` refers to `https://raw.githubusercontent.com/<owner>/<repo>/<articles_folder>`
118+
To use any media contained in your repository you can use relative paths.
119+
All relative paths will be resolved using the raw url of the markdown down file that
120+
is being processed.
124121

125122
Example:
126123
```
127-
![image](@/img1.png)
128-
<img src="@/img2.jpg" />
124+
![image](./img1.png)
125+
<img src="../assets/img2.jpg" />
129126
```
130127

131128
Will be parsed as
132129
```
133130
![image](https://raw.githubusercontent.com/<owner>/<repo>/<articles_folder>/img1.png)
134-
<img src="https://raw.githubusercontent.com/<owner>/<repo>/<articles_folder>/img2.jpg" />
131+
<img src="https://raw.githubusercontent.com/<owner>/<repo>/assets/img2.jpg" />
135132
```
136133

137134
## Developing
@@ -164,4 +161,4 @@ Please submit a PR with any contribution. Refer to the list of `TODO's` or open
164161
- [ ] Support publishing to only 1 platform
165162
- [ ] Support edition and auto update of articles
166163
- [ ] Support multiple articles
167-
- [x] Relative images to github raw server
164+
- [x] Relative paths to github raw server

build/blogpub.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/* eslint-disable @typescript-eslint/no-non-null-assertion */
22
import Handlebars from 'handlebars';
3+
import path from 'path';
34
import * as core from '@actions/core';
45
import { context, getOctokit } from '@actions/github';
56
import { AxiosError } from 'axios';
@@ -11,7 +12,9 @@ import { parseArticle } from '$/parser';
1112

1213
type Github = ReturnType<typeof getOctokit>;
1314

14-
async function loadArticleContent(github: Github, folderName: string): Promise<string> {
15+
async function loadArticleFile(
16+
github: Github, folderName: string,
17+
): Promise<{ rawUrl: string, content: string}> {
1518
const { owner, repo } = context.repo;
1619
// NOTE: Pagination returns 30 files by default
1720
const commit = (
@@ -31,7 +34,7 @@ async function loadArticleContent(github: Github, folderName: string): Promise<s
3134
const newArticle = mdFiles[0];
3235
core.debug(`Using ${newArticle.filename!}`);
3336
const content = await fs.readFile(`./${newArticle.filename!}`, 'utf8');
34-
return content;
37+
return { rawUrl: newArticle.raw_url!, content };
3538
}
3639

3740
export async function run() {
@@ -43,18 +46,13 @@ export async function run() {
4346
const mediumBaseUrl = core.getInput('medium_base_url', { required: false });
4447
const devtoApiKey = core.getInput('devto_api_key', { required: true });
4548

46-
const rawGithubUrl = context.serverUrl
47-
.replace('//github.com', '//raw.githubusercontent.com');
48-
4949
const github = getOctokit(ghToken);
5050

51-
const articleContent = await loadArticleContent(github, articlesFolder);
52-
const { repo, owner } = context.repo;
53-
const baseUrl = `${rawGithubUrl}/${owner}/${repo}/${context.ref.replace('refs/heads/', '')}/${articlesFolder}`;
51+
const articleFile = await loadArticleFile(github, articlesFolder);
52+
const baseUrl = path.dirname(articleFile.rawUrl);
5453
/* istanbul ignore next */
5554
core.debug(`Base URL: ${baseUrl}`);
56-
const article = parseArticle(articleContent, baseUrl);
57-
55+
const article = parseArticle(articleFile.content, `${baseUrl}/`);
5856
const template = Handlebars.compile(article.content);
5957

6058
/* istanbul ignore next */

src/parser.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { load as loadYaml } from 'js-yaml';
22

33
import { Article, ArticleConfig, MediumLicense } from './types';
44

5-
const RelativeImagesRegex = /!\[.*\]\(@\/.*\)|<img.*src=["'](@)\/.*["']/i;
5+
const RelativePathRegex = /[\.]{1,2}\//;
66

77
function getMetadataIndexes(lines: string[]): number[] {
88
const indexes: number[] = [];
@@ -30,8 +30,8 @@ function getArticleTitle(lines: string[]): string | null {
3030

3131
function parseRelativeImages(lines: string[], baseUrl: string) {
3232
for (let i = 0; i < lines.length; i++) {
33-
if (RelativeImagesRegex.test(lines[i])) {
34-
lines[i] = lines[i].replace('@', baseUrl);
33+
if (RelativePathRegex.test(lines[i])) {
34+
lines[i] = lines[i].replace(RelativePathRegex, baseUrl);
3535
}
3636
}
3737
}

test/main.spec.ts

Lines changed: 18 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ jest.mock('$/api/devto');
2424
jest.mock('$/parser');
2525
jest.mock('@actions/github', () => ({
2626
context: {
27-
serverUrl: 'https://github.com',
28-
ref: 'refs/heads/main',
2927
repo: {
3028
owner: 'owner',
3129
repo: 'repo',
@@ -41,6 +39,17 @@ describe('blogpub', () => {
4139

4240
(getOctokit as jest.Mock).mockReturnValue(octokitMock);
4341

42+
const fileData = {
43+
data: {
44+
files: [
45+
{
46+
filename: 'blogs/blog-01.md',
47+
raw_url: 'https://raw.githubusercontent.com/owner/repo/main/blogs/blog-01.md',
48+
},
49+
],
50+
},
51+
};
52+
4453
it('should set failed when fails to get PR info', async () => {
4554
const err = new Error('github');
4655
octokitMock.request.mockRejectedValue(err);
@@ -82,15 +91,7 @@ describe('blogpub', () => {
8291
});
8392
const err = new Error('fs');
8493
(promises.readFile as jest.Mock).mockRejectedValue(err);
85-
octokitMock.request.mockResolvedValue({
86-
data: {
87-
files: [
88-
{
89-
filename: 'blogs/blog-01.md',
90-
},
91-
],
92-
},
93-
});
94+
octokitMock.request.mockResolvedValue(fileData);
9495

9596
await run();
9697

@@ -109,15 +110,7 @@ describe('blogpub', () => {
109110
(parseArticle as jest.Mock).mockImplementation(() => {
110111
throw err;
111112
});
112-
octokitMock.request.mockResolvedValue({
113-
data: {
114-
files: [
115-
{
116-
filename: 'blogs/blog-01.md',
117-
},
118-
],
119-
},
120-
});
113+
octokitMock.request.mockResolvedValue(fileData);
121114

122115
await run();
123116

@@ -149,15 +142,7 @@ describe('blogpub', () => {
149142
content: 'parsed',
150143
});
151144
(medium.createArticle as jest.Mock).mockRejectedValue(err);
152-
octokitMock.request.mockResolvedValue({
153-
data: {
154-
files: [
155-
{
156-
filename: 'blogs/blog-01.md',
157-
},
158-
],
159-
},
160-
});
145+
octokitMock.request.mockResolvedValue(fileData);
161146

162147
await run();
163148

@@ -182,15 +167,7 @@ describe('blogpub', () => {
182167
});
183168
(devto.createArticle as jest.Mock).mockRejectedValue(new Error(''));
184169
(medium.createArticle as jest.Mock).mockResolvedValue({ url: 'medium.com/new' });
185-
octokitMock.request.mockResolvedValue({
186-
data: {
187-
files: [
188-
{
189-
filename: 'blogs/blog-01.md',
190-
},
191-
],
192-
},
193-
});
170+
octokitMock.request.mockResolvedValue(fileData);
194171

195172
await run();
196173

@@ -225,15 +202,7 @@ describe('blogpub', () => {
225202
});
226203
(medium.createArticle as jest.Mock).mockResolvedValue({ url: 'medium.com/new' });
227204
(devto.createArticle as jest.Mock).mockRejectedValue(err);
228-
octokitMock.request.mockResolvedValue({
229-
data: {
230-
files: [
231-
{
232-
filename: 'blogs/blog-01.md',
233-
},
234-
],
235-
},
236-
});
205+
octokitMock.request.mockResolvedValue(fileData);
237206

238207
await run();
239208

@@ -266,15 +235,7 @@ describe('blogpub', () => {
266235
});
267236
(medium.createArticle as jest.Mock).mockResolvedValue({ url: 'medium.com/new' });
268237
(devto.createArticle as jest.Mock).mockResolvedValue({ url: 'dev.to/new' });
269-
octokitMock.request.mockResolvedValue({
270-
data: {
271-
files: [
272-
{
273-
filename: 'blogs/blog-01.md',
274-
},
275-
],
276-
},
277-
});
238+
octokitMock.request.mockResolvedValue(fileData);
278239

279240
await run();
280241

@@ -285,6 +246,6 @@ describe('blogpub', () => {
285246
});
286247
expect(core.setOutput).toHaveBeenCalledWith('devto_url', 'dev.to/new');
287248
expect(parseArticle).toHaveBeenCalledWith(
288-
'content', 'https://raw.githubusercontent.com/owner/repo/main/blogs');
249+
'content', 'https://raw.githubusercontent.com/owner/repo/main/blogs/');
289250
});
290251
});

test/parser.spec.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,20 +82,25 @@ published: false
8282
# Main Title
8383
some content
8484
85-
![img](@/assets/img.png)
85+
![img](./assets/img.png)
86+
![img](../global/img.png)
8687
87-
<img alt="image" src="@/assets/img.jpg" />
88+
<img alt="image" src="./assets/img.gif" />
8889
8990
## Description
9091
`;
91-
const parsed = parseArticle(article, 'https://raw.github.com/protiumx/blogpub/main/articles');
92+
const parsed = parseArticle(article, 'https://raw.github.com/protiumx/blogpub/main/articles/');
9293
expect(
9394
parsed.content.includes(
9495
'![img](https://raw.github.com/protiumx/blogpub/main/articles/assets/img.png)',
9596
)).toBeTruthy();
9697
expect(
9798
parsed.content.includes(
98-
'<img alt="image" src="https://raw.github.com/protiumx/blogpub/main/articles/assets/img.jpg"',
99+
'![img](https://raw.github.com/protiumx/blogpub/main/articles/global/img.png)',
100+
)).toBeTruthy();
101+
expect(
102+
parsed.content.includes(
103+
'<img alt="image" src="https://raw.github.com/protiumx/blogpub/main/articles/assets/img.gif"',
99104
)).toBeTruthy();
100105
});
101106
});

0 commit comments

Comments
 (0)