Peter Bacon Darwin 1616cae5cf build(aio): add renderExamples processor
This processor will eventually replace the `{@example}` inline tags
because it provides a cleaner approach that also supports tabbed examples
straight out of the box.

The idea is that authors will simply add a `path` and (optionally) a `region`
attribute to `<code-example>` or `<code-pane>` elements in their docs.
This indicates to dgeni that the relevant example needs to be injected
into the content of this element.

For example, assume that there is an example file `toh-pt1/index.hml` with
a region called `title`, which looks like:

```
<h1>Tour of Heroes</h1>
```

Then the document author could get this to appear in the docs as a
standalone example:

```
<code-example path="toh-pt1" region="title"></code-example>
```

Or as part of a tabbed group:

```
<code-tabs>
  <code-pane path="toh-pt1" region="title"></code-pane>
</code-tabs>
```

If no `path` attribute is provided then the element is ignored, which
enables authors to provide inline code instead:

```
<code-example>
 Some &lt;html&gt escaped code
</code-example>
```

Also all attributes other than `path` and `region` are ignored and passed
through to the final rendered output allowing the author to provide
styling hints:

```
<code-example path="toh-pt1" region="title" linenums"15" class="important">
</code-example>
```
2017-03-25 21:32:30 +00:00

93 lines
2.1 KiB
JavaScript

module.exports = {
/**
* Transform the values of an object via a mapper function
* @param {Object} obj
* @param {Function} mapper
*/
mapObject(obj, mapper) {
const mappedObj = {};
Object.keys(obj).forEach(key => { mappedObj[key] = mapper(key, obj[key]); });
return mappedObj;
},
/**
* Parses the attributes from a string taken from an HTML element start tag
* E.g. ` a="one" b="two" `
* @param {string} str
*/
parseAttributes(str) {
const attrMap = {};
let index = 0, key, value;
skipSpace();
while(index < str.length) {
takeAttribute();
skipSpace();
}
function takeAttribute() {
const key = takeKey();
skipSpace();
if (tryEquals()) {
skipSpace();
const quote = tryQuote();
attrMap[key] = takeValue(quote);
// skip the closing quote or whitespace
index++;
} else {
attrMap[key] = true;
}
}
function skipSpace() {
while(index < str.length && /\s/.test(str[index])) {
index++;
}
}
function tryEquals() {
if (str[index] === '=') {
index++;
return true;
}
}
function takeKey() {
let startIndex = index;
while(index < str.length && /[^\s=]/.test(str[index])) {
index++;
}
return str.substring(startIndex, index);
}
function tryQuote() {
const quote = str[index];
if (['"', "'"].indexOf(quote) !== -1) {
index++;
return quote;
}
}
function takeValue(quote) {
let startIndex = index;
if (quote) {
while(index < str.length && str[index] !== quote) {
index++;
}
if (index >= str.length) {
throw new Error(`Unterminated quoted attribute value in \`${str}\`. Starting at ${startIndex}. Expected a ${quote} but got "end of string".`);
}
} else {
while(index < str.length && /\S/.test(str[index])) {
index++;
}
}
return str.substring(startIndex, index);
}
return attrMap;
}
};