diff --git a/src/browserlib/extract-cddl.mjs b/src/browserlib/extract-cddl.mjs index 769349ce..7f93c55d 100644 --- a/src/browserlib/extract-cddl.mjs +++ b/src/browserlib/extract-cddl.mjs @@ -32,10 +32,11 @@ export default function () { // `
` 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 = {};
@@ -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.
*
diff --git a/src/browserlib/get-code-elements.mjs b/src/browserlib/get-code-elements.mjs
index 1b3d4632..4daf0300 100644
--- a/src/browserlib/get-code-elements.mjs
+++ b/src/browserlib/get-code-elements.mjs
@@ -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
diff --git a/test/extract-cddl.js b/test/extract-cddl.js
index 49f09c55..a4e9d840 100644
--- a/test/extract-cddl.js
+++ b/test/extract-cddl.js
@@ -53,6 +53,60 @@ typedef = tstr
groupdef = tstr`
},
+ {
+ title: 'excludes CDDL generated in the Bikeshed CDDL index section',
+ html: `real = tstr
+
+ CDDL Index
+ Remote end definition
+ real = tstr
+ Local end definition
+ real = tstr
+
+ Next section
+ other = tstr
`,
+ res: `real = tstr
+
+other = tstr`
+ },
+
+ {
+ title: 'excludes CDDL in a container with the CDDL index ID',
+ html: `real = tstr
+
+ CDDL Index
+ real = tstr
+
+ other = tstr
`,
+ res: `real = tstr
+
+other = tstr`
+ },
+
+ {
+ title: 'excludes CDDL in index subsections wrapped in section elements',
+ html: `real = tstr
+
+ CDDL Index
+ Remote end definition
real = tstr
+
+ Next
other = tstr
`,
+ res: `real = tstr
+
+other = tstr`
+ },
+
+ {
+ title: 'does not exclude CDDL modules from an index without modules',
+ html: `cddl = tstr
+ CDDL Index
+ cddl = tstr
`,
+ res: [
+ { name: 'all', cddl: 'cddl = tstr' },
+ { name: 'mod', cddl: 'cddl = tstr' }
+ ]
+ },
+
{
title: 'extracts CDDL module names from data-cddl-module',
html: `cddl = tstr
`,