ecmarkup
Version:
Custom element definitions and core utilities for markup that specifies ECMAScript and related technologies.
155 lines (154 loc) • 6.92 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.collectNodes = collectNodes;
function collectNodes(report, mainSource, spec, document) {
const headers = [];
const mainGrammar = [];
const sdos = [];
const earlyErrors = [];
const algorithms = [];
let failed = false;
let inAnnexB = false;
const lintWalker = document.createTreeWalker(document.body, 1 /* elements */);
function visitCurrentNode() {
const node = lintWalker.currentNode;
const thisNodeIsAnnexB = node.nodeName === 'EMU-ANNEX' &&
node.id === 'sec-additional-ecmascript-features-for-web-browsers';
if (thisNodeIsAnnexB) {
inAnnexB = true;
}
// Don't bother collecting early errors and SDOs from Annex B.
// This is mostly so we don't have to deal with having two inconsistent copies of some of the grammar productions.
if (!inAnnexB) {
if (node.nodeName === 'EMU-CLAUSE') {
// Look for early errors
const first = node.firstElementChild;
if (first !== null && first.nodeName === 'H1') {
const title = textContentExcludingDeleted(first);
headers.push({ element: first, contents: title });
if (title.trim() === 'Static Semantics: Early Errors') {
let grammar = null;
let lists = [];
let warned = false;
for (const child of node.children) {
if (child.nodeName === 'EMU-GRAMMAR') {
if (grammar !== null) {
if (lists.length === 0) {
spec.warn({
type: 'node',
node: grammar,
ruleId: 'early-error-shape',
message: 'unrecognized structure for early errors: multiple consecutive <emu-grammar>s without intervening <ul> of errors',
});
warned = true;
break;
}
earlyErrors.push({ grammar, lists });
}
grammar = child;
lists = [];
}
else if (child.nodeName === 'UL') {
if (grammar === null) {
spec.warn({
type: 'node',
node: child,
ruleId: 'early-error-shape',
message: 'unrecognized structure for early errors: <ul> without preceding <emu-grammar>',
});
warned = true;
break;
}
lists.push(child);
}
}
if (grammar === null) {
if (!warned) {
spec.warn({
type: 'node',
node,
ruleId: 'early-error-shape',
message: 'unrecognized structure for early errors: no <emu-grammar>',
});
}
}
else if (lists.length === 0) {
if (!warned) {
spec.warn({
type: 'node',
node,
ruleId: 'early-error-shape',
message: 'unrecognized structure for early errors: no <ul> of errors',
});
}
}
else {
earlyErrors.push({ grammar, lists });
}
}
}
}
else if (node.nodeName === 'EMU-GRAMMAR' && !node.hasAttribute('example')) {
// Look for grammar definitions and SDOs
if (node.getAttribute('type') === 'definition') {
const loc = spec.locate(node);
if (!loc)
return;
const { source: importSource } = loc;
if (loc.endTag == null) {
failed = true;
// we'll warn for this in collect-tag-diagnostics; no need to do so here
}
else {
const start = loc.startTag.endOffset;
const end = loc.endTag.startOffset;
const realSource = (importSource !== null && importSource !== void 0 ? importSource : mainSource).slice(start, end);
mainGrammar.push({ element: node, source: realSource });
}
}
else {
const next = lintWalker.nextSibling();
if (next) {
if (next.nodeName === 'EMU-ALG') {
sdos.push({ grammar: node, alg: next });
}
lintWalker.previousSibling();
}
}
}
}
if (node.nodeName === 'EMU-ALG' && !node.hasAttribute('example')) {
algorithms.push({ element: node });
}
const firstChild = lintWalker.firstChild();
if (firstChild) {
while (true) {
visitCurrentNode();
const next = lintWalker.nextSibling();
if (!next)
break;
}
lintWalker.parentNode();
}
if (thisNodeIsAnnexB) {
inAnnexB = false;
}
}
visitCurrentNode();
if (failed) {
return { success: false };
}
return { success: true, mainGrammar, headers, sdos, earlyErrors, algorithms };
}
function textContentExcludingDeleted(node) {
let retval = '';
node.childNodes.forEach(value => {
if (value.nodeType === 3) {
retval += value.nodeValue;
}
else if (value.nodeType !== 1 || value.tagName !== 'DEL') {
retval += textContentExcludingDeleted(value);
}
});
return retval;
}