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
38 changes: 35 additions & 3 deletions src/browserlib/extract-cddl.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,11 @@ export default function () {
// `<pre class="cddl">` convention, or they don't flag CDDL blocks in any
// way, making it impossible to extract them.
const cddlSelectors = ['pre.cddl:not(.exclude):not(.extract)'];
const excludeSelectors = ['#cddl-index'];

// Retrieve all elements that contains CDDL content
const cddlEls = getCodeElements(cddlSelectors, { excludeSelectors });
// Bikeshed generates a CDDL index that repeats all CDDL blocks, as
// siblings that follow the index heading rather than descendants of it.
const isInCddlIndex = createSectionTest(document.getElementById('cddl-index'));
const cddlEls = getCodeElements(cddlSelectors, { excludeFilter: isInCddlIndex });

// Start by assembling the list of modules
const modules = {};
Expand Down Expand Up @@ -97,6 +98,37 @@ export default function () {
}


/**
* Return a function that tells whether an element belongs to the section
* introduced by the given element. When that element is a heading, the
* section runs from the heading to the next heading of the same or a higher
* level. Otherwise, the section is the element's subtree.
*/
function createSectionTest(sectionEl) {
if (!sectionEl) {
return () => false;
}
const level = getHeadingLevel(sectionEl);
if (!level) {
return el => sectionEl.contains(el);
}
const sectionEnd = [...document.querySelectorAll('h1, h2, h3, h4, h5, h6')]
.find(heading => getHeadingLevel(heading) <= level && follows(sectionEl, heading));
return el => follows(sectionEl, el) && (!sectionEnd || follows(el, sectionEnd));
}


function getHeadingLevel(el) {
const match = el.tagName.match(/^H([1-6])$/i);
return match ? parseInt(match[1], 10) : 0;
}


function follows(el, other) {
return !!(el.compareDocumentPosition(other) & Node.DOCUMENT_POSITION_FOLLOWING);
}


/**
* Retrieve the list of CDDL module shortnames that the element references.
*
Expand Down
9 changes: 6 additions & 3 deletions src/browserlib/get-code-elements.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,18 @@ import cloneAndClean from './clone-and-clean.mjs';
* Helper function that returns a set of code elements in document order based
* on a given set of selectors, excluding elements that are within an index.
*
* The function excludes elements defined in informative sections.
* The function excludes elements defined in informative sections, elements
* that have an ancestor matching one of the exclude selectors, and elements
* for which the exclude filter, called on the live element, returns true.
*
* The code elements are cloned and cleaned before they are returned to strip
* annotations and other asides.
*/
export default function getCodeElements(codeSelectors, { excludeSelectors = [] }) {
export default function getCodeElements(codeSelectors, { excludeSelectors = [], excludeFilter = () => false }) {
return [...document.querySelectorAll(codeSelectors.join(', '))]
// Skip excluded and elements and those in informative content
.filter(el => !el.closest(excludeSelectors.join(', ')))
.filter(el => excludeSelectors.length === 0 || !el.closest(excludeSelectors.join(', ')))
.filter(el => !excludeFilter(el))
.filter(el => !el.closest(informativeSelector))

// Clone and clean the elements
Expand Down
54 changes: 54 additions & 0 deletions test/extract-cddl.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,60 @@ typedef = tstr
groupdef = tstr`
},

{
title: 'excludes CDDL generated in the Bikeshed CDDL index section',
html: `<pre class="cddl">real = tstr</pre>

<h2 id="cddl-index">CDDL Index</h2>
<h3>Remote end definition</h3>
<pre class="cddl">real = tstr</pre>
<h3>Local end definition</h3>
<pre class="cddl">real = tstr</pre>

<h2 id="something-else">Next section</h2>
<pre class="cddl">other = tstr</pre>`,
res: `real = tstr

other = tstr`
},

{
title: 'excludes CDDL in a container with the CDDL index ID',
html: `<pre class="cddl">real = tstr</pre>
<div id="cddl-index">
<h2>CDDL Index</h2>
<pre class="cddl">real = tstr</pre>
</div>
<pre class="cddl">other = tstr</pre>`,
res: `real = tstr

other = tstr`
},

{
title: 'excludes CDDL in index subsections wrapped in section elements',
html: `<section><pre class="cddl">real = tstr</pre></section>
<section>
<h2 id="cddl-index">CDDL Index</h2>
<section><h3>Remote end definition</h3><pre class="cddl">real = tstr</pre></section>
</section>
<section><h2>Next</h2><pre class="cddl">other = tstr</pre></section>`,
res: `real = tstr

other = tstr`
},

{
title: 'does not exclude CDDL modules from an index without modules',
html: `<pre class="cddl" data-cddl-module="mod">cddl = tstr</pre>
<h2 id="cddl-index">CDDL Index</h2>
<pre class="cddl">cddl = tstr</pre>`,
res: [
{ name: 'all', cddl: 'cddl = tstr' },
{ name: 'mod', cddl: 'cddl = tstr' }
]
},

{
title: 'extracts CDDL module names from data-cddl-module',
html: `<pre class="cddl" data-cddl-module="mod">cddl = tstr</pre>`,
Expand Down
Loading