1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 |
|
4 | function 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 | }
|
116 | exports.default = iterator;
|