
This commit implements various tags, inline tags and changes the markdown renderer to use Rho. This enables us to generate guide type documents.
123 lines
4.0 KiB
JavaScript
123 lines
4.0 KiB
JavaScript
const blockC = require('./region-matchers/block-c');
|
|
const html = require('./region-matchers/html');
|
|
const inlineC = require('./region-matchers/inline-c');
|
|
const inlineCOnly = require('./region-matchers/inline-c-only');
|
|
const inlineHash = require('./region-matchers/inline-hash');
|
|
const NO_NAME_REGION = '';
|
|
const DEFAULT_PLASTER = '. . .';
|
|
const {mapObject} = require('../utils');
|
|
|
|
module.exports = function regionParser() {
|
|
return regionParserImpl;
|
|
};
|
|
|
|
regionParserImpl.regionMatchers = {
|
|
ts: inlineC,
|
|
js: inlineC,
|
|
es6: inlineC,
|
|
dart: inlineC,
|
|
html: html,
|
|
css: blockC,
|
|
yaml: inlineHash,
|
|
jade: inlineCOnly
|
|
};
|
|
|
|
/**
|
|
* @param contents string
|
|
* @param fileType string
|
|
* @returns {contents: string, regions: {[regionName: string]: string}}
|
|
*/
|
|
function regionParserImpl(contents, fileType) {
|
|
const regionMatcher = regionParserImpl.regionMatchers[fileType];
|
|
const openRegions = [];
|
|
const regionMap = {};
|
|
|
|
if (regionMatcher) {
|
|
let plaster = regionMatcher.createPlasterComment(DEFAULT_PLASTER);
|
|
const lines = contents.split(/\r?\n/).filter((line, index) => {
|
|
const startRegion = line.match(regionMatcher.regionStartMatcher);
|
|
const endRegion = line.match(regionMatcher.regionEndMatcher);
|
|
const updatePlaster = line.match(regionMatcher.plasterMatcher);
|
|
|
|
// start region processing
|
|
if (startRegion) {
|
|
// open up the specified region
|
|
const regionNames = getRegionNames(startRegion[1]);
|
|
if (regionNames.length === 0) {
|
|
regionNames.push('');
|
|
}
|
|
regionNames.forEach(regionName => {
|
|
const region = regionMap[regionName];
|
|
if (region) {
|
|
if (region.open) {
|
|
throw new RegionParserError(
|
|
`Tried to open a region, named "${regionName}", that is already open`, index);
|
|
}
|
|
region.open = true;
|
|
region.lines.push(plaster);
|
|
} else {
|
|
regionMap[regionName] = {lines: [], open: true};
|
|
}
|
|
openRegions.push(regionName);
|
|
});
|
|
|
|
// end region processing
|
|
} else if (endRegion) {
|
|
if (openRegions.length === 0) {
|
|
throw new RegionParserError('Tried to close a region when none are open', index);
|
|
}
|
|
// close down the specified region (or most recent if no name is given)
|
|
const regionNames = getRegionNames(endRegion[1]);
|
|
if (regionNames.length === 0) {
|
|
regionNames.push(openRegions[openRegions.length - 1]);
|
|
}
|
|
|
|
regionNames.forEach(regionName => {
|
|
const region = regionMap[regionName];
|
|
if (!region || !region.open) {
|
|
throw new RegionParserError(
|
|
`Tried to close a region, named "${regionName}", that is not open`, index);
|
|
}
|
|
region.open = false;
|
|
removeLast(openRegions, regionName);
|
|
});
|
|
|
|
// doc plaster processing
|
|
} else if (updatePlaster) {
|
|
plaster = regionMatcher.createPlasterComment(updatePlaster[1].trim());
|
|
|
|
// simple line of content processing
|
|
} else {
|
|
openRegions.forEach(regionName => regionMap[regionName].lines.push(line));
|
|
// do not filter out this line from the content
|
|
return true;
|
|
}
|
|
|
|
// this line contained an annotation so let's filter it out
|
|
return false;
|
|
});
|
|
return {
|
|
contents: lines.join('\n'),
|
|
regions: mapObject(regionMap, (regionName, region) => region.lines.join('\n'))
|
|
};
|
|
} else {
|
|
return {contents, regions: {}};
|
|
}
|
|
}
|
|
|
|
function getRegionNames(input) {
|
|
return input.split(',').map(name => name.trim()).filter(name => name.length > 0);
|
|
}
|
|
|
|
function removeLast(array, item) {
|
|
const index = array.lastIndexOf(item);
|
|
array.splice(index, 1);
|
|
}
|
|
|
|
function RegionParserError(message, lineNum) {
|
|
this.message = `regionParser: ${message} (at line ${lineNum}).`;
|
|
this.lineNum = lineNum;
|
|
this.stack = (new Error()).stack;
|
|
}
|
|
RegionParserError.prototype = Object.create(Error.prototype);
|
|
RegionParserError.prototype.constructor = RegionParserError; |