Skip to content
Merged
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
8 changes: 4 additions & 4 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,15 @@ global.app.use(function(req, res, next){

// Middleware that loads spec content
var read = require("./core/middleware/read");
global.app.use(read.handleIndex);
global.app.use(read.process);

// Markdown
global.app.use(require("./core/middleware/md").process);
global.app.use(require("./core/middleware/mdTag").process);

// Load user defined middleware, that processes spec content
require("./core/middleware/userMiddleware");

// Basic markdown support
global.app.use(require("./core/middleware/markdown").process);

// Middleware that wraps spec with Source template
global.app.use(require("./core/middleware/wrap").process);

Expand Down
7 changes: 5 additions & 2 deletions assets/css/reset.less
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,14 @@ body {
});

.source-section-reset(ol, {
margin: 15px 0 15px 5px;
margin: 25px 0 25px 22px;
});

.source-section-reset(~'ol > li', {
list-style-type: decimal !important;
font-family: @font-family-main;
font-size: @fz-size-m;
line-height: 1.5;
list-style: outside decimal;
});

//a {
Expand Down
5 changes: 4 additions & 1 deletion assets/css/variables.less
Original file line number Diff line number Diff line change
Expand Up @@ -95,26 +95,29 @@
* @reset - Boolean enable of disable reset (enabled by default) [true | false]
*/
.source-only(@selector, @rules, @reset: true) {
.source_section > *@{notCleaningClasses} > @{selector},
.source_section > *@{notCleaningClasses} > @{selector},
.source_section > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_section > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_section > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},

.source_info > @{selector},
.source_info > *@{notCleaningClasses} > @{selector},
.source_info > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_info > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_info > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},

.source_doc > @{selector},
.source_doc > *@{notCleaningClasses} > @{selector},
.source_doc > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_doc > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_doc > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},

.source_warn > @{selector},
.source_warn > *@{notCleaningClasses} > @{selector},
.source_warn > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_warn > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
.source_warn > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},

.source_deps > @{selector},
.source_deps > *@{notCleaningClasses} > @{selector},
.source_deps > *@{notCleaningClasses} > *@{notCleaningClasses} > @{selector},
Expand Down
4 changes: 2 additions & 2 deletions core/file-tree/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ var config = {
excludedDirs: ['data', 'plugins', 'node_modules', '.git', '.idea'],

// File masks for search
fileMask: ['index.html', 'index.src', 'index.jade', 'index.haml'],
fileMask: ['index.html', 'index.src', 'index.jade', 'index.haml', 'index.md', 'readme.md'],
cron: false,
cronProd: true,
cronRepeatTime: 60000,
Expand Down Expand Up @@ -48,7 +48,7 @@ var isSpec = function (file) {
var response = false;

config.fileMask.map(function (specFile) {
if (file === specFile) {
if (file.toLowerCase() === specFile) {
response = true;
}
});
Expand Down
68 changes: 68 additions & 0 deletions core/middleware/md.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict';

var cheerio = require('cheerio');
var prettyHrtime = require('pretty-hrtime');

var marked = require('marked');
var renderer = new marked.Renderer();
marked.setOptions({
renderer: renderer
});

/*
* Get file content from response and parse contained Markdown markup
*
* @param {object} req - Request object
* @param {object} res - Response object
* @param {function} next - The callback function
* */
exports.process = function (req, res, next) {
if (req.specData && req.specData.renderedHtml && req.specData.isMd) {
var start = process.hrtime();
var input = req.specData.renderedHtml;

// Processing with native markdown renderer
renderer.code = function (code, language) {
if (language === 'example') {
return '<div class="source_example">'+ code +'</div>';
} else if (language && language !== '') {
return '<code class="src-'+ language +' source_visible">'+ code +'</code>';
} else {
return '<pre><code class="lang-source_wide-code">'+ code +'</code></pre>';
}
};

var $ = cheerio.load(marked(input));

// Spec description
var $H1 = $('h1');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose it would be great to have an ability to configure/redefine this structure (I mean h1,h2 usage), isn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's predefined markup, that will be also generated from info.json, I think configuring this one will be an overhead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does't seem to be the real overhead, strictly speaking. Anyway, it's up to you. I'm not quite sure in it.

var $afterH1 = $H1.nextUntil('h2');
$afterH1.remove();
$H1.after('<div class="source_info">'+ $afterH1 +'</div>');

// Spec sections
$('h2').each(function(){
var $this = $(this);
var $sectionElems = $this.nextUntil('h2');
var id = $this.attr('id');
$this.removeAttr('id');
$sectionElems.remove();

$(this).replaceWith([
'<div class="source_section" id="'+ id +'">',
$this + $sectionElems,
'</div>'
].join(''));

});

req.specData.renderedHtml = $.html();

var end = process.hrtime(start);
global.log.debug('Markdown processing took: ', prettyHrtime(end));

next();
} else {
next();
}
};
File renamed without changes.
169 changes: 79 additions & 90 deletions core/middleware/read.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,134 +5,123 @@ var path = require('path');
var pathToApp = path.dirname(require.main.filename);

/**
* Get spec content and write it to request
* Handling Spec request
*
* @param {object} req - Request object
* @param {object} res - Response object
* @param {function} next - The callback function
* */
var handleRequest = function(req, res, next) {
var handleSpec = function(req, res, next) {
// Filled during middleware processing
req.specData = {};

// get the physical path of a requested file
var physicalPath = global.app.get('user') + req.path;
// Get the physical path of a requested file
var physicalPath = path.join(global.app.get('user'), req.path);

// TODO: move to config with array of exclusions
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed promise (TODO)?

if (req.path.lastIndexOf('/docs/', 0) === 0) {
physicalPath = pathToApp + req.path;
}

// Extension of a requested file
var extension = path.extname(physicalPath).replace(".", "");
var directory = path.dirname(physicalPath); // get the dir of a requested file
//var filename = path.basename(physicalPath); // filename of a requested file
var extension = path.extname(physicalPath).replace(".", ""); // extension of a requested file
var supportedExtensions = global.opts.core.common.extensions;
var extIndex = supportedExtensions.indexOf(extension);

var infoJson = directory + '/' + global.opts.core.common.infoFile;

// in case if one of supported filetypes is requested
if (extIndex >= 0) {
fs.exists(physicalPath, function(exists) {

if (exists) {
fs.readFile(physicalPath, 'utf8', function (err, data) {
data = data.replace(/^\s+|\s+$/g, '');
if (err) {
res.send(err);
} else {

fs.readFile(infoJson, 'utf8', function (err, info) {
if (err) {
info = {
title: "New spec",
author: "Anonymous",
keywords: ""
};
} else {
info = JSON.parse(info);
}

// if requested file is one of supported filetypes, then write proper flag to request. f.e. req.specData.isJade; // true
if (extension === supportedExtensions[extIndex]) {
var capitalizedExtension = extension.charAt(0).toUpperCase() + extension.slice(1);
req.specData["is" + capitalizedExtension] = true;
}

req.specData.info = info; // add spec info object to request
req.specData.renderedHtml = data; // add spec content to request

next();
});
}

});
fs.readFile(physicalPath, 'utf8', function (err, data) {
if (err) {
res.send(err);
return;
}

data = data.replace(/^\s+|\s+$/g, '');

fs.readFile(infoJson, 'utf8', function (err, info) {
if (err) {
info = {
title: "New spec",
author: "Anonymous",
keywords: ""
};
} else {
next();
info = JSON.parse(info);
}

var capitalizedExtension = extension.charAt(0).toUpperCase() + extension.slice(1);

req.specData["is" + capitalizedExtension] = true;
req.specData.info = info; // add spec info object to request
req.specData.renderedHtml = data; // add spec content to request

next();
});
});
};

/**
* Checking if Spec is requested
*
* @param {object} req - Request object
* @param {object} res - Response object
* @param {function} next - The callback function
* */
exports.process = function(req, res, next) {
// Get the physical path of a requested file
var physicalPath = global.app.get('user') + req.path;

// TODO: move to config with array of exclusions
if (req.path.lastIndexOf('/docs/', 0) === 0) {
physicalPath = pathToApp + req.path;
}
// if directory is requested
else if (extension === "") {

// Extension of a requested file
var extension = path.extname(physicalPath).replace(".", "");

// Check if folder is requested
if (extension === "") {
var requestedDir = req.path;
var supportedExtensions = global.opts.core.common.extensions;

// append trailing slash
// Append trailing slash
if (requestedDir.slice(-1) !== '/') {
requestedDir += '/';
}

var oneOfExtensionsFound = false;

for (var j = 0; j < supportedExtensions.length; j++) {
var fileName = "index." + supportedExtensions[j];

if (fs.existsSync(physicalPath + fileName)) {
var specNotFileFound = true;
var checkingSpecFile = function(supportedIndexFormat){
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be it would be better to move this function out of export.process?

if (specNotFileFound && fs.existsSync(physicalPath + supportedIndexFormat)) {
// Passing req params
var urlParams = req.url.split('?')[1];
var paramsString = urlParams ? '?' + urlParams : '';
req.url = requestedDir + fileName + paramsString;

// recursive call
handleRequest(req, res, next);
// Modifying url and saving params string
req.url = requestedDir + supportedIndexFormat + paramsString;

oneOfExtensionsFound = true;
break;
// Recursive call
handleSpec(req, res, next);

specNotFileFound = false;
}
}
};

if (!oneOfExtensionsFound) {
next();
// First check if any supported file exists in dir
for (var j = 0; j < supportedExtensions.length; j++) {
if (specNotFileFound) {
var supportedIndexFormat = "index." + supportedExtensions[j];

checkingSpecFile(supportedIndexFormat);
} else {
break;
}
}

} else {
next();
}
};
// Then check if component have readme.md
checkingSpecFile('readme.md');

/**
* check if requested file is *.src and render
*
* @param {object} req - Request object
* @param {object} res - Response object
* @param {function} next - The callback function
* */
exports.process = function (req, res, next) {
handleRequest(req, res, next);
};
if (specNotFileFound) next();

/**
* if URL ends with "index.src" => redirect to trailing slash
*
* @param {object} req - Request object
* @param {object} res - Response object
* @param {function} next - The callback function
* */
exports.handleIndex = function (req, res, next) {
if (req.path.slice(-9) === 'index.src') {
// Keeping params on redirect
var urlParams = req.url.split('?')[1];
var paramsSting = urlParams ? '?' + urlParams : '';
res.redirect(301, req.path.slice(0, -9) + paramsSting);
} else {
next();
}
};
};
Loading