Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,4 @@ Here are the links to all repositories with examples used in the documentation:
<a name="todo-list"></a>
TODO list (Ideas for the next version)
---

1. Implement [Razor-style `@* *@` comments](https://github.com/DevelAx/RazorExpress/blob/master/docs/syntax.md#comments).
2. ~~Make the library available for use on the client side (in the browser).~~([done](https://www.npmjs.com/package/razjs))
3. Implement caching compiled templates.
4. Async partial views.
5. Make `HtmlString` class public for making functions returnin *raw-values* as expessions.
1. Implement caching compiled templates.
2 changes: 1 addition & 1 deletion core/HtmlString.js → core/HtmlString.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = class HtmlString {
export class HtmlString {
constructor(html) {
this.html = html;
}
Expand Down
196 changes: 178 additions & 18 deletions core/Razor.js → core/Razor.mjs
Original file line number Diff line number Diff line change
@@ -1,42 +1,49 @@
require('./utils');
const fs = require('fs');
import * as utils from "./utils.mjs"

const path = require('path');
Utils.path = path;
Utils.isServer = true;
import * as fs from "fs"
import * as pfs from "fs/promises"
import * as path from "path"

utils.Utils.path = path;
utils.Utils.isServer = true;
// path.fileName = function (fullFileName, withExt) {
// if (withExt) return path.win32.basename(fullFileName);
// let extension = path.extname(fullFileName);
// return path.win32.basename(fullFileName, extension);
// };
path.cutLastSegment = function (dir) {
export let cutLastSegment = function (dir) {
dir = path.normalize(dir);
let pos = dir.lastIndexOf(path.sep);
if (pos === -1) return '';
return dir.substring(0, pos);
};

const initParser = require('./parser');
const ErrorsFactory = require('./errors/errors');
const dbg = require('./dbg/debugger');
import * as initParser_ from "./parser.mjs"
const initParser = initParser_.default;
import { ParserErrorFactory } from "./errors/errors.en.mjs"
import * as dbg from "./dbg/debugger.mjs"
import * as logger from "./dbg/logger.mjs"
const allowLoggingInDebugModel = false;

'use strict';
const viewStartName = '_viewStart';
const EOL = require('os').EOL;
import { EOL } from "os";

module.exports = class Razor {
export class Razor {
constructor(options, razorOpts) {
this.options = options;
this.ext = options.settings['view engine'] || razorOpts.ext;
this.env = options.settings.env;
const debug = dbg.isDebugMode;
const log = require('./dbg/logger')({ on: debug && allowLoggingInDebugModel });
const log = logger.default({ on: debug && allowLoggingInDebugModel });
this.parser = initParser({ express: true, dbg, log });
this.viewsDir = path.resolve(this.options.settings.views);
}

renderFile(filepath, done) {



let originFilePath = filepath;
filepath = path.normalize(filepath);
//let fileName = path.fileName(filepath);
Expand All @@ -47,7 +54,7 @@ module.exports = class Razor {

fs.readFile(filepath, (err, data) => {
if (err) {
let error = new ErrorsFactory({ filename: path.basename(originFilePath) }).errorReadingFile(err);
let error = new ParserErrorFactory({ filename: path.basename(originFilePath) }).errorReadingFile(err);
return done(error); // Tested by [0# Razor.readFile].
}

Expand All @@ -69,13 +76,86 @@ module.exports = class Razor {
findPartialSync: (layoutName, filePath, errorsFactory, cache) => {
var startDir = path.dirname(filePath);
return this.findPartialSync(startDir, layoutName, [], errorsFactory, cache);
},
findPartialAsync: (layoutName, filePath, errorsFactory, cache) => {
var startDir = path.dirname(filePath);
return this.findPartialAsync(startDir, layoutName, [], errorsFactory, cache);
}
};

this.parser.compile(parserArgs, done);
this.parser.compileAsync(parserArgs).then((data) => {
done(null, data);
}).catch((error) => {
done(error);
});
//this.parser.compile(parserArgs,done);
});
});
}
async renderFileAsync(filepath) {
let originFilePath = filepath;
filepath = path.normalize(filepath);
//let fileName = path.fileName(filepath);
//let viewsPath = path.normalize(this.options.settings.views);

if (!path.extname(filepath))
filepath += '.' + this.ext;

try {
var data = await pfs.readFile(filepath);
let currentDir = path.dirname(filepath);
let jsHtml = this.addFileNameIfDev(data, filepath);


var viewStartsJsHtml = await this.findViewStartsAsync(currentDir, '')

let parserArgs = {
filePath: filepath,
template: viewStartsJsHtml + jsHtml,
model: this.options,
findPartial: (layoutName, filePath, errorsFactory, done) => {
var startDir = path.dirname(filePath);
this.findPartial(startDir, layoutName, [], errorsFactory, done);
},
findPartialSync: (layoutName, filePath, errorsFactory, cache) => {
var startDir = path.dirname(filePath);
return this.findPartialSync(startDir, layoutName, [], errorsFactory, cache);
},
findPartialAsync: (layoutName, filePath, errorsFactory, cache) => {
var startDir = path.dirname(filePath);
return this.findPartialAsync(startDir, layoutName, [], errorsFactory, cache);
}
};

return this.parser.compileAsync(parserArgs);
}
catch (err) {
let error = new ErrorsFactory({ filename: path.basename(originFilePath) }).errorReadingFile(err);
throw error; // Tested by [0# Razor.readFile].
}
}

async findViewStartsAsync(startDir, buffer, done) {
const fileName = this.viewStartName();
const filePath = path.join(startDir, fileName);

try {
var data = await pfs.readFile(filePath)
let dataStr = this.addFileNameIfDev(data, filePath);
buffer = (buffer) ? dataStr + buffer : dataStr; // the `concat` order is important here!
}
catch (err) {
if (err.code !== 'ENOENT') {
let error = new ErrorsFactory({ filename: path.basename(filePath) }).errorReadingFile(err);
return done(error); // Tested by [#1 Razor.findViewStarts].
}
}
startDir = startDir.equal(this.viewsDir, true) ? null : cutLastSegment(startDir);

if (startDir)
return await this.findViewStartsAsync(startDir, buffer, done);

return buffer;
}

findViewStarts(startDir, buffer, done) {
const fileName = this.viewStartName();
Expand All @@ -93,7 +173,7 @@ module.exports = class Razor {
buffer = (buffer) ? dataStr + buffer : dataStr; // the `concat` order is important here!
}

startDir = startDir.equal(this.viewsDir, true) ? null : path.cutLastSegment(startDir);
startDir = startDir.equal(this.viewsDir, true) ? null : cutLastSegment(startDir);

if (startDir)
return this.findViewStarts(startDir, buffer, done);
Expand Down Expand Up @@ -161,7 +241,7 @@ module.exports = class Razor {
}
catch (err) {
if (err.code === 'ENOENT') { // the file doesn't exist, lets see a dir up..
startDir = startDir.equal(this.viewsDir, true) ? null : path.cutLastSegment(startDir);
startDir = startDir.equal(this.viewsDir, true) ? null : cutLastSegment(startDir);

if (!startDir)
throw errorsFactory.partialViewNotFound(partialViewName, searchedLocations); // [#2.1].
Expand All @@ -182,6 +262,86 @@ module.exports = class Razor {
return result;
}
}
async findPartialAsync(startDir, partialViewName, searchedLocations, errorsFactory, cache) {
searchedLocations = searchedLocations || [];

if (!partialViewName || !partialViewName.length)
throw errorsFactory.partialLayoutNameExpected(); // Tested by [2.2].

let viewFileExt = path.extname(partialViewName);

if (!viewFileExt.equal('.' + this.ext))
partialViewName += '.' + this.ext;

if (partialViewName[0] === '/' || partialViewName[0] === '.') {
let viewPath = path.normalize(partialViewName);

if (partialViewName[0] === '/') { // it's relative to the `views` root folder
if (!viewPath.startsWithIC(this.viewsDir)) // for linux only (in Windows an absolute path cannot start with '/')
viewPath = path.join(this.viewsDir, viewPath);
// [#2.4.1], [#2.4.2], [#2.4.3]
}
else if (partialViewName[0] === '.') { // it's relative to the current folder
viewPath = path.join(startDir, viewPath); // [#2.4.4], [#2.4.5]
}

try {
searchedLocations.push(viewPath);
let cachedData = cache && cache[viewPath];

if (cachedData)
return cachedData;

let data = await pfs.readFile(viewPath);
let dataStr = this.addFileNameIfDev(data, viewPath);
return successResult(dataStr, viewPath);
}
catch (err) {
if (err.code === 'ENOENT')
throw errorsFactory.partialViewNotFound(path.basename(partialViewName), searchedLocations); // [#2.3]

throw errorsFactory.errorReadingView(viewPath, err); // [#2.3.1]
}
}

partialViewName = path.normalize(partialViewName);
// it's just a layout name without any path, start search from the current dir..
let filePath = path.join(startDir, partialViewName);

try {
searchedLocations.push(filePath);
let cachedData = cache && cache[filePath];

if (cachedData)
return cachedData;

let data = await pfs.readFile(filePath);
let dataStr = this.addFileNameIfDev(data, filePath);
return successResult(dataStr, filePath);
}
catch (err) {
if (err.code === 'ENOENT') { // the file doesn't exist, lets see a dir up..
startDir = startDir.equal(this.viewsDir, true) ? null : cutLastSegment(startDir);

if (!startDir)
throw errorsFactory.partialViewNotFound(partialViewName, searchedLocations); // [#2.1].
else
return await this.findPartialAsync(startDir, partialViewName, searchedLocations, errorsFactory, cache);
}
else {
throw errorsFactory.errorReadingView(filePath, err); // [#2].
}
}

function successResult(data, filePath) {
var result = { data, filePath };

if (cache)
cache[filePath] = result;

return result;
}
}

findPartial(startDir, partialViewName, searchedLocations, errorsFactory, done) {
searchedLocations = searchedLocations || [];
Expand Down Expand Up @@ -228,7 +388,7 @@ module.exports = class Razor {
fs.readFile(filePath, (err, data) => {
if (err) {
if (err.code === 'ENOENT') { // the file doesn't exist, lets see a dir up..
startDir = startDir.equal(this.viewsDir, true) ? null : path.cutLastSegment(startDir);
startDir = startDir.equal(this.viewsDir, true) ? null : cutLastSegment(startDir);

if (!startDir)
return done(errorsFactory.partialViewNotFound(partialViewName, searchedLocations)); // [#2.5]
Expand Down
9 changes: 5 additions & 4 deletions core/bundle-js.js → core/bundle-js.mjs
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
'use strict';

import { setDebugMode, isDebugMode } from './dbg/debugger.mjs';
import * as p from "./parser.mjs"
window.raz = {
set debug(value) {
require('../core/dbg/debugger').isDebugMode = value;
setDebugMode(value);
},
get debug(){
return require('../core/dbg/debugger').isDebugMode;
return isDebugMode;
},
render(template, model) {
if (!this.parser)
this.parser = require('./parser')();
this.parser = p.default();

return this.parser.compileSync(template, model);
}
Expand Down
4 changes: 0 additions & 4 deletions core/dbg/debugger.js

This file was deleted.

6 changes: 6 additions & 0 deletions core/dbg/debugger.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export var isDebugMode= false;
export const isBrowser = (typeof window !== 'undefined');
export function setDebugMode(value)
{
isDebugMode = value;
}
37 changes: 0 additions & 37 deletions core/dbg/logger.js

This file was deleted.

Loading