Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/core/src/countBallotsFromGit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export default async function countFromGit({

await Promise.all(decryptPromises);

const result = vote.count({ discardedCommits });
const result = vote.count({ discardedCommits, keepOnlyFirstLineInSummary: vote.voteFileData.keepOnlyFirstLineInSummary });

if (commitJsonSummary != null) {
if (lastCommitRef !== "HEAD") {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface VoteFileFormat {
checksum?: string;

canShuffleCandidates?: boolean;
keepOnlyFirstLineInSummary?: boolean;
requireSignedBallots?: boolean;
}
function instanceOfVoteFile(object): object is VoteFileFormat {
Expand Down
12 changes: 8 additions & 4 deletions packages/core/src/summary/condorcetSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ interface BallotSummarize {
minCandidates?: VoteCandidate[];
orderedCandidates?: VoteCandidate[][];
}
export function getSummarizedBallot(ballot: Ballot): BallotSummarize {
export function getSummarizedBallot(
ballot: Ballot,
keepOnlyFirstLineInSummary?: boolean
): BallotSummarize {
let maxNote = Number.MIN_SAFE_INTEGER;
let minNote = Number.MAX_SAFE_INTEGER;
for (const [, score] of ballot.preferences) {
Expand All @@ -91,7 +94,8 @@ export function getSummarizedBallot(ballot: Ballot): BallotSummarize {
for (const [candidate, score] of ballot.preferences) {
const candidatesForThisScore = orderedPreferences.get(score);
const markdownCandidate = `**${cleanMarkdown(
candidate.replace(/\.$/, "")
candidate,
keepOnlyFirstLineInSummary
)}**`;
if (candidatesForThisScore == null) {
orderedPreferences.set(score, [markdownCandidate]);
Expand All @@ -106,7 +110,7 @@ export function getSummarizedBallot(ballot: Ballot): BallotSummarize {
};
}
const group = score === minNote ? minCandidates : maxCandidates;
group.push(`**${cleanMarkdown(candidate).replace(/\.$/, "")}**`);
group.push(`**${cleanMarkdown(candidate, keepOnlyFirstLineInSummary)}**`);
}
return { minCandidates, maxCandidates };
}
Expand All @@ -116,7 +120,7 @@ export default class CondorcetElectionSummary extends ElectionSummary {

summarizeBallot(ballot: Ballot) {
return summarizeCondorcetBallotForElectionSummary(
getSummarizedBallot(ballot),
getSummarizedBallot(ballot, this.keepOnlyFirstLineInSummary),
4
);
}
Expand Down
19 changes: 14 additions & 5 deletions packages/core/src/summary/electionSummary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@ import type { Actor, Ballot, VoteCandidate, VoteCommit } from "../vote";
import type { CandidateScores } from "../votingMethods/VotingMethodImplementation";
import cleanMarkdown from "../utils/cleanMarkdown.js";

function displayWinners(winners: VoteCandidate[]) {
function displayWinners(winners: VoteCandidate[], keepOnlyFirstLineInSummary?: boolean) {
if (winners.length === 0) return "None.";
if (winners.length === 1) return cleanMarkdown(winners[0]);
if (winners.length === 1) return cleanMarkdown(winners[0], keepOnlyFirstLineInSummary);
const delimiter = "\n - ";
return delimiter + winners.map(cleanMarkdown).join(delimiter);
return delimiter + winners.map(
keepOnlyFirstLineInSummary ?
(l) => cleanMarkdown(l, keepOnlyFirstLineInSummary) :
(l) => cleanMarkdown(l).split('\n').join('\n ')
).join(delimiter);
}

export interface DiscardedCommit {
Expand All @@ -23,6 +27,7 @@ export interface ElectionSummaryOptions {
ballots: Ballot[];
privateKey: string;
discardedCommits?: DiscardedCommit[];
keepOnlyFirstLineInSummary?: boolean;
}
export default abstract class ElectionSummary {
subject: string;
Expand All @@ -35,6 +40,7 @@ export default abstract class ElectionSummary {
privateKey: string;
participants: Actor[];
discardedCommits: DiscardedCommit[];
keepOnlyFirstLineInSummary: boolean;

abstract scoreText: string;

Expand All @@ -48,6 +54,7 @@ export default abstract class ElectionSummary {
ballots: unsortedBallots,
privateKey,
discardedCommits,
keepOnlyFirstLineInSummary,
}: ElectionSummaryOptions) {
this.subject = subject;
this.startDate = startDate;
Expand All @@ -56,6 +63,7 @@ export default abstract class ElectionSummary {
this.winners = winners;
this.result = result;
this.discardedCommits = discardedCommits;
this.keepOnlyFirstLineInSummary = !!keepOnlyFirstLineInSummary;

this.sortedBallots = unsortedBallots
.slice()
Expand All @@ -79,7 +87,8 @@ ${this.startDate ? `**Start date**: ${this.startDate} \n` : ""}**End date**: ${
## Results

**Winning candidate${this.winners.length === 1 ? "" : "s"}**: ${displayWinners(
this.winners
this.winners,
this.keepOnlyFirstLineInSummary
)}

### Table of results
Expand All @@ -88,7 +97,7 @@ ${this.startDate ? `**Start date**: ${this.startDate} \n` : ""}**End date**: ${
| --------- | ------------------- |
${Array.from(this.result)
.sort(([, scoreA], [, scoreB]) => scoreB - scoreA)
.map((result) => `| ${cleanMarkdown(result[0])} | ${result[1]} |`)
.map((result) => `| ${cleanMarkdown(result[0], this.keepOnlyFirstLineInSummary)} | ${result[1]} |`)
.join("\n")}

## Voting data
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/utils/cleanMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@ function cleanUnsupportedMarkdown(txt: string): string {
return txt.replace(/([_~*\\[\]<>`])/g, "\\$1");
}

export default function cleanMarkdown(txt: string): string {
function reduceToFirstLine(candidate: string) {
const i = candidate.indexOf('\n')
return i === -1 ? candidate : candidate.slice(0, i - Number(candidate[i] === '.' || candidate === ':'));
}
export default function cleanMarkdown(txt: string, keepOnlyFirstLineInSummary?: boolean): string {
if (keepOnlyFirstLineInSummary) txt = reduceToFirstLine(txt);
else if (txt.endsWith('.') || txt.endsWith(':')) txt = txt.slice(0, -1);

// Escape backticks for edge case scenarii (no code span support).
if (txt.includes("``") || txt.includes("\\`")) {
return cleanUnsupportedMarkdown(txt);
Expand Down