UNPKG

4.28 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3/*@internal*/
4function iterator(spec) {
5 const ids = [];
6 let inAnnex = false;
7 let currentLevel = 0;
8 return {
9 next(clauseStack, node) {
10 const annex = node.nodeName === 'EMU-ANNEX';
11 const level = clauseStack.length;
12 if (inAnnex && !annex) {
13 spec.warn({
14 type: 'node',
15 node,
16 ruleId: 'clause-after-annex',
17 message: 'clauses cannot follow annexes',
18 });
19 }
20 if (level - currentLevel > 1) {
21 spec.warn({
22 type: 'node',
23 node,
24 ruleId: 'skipped-caluse',
25 message: 'clause is being numbered without numbering its parent clause',
26 });
27 }
28 const nextNum = annex ? nextAnnexNum : nextClauseNum;
29 if (level === currentLevel) {
30 ids[currentLevel] = nextNum(clauseStack, node);
31 }
32 else if (level > currentLevel) {
33 ids.push(nextNum(clauseStack, node));
34 }
35 else {
36 ids.length = level + 1;
37 ids[level] = nextNum(clauseStack, node);
38 }
39 currentLevel = level;
40 return ids.flat().join('.');
41 },
42 };
43 function nextAnnexNum(clauseStack, node) {
44 const level = clauseStack.length;
45 if (level === 0 && node.hasAttribute('number')) {
46 spec.warn({
47 type: 'attr',
48 node,
49 attr: 'number',
50 ruleId: 'annex-clause-number',
51 message: 'top-level annexes do not support explicit numbers; if you need this, open a bug on ecmarkup',
52 });
53 }
54 if (!inAnnex) {
55 if (level > 0) {
56 spec.warn({
57 type: 'node',
58 node,
59 ruleId: 'annex-depth',
60 message: 'first annex must be at depth 0',
61 });
62 }
63 inAnnex = true;
64 return 'A';
65 }
66 if (level === 0) {
67 return String.fromCharCode(ids[0].charCodeAt(0) + 1);
68 }
69 return nextClauseNum(clauseStack, node);
70 }
71 function nextClauseNum({ length: level }, node) {
72 if (node.hasAttribute('number')) {
73 const nums = node
74 .getAttribute('number')
75 .split('.')
76 .map(n => Number(n));
77 if (nums.length === 0 || nums.some(num => !Number.isSafeInteger(num) || num <= 0)) {
78 spec.warn({
79 type: 'attr-value',
80 node,
81 attr: 'number',
82 ruleId: 'invalid-clause-number',
83 message: 'clause numbers must be positive integers or dotted lists of positive integers',
84 });
85 }
86 if (ids[level] !== undefined) {
87 if (nums.length !== ids[level].length) {
88 spec.warn({
89 type: 'attr-value',
90 node,
91 attr: 'number',
92 ruleId: 'invalid-clause-number',
93 message: 'multi-step explicit clause numbers should not be mixed with single-step clause numbers in the same parent clause',
94 });
95 }
96 else if (nums.some((n, i) => n < ids[level][i]) ||
97 nums.every((n, i) => n === ids[level][i])) {
98 spec.warn({
99 type: 'attr-value',
100 node,
101 attr: 'number',
102 ruleId: 'invalid-clause-number',
103 message: 'clause numbers should be strictly increasing',
104 });
105 }
106 }
107 return nums;
108 }
109 if (ids[level] === undefined)
110 return [1];
111 const head = ids[level].slice(0, -1);
112 const tail = ids[level][ids[level].length - 1];
113 return [...head, tail + 1];
114 }
115}
116exports.default = iterator;