shred and watch build tooling - v2 ( dgeni, gulp, jade)
This commit is contained in:
parent
1d4c56d7f8
commit
e38fc6b3a9
1433
gulpfile.js
1433
gulpfile.js
File diff suppressed because it is too large
Load Diff
|
@ -1,462 +1,38 @@
|
|||
//- Mixins and associated functions
|
||||
|
||||
//- _docsFor: used to identify the language this version of the docs if for;
|
||||
//- Should be one of: 'ts', 'dart' or 'js'. Set in lang specific _util-fns file.
|
||||
- var _docsFor = '';
|
||||
|
||||
//- Should match `_docsFor`, but in this case provides the full capitalized
|
||||
//- name of the language.
|
||||
- var _Lang = 'TypeScript';
|
||||
|
||||
//- Simple "macros" used via interpolation in text:
|
||||
//- e.g., the el variable has an `@Input` #{_decorator}.
|
||||
|
||||
//- Use #{_decorator} whereever the word "decorator" is expected, provided it is not
|
||||
//- preceded by the article "a". (E.g., will be "annotation" for Dart)
|
||||
- var _decorator = 'decorator';
|
||||
- var _decoratorCn = '装饰器';
|
||||
|
||||
//- Articles (which toggle between 'a' and 'an'). Used for, e.g.,
|
||||
//- array vs. list; decorator vs. annotation.
|
||||
- var _a = 'a';
|
||||
- var _an = 'an';
|
||||
|
||||
//- TS arrays vs. Dart lists
|
||||
- var _Array = 'Array';
|
||||
- var _array = 'array';
|
||||
|
||||
//- Promise vs. Future, etc
|
||||
- var _Promise = 'Promise';
|
||||
- var _PromiseUrl = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise';
|
||||
- var _PromiseLinked = '<a href="' + _PromiseUrl + '">' + _Promise + '</a>';
|
||||
- var _Observable = 'Observable';
|
||||
|
||||
//- Directories & folders
|
||||
- var _appDir = 'app';
|
||||
- var _indexHtmlDir = 'project root';
|
||||
- var _mainDir = _appDir;
|
||||
|
||||
//- Location of sample code
|
||||
- var _liveLink = 'live link';
|
||||
- var _ngRepoURL = 'https://github.com/angular/angular';
|
||||
- var _ngDocRepoURL = 'https://github.com/angular/angular.io';
|
||||
- var _qsRepo = 'https://github.com/angular/quickstart';
|
||||
- var _qsRepoZip = _qsRepo + '/archive/master.zip';
|
||||
|
||||
- var _npm = 'npm';
|
||||
|
||||
//- NgModule related
|
||||
- var _AppModuleVsAppComp = 'AppModule'
|
||||
- var _appModuleTsVsAppCompTs = 'src/app/app.module.ts'
|
||||
- var _appModuleTsVsMainTs = 'src/app/app.module.ts'
|
||||
- var _bootstrapModule = 'bootstrapModule'
|
||||
- var _declsVsDirectives = 'declarations'
|
||||
- var _moduleVsComp = 'module'
|
||||
- var _moduleVsRootComp = 'module'
|
||||
- var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic'
|
||||
|
||||
//- Other
|
||||
- var _truthy = 'truthy';
|
||||
- var _falsy = 'falsy';
|
||||
|
||||
//- Used to prefix identifiers that are private. In Dart this will be '_'.
|
||||
- var _priv = '';
|
||||
|
||||
//- Use to conditionally include the block that follows +ifDocsFor(...).
|
||||
//- Generally favor use of Jade named blocks instead. ifDocsFor is convenient
|
||||
//- for prose that should appear only in one language version.
|
||||
mixin ifDocsFor(langPattern)
|
||||
if _docsFor.toLowerCase().match(langPattern.toLowerCase())
|
||||
block
|
||||
|
||||
//- Use to map inlined (prose) TS paths into, say, Dart paths via the
|
||||
//- adjustTsExamplePathForDart transformer function.
|
||||
mixin adjExPath(path)
|
||||
if adjustTsExamplePathForDart
|
||||
| #{adjustTsExamplePathForDart(path)}
|
||||
else
|
||||
| #{path}
|
||||
|
||||
mixin includeShared(filePath, region)
|
||||
- var newPath = translatePath(filePath, region);
|
||||
!=partial(newPath)
|
||||
|
||||
mixin makeExample(_filePath, region, _title, stylePatterns)
|
||||
- var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title});
|
||||
- var filePath = adjustments.filePath;
|
||||
- var title = adjustments.title;
|
||||
- var language = attributes.language || getExtn(filePath);
|
||||
- var frag = getFrag(filePath, region);
|
||||
- var defaultFormat = frag.split('\n').length > 2 ? "linenums" : "";
|
||||
- var format = attributes.format || defaultFormat;
|
||||
- if (attributes.format === '.') format = '';
|
||||
- var avoid = !!attributes.avoid;
|
||||
- var avoidClass = avoid ? 'is-anti-pattern' : '';
|
||||
|
||||
div(class="code-example #{avoidClass}")
|
||||
if (title)
|
||||
header
|
||||
h4 #{title}
|
||||
code-example(language="#{language}" format="#{format}")
|
||||
!= styleString(frag, stylePatterns)
|
||||
|
||||
//- Like makeExample, but: (1) doesn't show line numbers. (2) If region
|
||||
//- is omitted and title is 'foo (r)' then region is taken as 'r'.
|
||||
//- (3) Title will always end with a phrase in parentheses; if no such
|
||||
//- ending is given or is just (), then the title will be suffixed with
|
||||
//- either "(excerpt)", or "(#{_region})" when _region is defined.
|
||||
mixin makeExcerpt(_filePath, _region, _title, stylePatterns)
|
||||
- var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/);
|
||||
- var parenText;
|
||||
- if (matches) { _filePath = matches[1]; parenText = matches[2]; }
|
||||
- var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title});
|
||||
- var filePath = adjustments.filePath;
|
||||
- var title = adjustments.title;
|
||||
- var region = _region || (_region === '' ? '' : parenText);
|
||||
- var excerpt = parenText || region || 'excerpt';
|
||||
- if (title) title = title + ' (' + excerpt + ')';
|
||||
+makeExample(filePath, region, title, stylePatterns)(format='.')
|
||||
|
||||
//- Get the doc example name either from `_example` if set, or
|
||||
//- extract the example name from `current`.
|
||||
- var getExampleName = function() {
|
||||
- var dir = current.path[current.path.length - 1];
|
||||
- return _example ? _example : dir == 'latest' ? current.source : dir;
|
||||
- };
|
||||
|
||||
mixin makeTabs(filePaths, regions, tabNames, stylePatterns)
|
||||
- filePaths = strSplit(filePaths);
|
||||
- if (adjustTsExamplePathForDart) filePaths = filePaths.map(adjustTsExamplePathForDart);
|
||||
- regions = strSplit(regions, filePaths.length);
|
||||
- tabNames = strSplit(tabNames, filePaths.length);
|
||||
- if (adjustTsExampleTitleForDart) tabNames = tabNames.map(adjustTsExampleTitleForDart);
|
||||
|
||||
code-tabs
|
||||
each filePath,index in filePaths
|
||||
- var region = regions[index].trim();
|
||||
- var tabName = tabNames[index].trim();
|
||||
- var language = attributes.language || getExtn(filePath);
|
||||
- var format = attributes.format || "linenums";
|
||||
|
||||
- var frag = getFrag(filePath, region);
|
||||
- var sps = Array.isArray(stylePatterns) ? stylePatterns[index] : stylePatterns;
|
||||
code-pane(language="#{language}" name="#{tabName}" format="#{format}")
|
||||
!= styleString(frag, sps)
|
||||
|
||||
mixin makeJson( filePath, jsonConfig, title, stylePatterns)
|
||||
- var language = attributes.language || getExtn(filePath);
|
||||
- var format = attributes.format || "linenums";
|
||||
- var frag = getFrag(filePath, '');
|
||||
- var json = unescapeHtml(frag);
|
||||
- var jsonExtract = extractJson(json, jsonConfig);
|
||||
- var avoid = !!attributes.avoid;
|
||||
- var avoidClass = avoid ? 'is-anti-pattern' : '';
|
||||
|
||||
div(class="code-example #{avoidClass}")
|
||||
if (title)
|
||||
header
|
||||
h4 #{title}
|
||||
code-example(language="#{language}" format="#{format}")
|
||||
if (jsonExtract == 'ERROR')
|
||||
err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}"
|
||||
err 错误: 无法通过配置"#{jsonConfig.toString()}"解析JSON
|
||||
else
|
||||
!= styleString(jsonExtract, stylePatterns)
|
||||
|
||||
if !jade2ng
|
||||
//- Open (and close) an explanation <div>. See QuickStart
|
||||
script.
|
||||
function why(id, backTo) {
|
||||
var id = "#"+id;
|
||||
var el = document.querySelector(id);
|
||||
el.hidden=el.hidden=!el.hidden;
|
||||
|
||||
if (el.hidden && backTo){
|
||||
// the next line is required to work around a bug in WebKit (Chrome / Safari)
|
||||
location.href = "#";
|
||||
location.href = "#" + backTo;
|
||||
}
|
||||
}
|
||||
script.
|
||||
function verbose(isVerbose) {
|
||||
isVerbose = !! isVerbose;
|
||||
var el = document.querySelector('button.verbose.off');
|
||||
el.style.display = isVerbose ? 'block' : 'none';
|
||||
var el = document.querySelector('button.verbose.on');
|
||||
el.style.display = isVerbose ? 'none' : 'block';
|
||||
|
||||
CCSStylesheetRuleStyle('main','.l-verbose-section', 'display',
|
||||
isVerbose ? 'block' : 'none');
|
||||
}
|
||||
|
||||
script.
|
||||
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
|
||||
/* returns the value of the element style of the rule in the stylesheet
|
||||
* If no value is given, reads the value
|
||||
* If value is given, the value is changed and returned
|
||||
* If '' (empty string) is given, erases the value.
|
||||
* The browser will apply the default one
|
||||
*
|
||||
* string stylesheet: part of the .css name to be recognized, e.g. 'default'
|
||||
* string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td'
|
||||
* string style: camelCase element style, e.g. 'fontSize'
|
||||
* string value optional : the new value
|
||||
*/
|
||||
var CCSstyle = undefined, rules, sheet;
|
||||
for(var m in document.styleSheets){
|
||||
sheet = document.styleSheets[m];
|
||||
if(sheet.href && sheet.href.indexOf(stylesheet) != -1){
|
||||
rules = sheet[document.all ? 'rules' : 'cssRules'];
|
||||
for(var n in rules){
|
||||
console.log(rules[n].selectorText);
|
||||
if(rules[n].selectorText == selectorText){
|
||||
CCSstyle = rules[n].style;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(value == undefined)
|
||||
return CCSstyle[style]
|
||||
else
|
||||
return CCSstyle[style] = value
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------
|
||||
//- Converts the given project-relative path (like 'app/main.ts')
|
||||
//- to a doc folder relative path (like 'quickstart/ts/app/main.ts')
|
||||
//- by prefixing it with '<example-name>/ts/'. If title is not given,
|
||||
//- then the project-relative path is used, adjusted to remove numeric
|
||||
//- file version qualifiers; e.g. 'styles.1.css' becomes 'styles.css'.
|
||||
- var adjExampleProjPathAndTitle = function(ex/*:{filePath,title}*/) {
|
||||
- // E.g. of a project relative path is 'app/main.ts'
|
||||
- if (ex.title === null || ex.title === undefined) {
|
||||
- // Title is not given so take it to be ex.filePath.
|
||||
- // Title like styles.1.css or foo_1.dart? Then drop the '.1' or '_1' qualifier:
|
||||
- var matches = ex.filePath.match(/^(.*)[\._]\d(\.\w+)$/);
|
||||
- ex.title = matches ? matches[1] + matches[2] : ex.filePath;
|
||||
- }
|
||||
- ex.filePath = getExampleName() + '/' + _docsFor + '/' + ex.filePath;
|
||||
- return ex;
|
||||
- };
|
||||
|
||||
//- If the given path is project relative, then first convert it using
|
||||
//- adjExampleProjPathAndTitle(ex). Then the path is adjusted to match
|
||||
//- the documentation language.
|
||||
- var adjustExamplePathAndTitle = function(ex/*:{filePath,title}*/) {
|
||||
- // Not a doc folder relative path? Assume that it is app project relative.
|
||||
- if(isProjRelDir(ex.filePath)) adjExampleProjPathAndTitle(ex);
|
||||
- // Adjust doc folder relative paths if adjustment functions exist.
|
||||
- if(adjustTsExamplePathForDart) ex.filePath = adjustTsExamplePathForDart(ex.filePath);
|
||||
- if(adjustTsExampleTitleForDart) ex.title = adjustTsExampleTitleForDart(ex.title);
|
||||
- return ex;
|
||||
- };
|
||||
|
||||
//- Returns truthy iff path is example project relative.
|
||||
- var isProjRelDir = function(path) {
|
||||
- return !path.match(/\/(js|ts|dart)(-snippets)?\//) && !path.endsWith('e2e-spec.ts');
|
||||
- // Last conjunct handles case for shared project e2e test file like
|
||||
- // cb-component-communication/e2e-spec.js (is shared between ts & dart)
|
||||
- // TODO: generalize: compare start with getExampleName(); which needs to be fixed.
|
||||
- };
|
||||
|
||||
- var translatePath = function(filePath, region) {
|
||||
- filePath = filePath.trim();
|
||||
- var regionPad = (region && region.length) ? '-' + region.toString() : '';
|
||||
- var matches = /{(.*)}.*/.exec(filePath);
|
||||
- if (matches) {
|
||||
- var topLevelDir = matches[1];
|
||||
- var currentPath = current.path;
|
||||
- var subPaths = currentPath.slice(2);
|
||||
- // subPaths[subPaths.length - 1] = "_." + subPaths[subPaths.length - 1];
|
||||
- subPaths[subPaths.length - 1] = "_fragments/" + subPaths[subPaths.length - 1];
|
||||
- var newPath = getPathToDocs() + topLevelDir + '/' + subPaths.join("/");
|
||||
- var result = newPath + regionPad + ".jade";
|
||||
- } else {
|
||||
- var extn = getExtn(filePath);
|
||||
- var baseFileName = getBaseFileName(filePath);
|
||||
- var noExtnFileName = baseFileName.substr(0,baseFileName.length - (extn.length + 1));
|
||||
- var folder = getFolder(filePath);
|
||||
- // var result = folder + "/_." + noExtnFileName + regionPad + "." + extn;
|
||||
- var result = folder + "/_fragments/" + noExtnFileName + regionPad + "." + extn;
|
||||
- }
|
||||
- return result
|
||||
- }
|
||||
|
||||
|
||||
- var EMPTY_STRINGS = [ '','','','','','',''];
|
||||
|
||||
- var strSplit = function(str, length) {
|
||||
- var res;
|
||||
- str = str || '';
|
||||
- if (!length) {
|
||||
- res = str.split(",");
|
||||
- } else {
|
||||
- res = str.split(",");
|
||||
- if (res.length < length) {
|
||||
- res = res.concat(EMPTY_STRINGS.slice(0, length - res.length));
|
||||
- }
|
||||
- }
|
||||
- return res;
|
||||
- }
|
||||
|
||||
- var getFrag = function(filePath, region) {
|
||||
- var fullFileName = getFragFilePath(filePath, region);
|
||||
- var frag = partial(fullFileName);
|
||||
- var getFrag = function(fileName) {
|
||||
- var frag = partial(fileName);
|
||||
- if (frag == null) {
|
||||
- return "出错的文件: " + fullFileName + " 所在路径: " + current.path + " 文档路径: " + getPathToDocs();
|
||||
- return "BAD FILENAME: " + fileName + " Current path: " + current.path;
|
||||
- } else {
|
||||
- // ``` gets translated to <pre><code>.....</code></pre> and we need
|
||||
- // to remove this from the fragment prefix is 11 long and suffix is 13 long
|
||||
- frag = frag.substring(11, frag.length-13);
|
||||
- // Uncomment next line for debugging.
|
||||
- // frag = "FileName: " + fullFileName + " Current path: " + current.path + " PathToDocs: " + getPathToDocs() + "\n" + frag;
|
||||
- return frag;
|
||||
- var r = frag.substring(11, frag.length-13);
|
||||
- return r;
|
||||
- }
|
||||
- }
|
||||
|
||||
- var extractJson = function(json, jsonConfig ) {
|
||||
- try {
|
||||
- if (jsonConfig) {
|
||||
- return extractJsonFragment(json, jsonConfig.rootPath || null, jsonConfig.paths || [], jsonConfig.space || " ");
|
||||
- } else {
|
||||
- return json;
|
||||
- }
|
||||
- } catch (e) {
|
||||
- return "ERROR";
|
||||
- // return json;
|
||||
- }
|
||||
- }
|
||||
|
||||
- var unescapeHtml = function(s) {
|
||||
- // can't break across multiple lines because of jade limitations.
|
||||
- return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'");
|
||||
- }
|
||||
|
||||
- var styleString = function(source, stylePatterns) {
|
||||
- if (stylePatterns) {
|
||||
- for (var styleName in stylePatterns) {
|
||||
- var rxs = stylePatterns[styleName];
|
||||
- rxs = Array.isArray(rxs) ? rxs : [rxs];
|
||||
- rxs.forEach(function(rx) {
|
||||
- source = applyStyle(source, styleName, rx );
|
||||
- });
|
||||
- }
|
||||
- }
|
||||
- return source;
|
||||
- }
|
||||
|
||||
|
||||
- var getFragFilePath = function (filePath, region) {
|
||||
- filePath = filePath.trim();
|
||||
- var extn = getExtn(filePath);
|
||||
- var fileBase = filePath.substr(0,filePath.length - (extn.length + 1));
|
||||
- var regionPad = (region && region.length) ? '-' + region.toString() : '';
|
||||
- var fullFileName = getPathToFrags() + fileBase + regionPad + "." + extn + '.md';
|
||||
- return fullFileName;
|
||||
- }
|
||||
|
||||
//- styles a string according to a regular expression.
|
||||
//- The match groups resulting from the regexp application are what is styled
|
||||
//- (not the whole regexp).
|
||||
- var applyStyle = function(str, styleName, rx) {
|
||||
- var repls = {};
|
||||
- var matches;
|
||||
- do {
|
||||
- matches = rx.exec(str);
|
||||
- if (matches) {
|
||||
- matches.slice(1).forEach(function(match) {
|
||||
- var repl = '<span class="' + styleName + '">' + match + '</span>';
|
||||
- repls[match] = { repl: repl, isGlobal: rx.global };
|
||||
- });
|
||||
- }
|
||||
- } while (matches != null && rx.global );
|
||||
- for (var match in repls) {
|
||||
- var repl = repls[match];
|
||||
- // var escapedMatch = match.replace(/\\/g,'\\').replace(/\(/g,'\(').replace(/\)/g, '\)').replace(/\./,'\.');
|
||||
- // var rx2 = new RegExp(escapedMatch, repl.isGlobal ? "g" : "");
|
||||
- var rx2 = match;
|
||||
- str = str.replace(rx2, repl.repl);
|
||||
- };
|
||||
- return str;
|
||||
- }
|
||||
|
||||
- var getExtn = function(fileName) {
|
||||
- var ix = fileName.lastIndexOf('.');
|
||||
- return ix > 0 ? fileName.substr(ix+1) : "";
|
||||
- }
|
||||
|
||||
- var getBaseFileName = function(fileName) {
|
||||
- var ix = fileName.lastIndexOf('/');
|
||||
- return ix > 0 ? fileName.substr(ix+1) : "";
|
||||
- }
|
||||
// HACK: to avoid having to include a path in makeTabs calls
|
||||
- var currentPath = current.path;
|
||||
|
||||
- var getFolder = function(fileName) {
|
||||
- var ix = fileName.lastIndexOf('/');
|
||||
- return ix > 0 ? fileName.substr(0, ix) : "";
|
||||
- }
|
||||
// simple way to only take as many '../' sections as we need to back up to the 'docs' dir
|
||||
// from the current document
|
||||
// we will almost certainly never go 10 or 11 deep but ...
|
||||
- var pathToFrags = "../../../../../../../../../../../".substr(0, (currentPath.length-2)*3) + "_fragments/";
|
||||
|
||||
- var getPathToDocs = function() {
|
||||
- // simple way to only take as many '../' sections as we need to back up to the 'docs' dir
|
||||
- // from the current document
|
||||
- // we will almost certainly never go 10 or 11 deep but ...
|
||||
- return current.pathToDocs || "../../../../../../../../../../../".substr(0, (current.path.length-2)*3);
|
||||
- }
|
||||
|
||||
- var getPathToFrags = function() {
|
||||
- return getPathToDocs() + "_fragments/";
|
||||
- }
|
||||
|
||||
- var getPathToExamples = function() {
|
||||
- return getPathToDocs() + "_examples/";
|
||||
- }
|
||||
|
||||
//- Extract a subset of a json file in a specified order defined
|
||||
//- by extractPaths while retaining original order for any
|
||||
//- unspecified subobjects.
|
||||
//-
|
||||
//- based on the principle that JSON.parse(source) constructs objects
|
||||
//- in order from the top down in 'source' and JSON.stringify(source) iterates 'source'
|
||||
//- properties according to the order in which they were inserted. ( the spec actually
|
||||
//- discourages this assumption but this method will only
|
||||
//- run on node (v8) and the assumption seems safe there. )
|
||||
- function extractJsonFragment(source, rootPath, extractPaths, space) {
|
||||
- var objSource = JSON.parse(source);
|
||||
- if (rootPath && rootPath.length > 0) {
|
||||
- objSource = getSubObject(objSource, rootPath);
|
||||
- }
|
||||
- var objDest = {};
|
||||
- extractPaths.trim().split(",").forEach(function(dotPath) {
|
||||
- processPath(objSource, objDest, dotPath );
|
||||
- });
|
||||
- var result = JSON.stringify(objDest, null, space || " ");
|
||||
- return result;
|
||||
|
||||
- function getSubObject(source, path) {
|
||||
- var nextSource = source;
|
||||
- var pathParts = path.trim().split(".");
|
||||
- while (pathParts.length > 0) {
|
||||
- var nextProp = pathParts.shift();
|
||||
- nextSource = nextSource[nextProp];
|
||||
- }
|
||||
- return nextSource;
|
||||
- }
|
||||
|
||||
- function processPath(source, dest, dotPath) {
|
||||
- var nextSource = source;
|
||||
- var nextDest = dest;
|
||||
- var pathParts = dotPath.trim().split(".");
|
||||
- while (pathParts.length > 0) {
|
||||
- var nextProp = pathParts.shift();
|
||||
- nextSource = nextSource[nextProp];
|
||||
- if (pathParts.length > 0) {
|
||||
- var val = nextDest[nextProp] || {};
|
||||
- nextDest[nextProp] = val;
|
||||
- nextDest = val;
|
||||
- } else {
|
||||
- nextDest[nextProp] = nextSource;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
mixin makeTabs(path, fileNames, tabNames)
|
||||
- fileNames = fileNames.split(",");
|
||||
- tabNames = tabNames.split(",")
|
||||
// .p Length #{currentPath.length}
|
||||
code-tabs
|
||||
each fileName,index in fileNames
|
||||
- var tabName = tabNames[index].trim();
|
||||
- var fileName = fileNames[index].trim();
|
||||
- var extn = getExtn(fileName);
|
||||
// - var extPath = pathToFrags + (path.length ? path + "/" : "");
|
||||
- var extPath = pathToFrags + path + "/";
|
||||
code-pane(language="#{extn}" name="#{tabName}" format="linenums")
|
||||
!= getFrag(extPath + fileName + ".md")
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
module.exports = function regionExtractor() {
|
||||
// split out each fragment in {content} into a separate doc
|
||||
// a fragment is a section of text surrounded by
|
||||
// 1) In front: a comment marker followed by '#docregion' followed by an optional region name. For example:
|
||||
// <-- #docregion foo --> for html
|
||||
// or // #docregion foo for js/ts
|
||||
// 2) In back: a comment marker followed by '#enddocregion'
|
||||
// Regions can be nested and any regions not 'closed' are automatically closed at the end of the doc.
|
||||
return function(content, commentPrefixes) {
|
||||
|
||||
var lines = result = content.split(/\r?\n/);
|
||||
var docs = [];
|
||||
var docStack = [];
|
||||
var doc = null;
|
||||
var nullLine = '###';
|
||||
|
||||
lines.forEach(function(line, ix) {
|
||||
if (isCommentLine(line, commentPrefixes)) {
|
||||
if (hasRegionTag(line)) {
|
||||
doc = {startIx: ix, regionName: getRegionName(line)};
|
||||
lines[ix] = nullLine;
|
||||
docs.push(doc);
|
||||
docStack.push(doc);
|
||||
} else if (hasEndRegionTag(line)) {
|
||||
lines[ix] = nullLine;
|
||||
doc.endIx = ix;
|
||||
doc = docStack.pop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
docs.forEach(function(doc) {
|
||||
var content;
|
||||
if (doc.endIx) {
|
||||
content = lines.slice(doc.startIx + 1, doc.endIx).join('\n');
|
||||
} else {
|
||||
content = lines.slice(doc.startIx + 1).join('\n');
|
||||
}
|
||||
// eliminate all #docregion lines
|
||||
var rx = new RegExp(nullLine + '\n', 'g');
|
||||
doc.content = content.replace(rx, '');
|
||||
|
||||
});
|
||||
return docs;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function isCommentLine(line, commentPrefixes) {
|
||||
return commentPrefixes.some(function(prefix) {
|
||||
return line.trim().indexOf(prefix) == 0;
|
||||
});
|
||||
}
|
||||
|
||||
function hasRegionTag(line) {
|
||||
return line.indexOf("#docregion") >= 0;
|
||||
}
|
||||
|
||||
function hasEndRegionTag(line) {
|
||||
return line.indexOf("#enddocregion") >= 0;
|
||||
}
|
||||
|
||||
function getRegionName(line) {
|
||||
try {
|
||||
var name = line.match(/#docregion\s*(\S*).*/)[1];
|
||||
// Hack for html regions that look like <!-- #docregion --> or */
|
||||
name = name.replace("-->","").replace('\*\/',"");
|
||||
return name;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
Files in the `test_source` dir may not pass current coding conventions (such as missing EOF new lines). This is deliberate so that we can test
|
||||
the doc-shredder with edge conditions.
|
|
@ -0,0 +1,6 @@
|
|||
# Why the _fragments dir is checked in
|
||||
|
||||
Within this repo files generated as a result of shredding the `_examples` dir ( the contents of the `_fragments` dir) are checked in so that we can avoid running the
|
||||
shredder over the entire `_examples` dir each time someone refreshes the repo ( the `shred-full` gulp task).
|
||||
The gulp `serve-and-watch` shredder is only a ‘partial’ shredder. It only shred’s files in directories changed during
|
||||
the current session.
|
Loading…
Reference in New Issue