diff --git a/src/images/varejao.jpeg b/src/images/varejao.jpeg
new file mode 100644
index 0000000..7ebad97
Binary files /dev/null and b/src/images/varejao.jpeg differ
diff --git a/src/mocks/images.md b/src/mocks/images.md
new file mode 100644
index 0000000..ec3efb7
--- /dev/null
+++ b/src/mocks/images.md
@@ -0,0 +1,11 @@
+![Adriana Varejão Gallery](../images/varejao.jpeg)
+
+_Adriana Varejão Gallery_
+
+![Valeska Soares Gallery](http://valeskasoares.net/wp-content/uploads/2009/10/DSC8218.jpg)
+
+_Valeska Soares Gallery_
+
+![Sonic Pavillion](https://www.inhotim.org.br/wp-content/webp-express/webp-images/uploads/2021/02/CAPA_02042021DSC07311Joao_Kehl_.jpg.webp)
+
+_Sonic Pavillion_
diff --git a/src/services/article.js b/src/services/article.js
index e62fc2a..9d711c0 100644
--- a/src/services/article.js
+++ b/src/services/article.js
@@ -1,8 +1,9 @@
-const markdownService = require('./markdown');
+const assetsService = require('./assets');
const dateService = require('./date');
const domService = require('./dom');
const excerptService = require('./excerpt');
const { fileService } = require('./file');
+const markdownService = require('./markdown');
const stylesService = require('./styles');
const summaryService = require('./summary');
const templateService = require('./template');
@@ -39,7 +40,7 @@ function fillTemplate(template, article, summary){
const $ = parseHTMLString(template.replace('{{article}}', wrapArticle(summary, article)));
$('html').attr('lang', summary.lang);
$('head').append(`
${summary.title}`).append(buildMetaTags(summary));
- return stylesService.appendBaseStylesheet($.html());
+ return stylesService.appendBaseStylesheet(assetsService.handleRelativeImages($.html()));
}
function wrapArticle({ title, date, lang }, article){
diff --git a/src/services/article.test.js b/src/services/article.test.js
new file mode 100644
index 0000000..bcff8a6
--- /dev/null
+++ b/src/services/article.test.js
@@ -0,0 +1,32 @@
+const path = require('path');
+const configService = require('./config');
+const { fileService } = require('./file');
+const articleService = require('./article');
+
+describe('Articles Service', () => {
+ function mockTrivenConfig(){
+ const config = {
+ sourceDirectory: path.join(__dirname, '../mocks'),
+ outputDirectory: path.join(process.cwd(), './triven')
+ };
+ configService.get = jest.fn(() => config);
+ return config;
+ }
+
+ beforeEach(() => {
+ fileService.copySync = jest.fn();
+ });
+
+ it('should copy relative images to assets directory and update its source in markup', () => {
+ const { outputDirectory } = mockTrivenConfig();
+ const filepath = path.join(__dirname, '../mocks/images.md');
+ const { article } = articleService.build(filepath);
+ const expectedFilename = 'varejao-a8774002d2f7fef27b27f665c7e7227c.jpeg';
+ expect(article).toContain(`
`);
+ expect(fileService.copySync).toHaveBeenCalledTimes(1);
+ expect(fileService.copySync).toHaveBeenCalledWith(
+ `${path.join(__dirname, '../images/varejao.jpeg')}`,
+ `${outputDirectory}/assets/${expectedFilename}`
+ );
+ });
+});
diff --git a/src/services/assets.js b/src/services/assets.js
index 75d4f8d..ac638c0 100644
--- a/src/services/assets.js
+++ b/src/services/assets.js
@@ -1,4 +1,6 @@
const md5 = require('md5');
+const path = require('path');
+const domService = require('./dom');
const configService = require('./config');
const minifyService = require('./minify');
const { fileService } = require('./file');
@@ -7,34 +9,79 @@ const _public = {};
let cache = [];
-_public.save = filepath => {
- const cachedFilename = findFilenameByFilepath(filepath);
- if(cachedFilename) return cachedFilename;
- const filename = saveAsset(filepath);
- cache.push({ filepath, filename });
- return filename;
+_public.save = filepath => handle(filepath, () => saveAsset(filepath));
+
+_public.copy = filepath => handle(filepath, () => copyAsset(filepath));
+
+_public.handleRelativeImages = htmlString => {
+ const $ = domService.parseHTMLString(htmlString);
+ $('img').filter((index, el) => isRelativeImage($(el).attr('src'))).each((index, el) => {
+ const filename = _public.copy(buildLocalImageFilepath($(el).attr('src')));
+ $(el).attr('src', `${getAssetsDirectoryName()}/${filename}`);
+ });
+ return $.html();
};
_public.flushCache = () => {
cache = [];
};
+function handle(filepath, act){
+ const cachedFilename = findFilenameByFilepath(filepath);
+ if(cachedFilename) return cachedFilename;
+ const filename = act();
+ cache.push({ filepath, filename });
+ return filename;
+}
+
function findFilenameByFilepath(filepath){
const cachedItem = cache.find(item => item.filepath === filepath);
return cachedItem && cachedItem.filename;
}
function saveAsset(filepath){
+ return store(filepath, ({ filename, file }) => {
+ fileService.write(`${getAssetsDirectoryFilepath()}/${filename}`, file);
+ });
+}
+
+function copyAsset(filepath){
+ return store(filepath, ({ filename }) => {
+ fileService.copySync(filepath, `${getAssetsDirectoryFilepath()}/${filename}`);
+ });
+}
+
+function store(filepath, storeAsset){
+ const { filename, file } = identifyFile(filepath);
+ storeAsset({ filename, file });
+ return filename;
+}
+
+function identifyFile(filepath){
const { name, extension } = fileService.getFileInfoByFilepath(filepath);
const file = minifyService.minifyByFilepath(filepath);
const filename = `${name}-${md5(file)}.${extension}`;
- fileService.write(`${getAssetsDirectory()}/${filename}`, file);
- return filename;
+ return { filename, file };
}
-function getAssetsDirectory(){
+function getAssetsDirectoryFilepath(){
const { outputDirectory } = configService.get();
- return `${outputDirectory}/assets`;
+ return `${outputDirectory}/${getAssetsDirectoryName()}`;
}
+function getAssetsDirectoryName(){
+ return 'assets';
+}
+
+function isRelativeImage(imgSrc){
+ return !isAbsoluteSrcRegex.test(imgSrc);
+}
+
+function buildLocalImageFilepath(imgSrc){
+ const { sourceDirectory } = configService.get();
+ return path.join(sourceDirectory, imgSrc);
+}
+
+const isAbsoluteSrcRegex = new RegExp(/^https?:\/\/.+/);
+
module.exports = _public;