UNPKG

5.31 kBJavaScriptView Raw
1"use strict";
2var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 return new (P || (P = Promise))(function (resolve, reject) {
5 function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 step((generator = generator.apply(thisArg, _arguments || [])).next());
9 });
10};
11Object.defineProperty(exports, "__esModule", { value: true });
12const Builder_1 = require("./Builder");
13const utils_1 = require("./utils");
14const utils_2 = require("./lint/utils");
15const emd = require("ecmarkdown");
16function findLabeledSteps(root) {
17 const steps = [];
18 emd.visit(root, {
19 enter(node) {
20 if (node.name === 'ordered-list-item' && node.id != null) {
21 steps.push(node);
22 }
23 },
24 });
25 return steps;
26}
27/*@internal*/
28class Algorithm extends Builder_1.default {
29 static enter(context) {
30 return __awaiter(this, void 0, void 0, function* () {
31 context.inAlg = true;
32 const { spec, node, clauseStack } = context;
33 const innerHTML = node.innerHTML; // TODO use original slice, forward this from linter
34 let emdTree;
35 if ('ecmarkdownTree' in node) {
36 emdTree = node.ecmarkdownTree;
37 }
38 else {
39 try {
40 emdTree = emd.parseAlgorithm(innerHTML);
41 }
42 catch (e) {
43 utils_1.warnEmdFailure(spec.warn, node, e);
44 }
45 }
46 if (emdTree == null) {
47 node.innerHTML = utils_1.wrapEmdFailure(innerHTML);
48 return;
49 }
50 if (spec.opts.lintSpec && spec.locate(node) != null && !node.hasAttribute('example')) {
51 const clause = clauseStack[clauseStack.length - 1];
52 const namespace = clause ? clause.namespace : spec.namespace;
53 const nonterminals = utils_2.collectNonterminalsFromEmd(emdTree).map(({ name, loc }) => ({
54 name,
55 loc,
56 node,
57 namespace,
58 }));
59 spec._ntStringRefs = spec._ntStringRefs.concat(nonterminals);
60 }
61 const rawHtml = emd.emit(emdTree);
62 // replace spaces after !/? with   to prevent bad line breaking
63 const html = rawHtml.replace(/((?:\s+|>)[!?])\s+(\w+\s*\()/g, '$1 $2');
64 node.innerHTML = html;
65 const labeledStepEntries = [];
66 const replaces = node.getAttribute('replaces-step');
67 if (replaces) {
68 context.spec.replacementAlgorithms.push({
69 element: node,
70 target: replaces,
71 });
72 context.spec.replacementAlgorithmToContainedLabeledStepEntries.set(node, labeledStepEntries);
73 }
74 if (replaces && node.firstElementChild.children.length > 1) {
75 const labeledSteps = findLabeledSteps(emdTree);
76 for (const step of labeledSteps) {
77 const itemSource = innerHTML.slice(step.location.start.offset, step.location.end.offset);
78 const offset = itemSource.match(/^\s*\d+\. \[id="/)[0].length;
79 spec.warn({
80 type: 'contents',
81 ruleId: 'labeled-step-in-replacement',
82 message: 'labeling a step in a replacement algorithm which has multiple top-level steps is unsupported because the resulting step number would be ambiguous',
83 node,
84 nodeRelativeLine: step.location.start.line,
85 nodeRelativeColumn: step.location.start.column + offset,
86 });
87 }
88 }
89 for (const step of node.querySelectorAll('li[id]')) {
90 const entry = {
91 type: 'step',
92 id: step.id,
93 stepNumbers: getStepNumbers(step),
94 };
95 context.spec.biblio.add(entry);
96 if (replaces) {
97 // The biblio entries for labeled steps in replacement algorithms will be modified in-place by a subsequent pass
98 labeledStepEntries.push(entry);
99 context.spec.labeledStepsToBeRectified.add(step.id);
100 }
101 }
102 });
103 }
104 static exit(context) {
105 context.inAlg = false;
106 }
107}
108exports.default = Algorithm;
109Algorithm.elements = ['EMU-ALG'];
110function getStepNumbers(item) {
111 var _a;
112 const { indexOf } = Array.prototype;
113 const counts = [];
114 while (((_a = item.parentElement) === null || _a === void 0 ? void 0 : _a.tagName) === 'OL') {
115 counts.unshift(1 + indexOf.call(item.parentElement.children, item));
116 item = item.parentElement.parentElement;
117 }
118 return counts;
119}