General
- The Foreword section contains author-supplied prose, e.g. list of substantive changes since the last edition,
+
The Foreword section contains author-supplied prose, e.g. list of substantive changes since the last edition,
that is added to the SMPTE boilerplate text.
- The absence of this section indicates that no author-supplied prose was provided.
+ The absence of this section indicates that no author-supplied prose was provided.
The id attribute shall be present on the section element and equal to
sec-foreword.
@@ -484,7 +484,7 @@ General
RDD
- When pubType is set to RDD, the Foreword section shall be present and there there shall be a single dl, after any author-supplied prose if supplied, which contains contact information about the proponent(s) of the RDD document.
+ When pubType is set to RDD, the Foreword section shall be present and there there shall be a single dl, after any author-supplied prose if supplied, which contains contact information about the proponent(s) of the RDD document.
The id attribute shall be present on the dl element and equal to
element-proponent.
@@ -516,11 +516,11 @@ RDD
- Introduction section
+ Introduction section
- The Introduction section contains author-supplied prose that forms the introduction of the document.
+ The Introduction section contains author-supplied prose that forms the introduction of the document.
- The absence of this section indicates that the document has no introduction.
+ The absence of this section indicates that the document has no introduction.
The id attribute shall be present on the section element and equal to
sec-introduction.
@@ -537,9 +537,9 @@ Introduction section
- Scope section
+ Scope section
- The Scope section contains author-supplied prose that forms the scope of the document.
+ The Scope section contains author-supplied prose that forms the scope of the document.
The id attribute shall be present on the section element and equal to
sec-scope.
@@ -555,12 +555,12 @@ Scope section
- Normative references section
+ Normative references section
- The Normative references section collects normative references cited in the document.
+ The Normative references section collects normative references cited in the document.
The id attribute shall be present on the section element and equal to
sec-normative-references.
The heading shall not be present.
- The absence of this section indicates that no normative references are cited by the document.
+ The absence of this section indicates that no normative references are cited by the document.
- If present, the section shall contain a single ul element where each li
+
If present, the section shall contain a single ul element where each li
element is a normative reference, such that:
@@ -634,9 +634,9 @@ Normative references section
- Terms and definitions section
+ Terms and definitions section
- The Terms and definitions section collects terms, abbreviations and symbols that are not defined inline the
+
The Terms and definitions section collects terms, abbreviations and symbols that are not defined inline the
clauses of the document, as described in .
The id attribute shall be present on the section element and equal to
@@ -644,7 +644,7 @@
Terms and definitions section
The heading shall not be present.
- The absence of this section indicates that all terms and abbreviations are defined inline the clauses of the
+
The absence of this section indicates that all terms and abbreviations are defined inline the clauses of the
document.
If present, the section contains one or both of the following elements:
@@ -665,13 +665,13 @@ Terms and definitions section
can follow the first dt element, in which case all the terms, abbreviations and symbols in the immediately
preceding dt elements are synonyms.
The dd elements following the dt element(s) shall appear in the following
- order — each group is optional, but if present, it shall appear in this sequence:
+ order — each group is optional (except the definition), but if present, it shall appear in this sequence:
- - Definition: the first
dd element shall be the definition of the term. This element is required.
+ - Deprecated: the first
dd element, if present, shall have a class
+ attribute containing deprecated, indicating the term is deprecated. At most one such element is permitted.
+ - Definition: the next
dd element shall be the definition of the term. This element is required.
References to other defined terms and dfn elements are permitted using <a> elements without an
href attribute. Citations to clauses or external references (i.e. <a href="#bib-HTML-5">) are not permitted.
- - Deprecated: the next
dd element, if present, shall have a class
- attribute containing deprecated, indicating the term is deprecated. At most one such element is permitted.
- Examples: the next
dd element(s), if present, shall each have a class
attribute containing example.
- Notes: the next
dd element(s), if present, shall each have a class
@@ -695,9 +695,9 @@ Terms and definitions section
</ul>
<dl id="terms-int-defs">
<dt><dfn>key number</dfn></dt>
- <dd>number that is printed with ink or exposed onto the film at the time of
- manufacture at regular intervals, typically one foot.</dd>
<dd class="deprecated">deprecated term</dd>
+ <dd>number that is printed with ink or exposed onto the film at the time of
+ manufacture at regular intervals, typically one foot</dd>
<dd class="example">An example of a key number is 12345.</dd>
<dd class="note">Key number shall not be confused with key frame.</dd>
<dd class="source"><a href="#bib-key-number-spec"></a>, modified — definition has been updated.</dd>
@@ -706,26 +706,26 @@ Terms and definitions section
- The boilerplate of the section will be generated automatically.
+ The boilerplate of the clause will be generated automatically.
- Prose section(s)
+ Prose section(s)
- Each Prose section contains author-supplied technical prose.
+ Each Prose sectioncontains author-supplied technical prose.
- A Prose section may contain other nested Prose sections. If any child of a Prose section is a
- Prose section, then all children shall be Prose sections.
+ A Prose section may contain other nested Prose section elements. If any child of a Prose section is a
+ Prose section, then all children shall be Prose section elements.
The id attribute shall be present and its value should be prefixed with sec-.
- The class attribute of a Prose section shall not contain the annex class.
+ The class attribute of a Prose section shall not contain the annex class.
- A section heading element of the appropriate level shall be present, starting with level 2 (h2) for all
- Prose sections that are children of the body element.
+ A section heading element of the appropriate level shall be present, starting with level 2 (h2) for all
+ Prose section elements that are children of the body element.
- Prose sections are automatically numbered, so neither the heading element nor its id attribute should
+
Prose section elements are automatically numbered, so neither the heading element nor its id attribute should
contain numbering information.
@@ -748,28 +748,28 @@ Prose section(s)
- Annex section(s)
+ Annex section(s)
- An Annex section contains an author-supplied technical annex.
+ An Annex section contains an author-supplied technical annex.
- The requirements for an Annex section are the same as those of a Prose section, with the exception that the
- Annex section shall contain the class attribute with value of annex.
+ The requirements for an Annex section are the same as those of a Prose section, with the exception that the
+ Annex section shall contain the class attribute with value of annex.
- An Annex section shall not contain nested annex sections.
+ An Annex section shall not contain nested annex class elements.
- By default, an Annex section is labeled as (Normative). To label any Annex section as (Informative), the class attribute value of informative shall be present.
+ By default, an Annex section is labeled as (Normative). To label any Annex section as (Informative), the class attribute value of informative shall be present.
-
<section class="annex informative" id="sec-addtional-info">
+<section class="annex informative" id="sec-additional-info">
<h2>Additional Info</h2>
<section id="sec-additional-info-sub-section">
- <h3>Additional Info Sub Section</h3>
+ <h3>Additional Info Sub Clause</h3>
<p>Some technical content</p>
</section>
<section id="sec-additional-info-sub-section-more">
- <h3>Additional Info Sub Section More</h3>
+ <h3>Additional Info Sub Clause More</h3>
<p>Some technical content</p>
</section>
</section>
@@ -779,18 +779,18 @@ Annex section(s)
- Additional elements section
+ Additional elements section
- The additional elements section collects the non-prose elements of the document.
+ The additional elements section collects the non-prose elements of the document.
The id attribute shall be present on the section element and equal to
sec-elements.
- The heading of the section shall not be present.
+ The heading of thesection shall not be present.
- If present, the section shall:
+ If present, the section shall:
- - come immediately before the Bibliography section; and
+ - come immediately before the Bibliography
section; and
- contain a single ordered list
ol where each element li contains exactly one a
that links to an element of the document.
@@ -824,27 +824,29 @@ Additional elements section
<section id="sec-elements">
<ol>
<li>
- <a id="element-sample-text" title="Description of the element" href="./elements/form.docx"></a>
+ <a id="element-sample-text" title="Description of the element" href="elements/form.docx"></a>
</li>
</ol>
</section>
+
+ This clause will automatically be labeled as the last Annex clause and marked as informative.
- Bibliography section
+ Bibliography section
- The Bibliography section contains author-supplied bibliographic references.
+ The Bibliography section contains author-supplied bibliographic references.
The id attribute shall be present on the section element and equal to
sec-bibliography.
The heading shall not be present.
- The absence of this section indicates that no bibliographic references are cited by the document.
+ The absence of this section indicates that no bibliographic references are cited by the document.
- If present, the section shall contain a single ul element that conforms to the same requirements as the
- ul element of the normative references section.
+ If present, the section shall contain a single ul element that conforms to the same requirements as the
+ ul element of the normative references section.
<section id="sec-bibliography">
@@ -869,7 +871,7 @@ Other elements
Referencing clauses
When referencing a clause, an a element with its href attribute referencing a
- section element shall be used. The text of the link will be automatically set to section number.
+ section element shall be used. The text of the link will be automatically set to clause number.
@@ -1478,7 +1480,7 @@ Using class attributes
annex
- - Used on a
section element to designate the section as an annex. See .
+ - Used on a
section element to designate the clause as an annex. See .
note
- Applied to
p, div, or dd elements to create a formatted and automatically numbered note. See .
@@ -1781,10 +1783,43 @@ Repo setup
+
+
+
+
diff --git a/js/validate.mjs b/js/validate.mjs
index 06a1035..1145f57 100644
--- a/js/validate.mjs
+++ b/js/validate.mjs
@@ -115,7 +115,15 @@ function validateFootnoteReferences(root, logger) {
}
}
-export function smpteValidate(doc, logger) {
+export function validateDataIncludes(doc, logger, fileExists = null) {
+ for (const el of doc.querySelectorAll("pre[data-include]")) {
+ const src = el.getAttribute("data-include");
+ if (fileExists === null || !fileExists(src))
+ logger.error(`data-include file not found: ${src}`, el);
+ }
+}
+
+export function smpteValidate(doc, logger, fileExists = null) {
const docMetadata = smpte.validateHead(doc.head, logger);
validateDisallowedHeadLinks(doc.head, logger);
validateDisallowedStyleAttributes(doc.documentElement, logger);
@@ -124,6 +132,8 @@ export function smpteValidate(doc, logger) {
validateTfootNoteOrder(doc.documentElement, logger);
validateFootnoteReferences(doc.documentElement, logger);
validateBody(doc.body, logger);
+ if (fileExists !== null)
+ validateDataIncludes(doc, logger, fileExists);
return docMetadata;
}
@@ -736,10 +746,18 @@ class InternalDefinitionsMatcher {
if (count === 0) {
const next = children[0];
- logger.error(`Out of order or unrecognized element in definition${next ? `: ${next.localName}${next.className ? `.${next.className}` : ""}` : ""}
Required order is: definition, deprecated, example, note, source`, next || element);
+ logger.error(`Out of order or unrecognized element in definition${next ? `: ${next.localName}${next.className ? `.${next.className}` : ""}` : ""}
Required order is: deprecated, definition, example, note, source`, next || element);
break;
}
+ /* look for deprecated marker (at most one) */
+
+ if (children.length > 0 && DefinitionDeprecatedMatcher.match(children[0], logger)) {
+ children.shift();
+ if (children.length > 0 && DefinitionDeprecatedMatcher.match(children[0], logger))
+ logger.error(`Only one dd.deprecated is permitted per term`, children[0]);
+ }
+
/* look for definition */
if (children.length > 0 &&
@@ -748,13 +766,7 @@ class InternalDefinitionsMatcher {
children.shift();
}
- /* look for deprecated marker (at most one) */
-
- if (children.length > 0 && DefinitionDeprecatedMatcher.match(children[0], logger)) {
- children.shift();
- if (children.length > 0 && DefinitionDeprecatedMatcher.match(children[0], logger))
- logger.error(`Only one dd.deprecated is permitted per term`, children[0]);
- }
+
/* look for examples to entry */
count = 0;
diff --git a/scripts/validate.mjs b/scripts/validate.mjs
index b3d2533..5dd1428 100644
--- a/scripts/validate.mjs
+++ b/scripts/validate.mjs
@@ -28,11 +28,14 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
import * as jsdom from "jsdom"
import process from "process";
import * as fs from "fs";
+import * as path from "path";
import {smpteValidate} from "../js/validate.mjs";
async function main() {
- const dom = new jsdom.JSDOM(fs.readFileSync(process.argv[2]));
- smpteValidate(dom.window.document, console);
+ const filePath = path.resolve(process.argv[2]);
+ const dom = new jsdom.JSDOM(fs.readFileSync(filePath));
+ const fileExists = (src) => fs.existsSync(path.resolve(path.dirname(filePath), src));
+ smpteValidate(dom.window.document, console, fileExists);
}
main().catch(e => { console.error(e); process.exitCode = 1; });
diff --git a/smpte.js b/smpte.js
index f1622a6..6ad8422 100644
--- a/smpte.js
+++ b/smpte.js
@@ -28,7 +28,7 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-import { smpteValidate } from "./js/validate.mjs";
+import { smpteValidate, validateDataIncludes } from "./js/validate.mjs";
import * as smpte from "./js/common.mjs";
class Logger {
@@ -77,7 +77,7 @@ function resolveScriptRelativePath(path) {
function asyncFetchLocal(url) {
return new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest
- xhr.onload = () => resolve(xhr.responseText);
+ xhr.onload = () => xhr.status === 200 ? resolve(xhr.responseText) : reject(new TypeError(`File not found: ${url}`));
xhr.onerror = () => reject(new TypeError('Local request failed'));
xhr.open('GET', url);
xhr.send(null);
@@ -91,7 +91,7 @@ async function asyncAddStylesheet(url) {
s.textContent = data;
document.head.appendChild(s);
})
- .catch(err => logError("Cannot fetch: " + err));
+ .catch(err => logger_.error("Cannot fetch: " + err));
}
function fillTemplate(template, data) {
@@ -593,7 +593,7 @@ function insertElementsAnnex(docMetadata) {
return;
}
- sec.classList.add("unnumbered");
+ sec.classList.add("annex", "informative");
const intro = document.createElement("p");
intro.innerText = "The following are the non-prose elements of this document:"
@@ -900,6 +900,50 @@ function addHeadingLinks(docMetadata) {
heading.appendChild(headingLink);
}
+
+ for (const table of document.querySelectorAll("table[id]")) {
+ const caption = table.querySelector("caption");
+ if (!caption) continue;
+ const link = document.createElement("a");
+ link.className = "heading-link";
+ link.href = `#${table.id}`;
+ link.innerHTML = "🔗";
+ caption.appendChild(link);
+ }
+
+ for (const figure of document.querySelectorAll("figure[id]")) {
+ const figcaption = figure.querySelector("figcaption");
+ if (!figcaption) continue;
+ const link = document.createElement("a");
+ link.className = "heading-link";
+ link.href = `#${figure.id}`;
+ link.innerHTML = "🔗";
+ figcaption.appendChild(link);
+ }
+
+ for (const formula of document.querySelectorAll("div.formula[id]")) {
+ const link = document.createElement("a");
+ link.className = "heading-link";
+ link.href = `#${formula.id}`;
+ link.innerHTML = "🔗";
+ formula.appendChild(link);
+ }
+
+ for (const note of document.querySelectorAll(".note[id]")) {
+ const link = document.createElement("a");
+ link.className = "heading-link";
+ link.href = `#${note.id}`;
+ link.innerHTML = "🔗";
+ note.appendChild(link);
+ }
+
+ for (const example of document.querySelectorAll(".example[id]")) {
+ const link = document.createElement("a");
+ link.className = "heading-link";
+ link.href = `#${example.id}`;
+ link.innerHTML = "🔗";
+ example.appendChild(link);
+ }
}
function numberSections(element, curHeadingNumber) {
@@ -1187,7 +1231,6 @@ function numberExamples() {
headingLabel.appendChild(document.createTextNode("EXAMPLE "));
headingLabel.appendChild(headingNumberElement);
- headingLabel.appendChild(document.createTextNode(" — "));
example.insertBefore(headingLabel, example.firstChild);
}
@@ -1475,9 +1518,9 @@ function asyncInsertSnippets() {
return Promise.all(Array.from(
document.querySelectorAll("pre[data-include]"),
(e) => {
- asyncFetchLocal(e.getAttribute("data-include"))
- .then(data => e.textContent = data)
- .catch(err => logError("Cannot fetch: " + err));
+ return asyncFetchLocal(e.getAttribute("data-include"))
+ .then(data => { e.textContent = data; e.removeAttribute("data-include"); })
+ .catch(() => {});
}
));
}
@@ -1564,6 +1607,7 @@ document.addEventListener('DOMContentLoaded', async () => {
try {
smpteValidate(window.document, logger_);
await render();
+ validateDataIncludes(window.document, logger_);
window._smpteRenderComplete = true;
} catch (e) {
logger_.error(e);
diff --git a/test/resources/html/snippets/example.txt b/test/resources/html/snippets/example.txt
new file mode 100644
index 0000000..d457d9a
--- /dev/null
+++ b/test/resources/html/snippets/example.txt
@@ -0,0 +1 @@
+This an example.
\ No newline at end of file
diff --git a/test/resources/html/validation/snippet-invalid.html b/test/resources/html/validation/snippet-invalid.html
new file mode 100644
index 0000000..1ffff6b
--- /dev/null
+++ b/test/resources/html/validation/snippet-invalid.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Title of the document
+
+
+
+ This is the scope of the document.
+
+
+
+ External code snippets
+ External code snippet:
+
+
+
+
+
\ No newline at end of file
diff --git a/test/resources/html/validation/snippet-valid.html b/test/resources/html/validation/snippet-valid.html
new file mode 100644
index 0000000..f8ba91f
--- /dev/null
+++ b/test/resources/html/validation/snippet-valid.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Title of the document
+
+
+
+ This is the scope of the document.
+
+
+
+ External code snippets
+ External code snippet:
+
+
+
+
+
\ No newline at end of file
diff --git a/test/resources/html/validation/terms-note-to-entry-2-invalid.html b/test/resources/html/validation/terms-note-to-entry-2-invalid.html
index ab7f029..d907a74 100644
--- a/test/resources/html/validation/terms-note-to-entry-2-invalid.html
+++ b/test/resources/html/validation/terms-note-to-entry-2-invalid.html
@@ -31,6 +31,7 @@
- Clear
- CLR
- something that is clean
+ - old
- The term shall not be used to refer to clarity of mind.
- The term is not intended to be used ever.
diff --git a/test/resources/html/validation/terms-note-to-entry-2-valid.html b/test/resources/html/validation/terms-note-to-entry-2-valid.html
index fbfca81..9ef723a 100644
--- a/test/resources/html/validation/terms-note-to-entry-2-valid.html
+++ b/test/resources/html/validation/terms-note-to-entry-2-valid.html
@@ -30,6 +30,7 @@
- Clear
- CLR
+ - sub-black
- something that is clean
- The term shall not be used to refer to clarity of mind.
- The term is not intended to be used ever.
diff --git a/test/src/testValidation.mjs b/test/src/testValidation.mjs
index 10c38e0..ce99e29 100644
--- a/test/src/testValidation.mjs
+++ b/test/src/testValidation.mjs
@@ -33,8 +33,8 @@ import {smpteValidate, ErrorLogger} from "../../js/validate.mjs";
const testDirPath = "test/resources/html/validation";
-async function _test(path) {
- const dom = new jsdom.JSDOM(fs.readFileSync(path));
+async function _test(filePath) {
+ const dom = new jsdom.JSDOM(fs.readFileSync(filePath));
const expectation = dom.window.document.head.querySelector("meta[itemprop='test']").getAttribute("content");
@@ -42,8 +42,10 @@ async function _test(path) {
let hasThrown = false;
+ const fileExists = (src) => fs.existsSync(path.resolve(path.dirname(filePath), src));
+
try {
- smpteValidate(dom.window.document, logger);
+ smpteValidate(dom.window.document, logger, fileExists);
} catch (e) {
logger.error(`Exception: ${e.stack}`);
hasThrown = true;
@@ -52,11 +54,11 @@ async function _test(path) {
const hasPassed = !logger.hasFailed() && !hasThrown;
if ((expectation === "valid" && hasPassed) || (expectation !== "valid" && !hasPassed)) {
- console.log(`${path} passed.`);
+ console.log(`${filePath} passed.`);
return true;
}
- console.log(`**** ${path} failed.`);
+ console.log(`**** ${filePath} failed.`);
logger.errorList().map(msg => console.log(` ${msg.message}`));
return false;