@condorcet.vote/cef-writer 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +419 -0
- package/dist/Cef.d.ts +188 -0
- package/dist/Cef.d.ts.map +1 -0
- package/dist/Cef.js +291 -0
- package/dist/CefFormat.d.ts +57 -0
- package/dist/CefFormat.d.ts.map +1 -0
- package/dist/CefFormat.js +133 -0
- package/dist/CommentLine.d.ts +18 -0
- package/dist/CommentLine.d.ts.map +1 -0
- package/dist/CommentLine.js +27 -0
- package/dist/Exception/CefFormatException.d.ts +16 -0
- package/dist/Exception/CefFormatException.d.ts.map +1 -0
- package/dist/Exception/CefFormatException.js +19 -0
- package/dist/Exception/CefWriteException.d.ts +12 -0
- package/dist/Exception/CefWriteException.d.ts.map +1 -0
- package/dist/Exception/CefWriteException.js +13 -0
- package/dist/Exception/DuplicateCandidateException.d.ts +9 -0
- package/dist/Exception/DuplicateCandidateException.d.ts.map +1 -0
- package/dist/Exception/DuplicateCandidateException.js +8 -0
- package/dist/Exception/InvalidUtf8Exception.d.ts +13 -0
- package/dist/Exception/InvalidUtf8Exception.d.ts.map +1 -0
- package/dist/Exception/InvalidUtf8Exception.js +12 -0
- package/dist/Exception/InvalidValueException.d.ts +15 -0
- package/dist/Exception/InvalidValueException.d.ts.map +1 -0
- package/dist/Exception/InvalidValueException.js +14 -0
- package/dist/Exception/InvalidWriterStateException.d.ts +14 -0
- package/dist/Exception/InvalidWriterStateException.d.ts.map +1 -0
- package/dist/Exception/InvalidWriterStateException.js +13 -0
- package/dist/Exception/ReservedCharacterException.d.ts +12 -0
- package/dist/Exception/ReservedCharacterException.d.ts.map +1 -0
- package/dist/Exception/ReservedCharacterException.js +11 -0
- package/dist/Exception/index.d.ts +8 -0
- package/dist/Exception/index.d.ts.map +1 -0
- package/dist/Exception/index.js +7 -0
- package/dist/FileWriteTarget.d.ts +27 -0
- package/dist/FileWriteTarget.d.ts.map +1 -0
- package/dist/FileWriteTarget.js +35 -0
- package/dist/Parameter/CandidatesParameter.d.ts +20 -0
- package/dist/Parameter/CandidatesParameter.d.ts.map +1 -0
- package/dist/Parameter/CandidatesParameter.js +39 -0
- package/dist/Parameter/CustomParameter.d.ts +19 -0
- package/dist/Parameter/CustomParameter.d.ts.map +1 -0
- package/dist/Parameter/CustomParameter.js +35 -0
- package/dist/Parameter/ImplicitRankingParameter.d.ts +11 -0
- package/dist/Parameter/ImplicitRankingParameter.d.ts.map +1 -0
- package/dist/Parameter/ImplicitRankingParameter.js +16 -0
- package/dist/Parameter/NumberOfSeatsParameter.d.ts +14 -0
- package/dist/Parameter/NumberOfSeatsParameter.d.ts.map +1 -0
- package/dist/Parameter/NumberOfSeatsParameter.js +23 -0
- package/dist/Parameter/ParameterInterface.d.ts +20 -0
- package/dist/Parameter/ParameterInterface.d.ts.map +1 -0
- package/dist/Parameter/ParameterInterface.js +1 -0
- package/dist/Parameter/StandardParameter.d.ts +14 -0
- package/dist/Parameter/StandardParameter.d.ts.map +1 -0
- package/dist/Parameter/StandardParameter.js +14 -0
- package/dist/Parameter/VotingMethodsParameter.d.ts +16 -0
- package/dist/Parameter/VotingMethodsParameter.d.ts.map +1 -0
- package/dist/Parameter/VotingMethodsParameter.js +29 -0
- package/dist/Parameter/WeightAllowedParameter.d.ts +11 -0
- package/dist/Parameter/WeightAllowedParameter.d.ts.map +1 -0
- package/dist/Parameter/WeightAllowedParameter.js +16 -0
- package/dist/Parameter/index.d.ts +9 -0
- package/dist/Parameter/index.d.ts.map +1 -0
- package/dist/Parameter/index.js +7 -0
- package/dist/Ranking.d.ts +91 -0
- package/dist/Ranking.d.ts.map +1 -0
- package/dist/Ranking.js +162 -0
- package/dist/VoteLine.d.ts +156 -0
- package/dist/VoteLine.d.ts.map +1 -0
- package/dist/VoteLine.js +289 -0
- package/dist/index.browser.d.ts +17 -0
- package/dist/index.browser.d.ts.map +1 -0
- package/dist/index.browser.js +16 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.node.d.ts +19 -0
- package/dist/index.node.d.ts.map +1 -0
- package/dist/index.node.js +25 -0
- package/package.json +79 -0
- package/src/Cef.ts +405 -0
- package/src/CefFormat.ts +152 -0
- package/src/CommentLine.ts +32 -0
- package/src/Exception/CefFormatException.ts +19 -0
- package/src/Exception/CefWriteException.ts +13 -0
- package/src/Exception/DuplicateCandidateException.ts +8 -0
- package/src/Exception/InvalidUtf8Exception.ts +12 -0
- package/src/Exception/InvalidValueException.ts +14 -0
- package/src/Exception/InvalidWriterStateException.ts +13 -0
- package/src/Exception/ReservedCharacterException.ts +11 -0
- package/src/Exception/index.ts +7 -0
- package/src/FileWriteTarget.ts +42 -0
- package/src/Parameter/CandidatesParameter.ts +49 -0
- package/src/Parameter/CustomParameter.ts +45 -0
- package/src/Parameter/ImplicitRankingParameter.ts +17 -0
- package/src/Parameter/NumberOfSeatsParameter.ts +25 -0
- package/src/Parameter/ParameterInterface.ts +20 -0
- package/src/Parameter/StandardParameter.ts +13 -0
- package/src/Parameter/VotingMethodsParameter.ts +36 -0
- package/src/Parameter/WeightAllowedParameter.ts +17 -0
- package/src/Parameter/index.ts +8 -0
- package/src/Ranking.ts +197 -0
- package/src/VoteLine.ts +398 -0
- package/src/index.browser.ts +36 -0
- package/src/index.node.ts +47 -0
- package/src/index.ts +8 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An ordered ranking of candidates.
|
|
3
|
+
*
|
|
4
|
+
* The ranking is expressed as an ordered list of ranks; each rank is itself a
|
|
5
|
+
* list of candidate names tied at that position. An empty top-level ranking
|
|
6
|
+
* (`[]`) renders as the `/EMPTY_RANKING/` blank-ballot sentinel.
|
|
7
|
+
*
|
|
8
|
+
* A `Ranking` is immutable and self-validating: any specification violation
|
|
9
|
+
* (reserved character, empty rank, duplicate candidate) throws a
|
|
10
|
+
* {@link CefFormatException} at construction time. Render it to a CEF string
|
|
11
|
+
* with {@link format} (or by casting to `string` via {@link toString}).
|
|
12
|
+
*/
|
|
13
|
+
export declare class Ranking {
|
|
14
|
+
readonly ranks: readonly (readonly string[])[];
|
|
15
|
+
/**
|
|
16
|
+
* @param ranks Ordered ranks; each inner list is non-empty. Pass `[]` for
|
|
17
|
+
* the `/EMPTY_RANKING/` blank ballot.
|
|
18
|
+
*
|
|
19
|
+
* @throws {CefFormatException} on any specification violation
|
|
20
|
+
*/
|
|
21
|
+
constructor(ranks: readonly (readonly string[])[]);
|
|
22
|
+
/**
|
|
23
|
+
* Build a {@link Ranking} from a ranking-only string.
|
|
24
|
+
*
|
|
25
|
+
* The string may contain candidate names joined by the `>` (rank) and `=`
|
|
26
|
+
* (tie) operators, or the `/EMPTY_RANKING/` sentinel. Any reserved character
|
|
27
|
+
* (`^`, `*`, `#`, `;`, `,`, `/`), the `||` tag separator, or a line break is
|
|
28
|
+
* rejected — there is no way to smuggle a weight, quantifier, tag or inline
|
|
29
|
+
* comment through the string.
|
|
30
|
+
*
|
|
31
|
+
* @param ranking Ranking only, e.g. `"A > B = C"` or `"/EMPTY_RANKING/"`.
|
|
32
|
+
*
|
|
33
|
+
* @throws {CefFormatException}
|
|
34
|
+
*/
|
|
35
|
+
static fromString(ranking: string): Ranking;
|
|
36
|
+
/**
|
|
37
|
+
* Validate a ranking-only string without allocating a {@link Ranking}.
|
|
38
|
+
*
|
|
39
|
+
* Runs the exact same checks as {@link fromString} (empty input, `||` tag
|
|
40
|
+
* separator, reserved characters, line breaks, duplicate candidates) but
|
|
41
|
+
* never materialises the parsed structure nor a `Ranking` instance — useful
|
|
42
|
+
* for hot paths that write the ranking string verbatim after a strict format
|
|
43
|
+
* check.
|
|
44
|
+
*
|
|
45
|
+
* @param ranking Ranking only, e.g. `"A > B = C"` or `"/EMPTY_RANKING/"`.
|
|
46
|
+
*
|
|
47
|
+
* @throws {CefFormatException}
|
|
48
|
+
*/
|
|
49
|
+
static assertValidString(ranking: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Trim a ranking-only string and reject the two patterns that the
|
|
52
|
+
* per-candidate validation cannot catch on its own: an empty input and the
|
|
53
|
+
* `||` tag separator. Returns the trimmed work string.
|
|
54
|
+
*
|
|
55
|
+
* @throws {CefFormatException}
|
|
56
|
+
*/
|
|
57
|
+
private static normalizeString;
|
|
58
|
+
/**
|
|
59
|
+
* Render the ranking — *without* trailing newline, tags, weight, quantifier
|
|
60
|
+
* or inline comment — using the spacing flavor selected by `autoFormat`.
|
|
61
|
+
*
|
|
62
|
+
* When `autoFormat` is `true` (default), ranks are separated by `" > "` and
|
|
63
|
+
* tied candidates by `" = "`; when `false`, the most compact `>` / `=` form
|
|
64
|
+
* is emitted. An empty ranking yields the `/EMPTY_RANKING/` sentinel.
|
|
65
|
+
*/
|
|
66
|
+
format(autoFormat?: boolean): string;
|
|
67
|
+
/**
|
|
68
|
+
* Render the ranking in its relaxed (auto-formatted) flavor.
|
|
69
|
+
*/
|
|
70
|
+
toString(): string;
|
|
71
|
+
/**
|
|
72
|
+
* Split a cleaned ranking string into its raw, *un-validated* rank/tie
|
|
73
|
+
* structure. The `/EMPTY_RANKING/` sentinel maps to an empty list. Ranks are
|
|
74
|
+
* separated by `>`, tied candidates within a rank by `=`; every token is
|
|
75
|
+
* trimmed but not otherwise checked here.
|
|
76
|
+
*/
|
|
77
|
+
private static split;
|
|
78
|
+
/**
|
|
79
|
+
* @throws {CefFormatException}
|
|
80
|
+
*/
|
|
81
|
+
private static validate;
|
|
82
|
+
/**
|
|
83
|
+
* Trim and validate a single candidate name, rejecting reserved characters,
|
|
84
|
+
* line breaks, invalid UTF-8 and duplicates. The `seen` set is updated to
|
|
85
|
+
* detect repeats across the whole ranking.
|
|
86
|
+
*
|
|
87
|
+
* @throws {CefFormatException}
|
|
88
|
+
*/
|
|
89
|
+
private static assertCandidate;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=Ranking.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Ranking.d.ts","sourceRoot":"","sources":["../src/Ranking.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;GAWG;AACH,qBAAa,OAAO;IAClB,SAAgB,KAAK,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,CAAC;IAEtD;;;;;OAKG;gBACgB,KAAK,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE;IAIxD;;;;;;;;;;;;OAYG;WACW,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIlD;;;;;;;;;;;;OAYG;WACW,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAgBtD;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;IAkB9B;;;;;;;OAOG;IACI,MAAM,CAAC,UAAU,UAAO,GAAG,MAAM;IAWxC;;OAEG;IACI,QAAQ,IAAI,MAAM;IAIzB;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,KAAK;IAoBpB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ;IAqBvB;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,eAAe;CAc/B"}
|
package/dist/Ranking.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { CefFormat } from './CefFormat';
|
|
2
|
+
import { DuplicateCandidateException, InvalidValueException } from './Exception';
|
|
3
|
+
/**
|
|
4
|
+
* An ordered ranking of candidates.
|
|
5
|
+
*
|
|
6
|
+
* The ranking is expressed as an ordered list of ranks; each rank is itself a
|
|
7
|
+
* list of candidate names tied at that position. An empty top-level ranking
|
|
8
|
+
* (`[]`) renders as the `/EMPTY_RANKING/` blank-ballot sentinel.
|
|
9
|
+
*
|
|
10
|
+
* A `Ranking` is immutable and self-validating: any specification violation
|
|
11
|
+
* (reserved character, empty rank, duplicate candidate) throws a
|
|
12
|
+
* {@link CefFormatException} at construction time. Render it to a CEF string
|
|
13
|
+
* with {@link format} (or by casting to `string` via {@link toString}).
|
|
14
|
+
*/
|
|
15
|
+
export class Ranking {
|
|
16
|
+
ranks;
|
|
17
|
+
/**
|
|
18
|
+
* @param ranks Ordered ranks; each inner list is non-empty. Pass `[]` for
|
|
19
|
+
* the `/EMPTY_RANKING/` blank ballot.
|
|
20
|
+
*
|
|
21
|
+
* @throws {CefFormatException} on any specification violation
|
|
22
|
+
*/
|
|
23
|
+
constructor(ranks) {
|
|
24
|
+
this.ranks = Ranking.validate(ranks);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a {@link Ranking} from a ranking-only string.
|
|
28
|
+
*
|
|
29
|
+
* The string may contain candidate names joined by the `>` (rank) and `=`
|
|
30
|
+
* (tie) operators, or the `/EMPTY_RANKING/` sentinel. Any reserved character
|
|
31
|
+
* (`^`, `*`, `#`, `;`, `,`, `/`), the `||` tag separator, or a line break is
|
|
32
|
+
* rejected — there is no way to smuggle a weight, quantifier, tag or inline
|
|
33
|
+
* comment through the string.
|
|
34
|
+
*
|
|
35
|
+
* @param ranking Ranking only, e.g. `"A > B = C"` or `"/EMPTY_RANKING/"`.
|
|
36
|
+
*
|
|
37
|
+
* @throws {CefFormatException}
|
|
38
|
+
*/
|
|
39
|
+
static fromString(ranking) {
|
|
40
|
+
return new Ranking(Ranking.split(Ranking.normalizeString(ranking)));
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Validate a ranking-only string without allocating a {@link Ranking}.
|
|
44
|
+
*
|
|
45
|
+
* Runs the exact same checks as {@link fromString} (empty input, `||` tag
|
|
46
|
+
* separator, reserved characters, line breaks, duplicate candidates) but
|
|
47
|
+
* never materialises the parsed structure nor a `Ranking` instance — useful
|
|
48
|
+
* for hot paths that write the ranking string verbatim after a strict format
|
|
49
|
+
* check.
|
|
50
|
+
*
|
|
51
|
+
* @param ranking Ranking only, e.g. `"A > B = C"` or `"/EMPTY_RANKING/"`.
|
|
52
|
+
*
|
|
53
|
+
* @throws {CefFormatException}
|
|
54
|
+
*/
|
|
55
|
+
static assertValidString(ranking) {
|
|
56
|
+
const work = Ranking.normalizeString(ranking);
|
|
57
|
+
if (work === CefFormat.EMPTY_RANKING) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const seen = new Set();
|
|
61
|
+
for (const rankString of work.split('>')) {
|
|
62
|
+
for (const candidate of rankString.split('=')) {
|
|
63
|
+
Ranking.assertCandidate(candidate, seen);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Trim a ranking-only string and reject the two patterns that the
|
|
69
|
+
* per-candidate validation cannot catch on its own: an empty input and the
|
|
70
|
+
* `||` tag separator. Returns the trimmed work string.
|
|
71
|
+
*
|
|
72
|
+
* @throws {CefFormatException}
|
|
73
|
+
*/
|
|
74
|
+
static normalizeString(ranking) {
|
|
75
|
+
const work = ranking.trim();
|
|
76
|
+
if (work === '') {
|
|
77
|
+
throw new InvalidValueException('Ranking string cannot be empty; use "/EMPTY_RANKING/" for a blank ballot.');
|
|
78
|
+
}
|
|
79
|
+
// The "||" tag separator is the only forbidden pattern that per-candidate
|
|
80
|
+
// validation would not catch on its own ("|" is not a reserved character),
|
|
81
|
+
// so reject it explicitly here. Every reserved character and line break is
|
|
82
|
+
// rejected later, candidate by candidate.
|
|
83
|
+
CefFormat.assertNoTagSeparator(work, 'Ranking');
|
|
84
|
+
return work;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Render the ranking — *without* trailing newline, tags, weight, quantifier
|
|
88
|
+
* or inline comment — using the spacing flavor selected by `autoFormat`.
|
|
89
|
+
*
|
|
90
|
+
* When `autoFormat` is `true` (default), ranks are separated by `" > "` and
|
|
91
|
+
* tied candidates by `" = "`; when `false`, the most compact `>` / `=` form
|
|
92
|
+
* is emitted. An empty ranking yields the `/EMPTY_RANKING/` sentinel.
|
|
93
|
+
*/
|
|
94
|
+
format(autoFormat = true) {
|
|
95
|
+
if (this.ranks.length === 0) {
|
|
96
|
+
return CefFormat.EMPTY_RANKING;
|
|
97
|
+
}
|
|
98
|
+
const rankSep = autoFormat ? ' > ' : '>';
|
|
99
|
+
const tieSep = autoFormat ? ' = ' : '=';
|
|
100
|
+
return this.ranks.map((rank) => rank.join(tieSep)).join(rankSep);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Render the ranking in its relaxed (auto-formatted) flavor.
|
|
104
|
+
*/
|
|
105
|
+
toString() {
|
|
106
|
+
return this.format();
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Split a cleaned ranking string into its raw, *un-validated* rank/tie
|
|
110
|
+
* structure. The `/EMPTY_RANKING/` sentinel maps to an empty list. Ranks are
|
|
111
|
+
* separated by `>`, tied candidates within a rank by `=`; every token is
|
|
112
|
+
* trimmed but not otherwise checked here.
|
|
113
|
+
*/
|
|
114
|
+
static split(work) {
|
|
115
|
+
if (work === CefFormat.EMPTY_RANKING) {
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
const rawRanking = [];
|
|
119
|
+
for (const rankString of work.split('>')) {
|
|
120
|
+
const rank = [];
|
|
121
|
+
for (const candidate of rankString.split('=')) {
|
|
122
|
+
rank.push(candidate.trim());
|
|
123
|
+
}
|
|
124
|
+
rawRanking.push(rank);
|
|
125
|
+
}
|
|
126
|
+
return rawRanking;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* @throws {CefFormatException}
|
|
130
|
+
*/
|
|
131
|
+
static validate(ranks) {
|
|
132
|
+
const cleaned = [];
|
|
133
|
+
const seen = new Set();
|
|
134
|
+
ranks.forEach((rank, rankIndex) => {
|
|
135
|
+
if (rank.length === 0) {
|
|
136
|
+
throw new InvalidValueException(`Rank #${String(rankIndex + 1)} is empty.`);
|
|
137
|
+
}
|
|
138
|
+
const cleanedRank = [];
|
|
139
|
+
for (const candidate of rank) {
|
|
140
|
+
cleanedRank.push(Ranking.assertCandidate(candidate, seen));
|
|
141
|
+
}
|
|
142
|
+
cleaned.push(cleanedRank);
|
|
143
|
+
});
|
|
144
|
+
return cleaned;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Trim and validate a single candidate name, rejecting reserved characters,
|
|
148
|
+
* line breaks, invalid UTF-8 and duplicates. The `seen` set is updated to
|
|
149
|
+
* detect repeats across the whole ranking.
|
|
150
|
+
*
|
|
151
|
+
* @throws {CefFormatException}
|
|
152
|
+
*/
|
|
153
|
+
static assertCandidate(candidate, seen) {
|
|
154
|
+
const trimmed = candidate.trim();
|
|
155
|
+
CefFormat.assertValueIsClean(trimmed, 'Ranked candidate');
|
|
156
|
+
if (seen.has(trimmed)) {
|
|
157
|
+
throw new DuplicateCandidateException(`Candidate "${trimmed}" appears more than once in the ranking.`);
|
|
158
|
+
}
|
|
159
|
+
seen.add(trimmed);
|
|
160
|
+
return trimmed;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { Ranking } from './Ranking';
|
|
2
|
+
/**
|
|
3
|
+
* A single ballot.
|
|
4
|
+
*
|
|
5
|
+
* Instances are never built with `new`: use one of the static named
|
|
6
|
+
* constructors — {@link fromRanking} (typed ranks or a {@link Ranking}),
|
|
7
|
+
* {@link fromString} (a full CEF vote-line string), or
|
|
8
|
+
* {@link fromRawRankingString} (a pre-validated *verbatim* ranking string).
|
|
9
|
+
*
|
|
10
|
+
* The ranking is held as a {@link Ranking} value object on {@link ranking}. An
|
|
11
|
+
* empty ranking renders as the `/EMPTY_RANKING/` blank-ballot sentinel. In the
|
|
12
|
+
* verbatim mode the ranking string is written untouched and is *not* parsed,
|
|
13
|
+
* so {@link ranking} is `null`.
|
|
14
|
+
*
|
|
15
|
+
* Optional companions:
|
|
16
|
+
* - `tags` — labels separated by `,`, appended before `||`;
|
|
17
|
+
* - `weight` — strictly positive integer; only meaningful when the
|
|
18
|
+
* `Weight Allowed` parameter is enabled in the document;
|
|
19
|
+
* - `quantifier` — strictly positive integer that collapses identical
|
|
20
|
+
* votes onto a single line;
|
|
21
|
+
* - `inlineComment` — free-form trailing comment introduced by `#`.
|
|
22
|
+
*/
|
|
23
|
+
export declare class VoteLine {
|
|
24
|
+
/**
|
|
25
|
+
* The parsed ranking, or `null` when the ballot was built from a verbatim
|
|
26
|
+
* ranking string via {@link fromRawRankingString} — in that mode the ranking
|
|
27
|
+
* is deliberately *not* parsed into a {@link Ranking} structure.
|
|
28
|
+
*/
|
|
29
|
+
readonly ranking: Ranking | null;
|
|
30
|
+
/**
|
|
31
|
+
* Verbatim, pre-validated ranking string written to the output untouched.
|
|
32
|
+
* Set only in the {@link fromRawRankingString} mode; `null` otherwise (when
|
|
33
|
+
* {@link ranking} carries the parsed structure instead).
|
|
34
|
+
*/
|
|
35
|
+
private readonly rawRanking;
|
|
36
|
+
readonly tags: readonly string[];
|
|
37
|
+
readonly weight: number | null;
|
|
38
|
+
readonly quantifier: number | null;
|
|
39
|
+
readonly inlineComment: string | null;
|
|
40
|
+
/**
|
|
41
|
+
* @internal Use a static named constructor instead: {@link fromRanking},
|
|
42
|
+
* {@link fromString} or {@link fromRawRankingString}.
|
|
43
|
+
*
|
|
44
|
+
* @throws {CefFormatException} on any specification violation
|
|
45
|
+
*/
|
|
46
|
+
private constructor();
|
|
47
|
+
/**
|
|
48
|
+
* Build a {@link VoteLine} from typed ranks or a ready-made {@link Ranking}.
|
|
49
|
+
*
|
|
50
|
+
* This is the primary, typed constructor. The `ranking` argument is either an
|
|
51
|
+
* ordered list of ranks (each inner list a non-empty group of tied
|
|
52
|
+
* candidates; pass `[]` for the `/EMPTY_RANKING/` blank ballot) or a
|
|
53
|
+
* {@link Ranking} value object.
|
|
54
|
+
*
|
|
55
|
+
* @throws {CefFormatException} on any specification violation
|
|
56
|
+
*/
|
|
57
|
+
static fromRanking(ranking: readonly (readonly string[])[] | Ranking, options?: {
|
|
58
|
+
tags?: readonly string[];
|
|
59
|
+
weight?: number | null;
|
|
60
|
+
quantifier?: number | null;
|
|
61
|
+
inlineComment?: string | null;
|
|
62
|
+
}): VoteLine;
|
|
63
|
+
/**
|
|
64
|
+
* Build a {@link VoteLine} from a raw CEF vote-line string.
|
|
65
|
+
*
|
|
66
|
+
* Accepted shape — every component except the ranking is optional:
|
|
67
|
+
*
|
|
68
|
+
* [tag1, tag2 || ] ranking [ ^weight] [ *quantifier] [# comment]
|
|
69
|
+
*
|
|
70
|
+
* Both the relaxed and the compact spacing flavors are accepted, e.g.
|
|
71
|
+
* `"A>B^7*2"` and `"A > B ^7 * 2"` parse identically. The `/EMPTY_RANKING/`
|
|
72
|
+
* sentinel is recognised as a blank ballot.
|
|
73
|
+
*
|
|
74
|
+
* The string is parsed into its components; the resulting `VoteLine` is then
|
|
75
|
+
* constructed through the normal constructor, so every validation rule
|
|
76
|
+
* (reserved characters, empty rank, duplicate candidate, positive weight /
|
|
77
|
+
* quantifier) applies.
|
|
78
|
+
*
|
|
79
|
+
* @throws {CefFormatException}
|
|
80
|
+
*/
|
|
81
|
+
static fromString(line: string): VoteLine;
|
|
82
|
+
/**
|
|
83
|
+
* Validate that `line` is a syntactically valid CEF vote line, without
|
|
84
|
+
* allocating a `VoteLine` instance.
|
|
85
|
+
*
|
|
86
|
+
* The exact same parsing and validation pipeline that {@link fromString} uses
|
|
87
|
+
* is applied — only the final object construction is skipped. Useful for hot
|
|
88
|
+
* paths that want to write a pre-built line straight to the output after a
|
|
89
|
+
* strict format check.
|
|
90
|
+
*
|
|
91
|
+
* @throws {CefFormatException}
|
|
92
|
+
*/
|
|
93
|
+
static assertValidString(line: string): void;
|
|
94
|
+
/**
|
|
95
|
+
* Build a {@link VoteLine} from a ranking-only string, kept *verbatim*.
|
|
96
|
+
*
|
|
97
|
+
* The special, allocation-light sibling of {@link fromRanking}: the ranking
|
|
98
|
+
* string is validated as a ranking and *nothing else* — any reserved
|
|
99
|
+
* character (`^`, `*`, `#`, `;`, `,`, `/`), the `||` tag separator, or a line
|
|
100
|
+
* break is rejected, so it cannot smuggle a weight, quantifier, tag or inline
|
|
101
|
+
* comment — but it is **not** parsed into a {@link Ranking}. The string is
|
|
102
|
+
* stored as-is and written untouched by {@link format} (only the
|
|
103
|
+
* library-built companions — the `||` separator, `^weight`, `*quantifier` —
|
|
104
|
+
* follow `autoFormat`). The resulting instance therefore has a `null`
|
|
105
|
+
* {@link ranking}. Used by `Cef.addRawVote()`.
|
|
106
|
+
*
|
|
107
|
+
* @throws {CefFormatException}
|
|
108
|
+
*/
|
|
109
|
+
static fromRawRankingString(ranking: string, options?: {
|
|
110
|
+
tags?: readonly string[];
|
|
111
|
+
weight?: number | null;
|
|
112
|
+
quantifier?: number | null;
|
|
113
|
+
}): VoteLine;
|
|
114
|
+
/**
|
|
115
|
+
* Shared parser+validator used by {@link fromString} and
|
|
116
|
+
* {@link assertValidString}.
|
|
117
|
+
*
|
|
118
|
+
* Trims the input, extracts every component, and runs the same per-field
|
|
119
|
+
* validation (reserved characters, empty rank, duplicate candidate, positive
|
|
120
|
+
* weight / quantifier, single-line comment) that the constructor performs.
|
|
121
|
+
* Returns the components.
|
|
122
|
+
*
|
|
123
|
+
* @throws {CefFormatException}
|
|
124
|
+
*/
|
|
125
|
+
private static parseStringComponents;
|
|
126
|
+
/**
|
|
127
|
+
* Render the ballot — *without* trailing newline or inline comment — using
|
|
128
|
+
* the spacing flavor selected by `autoFormat`.
|
|
129
|
+
*/
|
|
130
|
+
format(autoFormat?: boolean): string;
|
|
131
|
+
/**
|
|
132
|
+
* Return the ranking part of the line: the verbatim string in raw mode, or
|
|
133
|
+
* the parsed ranking rendered with `autoFormat` otherwise.
|
|
134
|
+
*/
|
|
135
|
+
private renderRanking;
|
|
136
|
+
/**
|
|
137
|
+
* Reject a non-null, non-positive weight or quantifier.
|
|
138
|
+
*
|
|
139
|
+
* @throws {CefFormatException}
|
|
140
|
+
*/
|
|
141
|
+
private static assertCompanions;
|
|
142
|
+
/**
|
|
143
|
+
* Wrap a ranking string with the tag prefix and the weight / quantifier
|
|
144
|
+
* suffix, using the spacing flavor selected by `autoFormat`.
|
|
145
|
+
*/
|
|
146
|
+
private assembleLine;
|
|
147
|
+
/**
|
|
148
|
+
* @throws {CefFormatException}
|
|
149
|
+
*/
|
|
150
|
+
private static validateTags;
|
|
151
|
+
/**
|
|
152
|
+
* Strip trailing whitespace, mirroring PHP's `rtrim()`.
|
|
153
|
+
*/
|
|
154
|
+
private static rtrim;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=VoteLine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"VoteLine.d.ts","sourceRoot":"","sources":["../src/VoteLine.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,QAAQ;IACnB;;;;OAIG;IACH,SAAgB,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IAExC;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAE3C,SAAgB,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IAExC,SAAgB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtC,SAAgB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1C,SAAgB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7C;;;;;OAKG;IACH,OAAO;IAwCP;;;;;;;;;OASG;WACW,WAAW,CACvB,OAAO,EAAE,SAAS,CAAC,SAAS,MAAM,EAAE,CAAC,EAAE,GAAG,OAAO,EACjD,OAAO,GAAE;QACP,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC1B,GACL,QAAQ;IAWX;;;;;;;;;;;;;;;;;OAiBG;WACW,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAahD;;;;;;;;;;OAUG;WACW,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAInD;;;;;;;;;;;;;;OAcG;WACW,oBAAoB,CAChC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;QACP,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACvB,GACL,QAAQ;IAUX;;;;;;;;;;OAUG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAgFpC;;;OAGG;IACI,MAAM,CAAC,UAAU,UAAO,GAAG,MAAM;IAIxC;;;OAGG;IACH,OAAO,CAAC,aAAa;IAcrB;;;;OAIG;IACH,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAU/B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAsBpB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,YAAY;IAkB3B;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,KAAK;CAGrB"}
|