d7ca263cc4
This commit updates the necessary config files to run the angular.io and docs tooling unit tests in random order (and fixes the tests that were failing due to their dependence on the previous ordered execution). Besides being a good idea anyway, running tests in random order is the new [default behavior in jasmine@3.0.0][1], so this commit is in preparation of upgrading jasmine to the latest version. [1]: https://github.com/jasmine/jasmine/blob/v3.0.0/release_notes/3.0.md#breaking-changes PR Close #31527
146 lines
4.7 KiB
JavaScript
146 lines
4.7 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 DEFAULT_PLASTER = '. . .';
|
|
const {mapObject} = require('../../helpers/utils');
|
|
|
|
module.exports = function regionParser() {
|
|
regionParserImpl.regionMatchers = {
|
|
ts: inlineC,
|
|
js: inlineC,
|
|
es6: inlineC,
|
|
dart: inlineC,
|
|
html: html,
|
|
svg: html,
|
|
css: blockC,
|
|
yaml: inlineHash,
|
|
yml: inlineHash,
|
|
jade: inlineCOnly,
|
|
pug: inlineCOnly,
|
|
json: inlineC,
|
|
'json.annotated': inlineC
|
|
};
|
|
|
|
return regionParserImpl;
|
|
|
|
/**
|
|
* @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;
|
|
if (plaster) {
|
|
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) {
|
|
const plasterString = updatePlaster[1].trim();
|
|
plaster = plasterString ? regionMatcher.createPlasterComment(plasterString) : '';
|
|
|
|
// 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;
|
|
});
|
|
if (!regionMap['']) {
|
|
regionMap[''] = {lines};
|
|
}
|
|
return {
|
|
contents: lines.join('\n'),
|
|
regions: mapObject(regionMap, (regionName, region) => leftAlign(region.lines).join('\n'))
|
|
};
|
|
} else {
|
|
return {contents, regions: {}};
|
|
}
|
|
}
|
|
};
|
|
|
|
function getRegionNames(input) {
|
|
return (input.trim() === '') ? [] : input.split(',').map(name => name.trim());
|
|
}
|
|
|
|
function removeLast(array, item) {
|
|
const index = array.lastIndexOf(item);
|
|
array.splice(index, 1);
|
|
}
|
|
|
|
function leftAlign(lines) {
|
|
let indent = Number.MAX_VALUE;
|
|
lines.forEach(line => {
|
|
const lineIndent = line.search(/\S/);
|
|
if (lineIndent !== -1) {
|
|
indent = Math.min(lineIndent, indent);
|
|
}
|
|
});
|
|
return lines.map(line => line.substr(indent));
|
|
}
|
|
|
|
function RegionParserError(message, index) {
|
|
const lineNum = index + 1;
|
|
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;
|