@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.
Files changed (107) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +419 -0
  3. package/dist/Cef.d.ts +188 -0
  4. package/dist/Cef.d.ts.map +1 -0
  5. package/dist/Cef.js +291 -0
  6. package/dist/CefFormat.d.ts +57 -0
  7. package/dist/CefFormat.d.ts.map +1 -0
  8. package/dist/CefFormat.js +133 -0
  9. package/dist/CommentLine.d.ts +18 -0
  10. package/dist/CommentLine.d.ts.map +1 -0
  11. package/dist/CommentLine.js +27 -0
  12. package/dist/Exception/CefFormatException.d.ts +16 -0
  13. package/dist/Exception/CefFormatException.d.ts.map +1 -0
  14. package/dist/Exception/CefFormatException.js +19 -0
  15. package/dist/Exception/CefWriteException.d.ts +12 -0
  16. package/dist/Exception/CefWriteException.d.ts.map +1 -0
  17. package/dist/Exception/CefWriteException.js +13 -0
  18. package/dist/Exception/DuplicateCandidateException.d.ts +9 -0
  19. package/dist/Exception/DuplicateCandidateException.d.ts.map +1 -0
  20. package/dist/Exception/DuplicateCandidateException.js +8 -0
  21. package/dist/Exception/InvalidUtf8Exception.d.ts +13 -0
  22. package/dist/Exception/InvalidUtf8Exception.d.ts.map +1 -0
  23. package/dist/Exception/InvalidUtf8Exception.js +12 -0
  24. package/dist/Exception/InvalidValueException.d.ts +15 -0
  25. package/dist/Exception/InvalidValueException.d.ts.map +1 -0
  26. package/dist/Exception/InvalidValueException.js +14 -0
  27. package/dist/Exception/InvalidWriterStateException.d.ts +14 -0
  28. package/dist/Exception/InvalidWriterStateException.d.ts.map +1 -0
  29. package/dist/Exception/InvalidWriterStateException.js +13 -0
  30. package/dist/Exception/ReservedCharacterException.d.ts +12 -0
  31. package/dist/Exception/ReservedCharacterException.d.ts.map +1 -0
  32. package/dist/Exception/ReservedCharacterException.js +11 -0
  33. package/dist/Exception/index.d.ts +8 -0
  34. package/dist/Exception/index.d.ts.map +1 -0
  35. package/dist/Exception/index.js +7 -0
  36. package/dist/FileWriteTarget.d.ts +27 -0
  37. package/dist/FileWriteTarget.d.ts.map +1 -0
  38. package/dist/FileWriteTarget.js +35 -0
  39. package/dist/Parameter/CandidatesParameter.d.ts +20 -0
  40. package/dist/Parameter/CandidatesParameter.d.ts.map +1 -0
  41. package/dist/Parameter/CandidatesParameter.js +39 -0
  42. package/dist/Parameter/CustomParameter.d.ts +19 -0
  43. package/dist/Parameter/CustomParameter.d.ts.map +1 -0
  44. package/dist/Parameter/CustomParameter.js +35 -0
  45. package/dist/Parameter/ImplicitRankingParameter.d.ts +11 -0
  46. package/dist/Parameter/ImplicitRankingParameter.d.ts.map +1 -0
  47. package/dist/Parameter/ImplicitRankingParameter.js +16 -0
  48. package/dist/Parameter/NumberOfSeatsParameter.d.ts +14 -0
  49. package/dist/Parameter/NumberOfSeatsParameter.d.ts.map +1 -0
  50. package/dist/Parameter/NumberOfSeatsParameter.js +23 -0
  51. package/dist/Parameter/ParameterInterface.d.ts +20 -0
  52. package/dist/Parameter/ParameterInterface.d.ts.map +1 -0
  53. package/dist/Parameter/ParameterInterface.js +1 -0
  54. package/dist/Parameter/StandardParameter.d.ts +14 -0
  55. package/dist/Parameter/StandardParameter.d.ts.map +1 -0
  56. package/dist/Parameter/StandardParameter.js +14 -0
  57. package/dist/Parameter/VotingMethodsParameter.d.ts +16 -0
  58. package/dist/Parameter/VotingMethodsParameter.d.ts.map +1 -0
  59. package/dist/Parameter/VotingMethodsParameter.js +29 -0
  60. package/dist/Parameter/WeightAllowedParameter.d.ts +11 -0
  61. package/dist/Parameter/WeightAllowedParameter.d.ts.map +1 -0
  62. package/dist/Parameter/WeightAllowedParameter.js +16 -0
  63. package/dist/Parameter/index.d.ts +9 -0
  64. package/dist/Parameter/index.d.ts.map +1 -0
  65. package/dist/Parameter/index.js +7 -0
  66. package/dist/Ranking.d.ts +91 -0
  67. package/dist/Ranking.d.ts.map +1 -0
  68. package/dist/Ranking.js +162 -0
  69. package/dist/VoteLine.d.ts +156 -0
  70. package/dist/VoteLine.d.ts.map +1 -0
  71. package/dist/VoteLine.js +289 -0
  72. package/dist/index.browser.d.ts +17 -0
  73. package/dist/index.browser.d.ts.map +1 -0
  74. package/dist/index.browser.js +16 -0
  75. package/dist/index.d.ts +8 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +7 -0
  78. package/dist/index.node.d.ts +19 -0
  79. package/dist/index.node.d.ts.map +1 -0
  80. package/dist/index.node.js +25 -0
  81. package/package.json +79 -0
  82. package/src/Cef.ts +405 -0
  83. package/src/CefFormat.ts +152 -0
  84. package/src/CommentLine.ts +32 -0
  85. package/src/Exception/CefFormatException.ts +19 -0
  86. package/src/Exception/CefWriteException.ts +13 -0
  87. package/src/Exception/DuplicateCandidateException.ts +8 -0
  88. package/src/Exception/InvalidUtf8Exception.ts +12 -0
  89. package/src/Exception/InvalidValueException.ts +14 -0
  90. package/src/Exception/InvalidWriterStateException.ts +13 -0
  91. package/src/Exception/ReservedCharacterException.ts +11 -0
  92. package/src/Exception/index.ts +7 -0
  93. package/src/FileWriteTarget.ts +42 -0
  94. package/src/Parameter/CandidatesParameter.ts +49 -0
  95. package/src/Parameter/CustomParameter.ts +45 -0
  96. package/src/Parameter/ImplicitRankingParameter.ts +17 -0
  97. package/src/Parameter/NumberOfSeatsParameter.ts +25 -0
  98. package/src/Parameter/ParameterInterface.ts +20 -0
  99. package/src/Parameter/StandardParameter.ts +13 -0
  100. package/src/Parameter/VotingMethodsParameter.ts +36 -0
  101. package/src/Parameter/WeightAllowedParameter.ts +17 -0
  102. package/src/Parameter/index.ts +8 -0
  103. package/src/Ranking.ts +197 -0
  104. package/src/VoteLine.ts +398 -0
  105. package/src/index.browser.ts +36 -0
  106. package/src/index.node.ts +47 -0
  107. package/src/index.ts +8 -0
@@ -0,0 +1,398 @@
1
+ import { CefFormat } from './CefFormat';
2
+ import { InvalidValueException, InvalidWriterStateException } from './Exception';
3
+ import { Ranking } from './Ranking';
4
+
5
+ /**
6
+ * The five components parsed out of a full CEF vote-line string.
7
+ */
8
+ interface ParsedComponents {
9
+ ranking: Ranking;
10
+ tags: string[];
11
+ weight: number | null;
12
+ quantifier: number | null;
13
+ inlineComment: string | null;
14
+ }
15
+
16
+ /**
17
+ * A single ballot.
18
+ *
19
+ * Instances are never built with `new`: use one of the static named
20
+ * constructors — {@link fromRanking} (typed ranks or a {@link Ranking}),
21
+ * {@link fromString} (a full CEF vote-line string), or
22
+ * {@link fromRawRankingString} (a pre-validated *verbatim* ranking string).
23
+ *
24
+ * The ranking is held as a {@link Ranking} value object on {@link ranking}. An
25
+ * empty ranking renders as the `/EMPTY_RANKING/` blank-ballot sentinel. In the
26
+ * verbatim mode the ranking string is written untouched and is *not* parsed,
27
+ * so {@link ranking} is `null`.
28
+ *
29
+ * Optional companions:
30
+ * - `tags` — labels separated by `,`, appended before `||`;
31
+ * - `weight` — strictly positive integer; only meaningful when the
32
+ * `Weight Allowed` parameter is enabled in the document;
33
+ * - `quantifier` — strictly positive integer that collapses identical
34
+ * votes onto a single line;
35
+ * - `inlineComment` — free-form trailing comment introduced by `#`.
36
+ */
37
+ export class VoteLine {
38
+ /**
39
+ * The parsed ranking, or `null` when the ballot was built from a verbatim
40
+ * ranking string via {@link fromRawRankingString} — in that mode the ranking
41
+ * is deliberately *not* parsed into a {@link Ranking} structure.
42
+ */
43
+ public readonly ranking: Ranking | null;
44
+
45
+ /**
46
+ * Verbatim, pre-validated ranking string written to the output untouched.
47
+ * Set only in the {@link fromRawRankingString} mode; `null` otherwise (when
48
+ * {@link ranking} carries the parsed structure instead).
49
+ */
50
+ private readonly rawRanking: string | null;
51
+
52
+ public readonly tags: readonly string[];
53
+
54
+ public readonly weight: number | null;
55
+
56
+ public readonly quantifier: number | null;
57
+
58
+ public readonly inlineComment: string | null;
59
+
60
+ /**
61
+ * @internal Use a static named constructor instead: {@link fromRanking},
62
+ * {@link fromString} or {@link fromRawRankingString}.
63
+ *
64
+ * @throws {CefFormatException} on any specification violation
65
+ */
66
+ private constructor(
67
+ ranking: Ranking | string,
68
+ verbatim: boolean,
69
+ tags: readonly string[] = [],
70
+ weight: number | null = null,
71
+ quantifier: number | null = null,
72
+ inlineComment: string | null = null
73
+ ) {
74
+ if (verbatim) {
75
+ // Verbatim mode: validate the ranking string but skip parsing it into a
76
+ // Ranking — it is written as-is by format().
77
+ if (typeof ranking !== 'string') {
78
+ throw new InvalidWriterStateException('Verbatim mode requires a ranking string.');
79
+ }
80
+
81
+ Ranking.assertValidString(ranking);
82
+ this.ranking = null;
83
+ this.rawRanking = ranking.trim();
84
+ } else {
85
+ if (!(ranking instanceof Ranking)) {
86
+ throw new InvalidWriterStateException('Non-verbatim mode requires a Ranking instance.');
87
+ }
88
+
89
+ this.ranking = ranking;
90
+ this.rawRanking = null;
91
+ }
92
+
93
+ this.tags = VoteLine.validateTags(tags);
94
+
95
+ VoteLine.assertCompanions(weight, quantifier);
96
+
97
+ if (inlineComment !== null) {
98
+ CefFormat.assertSingleLine(inlineComment, 'Inline comment');
99
+ }
100
+
101
+ this.weight = weight;
102
+ this.quantifier = quantifier;
103
+ this.inlineComment = inlineComment;
104
+ }
105
+
106
+ /**
107
+ * Build a {@link VoteLine} from typed ranks or a ready-made {@link Ranking}.
108
+ *
109
+ * This is the primary, typed constructor. The `ranking` argument is either an
110
+ * ordered list of ranks (each inner list a non-empty group of tied
111
+ * candidates; pass `[]` for the `/EMPTY_RANKING/` blank ballot) or a
112
+ * {@link Ranking} value object.
113
+ *
114
+ * @throws {CefFormatException} on any specification violation
115
+ */
116
+ public static fromRanking(
117
+ ranking: readonly (readonly string[])[] | Ranking,
118
+ options: {
119
+ tags?: readonly string[];
120
+ weight?: number | null;
121
+ quantifier?: number | null;
122
+ inlineComment?: string | null;
123
+ } = {}
124
+ ): VoteLine {
125
+ return new VoteLine(
126
+ ranking instanceof Ranking ? ranking : new Ranking(ranking),
127
+ false,
128
+ options.tags ?? [],
129
+ options.weight ?? null,
130
+ options.quantifier ?? null,
131
+ options.inlineComment ?? null
132
+ );
133
+ }
134
+
135
+ /**
136
+ * Build a {@link VoteLine} from a raw CEF vote-line string.
137
+ *
138
+ * Accepted shape — every component except the ranking is optional:
139
+ *
140
+ * [tag1, tag2 || ] ranking [ ^weight] [ *quantifier] [# comment]
141
+ *
142
+ * Both the relaxed and the compact spacing flavors are accepted, e.g.
143
+ * `"A>B^7*2"` and `"A > B ^7 * 2"` parse identically. The `/EMPTY_RANKING/`
144
+ * sentinel is recognised as a blank ballot.
145
+ *
146
+ * The string is parsed into its components; the resulting `VoteLine` is then
147
+ * constructed through the normal constructor, so every validation rule
148
+ * (reserved characters, empty rank, duplicate candidate, positive weight /
149
+ * quantifier) applies.
150
+ *
151
+ * @throws {CefFormatException}
152
+ */
153
+ public static fromString(line: string): VoteLine {
154
+ const parts = VoteLine.parseStringComponents(line);
155
+
156
+ return new VoteLine(
157
+ parts.ranking,
158
+ false,
159
+ parts.tags,
160
+ parts.weight,
161
+ parts.quantifier,
162
+ parts.inlineComment
163
+ );
164
+ }
165
+
166
+ /**
167
+ * Validate that `line` is a syntactically valid CEF vote line, without
168
+ * allocating a `VoteLine` instance.
169
+ *
170
+ * The exact same parsing and validation pipeline that {@link fromString} uses
171
+ * is applied — only the final object construction is skipped. Useful for hot
172
+ * paths that want to write a pre-built line straight to the output after a
173
+ * strict format check.
174
+ *
175
+ * @throws {CefFormatException}
176
+ */
177
+ public static assertValidString(line: string): void {
178
+ VoteLine.parseStringComponents(line);
179
+ }
180
+
181
+ /**
182
+ * Build a {@link VoteLine} from a ranking-only string, kept *verbatim*.
183
+ *
184
+ * The special, allocation-light sibling of {@link fromRanking}: the ranking
185
+ * string is validated as a ranking and *nothing else* — any reserved
186
+ * character (`^`, `*`, `#`, `;`, `,`, `/`), the `||` tag separator, or a line
187
+ * break is rejected, so it cannot smuggle a weight, quantifier, tag or inline
188
+ * comment — but it is **not** parsed into a {@link Ranking}. The string is
189
+ * stored as-is and written untouched by {@link format} (only the
190
+ * library-built companions — the `||` separator, `^weight`, `*quantifier` —
191
+ * follow `autoFormat`). The resulting instance therefore has a `null`
192
+ * {@link ranking}. Used by `Cef.addRawVote()`.
193
+ *
194
+ * @throws {CefFormatException}
195
+ */
196
+ public static fromRawRankingString(
197
+ ranking: string,
198
+ options: {
199
+ tags?: readonly string[];
200
+ weight?: number | null;
201
+ quantifier?: number | null;
202
+ } = {}
203
+ ): VoteLine {
204
+ return new VoteLine(
205
+ ranking,
206
+ true,
207
+ options.tags ?? [],
208
+ options.weight ?? null,
209
+ options.quantifier ?? null
210
+ );
211
+ }
212
+
213
+ /**
214
+ * Shared parser+validator used by {@link fromString} and
215
+ * {@link assertValidString}.
216
+ *
217
+ * Trims the input, extracts every component, and runs the same per-field
218
+ * validation (reserved characters, empty rank, duplicate candidate, positive
219
+ * weight / quantifier, single-line comment) that the constructor performs.
220
+ * Returns the components.
221
+ *
222
+ * @throws {CefFormatException}
223
+ */
224
+ private static parseStringComponents(line: string): ParsedComponents {
225
+ const original = line;
226
+ let work = line.trim();
227
+
228
+ if (work === '') {
229
+ throw new InvalidValueException('Vote line string cannot be empty.');
230
+ }
231
+
232
+ let inlineComment: string | null = null;
233
+ const hashPos = work.indexOf('#');
234
+
235
+ if (hashPos !== -1) {
236
+ let after = work.slice(hashPos + 1);
237
+
238
+ if (after.startsWith(' ')) {
239
+ after = after.slice(1);
240
+ }
241
+
242
+ after = VoteLine.rtrim(after);
243
+ inlineComment = after !== '' ? after : null;
244
+ work = VoteLine.rtrim(work.slice(0, hashPos));
245
+ }
246
+
247
+ if (inlineComment !== null) {
248
+ CefFormat.assertSingleLine(inlineComment, 'Inline comment');
249
+ }
250
+
251
+ const rawTags: string[] = [];
252
+ const separator = CefFormat.TAGS_SEPARATOR;
253
+ const separatorPos = work.indexOf(separator);
254
+
255
+ if (separatorPos !== -1) {
256
+ const tagsPart = work.slice(0, separatorPos);
257
+ work = work.slice(separatorPos + separator.length).trim();
258
+
259
+ for (const rawTag of tagsPart.split(',')) {
260
+ rawTags.push(rawTag.trim());
261
+ }
262
+ }
263
+
264
+ let weight: number | null = null;
265
+ let quantifier: number | null = null;
266
+
267
+ const matches = /^([\s\S]*?)(?:\s*\^\s*(\d+))?(?:\s*\*\s*(\d+))?\s*$/.exec(work);
268
+
269
+ if (matches !== null) {
270
+ work = matches[1].trim();
271
+
272
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
273
+ if (matches[2] !== undefined) {
274
+ weight = Number.parseInt(matches[2], 10);
275
+ }
276
+
277
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
278
+ if (matches[3] !== undefined) {
279
+ quantifier = Number.parseInt(matches[3], 10);
280
+ }
281
+ }
282
+
283
+ if (weight !== null && weight < 1) {
284
+ throw new InvalidValueException('Weight must be a positive integer.');
285
+ }
286
+
287
+ if (quantifier !== null && quantifier < 1) {
288
+ throw new InvalidValueException('Quantifier must be a positive integer.');
289
+ }
290
+
291
+ if (work === '') {
292
+ throw new InvalidWriterStateException(`Vote line "${original.trim()}" has no ranking.`);
293
+ }
294
+
295
+ return {
296
+ ranking: Ranking.fromString(work),
297
+ tags: VoteLine.validateTags(rawTags),
298
+ weight,
299
+ quantifier,
300
+ inlineComment,
301
+ };
302
+ }
303
+
304
+ /**
305
+ * Render the ballot — *without* trailing newline or inline comment — using
306
+ * the spacing flavor selected by `autoFormat`.
307
+ */
308
+ public format(autoFormat = true): string {
309
+ return this.assembleLine(this.renderRanking(autoFormat), autoFormat);
310
+ }
311
+
312
+ /**
313
+ * Return the ranking part of the line: the verbatim string in raw mode, or
314
+ * the parsed ranking rendered with `autoFormat` otherwise.
315
+ */
316
+ private renderRanking(autoFormat: boolean): string {
317
+ if (this.rawRanking !== null) {
318
+ return this.rawRanking;
319
+ }
320
+
321
+ if (this.ranking === null) {
322
+ throw new InvalidWriterStateException(
323
+ 'VoteLine has neither a parsed ranking nor a verbatim ranking string.'
324
+ );
325
+ }
326
+
327
+ return this.ranking.format(autoFormat);
328
+ }
329
+
330
+ /**
331
+ * Reject a non-null, non-positive weight or quantifier.
332
+ *
333
+ * @throws {CefFormatException}
334
+ */
335
+ private static assertCompanions(weight: number | null, quantifier: number | null): void {
336
+ if (weight !== null && (!Number.isInteger(weight) || weight < 1)) {
337
+ throw new InvalidValueException('Weight must be a positive integer.');
338
+ }
339
+
340
+ if (quantifier !== null && (!Number.isInteger(quantifier) || quantifier < 1)) {
341
+ throw new InvalidValueException('Quantifier must be a positive integer.');
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Wrap a ranking string with the tag prefix and the weight / quantifier
347
+ * suffix, using the spacing flavor selected by `autoFormat`.
348
+ */
349
+ private assembleLine(ranking: string, autoFormat: boolean): string {
350
+ let line = '';
351
+
352
+ if (this.tags.length > 0) {
353
+ const tagSeparator = autoFormat ? ', ' : ',';
354
+ line += this.tags.join(tagSeparator);
355
+ line += autoFormat ? ' || ' : '||';
356
+ }
357
+
358
+ line += ranking;
359
+
360
+ if (this.weight !== null) {
361
+ line += autoFormat ? ' ^' + String(this.weight) : '^' + String(this.weight);
362
+ }
363
+
364
+ if (this.quantifier !== null) {
365
+ line += autoFormat ? ' * ' + String(this.quantifier) : '*' + String(this.quantifier);
366
+ }
367
+
368
+ return line;
369
+ }
370
+
371
+ /**
372
+ * @throws {CefFormatException}
373
+ */
374
+ private static validateTags(tags: readonly string[]): string[] {
375
+ const cleaned: string[] = [];
376
+
377
+ for (const tag of tags) {
378
+ const trimmed = tag.trim();
379
+
380
+ if (trimmed === '') {
381
+ throw new InvalidValueException('Tag cannot be empty.');
382
+ }
383
+
384
+ CefFormat.assertNoTagSeparator(trimmed, 'Tag');
385
+ CefFormat.assertValueIsClean(trimmed, 'Tag');
386
+ cleaned.push(trimmed);
387
+ }
388
+
389
+ return cleaned;
390
+ }
391
+
392
+ /**
393
+ * Strip trailing whitespace, mirroring PHP's `rtrim()`.
394
+ */
395
+ private static rtrim(value: string): string {
396
+ return value.replace(/\s+$/, '');
397
+ }
398
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * CEF Writer — a TypeScript library that streams valid Condorcet Election
3
+ * Format (CEF) documents to a string buffer with a friendly object API.
4
+ *
5
+ * This is the browser-only entry point. For Node.js usage, import from the
6
+ * main export which includes {@link FileWriteTarget} for file system access.
7
+ *
8
+ * TypeScript port of {@link https://github.com/CondorcetVote/CEF-Writer | CondorcetVote/CEF-Writer}.
9
+ */
10
+
11
+ export { Cef, StringBuffer, type CefOptions, type WriteTarget } from './Cef';
12
+ export { CefFormat } from './CefFormat';
13
+ export { CommentLine } from './CommentLine';
14
+ export { Ranking } from './Ranking';
15
+ export { VoteLine } from './VoteLine';
16
+
17
+ export {
18
+ CefFormatException,
19
+ CefWriteException,
20
+ DuplicateCandidateException,
21
+ InvalidUtf8Exception,
22
+ InvalidValueException,
23
+ InvalidWriterStateException,
24
+ ReservedCharacterException,
25
+ } from './Exception';
26
+
27
+ export {
28
+ CandidatesParameter,
29
+ CustomParameter,
30
+ ImplicitRankingParameter,
31
+ NumberOfSeatsParameter,
32
+ StandardParameter,
33
+ VotingMethodsParameter,
34
+ WeightAllowedParameter,
35
+ type ParameterInterface,
36
+ } from './Parameter';
@@ -0,0 +1,47 @@
1
+ /**
2
+ * CEF Writer — a TypeScript library that streams valid Condorcet Election
3
+ * Format (CEF) documents to a file or string buffer with a friendly object API.
4
+ *
5
+ * This is the Node.js entry point with full file system support via
6
+ * {@link FileWriteTarget}. For browser-only usage, import from
7
+ * `@condorcet.vote/cef-writer/browser` which excludes Node.js dependencies.
8
+ *
9
+ * TypeScript port of {@link https://github.com/CondorcetVote/CEF-Writer | CondorcetVote/CEF-Writer}.
10
+ */
11
+
12
+ import { Cef } from './Cef';
13
+ import { FileWriteTarget } from './FileWriteTarget';
14
+
15
+ // Wire the file-path convenience for Node.js. This is the side effect that
16
+ // makes `new Cef({ file: '/some/path' })` work; the browser entry point omits
17
+ // it, keeping `node:fs` out of browser bundles. Marked in package.json's
18
+ // `sideEffects` so bundlers never tree-shake this registration away.
19
+ Cef.fileWriteTargetFactory = (path: string): FileWriteTarget => new FileWriteTarget(path);
20
+
21
+ export { Cef, StringBuffer, type CefOptions, type WriteTarget } from './Cef';
22
+ export { FileWriteTarget } from './FileWriteTarget';
23
+ export { CefFormat } from './CefFormat';
24
+ export { CommentLine } from './CommentLine';
25
+ export { Ranking } from './Ranking';
26
+ export { VoteLine } from './VoteLine';
27
+
28
+ export {
29
+ CefFormatException,
30
+ CefWriteException,
31
+ DuplicateCandidateException,
32
+ InvalidUtf8Exception,
33
+ InvalidValueException,
34
+ InvalidWriterStateException,
35
+ ReservedCharacterException,
36
+ } from './Exception';
37
+
38
+ export {
39
+ CandidatesParameter,
40
+ CustomParameter,
41
+ ImplicitRankingParameter,
42
+ NumberOfSeatsParameter,
43
+ StandardParameter,
44
+ VotingMethodsParameter,
45
+ WeightAllowedParameter,
46
+ type ParameterInterface,
47
+ } from './Parameter';
package/src/index.ts ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * CEF Writer — default export for Node.js environments.
3
+ *
4
+ * For browser usage, import from `@condorcet.vote/cef-writer/browser` instead.
5
+ * See {@link https://github.com/CondorcetVote/CEF-Writer-Typescript#browser-usage | browser usage documentation}.
6
+ */
7
+
8
+ export * from './index.node';