Skip to content

Commit

Permalink
Merge pull request #10 from beforesemicolon/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ECorreia45 authored Jul 6, 2021
2 parents d999822 + cc9e2eb commit 55614ea
Show file tree
Hide file tree
Showing 61 changed files with 507 additions and 484 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ lerna-debug.log*

# projects files and directory
dist
docs

# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
Expand Down
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_modules
.npmignore
.DS_STORE
coverage
docs
test
.gitignore
website
Expand Down
12 changes: 12 additions & 0 deletions core/Attribute.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const {Attribute} = require('./Attribute');

describe('Attribute', () => {
it('should create', () => {
const attr = new Attribute();

expect(attr.execute).toBe(false);
expect(attr.bind).toBe(false);
expect(attr.process('val')).toBe('val');
expect(attr.render('val', {})).toEqual({});
});
});
2 changes: 1 addition & 1 deletion core/PartialFile.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class PartialFile extends File {

render(contextData = {}) {
const parsedHTML = parse(replaceSpecialCharactersInHTML(this.content), {
comment: this.options.env === 'development'
comment: true
});
parsedHTML.context = contextData;
const partialNode = new HTMLNode(parsedHTML, this.options);
Expand Down
11 changes: 2 additions & 9 deletions core/builder/utils/collect-and-update-node-source-link.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const {getFileSourceHashedDestPath} = require("./get-file-source-hashed-dest-path");
const {uniqueAlphaNumericId} = require("../../utils/unique-alpha-numeric-id");
const path = require('path');
const validUrl = require("valid-url");

function collectAndUpdateNodeSourceLink(node, pageFile, resources, fileDirPath) {
let srcPath = '';
Expand Down Expand Up @@ -40,15 +41,7 @@ function collectAndUpdateNodeSourceLink(node, pageFile, resources, fileDirPath)
default:
}

let isURL = false;

try {
new URL(srcPath);
isURL = true;
} catch (e) {
}

if (srcPath && typeof srcPath === 'string' && !isURL) {
if (srcPath && typeof srcPath === 'string' && !validUrl.isUri(srcPath)) {
if (/node_modules\//.test(srcPath)) {
srcPath = srcPath.replace(/^.+(?=node_modules)/, `${process.cwd()}/`);
} else {
Expand Down
30 changes: 0 additions & 30 deletions core/engine/extract-partial-and-page-routes.js

This file was deleted.

64 changes: 40 additions & 24 deletions core/engine/index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
const fs = require('fs');
const path = require('path');
const express = require("express");
const {PartialFile} = require("../PartialFile");
const {pageAndResourcesMiddleware} = require("./page-and-resources-middleware");
const {extractPartialAndPageRoutes} = require("./extract-partial-and-page-routes");
const {transform} = require('../transform');
const {getDirectoryFilesDetail} = require('../utils/getDirectoryFilesDetail');
const {File} = require('../File');
const validUrl = require('valid-url');

const defaultOptions = {
staticData: {},
Expand Down Expand Up @@ -40,17 +41,39 @@ const engine = (app, pagesDirectoryPath, opt = defaultOptions) => {
console.warn('HTML+ swapped "ENV" to development because the value provided is not a supported one.')
}

getDirectoryFilesDetail(pagesDirectoryPath, 'html')
.then(files => {
const {partials, pagesRoutes} = extractPartialAndPageRoutes(files, pagesDirectoryPath);
const partials = [];
const pagesRoutes = {};

return getDirectoryFilesDetail(pagesDirectoryPath, filePath => {
if (filePath.endsWith('.html')) {
const fileName = path.basename(filePath);

if (fileName.startsWith('_')) {
partials.push(new PartialFile(filePath, pagesDirectoryPath));
} else {
filePath = filePath.replace(pagesDirectoryPath, '');
const template = `${filePath.replace('.html', '')}`.slice(1);

if (filePath.endsWith('index.html')) {
pagesRoutes[filePath.replace('index.html', '')] = template;
} else {
pagesRoutes[filePath.replace('.html', '')] = template;
}

pagesRoutes[filePath.replace(/\/$/, '')] = template;
}
}

return false;
})
.then(() => {
app.engine('html', (filePath, {settings, _locals, cache, ...context}, callback) => {
const fileName = path.basename(filePath);

if (fileName.startsWith('_')) {
callback(new Error(`Cannot render partial(${fileName}) file as page. Partial files can only be included.`));
}

fs.readFile(filePath, (err, content) => {
if (err) return callback(err);
const file = new File(filePath, settings.views);
Expand All @@ -63,55 +86,48 @@ const engine = (app, pagesDirectoryPath, opt = defaultOptions) => {
customTags: opt.customTags,
customAttributes: opt.customAttributes,
partialFiles: partials,
onBeforeRender: (node, file) => {
onBeforeRender: (node, nodeFile) => {
let attrName = '';

if (node.tagName === 'link') {
attrName = 'href';
} else if (node.tagName === 'script') {
attrName = 'src';
}

const srcPath = node.attributes[attrName];
let isURL = false;

try {
new URL(srcPath);
isURL = true;
} catch (e) {
}

if (srcPath && !isURL) {
const resourceFullPath = path.resolve(file.fileDirectoryPath, srcPath);

if (srcPath && !validUrl.isUri(srcPath)) {
const resourceFullPath = path.resolve(nodeFile.fileDirectoryPath, srcPath);

if (resourceFullPath.startsWith(pagesDirectoryPath)) {
node.setAttribute(attrName, resourceFullPath.replace(pagesDirectoryPath, ''))
}
}
}
})

callback(null, result);
} catch (e) {
console.log(e.message);
console.error(e.message);
const cleanMsg = e.message
.replace(/\[\d+m/g, '')
.replace(/(>|<)/g, m => m === '<' ? '&lt;' : '&gt;');
callback(null, `<pre>${cleanMsg}</pre>`);
}
})
});

app.set('views', pagesDirectoryPath);
app.set('view engine', 'html');

app.use(pageAndResourcesMiddleware(
pagesRoutes,
pagesDirectoryPath,
opt
));
app.use(express.static(pagesDirectoryPath))

console.log('HTML+ engine is ready');
})
};
Expand Down
62 changes: 31 additions & 31 deletions core/engine/page-and-resources-middleware.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const path = require("path");
const {readFileContent} = require("../utils/readFileContent");
const {transform: transformResource} = require('../transformers');
const {File} = require('../File');

Expand All @@ -10,78 +9,79 @@ const sourcesExtensions = new Set([
'.less',
'.styl',
'.js',
'.mjs',
'.cjs',
'.ts',
'.tsx',
'.jsx',
])
]);
const cache = {};

function pageAndResourcesMiddleware(pagesRoutes, pagesDirectoryPath, {env, onPageRequest}) {
return async (req, res, next) => {
const ext = path.extname(req.path);

if (ext && sourcesExtensions.has(ext)) {
let content = '';
let contentType = 'text/css';
let resourcePath = '';
let file = null;

if (/node_modules/.test(req.path)) {
resourcePath = path.join(process.cwd(), req.path);

try {
content = readFileContent(resourcePath);

if (ext === '.css') {
res.setHeader('Content-Type', 'text/css');
} else if(ext === '.js' || ext === '.mjs') {
res.setHeader('Content-Type', 'application/javascript');
}

return res.send(content);
} catch(e) {
console.error(`Failed to load page resource "${req.path}"`, e);
return res.sendStatus(404);
}
} else {
resourcePath = path.join(pagesDirectoryPath, req.path);
}

resourcePath = path.join(pagesDirectoryPath, req.path);
if (env === 'production' && cache[resourcePath]) {
res.setHeader('Content-Type', cache[resourcePath].contentType);
return res.send(cache[resourcePath].content);
}

file = new File(resourcePath, pagesDirectoryPath);

try {
const file = new File(resourcePath, pagesDirectoryPath);

switch (ext) {
case '.scss':
case '.sass':
content = await transformResource.sass({file, env});
res.setHeader('Content-Type', 'text/css');
content = await transformResource.sass({file});
content = (await transformResource.css(content, {file, env})).content;
break;
case '.less':
content = await transformResource.less({file, env});
res.setHeader('Content-Type', 'text/css');
content = await transformResource.less({file});
content = (await transformResource.css(content, {file, env})).content;
break;
case '.styl':
content = await transformResource.stylus({file, env});
res.setHeader('Content-Type', 'text/css');
content = await transformResource.stylus({file});
content = (await transformResource.css(content, {file, env})).content;
break;
case '.css':
content = await transformResource.css({file, env});
res.setHeader('Content-Type', 'text/css');
content = (await transformResource.css({file, env})).content;
break;
case '.js':
case '.jsx':
case '.ts':
case '.tsx':
case '.mjs':
case '.cjs':
const result = await transformResource.js({file, env});
content = result.content;
res.setHeader('Content-Type', 'application/javascript');
contentType = 'application/javascript';
break;
}

if (env === 'production') {
cache[resourcePath] = {content, contentType}
}

res.setHeader('Content-Type', contentType);

return res.send(content);
} catch(e) {
console.error(`Failed to load page resource "${req.path}"`, e);
console.error(`Failed to load style/script content "${req.path}"`, e);
return res.sendStatus(404);
}
} else {
} else if(!ext || ext === '.html') {
const template = pagesRoutes[req.path] ?? pagesRoutes[`${req.path}/`] ?? pagesRoutes['/404'];

if (template) {
Expand Down
4 changes: 4 additions & 0 deletions core/parser/Comment.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const {Text} = require('./Text');

class Comment extends Text {
constructor(value) {
super(value);
}

get type() {
return 'comment';
}
Expand Down
11 changes: 11 additions & 0 deletions core/parser/Comment.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const {Comment} = require('./Comment');

describe('Comment', () => {
it('should create no data comment', () => {
const txt = new Comment('some {value}');

expect(txt.type).toEqual('comment')
expect(txt.value).toEqual('some {value}')
expect(txt.toString()).toEqual('<!-- some {value} -->')
});
});
6 changes: 3 additions & 3 deletions core/parser/HTMLNode.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class HTMLNode {
options = {...defaultOptions, ...options}
this.#node = typeof htmlString === 'string'
? parse(replaceSpecialCharactersInHTML(htmlString), {
comment: options.env === 'development'
comment: true
})
: htmlString;
this.#node.context = {...this.#node.context, ...options.context};
Expand Down Expand Up @@ -90,7 +90,7 @@ class HTMLNode {
? composeTagString(this, this.#node.innerHTML)
: `<fragment>${this.#node.outerHTML}</fragment>`;
const clonedNode = (parse(outerHTML, {
comment: this.#options.env === 'development'
comment: true
})).childNodes[0];

clonedNode.context = {...this.#node.context};
Expand All @@ -104,7 +104,7 @@ class HTMLNode {
? composeTagString(this, this.#node.innerHTML)
: `<fragment>${this.#node.outerHTML}</fragment>`;
const clonedNode = parse(outerHTML, {
comment: this.#options.env === 'development'
comment: true
}).childNodes[0];

clonedNode.context = {...this.#node.context, ...context};
Expand Down
1 change: 1 addition & 0 deletions core/parser/HTMLNode.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ describe('HTMLNode', () => {

expect(node.tagName).toEqual('h1');
expect(node.attributes).toEqual({id: "main-title"});
expect(node.type).toEqual('node');
expect(node.context).toEqual({});
expect(node.childNodes).toBeInstanceOf(Function);
expect(node.renderChildren).toBeInstanceOf(Function);
Expand Down
Loading

0 comments on commit 55614ea

Please sign in to comment.