stated-protocol-parser 1.0.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/README.md +198 -0
- package/dist/constants.d.ts +46 -0
- package/dist/constants.js +49 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +683 -0
- package/dist/types.d.ts +148 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +27 -0
- package/dist/v3.d.ts +4 -0
- package/dist/v3.js +63 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Stated Protocol Parser
|
|
2
|
+
|
|
3
|
+
A TypeScript library for parsing and formatting statements in the Stated protocol - a decentralized statement verification system.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install stated-protocol-parser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Statement Parsing & Formatting**: Parse and build statements with domain verification
|
|
14
|
+
- **Multiple Statement Types**: Support for various statement types including:
|
|
15
|
+
- Basic statements
|
|
16
|
+
- Quotations
|
|
17
|
+
- Polls and votes
|
|
18
|
+
- Organisation and person verifications
|
|
19
|
+
- Disputes (authenticity and content)
|
|
20
|
+
- Ratings, bounties, observations, and boycotts
|
|
21
|
+
- PDF signing
|
|
22
|
+
- Responses
|
|
23
|
+
- **Type Safety**: Full TypeScript support with comprehensive type definitions
|
|
24
|
+
- **Version Support**: Handles multiple format versions (v3 and v4)
|
|
25
|
+
- **Validation**: Built-in validation for all statement formats
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Basic Statement
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { buildStatement, parseStatement } from 'stated-protocol-parser';
|
|
33
|
+
|
|
34
|
+
// Build a statement
|
|
35
|
+
const statement = buildStatement({
|
|
36
|
+
domain: 'example.com',
|
|
37
|
+
author: 'Example Organization',
|
|
38
|
+
time: new Date(),
|
|
39
|
+
tags: ['announcement', 'update'],
|
|
40
|
+
content: 'This is our official statement.',
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Parse a statement
|
|
44
|
+
const parsed = parseStatement({ statement });
|
|
45
|
+
console.log(parsed.domain); // 'example.com'
|
|
46
|
+
console.log(parsed.author); // 'Example Organization'
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Poll
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { buildPollContent, parsePoll } from 'stated-protocol-parser';
|
|
53
|
+
|
|
54
|
+
const pollContent = buildPollContent({
|
|
55
|
+
poll: 'Should we implement feature X?',
|
|
56
|
+
options: ['Yes', 'No', 'Need more information'],
|
|
57
|
+
deadline: new Date('2024-12-31'),
|
|
58
|
+
scopeDescription: 'All registered users',
|
|
59
|
+
country: undefined,
|
|
60
|
+
city: undefined,
|
|
61
|
+
legalEntity: undefined,
|
|
62
|
+
domainScope: undefined,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const parsed = parsePoll(pollContent);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Organisation Verification
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { buildOrganisationVerificationContent, parseOrganisationVerification } from 'stated-protocol-parser';
|
|
72
|
+
|
|
73
|
+
const verification = buildOrganisationVerificationContent({
|
|
74
|
+
name: 'Example Corp',
|
|
75
|
+
country: 'United States',
|
|
76
|
+
city: 'New York',
|
|
77
|
+
legalForm: 'corporation',
|
|
78
|
+
domain: 'example.com',
|
|
79
|
+
// ... other fields
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Person Verification
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { buildPersonVerificationContent, parsePersonVerification } from 'stated-protocol-parser';
|
|
87
|
+
|
|
88
|
+
const verification = buildPersonVerificationContent({
|
|
89
|
+
name: 'John Doe',
|
|
90
|
+
dateOfBirth: new Date('1990-01-01'),
|
|
91
|
+
cityOfBirth: 'New York',
|
|
92
|
+
countryOfBirth: 'United States',
|
|
93
|
+
ownDomain: 'johndoe.com',
|
|
94
|
+
// ... other fields
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## API Reference
|
|
99
|
+
|
|
100
|
+
### Statement Functions
|
|
101
|
+
|
|
102
|
+
- `buildStatement(params)` - Build a statement string
|
|
103
|
+
- `parseStatement({ statement, allowNoVersion? })` - Parse a statement string
|
|
104
|
+
|
|
105
|
+
### Content Type Functions
|
|
106
|
+
|
|
107
|
+
Each content type has corresponding build and parse functions:
|
|
108
|
+
|
|
109
|
+
- **Quotation**: `buildQuotationContent()`, `parseQuotation()`
|
|
110
|
+
- **Poll**: `buildPollContent()`, `parsePoll()`
|
|
111
|
+
- **Vote**: `buildVoteContent()`, `parseVote()`
|
|
112
|
+
- **Organisation Verification**: `buildOrganisationVerificationContent()`, `parseOrganisationVerification()`
|
|
113
|
+
- **Person Verification**: `buildPersonVerificationContent()`, `parsePersonVerification()`
|
|
114
|
+
- **Dispute Authenticity**: `buildDisputeAuthenticityContent()`, `parseDisputeAuthenticity()`
|
|
115
|
+
- **Dispute Content**: `buildDisputeContentContent()`, `parseDisputeContent()`
|
|
116
|
+
- **Response**: `buildResponseContent()`, `parseResponseContent()`
|
|
117
|
+
- **PDF Signing**: `buildPDFSigningContent()`, `parsePDFSigning()`
|
|
118
|
+
- **Rating**: `buildRating()`, `parseRating()`
|
|
119
|
+
- **Bounty**: `buildBounty()`, `parseBounty()`
|
|
120
|
+
- **Observation**: `buildObservation()`, `parseObservation()`
|
|
121
|
+
- **Boycott**: `buildBoycott()`, `parseBoycott()`
|
|
122
|
+
|
|
123
|
+
### Constants
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import {
|
|
127
|
+
statementTypes,
|
|
128
|
+
legalForms,
|
|
129
|
+
peopleCountBuckets,
|
|
130
|
+
UTCFormat
|
|
131
|
+
} from 'stated-protocol-parser';
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Types
|
|
135
|
+
|
|
136
|
+
All TypeScript types are exported:
|
|
137
|
+
|
|
138
|
+
```typescript
|
|
139
|
+
import type {
|
|
140
|
+
Statement,
|
|
141
|
+
Quotation,
|
|
142
|
+
Poll,
|
|
143
|
+
OrganisationVerification,
|
|
144
|
+
PersonVerification,
|
|
145
|
+
Vote,
|
|
146
|
+
DisputeAuthenticity,
|
|
147
|
+
DisputeContent,
|
|
148
|
+
ResponseContent,
|
|
149
|
+
PDFSigning,
|
|
150
|
+
Rating,
|
|
151
|
+
Bounty,
|
|
152
|
+
Observation,
|
|
153
|
+
Boycott
|
|
154
|
+
} from 'stated-protocol-parser';
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Format Specifications
|
|
158
|
+
|
|
159
|
+
### Statement Format
|
|
160
|
+
|
|
161
|
+
Statements follow a specific format with required fields:
|
|
162
|
+
- Publishing domain
|
|
163
|
+
- Author
|
|
164
|
+
- Time (UTC format)
|
|
165
|
+
- Format version
|
|
166
|
+
- Statement content
|
|
167
|
+
|
|
168
|
+
Optional fields:
|
|
169
|
+
- Authorized signing representative
|
|
170
|
+
- Tags
|
|
171
|
+
- Superseded statement
|
|
172
|
+
|
|
173
|
+
### Validation Rules
|
|
174
|
+
|
|
175
|
+
- Statements must not exceed 3,000 characters
|
|
176
|
+
- Statements cannot contain double line breaks (`\n\n`)
|
|
177
|
+
- Time must be in UTC format
|
|
178
|
+
- Domain, author, and content are required fields
|
|
179
|
+
|
|
180
|
+
## Version Support
|
|
181
|
+
|
|
182
|
+
The library supports multiple format versions:
|
|
183
|
+
- **Version 3**: Legacy format with different poll structure
|
|
184
|
+
- **Version 4**: Current format (default)
|
|
185
|
+
|
|
186
|
+
Use `parsePoll(content, '3')` to parse version 3 polls.
|
|
187
|
+
|
|
188
|
+
## Error Handling
|
|
189
|
+
|
|
190
|
+
All parse functions throw descriptive errors when encountering invalid formats:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
try {
|
|
194
|
+
const parsed = parseStatement({ statement: invalidStatement });
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error('Invalid statement format:', error.message);
|
|
197
|
+
}
|
|
198
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export declare const legalForms: {
|
|
2
|
+
local_government: string;
|
|
3
|
+
state_government: string;
|
|
4
|
+
foreign_affairs_ministry: string;
|
|
5
|
+
corporation: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const statementTypes: {
|
|
8
|
+
statement: string;
|
|
9
|
+
quotation: string;
|
|
10
|
+
organisationVerification: string;
|
|
11
|
+
personVerification: string;
|
|
12
|
+
poll: string;
|
|
13
|
+
vote: string;
|
|
14
|
+
response: string;
|
|
15
|
+
disputeContent: string;
|
|
16
|
+
disputeAuthenticity: string;
|
|
17
|
+
boycott: string;
|
|
18
|
+
observation: string;
|
|
19
|
+
rating: string;
|
|
20
|
+
signPdf: string;
|
|
21
|
+
bounty: string;
|
|
22
|
+
unsupported: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const peopleCountBuckets: {
|
|
25
|
+
"0": string;
|
|
26
|
+
"10": string;
|
|
27
|
+
"100": string;
|
|
28
|
+
"1000": string;
|
|
29
|
+
"10000": string;
|
|
30
|
+
"100000": string;
|
|
31
|
+
"1000000": string;
|
|
32
|
+
"10000000": string;
|
|
33
|
+
};
|
|
34
|
+
export declare const UTCFormat: RegExp;
|
|
35
|
+
export declare const pollKeys: RegExp;
|
|
36
|
+
export declare const organisationVerificationKeys: RegExp;
|
|
37
|
+
export declare const personVerificationKeys: RegExp;
|
|
38
|
+
export declare const voteKeys: RegExp;
|
|
39
|
+
export declare const disputeAuthenticityKeys: RegExp;
|
|
40
|
+
export declare const disputeContentKeys: RegExp;
|
|
41
|
+
export declare const responseKeys: RegExp;
|
|
42
|
+
export declare const PDFSigningKeys: RegExp;
|
|
43
|
+
export declare const ratingKeys: RegExp;
|
|
44
|
+
export declare const BountyKeys: RegExp;
|
|
45
|
+
export declare const ObservationKeys: RegExp;
|
|
46
|
+
export declare const BoycottKeys: RegExp;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BoycottKeys = exports.ObservationKeys = exports.BountyKeys = exports.ratingKeys = exports.PDFSigningKeys = exports.responseKeys = exports.disputeContentKeys = exports.disputeAuthenticityKeys = exports.voteKeys = exports.personVerificationKeys = exports.organisationVerificationKeys = exports.pollKeys = exports.UTCFormat = exports.peopleCountBuckets = exports.statementTypes = exports.legalForms = void 0;
|
|
4
|
+
exports.legalForms = {
|
|
5
|
+
local_government: 'local government',
|
|
6
|
+
state_government: 'state government',
|
|
7
|
+
foreign_affairs_ministry: 'foreign affairs ministry',
|
|
8
|
+
corporation: 'corporation',
|
|
9
|
+
};
|
|
10
|
+
exports.statementTypes = {
|
|
11
|
+
statement: 'statement',
|
|
12
|
+
quotation: 'quotation',
|
|
13
|
+
organisationVerification: 'organisation_verification',
|
|
14
|
+
personVerification: 'person_verification',
|
|
15
|
+
poll: 'poll',
|
|
16
|
+
vote: 'vote',
|
|
17
|
+
response: 'response',
|
|
18
|
+
disputeContent: 'dispute_statement_content',
|
|
19
|
+
disputeAuthenticity: 'dispute_statement_authenticity',
|
|
20
|
+
boycott: 'boycott',
|
|
21
|
+
observation: 'observation',
|
|
22
|
+
rating: 'rating',
|
|
23
|
+
signPdf: "sign_pdf",
|
|
24
|
+
bounty: "bounty",
|
|
25
|
+
unsupported: "unsupported",
|
|
26
|
+
};
|
|
27
|
+
exports.peopleCountBuckets = {
|
|
28
|
+
"0": "0-10",
|
|
29
|
+
"10": "10-100",
|
|
30
|
+
"100": "100-1000",
|
|
31
|
+
"1000": "1000-10,000",
|
|
32
|
+
"10000": "10,000-100,000",
|
|
33
|
+
"100000": "100,000+",
|
|
34
|
+
"1000000": "1,000,000+",
|
|
35
|
+
"10000000": "10,000,000+",
|
|
36
|
+
};
|
|
37
|
+
exports.UTCFormat = /(Mon|Tue|Wed|Thu|Fri|Sat|Sun),\s\d{2}\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s\d{4}\s\d{2}:\d{2}:\d{2}\sGMT/;
|
|
38
|
+
exports.pollKeys = /(Type: |The poll outcome is finalized when the following nodes agree: |Voting deadline: |Poll: |Option 1: |Option 2: |Option 3: |Option 4: |Option 5: |Allow free text votes: |Who can vote: |Description: |Country scope: |City scope: |Legal form scope: |Domain scope: |All entities with the following property: |As observed by: |Link to query defining who can vote: )/g;
|
|
39
|
+
exports.organisationVerificationKeys = /(Type: |Description: |Name: |English name: |Country: |Legal entity: |Legal form: |Department using the domain: |Owner of the domain: |Foreign domain used for publishing statements: |Province or state: |Business register number: |City: |Longitude: |Latitude: |Population: |Logo: |Employee count: |Reliability policy: |Confidence: )/g;
|
|
40
|
+
exports.personVerificationKeys = /(Type: |Description: |Name: |Date of birth: |City of birth: |Country of birth: |Job title: |Employer: |Owner of the domain: |Foreign domain used for publishing statements: |Picture: |Verification method: |Confidence: |Reliability policy: )/g;
|
|
41
|
+
exports.voteKeys = /(Type: |Poll id: |Poll: |Option: )/g;
|
|
42
|
+
exports.disputeAuthenticityKeys = /(Type: |Description: |Hash of referenced statement: |Confidence: |Reliability policy: )/g;
|
|
43
|
+
exports.disputeContentKeys = /(Type: |Description: |Hash of referenced statement: |Confidence: |Reliability policy: )/g;
|
|
44
|
+
exports.responseKeys = /(Type: |Hash of referenced statement: |Response: )/;
|
|
45
|
+
exports.PDFSigningKeys = /(Type: |Description: |PDF file hash: )/;
|
|
46
|
+
exports.ratingKeys = /(Type: |Subject type: |Subject name: |URL that identifies the subject: |Document file hash: |Rated quality: |Our rating: |Comment: )/;
|
|
47
|
+
exports.BountyKeys = /(Type: |In order to: |We will reward any entity that: |The reward is: |In case of dispute, bounty claims are judged by: |The judge will be paid per investigated case with a maxium of: )/;
|
|
48
|
+
exports.ObservationKeys = /(Type: |Approach: |Confidence: |Reliability policy: |Subject: |Subject identity reference: |Observation reference: |Observed property: |Observed value: )/;
|
|
49
|
+
exports.BoycottKeys = /(Type: |Description: |Subject: |Subject identity reference: )/;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Statement, Quotation, Poll, OrganisationVerification, PersonVerification, Vote, DisputeAuthenticity, DisputeContent, ResponseContent, PDFSigning, Rating, Bounty, Observation, Boycott } from './types';
|
|
2
|
+
export * from './types';
|
|
3
|
+
export * from './constants';
|
|
4
|
+
export * from './utils';
|
|
5
|
+
export * from './v3';
|
|
6
|
+
export declare const buildStatement: ({ domain, author, time, tags, content, representative, supersededStatement }: Statement) => string;
|
|
7
|
+
export declare const parseStatement: ({ statement: s, allowNoVersion }: {
|
|
8
|
+
statement: string;
|
|
9
|
+
allowNoVersion?: boolean;
|
|
10
|
+
}) => Statement & {
|
|
11
|
+
type?: string;
|
|
12
|
+
formatVersion: string;
|
|
13
|
+
};
|
|
14
|
+
export declare const buildQuotationContent: ({ originalAuthor, authorVerification, originalTime, source, quotation, paraphrasedStatement, picture, confidence }: Quotation) => string;
|
|
15
|
+
export declare const parseQuotation: (s: string) => Quotation & {
|
|
16
|
+
type: string | undefined;
|
|
17
|
+
};
|
|
18
|
+
export declare const buildPollContent: ({ country, city, legalEntity, domainScope, judges, deadline, poll, scopeDescription, scopeQueryLink, options, allowArbitraryVote, requiredProperty: propertyScope, requiredPropertyObserver: propertyScopeObserver }: Poll) => string;
|
|
19
|
+
export declare const parsePoll: (s: string, version?: string) => Poll;
|
|
20
|
+
export declare const buildOrganisationVerificationContent: ({ name, englishName, country, city, province, legalForm, department, domain, foreignDomain, serialNumber, confidence, reliabilityPolicy, employeeCount, pictureHash, latitude, longitude, population }: OrganisationVerification) => string;
|
|
21
|
+
export declare const parseOrganisationVerification: (s: string) => OrganisationVerification;
|
|
22
|
+
export declare const buildPersonVerificationContent: ({ name, countryOfBirth, cityOfBirth, ownDomain, foreignDomain, dateOfBirth, jobTitle, employer, verificationMethod, confidence, picture, reliabilityPolicy }: PersonVerification) => string;
|
|
23
|
+
export declare const parsePersonVerification: (s: string) => PersonVerification;
|
|
24
|
+
export declare const buildVoteContent: ({ pollHash, poll, vote }: Vote) => string;
|
|
25
|
+
export declare const parseVote: (s: string) => Vote;
|
|
26
|
+
export declare const buildDisputeAuthenticityContent: ({ hash, confidence, reliabilityPolicy }: DisputeAuthenticity) => string;
|
|
27
|
+
export declare const parseDisputeAuthenticity: (s: string) => DisputeAuthenticity;
|
|
28
|
+
export declare const buildDisputeContentContent: ({ hash, confidence, reliabilityPolicy }: DisputeContent) => string;
|
|
29
|
+
export declare const parseDisputeContent: (s: string) => DisputeContent;
|
|
30
|
+
export declare const buildResponseContent: ({ hash, response }: ResponseContent) => string;
|
|
31
|
+
export declare const parseResponseContent: (s: string) => ResponseContent;
|
|
32
|
+
export declare const buildPDFSigningContent: ({ hash }: PDFSigning) => string;
|
|
33
|
+
export declare const parsePDFSigning: (s: string) => PDFSigning;
|
|
34
|
+
export declare const buildRating: ({ subjectName, subjectType, subjectReference, documentFileHash, rating, quality, comment }: Rating) => string;
|
|
35
|
+
export declare const parseRating: (s: string) => Rating;
|
|
36
|
+
export declare const buildBounty: ({ motivation, bounty, reward, judge, judgePay }: Bounty) => string;
|
|
37
|
+
export declare const parseBounty: (s: string) => Bounty;
|
|
38
|
+
export declare const buildObservation: ({ approach, confidence, reliabilityPolicy, subject, subjectReference, observationReference, property, value }: Observation) => string;
|
|
39
|
+
export declare const parseObservation: (s: string) => Observation;
|
|
40
|
+
export declare const buildBoycott: ({ description, subject, subjectReference }: Boycott) => string;
|
|
41
|
+
export declare const parseBoycott: (s: string) => Boycott;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,683 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.parseBoycott = exports.buildBoycott = exports.parseObservation = exports.buildObservation = exports.parseBounty = exports.buildBounty = exports.parseRating = exports.buildRating = exports.parsePDFSigning = exports.buildPDFSigningContent = exports.parseResponseContent = exports.buildResponseContent = exports.parseDisputeContent = exports.buildDisputeContentContent = exports.parseDisputeAuthenticity = exports.buildDisputeAuthenticityContent = exports.parseVote = exports.buildVoteContent = exports.parsePersonVerification = exports.buildPersonVerificationContent = exports.parseOrganisationVerification = exports.buildOrganisationVerificationContent = exports.parsePoll = exports.buildPollContent = exports.parseQuotation = exports.buildQuotationContent = exports.parseStatement = exports.buildStatement = void 0;
|
|
18
|
+
/* eslint-disable no-useless-concat */
|
|
19
|
+
const constants_1 = require("./constants");
|
|
20
|
+
const v3_1 = require("./v3");
|
|
21
|
+
const utils_1 = require("./utils");
|
|
22
|
+
const fallBackVersion = 3;
|
|
23
|
+
const version = 4;
|
|
24
|
+
__exportStar(require("./types"), exports);
|
|
25
|
+
__exportStar(require("./constants"), exports);
|
|
26
|
+
__exportStar(require("./utils"), exports);
|
|
27
|
+
__exportStar(require("./v3"), exports);
|
|
28
|
+
const buildStatement = ({ domain, author, time, tags, content, representative, supersededStatement }) => {
|
|
29
|
+
if (content.match(/\nPublishing domain: /))
|
|
30
|
+
throw (new Error("Statement must not contain 'Publishing domain: ', as this marks the beginning of a new statement."));
|
|
31
|
+
if (content.match(/\n\n/))
|
|
32
|
+
throw (new Error("Statement must not contain two line breaks in a row, as this is used for separating statements."));
|
|
33
|
+
if (typeof time !== 'object' || !time.toUTCString)
|
|
34
|
+
throw (new Error("Time must be a Date object."));
|
|
35
|
+
if (!domain)
|
|
36
|
+
throw (new Error("Publishing domain missing."));
|
|
37
|
+
const statement = "Publishing domain: " + domain + "\n" +
|
|
38
|
+
"Author: " + (author || "") + "\n" +
|
|
39
|
+
(representative && representative?.length > 0 ? "Authorized signing representative: " + (representative || "") + "\n" : '') +
|
|
40
|
+
"Time: " + time.toUTCString() + "\n" +
|
|
41
|
+
(tags && tags.length > 0 ? "Tags: " + tags.join(', ') + "\n" : '') +
|
|
42
|
+
(supersededStatement && supersededStatement?.length > 0 ? "Superseded statement: " + (supersededStatement || "") + "\n" : '') +
|
|
43
|
+
"Format version: " + version + "\n" +
|
|
44
|
+
"Statement content: " + content + (content.match(/\n$/) ? '' : "\n");
|
|
45
|
+
if (statement.length > 3000)
|
|
46
|
+
throw (new Error("Statement must not be longer than 3,000 characters."));
|
|
47
|
+
return statement;
|
|
48
|
+
};
|
|
49
|
+
exports.buildStatement = buildStatement;
|
|
50
|
+
const parseStatement = ({ statement: s, allowNoVersion = false }) => {
|
|
51
|
+
if (s.length > 3000)
|
|
52
|
+
throw (new Error("Statement must not be longer than 3,000 characters."));
|
|
53
|
+
if (s.match(/\n\n/))
|
|
54
|
+
throw new Error("Statements cannot contain two line breaks in a row, as this is used for separating statements.");
|
|
55
|
+
const statementRegex = new RegExp(''
|
|
56
|
+
+ /^Publishing domain: (?<domain>[^\n]+?)\n/.source
|
|
57
|
+
+ /Author: (?<author>[^\n]+?)\n/.source
|
|
58
|
+
+ /(?:Authorized signing representative: (?<representative>[^\n]*?)\n)?/.source
|
|
59
|
+
+ /Time: (?<time>[^\n]+?)\n/.source
|
|
60
|
+
+ /(?:Tags: (?<tags>[^\n]*?)\n)?/.source
|
|
61
|
+
+ /(?:Superseded statement: (?<supersededStatement>[^\n]*?)\n)?/.source
|
|
62
|
+
+ /(?:Format version: (?<formatVersion>[^\n]*?)\n)?/.source
|
|
63
|
+
+ /Statement content: (?:(?<typedContent>\n\tType: (?<type>[^\n]+?)\n[\s\S]+?\n$)|(?<content>[\s\S]+?\n$))/.source);
|
|
64
|
+
const match = s.match(statementRegex);
|
|
65
|
+
if (!match)
|
|
66
|
+
throw new Error("Invalid statement format:" + s);
|
|
67
|
+
const m = {
|
|
68
|
+
domain: match[1], author: match[2], representative: match[3], timeStr: match[4], tagsStr: match[5],
|
|
69
|
+
supersededStatement: match[6], formatVersion: match[7], content: match[8] || match[10],
|
|
70
|
+
type: match[9] ? match[9].toLowerCase().replace(' ', '_') : undefined
|
|
71
|
+
};
|
|
72
|
+
if (!(m['timeStr'].match(constants_1.UTCFormat)))
|
|
73
|
+
throw new Error("Invalid statement format: time must be in UTC");
|
|
74
|
+
if (!m['domain'])
|
|
75
|
+
throw new Error("Invalid statement format: domain is required");
|
|
76
|
+
if (!m['author'])
|
|
77
|
+
throw new Error("Invalid statement format: author is required");
|
|
78
|
+
if (!m['content'])
|
|
79
|
+
throw new Error("Invalid statement format: statement content is required");
|
|
80
|
+
if (!allowNoVersion && !m['formatVersion'])
|
|
81
|
+
throw new Error("Invalid statement format: format version is required");
|
|
82
|
+
const tags = m['tagsStr']?.split(', ');
|
|
83
|
+
const time = new Date(m['timeStr']);
|
|
84
|
+
return {
|
|
85
|
+
domain: m['domain'],
|
|
86
|
+
author: m['author'],
|
|
87
|
+
representative: m['representative'],
|
|
88
|
+
time,
|
|
89
|
+
tags: (tags && tags.length > 0) ? tags : undefined,
|
|
90
|
+
supersededStatement: m['supersededStatement'],
|
|
91
|
+
formatVersion: m['formatVersion'] || ('' + fallBackVersion),
|
|
92
|
+
content: m['content'],
|
|
93
|
+
type: m['type']?.toLowerCase().replace(' ', '_'),
|
|
94
|
+
};
|
|
95
|
+
};
|
|
96
|
+
exports.parseStatement = parseStatement;
|
|
97
|
+
const buildQuotationContent = ({ originalAuthor, authorVerification, originalTime, source, quotation, paraphrasedStatement, picture, confidence }) => {
|
|
98
|
+
if (quotation && quotation.match(/\n/))
|
|
99
|
+
throw (new Error("Quotation must not contain line breaks."));
|
|
100
|
+
if (!paraphrasedStatement && !quotation)
|
|
101
|
+
throw (new Error("Quotation must contain either a quotation or a paraphrased statement."));
|
|
102
|
+
const content = "\n" +
|
|
103
|
+
"\t" + "Type: Quotation" + "\n" +
|
|
104
|
+
"\t" + "Original author: " + originalAuthor + "\n" +
|
|
105
|
+
"\t" + "Author verification: " + authorVerification + "\n" +
|
|
106
|
+
(originalTime && originalTime?.length > 0 ? "\t" + "Original publication time: " + originalTime + "\n" : "") +
|
|
107
|
+
(source && source?.length > 0 ? "\t" + "Source: " + (source || "") + "\n" : '') +
|
|
108
|
+
(picture && picture.length > 0 ? "\t" + "Picture proof: " + (picture || "") + "\n" : '') +
|
|
109
|
+
(confidence && confidence?.length > 0 ? "\t" + "Confidence: " + (confidence || "") + "\n" : '') +
|
|
110
|
+
(quotation && quotation?.length > 0 ? "\t" + "Quotation: " + (quotation || "") + "\n" : '') +
|
|
111
|
+
(paraphrasedStatement && paraphrasedStatement?.length > 0 ? "\t" + "Paraphrased statement: " +
|
|
112
|
+
(paraphrasedStatement || "").replace(/\n\t([^\t])/, '\n\t\t($1)') + "\n" : '') +
|
|
113
|
+
"";
|
|
114
|
+
return content;
|
|
115
|
+
};
|
|
116
|
+
exports.buildQuotationContent = buildQuotationContent;
|
|
117
|
+
const parseQuotation = (s) => {
|
|
118
|
+
const voteRegex = new RegExp(''
|
|
119
|
+
+ /^\n\tType: Quotation\n/.source
|
|
120
|
+
+ /\tOriginal author: (?<originalAuthor>[^\n]+?)\n/.source
|
|
121
|
+
+ /\tAuthor verification: (?<authorVerification>[^\n]+?)\n/.source
|
|
122
|
+
+ /(?:\tOriginal publication time: (?<originalTime>[^\n]+?)\n)?/.source
|
|
123
|
+
+ /(?:\tSource: (?<source>[^\n]+?)\n)?/.source
|
|
124
|
+
+ /(?:\tPicture proof: (?<picture>[^\n]+?)\n)?/.source
|
|
125
|
+
+ /(?:\tConfidence: (?<confidence>[^\n]+?)\n)?/.source
|
|
126
|
+
+ /(?:\tQuotation: (?<quotation>[^\n]+?)\n)?/.source
|
|
127
|
+
+ /(?:\tParaphrased statement: (?:(?<paraphrasedTypedStatement>\n\t\tType: (?<type>[^\n]+?)\n[\s\S]+?)|(?<paraphrasedStatement>[\s\S]+?)))/.source
|
|
128
|
+
+ /$/.source);
|
|
129
|
+
let match = s.match(voteRegex);
|
|
130
|
+
if (!match)
|
|
131
|
+
throw new Error("Invalid quotation format: " + s);
|
|
132
|
+
let m = {};
|
|
133
|
+
m = {
|
|
134
|
+
originalAuthor: match[1], authorVerification: match[2], originalTime: match[3], source: match[4],
|
|
135
|
+
picture: match[5], confidence: match[6], quotation: match[7], paraphrasedStatement: match[8] || match[10],
|
|
136
|
+
type: match[9] ? match[9].toLowerCase().replace(' ', '_') : undefined
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
originalAuthor: m['originalAuthor'],
|
|
140
|
+
authorVerification: m['authorVerification'],
|
|
141
|
+
originalTime: m['originalTime'],
|
|
142
|
+
source: m['source'],
|
|
143
|
+
picture: m['picture'],
|
|
144
|
+
confidence: m['confidence'],
|
|
145
|
+
quotation: m['quotation'],
|
|
146
|
+
paraphrasedStatement: (m['paraphrasedStatement']?.replace(/\n\t\t/g, "\n\t")),
|
|
147
|
+
type: m['type']?.toLowerCase().replace(' ', '_'),
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
exports.parseQuotation = parseQuotation;
|
|
151
|
+
const buildPollContent = ({ country, city, legalEntity, domainScope, judges, deadline, poll, scopeDescription, scopeQueryLink, options, allowArbitraryVote, requiredProperty: propertyScope, requiredPropertyObserver: propertyScopeObserver }) => {
|
|
152
|
+
if (!poll)
|
|
153
|
+
throw (new Error("Poll must contain a poll question."));
|
|
154
|
+
const scopeContent = (scopeDescription ? "\t\t" + "Description: " + scopeDescription + "\n" : "") +
|
|
155
|
+
(country ? "\t\t" + "Country scope: " + country + "\n" : "") +
|
|
156
|
+
(city ? "\t\t" + "City scope: " + city + "\n" : "") +
|
|
157
|
+
(legalEntity ? "\t\t" + "Legal form scope: " + legalEntity + "\n" : "") +
|
|
158
|
+
(domainScope && domainScope?.length > 0 ? "\t\t" + "Domain scope: " + domainScope.join(', ') + "\n" : "") +
|
|
159
|
+
(propertyScope ? "\t\t" + "All entities with the following property: " + propertyScope + "\n" : "") +
|
|
160
|
+
(propertyScopeObserver ? "\t\t" + "As observed by: " + propertyScopeObserver + "\n" : "") +
|
|
161
|
+
(scopeQueryLink ? "\t\t" + "Link to query defining who can vote: " + scopeQueryLink + "\n" : "");
|
|
162
|
+
if (scopeContent.length > 0 && !scopeDescription)
|
|
163
|
+
throw (new Error("Poll must contain a description of who can vote."));
|
|
164
|
+
const content = "\n" +
|
|
165
|
+
"\t" + "Type: Poll" + "\n" +
|
|
166
|
+
(judges ? "\t" + "The poll outcome is finalized when the following nodes agree: " + judges + "\n" : "") +
|
|
167
|
+
(deadline ? "\t" + "Voting deadline: " + deadline.toUTCString() + "\n" : "") +
|
|
168
|
+
"\t" + "Poll: " + poll + "\n" +
|
|
169
|
+
(options.length > 0 && options[0] ? "\t" + "Option 1: " + options[0] + "\n" : "") +
|
|
170
|
+
(options.length > 1 && options[1] ? "\t" + "Option 2: " + options[1] + "\n" : "") +
|
|
171
|
+
(options.length > 2 && options[2] ? "\t" + "Option 3: " + options[2] + "\n" : "") +
|
|
172
|
+
(options.length > 3 && options[3] ? "\t" + "Option 4: " + options[3] + "\n" : "") +
|
|
173
|
+
(options.length > 4 && options[4] ? "\t" + "Option 5: " + options[4] + "\n" : "") +
|
|
174
|
+
((allowArbitraryVote === true || allowArbitraryVote === false) ? ("\t" + "Allow free text votes: " + (allowArbitraryVote ? 'Yes' : 'No') + "\n") : "") +
|
|
175
|
+
(scopeContent ? "\t" + "Who can vote: \n" + scopeContent : "") +
|
|
176
|
+
"";
|
|
177
|
+
return content;
|
|
178
|
+
};
|
|
179
|
+
exports.buildPollContent = buildPollContent;
|
|
180
|
+
const parsePoll = (s, version) => {
|
|
181
|
+
if (version && version === '3')
|
|
182
|
+
return (0, v3_1.parsePollV3)(s);
|
|
183
|
+
if (version && version !== '4')
|
|
184
|
+
throw new Error("Invalid version " + version);
|
|
185
|
+
const pollRegex = new RegExp(''
|
|
186
|
+
+ /^\n\tType: Poll\n/.source
|
|
187
|
+
+ /(?:\tThe poll outcome is finalized when the following nodes agree: (?<judges>[^\n]+?)\n)?/.source
|
|
188
|
+
+ /(?:\tVoting deadline: (?<deadline>[^\n]+?)\n)?/.source
|
|
189
|
+
+ /\tPoll: (?<poll>[^\n]+?)\n/.source
|
|
190
|
+
+ /(?:\tOption 1: (?<option1>[^\n]+?)\n)?/.source
|
|
191
|
+
+ /(?:\tOption 2: (?<option2>[^\n]+?)\n)?/.source
|
|
192
|
+
+ /(?:\tOption 3: (?<option3>[^\n]+?)\n)?/.source
|
|
193
|
+
+ /(?:\tOption 4: (?<option4>[^\n]+?)\n)?/.source
|
|
194
|
+
+ /(?:\tOption 5: (?<option5>[^\n]+?)\n)?/.source
|
|
195
|
+
+ /(?:\tAllow free text votes: (?<allowArbitraryVote>Yes|No)\n)?/.source
|
|
196
|
+
+ /(?:\tWho can vote: (?<whoCanVote>\n[\s\S]+?\n))?/.source
|
|
197
|
+
+ /$/.source);
|
|
198
|
+
let m = s.match(pollRegex);
|
|
199
|
+
if (!m)
|
|
200
|
+
throw new Error("Invalid poll format: " + s);
|
|
201
|
+
m = {
|
|
202
|
+
judges: m[1], deadline: m[2], poll: m[3],
|
|
203
|
+
option1: m[4], option2: m[5], option3: m[6], option4: m[7], option5: m[8],
|
|
204
|
+
allowArbitraryVote: m[9],
|
|
205
|
+
whoCanVote: m[10]
|
|
206
|
+
};
|
|
207
|
+
const whoCanVoteParsed = {};
|
|
208
|
+
if (m.whoCanVote) {
|
|
209
|
+
const whoCanVoteRegex = new RegExp(''
|
|
210
|
+
+ /^\n\t\tDescription: (?<scopeDescription>[^\n]+?)\n/.source
|
|
211
|
+
+ /(?:\t\tCountry scope: (?<countryScope>[^\n]+?)\n)?/.source
|
|
212
|
+
+ /(?:\t\tCity scope: (?<cityScope>[^\n]+?)\n)?/.source
|
|
213
|
+
+ /(?:\t\tLegal form scope: (?<legalEntity>[^\n]+?)\n)?/.source
|
|
214
|
+
+ /(?:\t\tDomain scope: (?<domainScope>[^\n]+?)\n)?/.source
|
|
215
|
+
+ /(?:\t\tAll entities with the following property: (?<propertyScope>[^\n]+?)\n)?/.source
|
|
216
|
+
+ /(?:\t\tAs observed by: (?<propertyScopeObserver>[^\n]+?)\n)?/.source
|
|
217
|
+
+ /(?:\t\tLink to query defining who can vote: (?<scopeQueryLink>[^\n]+?)\n)?/.source
|
|
218
|
+
+ /$/.source);
|
|
219
|
+
let m2 = m.whoCanVote.match(whoCanVoteRegex);
|
|
220
|
+
if (!m2)
|
|
221
|
+
throw new Error("Invalid who can vote section: " + m.whoCanVote);
|
|
222
|
+
whoCanVoteParsed['scopeDescription'] = m2[1];
|
|
223
|
+
whoCanVoteParsed['country'] = m2[2];
|
|
224
|
+
whoCanVoteParsed['city'] = m2[3];
|
|
225
|
+
whoCanVoteParsed['legalEntity'] = m2[4];
|
|
226
|
+
whoCanVoteParsed['domainScopeStr'] = m2[5];
|
|
227
|
+
whoCanVoteParsed['requiredProperty'] = m2[6];
|
|
228
|
+
whoCanVoteParsed['requiredPropertyObserver'] = m2[7];
|
|
229
|
+
whoCanVoteParsed['scopeQueryLink'] = m2[8];
|
|
230
|
+
}
|
|
231
|
+
const options = [m.option1, m.option2, m.option3, m.option4, m.option5].filter(o => o);
|
|
232
|
+
const domainScope = whoCanVoteParsed.domainScopeStr?.split(', ');
|
|
233
|
+
const allowArbitraryVote = (m['allowArbitraryVote'] === 'Yes' ? true :
|
|
234
|
+
(m['allowArbitraryVote'] === 'No' ? false : undefined));
|
|
235
|
+
const deadlineStr = m.deadline;
|
|
236
|
+
if (deadlineStr && !deadlineStr.match(constants_1.UTCFormat))
|
|
237
|
+
throw new Error("Invalid poll, deadline must be in UTC: " + deadlineStr);
|
|
238
|
+
return {
|
|
239
|
+
judges: m['judges'],
|
|
240
|
+
deadline: deadlineStr ? new Date(deadlineStr) : undefined,
|
|
241
|
+
poll: m['poll'],
|
|
242
|
+
options,
|
|
243
|
+
allowArbitraryVote,
|
|
244
|
+
country: whoCanVoteParsed['country'],
|
|
245
|
+
scopeDescription: whoCanVoteParsed['scopeDescription'],
|
|
246
|
+
requiredProperty: whoCanVoteParsed['requiredProperty'],
|
|
247
|
+
requiredPropertyObserver: whoCanVoteParsed['requiredPropertyObserver'],
|
|
248
|
+
scopeQueryLink: whoCanVoteParsed['scopeQueryLink'],
|
|
249
|
+
city: whoCanVoteParsed['city'],
|
|
250
|
+
legalEntity: whoCanVoteParsed['legalEntity'],
|
|
251
|
+
domainScope: (domainScope && domainScope.length > 0) ? domainScope : undefined,
|
|
252
|
+
};
|
|
253
|
+
};
|
|
254
|
+
exports.parsePoll = parsePoll;
|
|
255
|
+
const buildOrganisationVerificationContent = ({ name, englishName, country, city, province, legalForm, department, domain, foreignDomain, serialNumber, confidence, reliabilityPolicy, employeeCount, pictureHash, latitude, longitude, population }) => {
|
|
256
|
+
if (!name || !country || !legalForm || (!domain && !foreignDomain))
|
|
257
|
+
throw new Error("Missing required fields");
|
|
258
|
+
if (!Object.values(constants_1.legalForms).includes(legalForm))
|
|
259
|
+
throw new Error("Invalid legal form " + legalForm);
|
|
260
|
+
if (employeeCount && !Object.values(constants_1.peopleCountBuckets).includes(employeeCount))
|
|
261
|
+
throw new Error("Invalid employee count " + employeeCount);
|
|
262
|
+
if (population && !Object.values(constants_1.peopleCountBuckets).includes(population))
|
|
263
|
+
throw new Error("Invalid population " + population);
|
|
264
|
+
if (confidence && !('' + confidence)?.match(/^[0-9.]+$/))
|
|
265
|
+
throw new Error("Invalid confidence " + confidence);
|
|
266
|
+
return "\n" +
|
|
267
|
+
"\t" + "Type: Organisation verification" + "\n" +
|
|
268
|
+
"\t" + "Description: We verified the following information about an organisation." + "\n" +
|
|
269
|
+
"\t" + "Name: " + name + "\n" +
|
|
270
|
+
(englishName ? "\t" + "English name: " + englishName + "\n" : "") +
|
|
271
|
+
"\t" + "Country: " + country + "\n" +
|
|
272
|
+
"\t" + "Legal form: " + legalForm + "\n" +
|
|
273
|
+
(domain ? "\t" + "Owner of the domain: " + domain + "\n" : "") +
|
|
274
|
+
(foreignDomain ? "\t" + "Foreign domain used for publishing statements: " + foreignDomain + "\n" : "") +
|
|
275
|
+
(department ? "\t" + "Department using the domain: " + department + "\n" : "") +
|
|
276
|
+
(province ? "\t" + "Province or state: " + province + "\n" : "") +
|
|
277
|
+
(serialNumber ? "\t" + "Business register number: " + serialNumber + "\n" : "") +
|
|
278
|
+
(city ? "\t" + "City: " + city + "\n" : "") +
|
|
279
|
+
(latitude ? "\t" + "Latitude: " + latitude + "\n" : "") +
|
|
280
|
+
(longitude ? "\t" + "Longitude: " + longitude + "\n" : "") +
|
|
281
|
+
(population ? "\t" + "Population: " + population + "\n" : "") +
|
|
282
|
+
(pictureHash ? "\t" + "Logo: " + pictureHash + "\n" : "") +
|
|
283
|
+
(employeeCount ? "\t" + "Employee count: " + employeeCount + "\n" : "") +
|
|
284
|
+
(reliabilityPolicy ? "\t" + "Reliability policy: " + reliabilityPolicy + "\n" : "") +
|
|
285
|
+
(confidence ? "\t" + "Confidence: " + confidence + "\n" : "") +
|
|
286
|
+
"";
|
|
287
|
+
};
|
|
288
|
+
exports.buildOrganisationVerificationContent = buildOrganisationVerificationContent;
|
|
289
|
+
const parseOrganisationVerification = (s) => {
|
|
290
|
+
const organisationVerificationRegex = new RegExp(''
|
|
291
|
+
+ /^\n\tType: Organisation verification\n/.source
|
|
292
|
+
+ /\tDescription: We verified the following information about an organisation.\n/.source
|
|
293
|
+
+ /\tName: (?<name>[^\n]+?)\n/.source
|
|
294
|
+
+ /(?:\tEnglish name: (?<englishName>[^\n]+?)\n)?/.source
|
|
295
|
+
+ /\tCountry: (?<country>[^\n]+?)\n/.source
|
|
296
|
+
+ /\tLegal (?:form|entity): (?<legalForm>[^\n]+?)\n/.source
|
|
297
|
+
+ /(?:\tOwner of the domain: (?<domain>[^\n]+?)\n)?/.source
|
|
298
|
+
+ /(?:\tForeign domain used for publishing statements: (?<foreignDomain>[^\n]+?)\n)?/.source
|
|
299
|
+
+ /(?:\tDepartment using the domain: (?<department>[^\n]+?)\n)?/.source
|
|
300
|
+
+ /(?:\tProvince or state: (?<province>[^\n]+?)\n)?/.source
|
|
301
|
+
+ /(?:\tBusiness register number: (?<serialNumber>[^\n]+?)\n)?/.source
|
|
302
|
+
+ /(?:\tCity: (?<city>[^\n]+?)\n)?/.source
|
|
303
|
+
+ /(?:\tLatitude: (?<latitude>[^\n]+?)\n)?/.source
|
|
304
|
+
+ /(?:\tLongitude: (?<longitude>[^\n]+?)\n)?/.source
|
|
305
|
+
+ /(?:\tPopulation: (?<population>[^\n]+?)\n)?/.source
|
|
306
|
+
+ /(?:\tLogo: (?<pictureHash>[^\n]+?)\n)?/.source
|
|
307
|
+
+ /(?:\tEmployee count: (?<employeeCount>[01,+-]+?)\n)?/.source
|
|
308
|
+
+ /(?:\tReliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source
|
|
309
|
+
+ /(?:\tConfidence: (?<confidence>[0-9.]+?)\n)?/.source
|
|
310
|
+
+ /$/.source);
|
|
311
|
+
const m = s.match(organisationVerificationRegex);
|
|
312
|
+
if (!m)
|
|
313
|
+
throw new Error("Invalid organisation verification format: " + s);
|
|
314
|
+
return {
|
|
315
|
+
name: m[1],
|
|
316
|
+
englishName: m[2],
|
|
317
|
+
country: m[3],
|
|
318
|
+
legalForm: m[4],
|
|
319
|
+
domain: m[5],
|
|
320
|
+
foreignDomain: m[6],
|
|
321
|
+
department: m[7],
|
|
322
|
+
province: m[8],
|
|
323
|
+
serialNumber: m[9],
|
|
324
|
+
city: m[10],
|
|
325
|
+
latitude: m[11] ? parseFloat(m[11]) : undefined,
|
|
326
|
+
longitude: m[12] ? parseFloat(m[12]) : undefined,
|
|
327
|
+
population: m[13],
|
|
328
|
+
pictureHash: m[14],
|
|
329
|
+
employeeCount: m[15],
|
|
330
|
+
reliabilityPolicy: m[16],
|
|
331
|
+
confidence: m[17] ? parseFloat(m[17]) : undefined,
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
exports.parseOrganisationVerification = parseOrganisationVerification;
|
|
335
|
+
const buildPersonVerificationContent = ({ name, countryOfBirth, cityOfBirth, ownDomain, foreignDomain, dateOfBirth, jobTitle, employer, verificationMethod, confidence, picture, reliabilityPolicy }) => {
|
|
336
|
+
if (!name || !countryOfBirth || !cityOfBirth || !dateOfBirth || (!ownDomain && !foreignDomain)) {
|
|
337
|
+
console.log("Missing required fields: ", { name, countryOfBirth, cityOfBirth, dateOfBirth, ownDomain, foreignDomain });
|
|
338
|
+
return "";
|
|
339
|
+
}
|
|
340
|
+
const [day, month, year] = dateOfBirth.toUTCString().split(' ').filter((i, j) => [1, 2, 3].includes(j));
|
|
341
|
+
let content = "\n" +
|
|
342
|
+
"\t" + "Type: Person verification" + "\n" +
|
|
343
|
+
"\t" + "Description: We verified the following information about a person." + "\n" +
|
|
344
|
+
"\t" + "Name: " + name + "\n" +
|
|
345
|
+
"\t" + "Date of birth: " + [day.replace(/$0/, ''), month, year].join(' ') + "\n" +
|
|
346
|
+
"\t" + "City of birth: " + cityOfBirth + "\n" +
|
|
347
|
+
"\t" + "Country of birth: " + countryOfBirth + "\n" +
|
|
348
|
+
(jobTitle ? "\t" + "Job title: " + jobTitle + "\n" : "") +
|
|
349
|
+
(employer ? "\t" + "Employer: " + employer + "\n" : "") +
|
|
350
|
+
(ownDomain ? "\t" + "Owner of the domain: " + ownDomain + "\n" : "") +
|
|
351
|
+
(foreignDomain ? "\t" + "Foreign domain used for publishing statements: " + foreignDomain + "\n" : "") +
|
|
352
|
+
(picture ? "\t" + "Picture: " + picture + "\n" : "") +
|
|
353
|
+
(verificationMethod ? "\t" + "Verification method: " + verificationMethod + "\n" : "") +
|
|
354
|
+
(confidence ? "\t" + "Confidence: " + confidence + "\n" : "") +
|
|
355
|
+
(reliabilityPolicy ? "\t" + "Reliability policy: " + reliabilityPolicy + "\n" : "") +
|
|
356
|
+
"";
|
|
357
|
+
return content;
|
|
358
|
+
};
|
|
359
|
+
exports.buildPersonVerificationContent = buildPersonVerificationContent;
|
|
360
|
+
const parsePersonVerification = (s) => {
|
|
361
|
+
const domainVerificationRegex = new RegExp(''
|
|
362
|
+
+ /^\n\tType: Person verification\n/.source
|
|
363
|
+
+ /\tDescription: We verified the following information about a person.\n/.source
|
|
364
|
+
+ /\tName: (?<name>[^\n]+?)\n/.source
|
|
365
|
+
+ /\tDate of birth: (?<dateOfBirth>[^\n]+?)\n/.source
|
|
366
|
+
+ /\tCity of birth: (?<cityOfBirth>[^\n]+?)\n/.source
|
|
367
|
+
+ /\tCountry of birth: (?<countryOfBirth>[^\n]+?)\n/.source
|
|
368
|
+
+ /(?:\tJob title: (?<jobTitle>[^\n]+?)\n)?/.source
|
|
369
|
+
+ /(?:\tEmployer: (?<employer>[^\n]+?)\n)?/.source
|
|
370
|
+
+ /(?:\tOwner of the domain: (?<domain>[^\n]+?)\n)?/.source
|
|
371
|
+
+ /(?:\tForeign domain used for publishing statements: (?<foreignDomain>[^\n]+?)\n)?/.source
|
|
372
|
+
+ /(?:\tPicture: (?<picture>[^\n]+?)\n)?/.source
|
|
373
|
+
+ /(?:\tVerification method: (?<verificationMethod>[^\n]+?)\n)?/.source
|
|
374
|
+
+ /(?:\tConfidence: (?<confidence>[^\n]+?)\n)?/.source
|
|
375
|
+
+ /(?:\tReliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source
|
|
376
|
+
+ /$/.source);
|
|
377
|
+
const m = s.match(domainVerificationRegex);
|
|
378
|
+
if (!m)
|
|
379
|
+
throw new Error("Invalid person verification format: " + s);
|
|
380
|
+
if (m[2] && !m[2].match(utils_1.birthDateFormat))
|
|
381
|
+
throw new Error("Invalid birth date format: " + m[2]);
|
|
382
|
+
let { d, month, y } = m[2].match(utils_1.birthDateFormat)?.groups || {};
|
|
383
|
+
if (!d || !month || !y)
|
|
384
|
+
throw new Error("Invalid birth date format: " + m[2]);
|
|
385
|
+
return {
|
|
386
|
+
name: m[1],
|
|
387
|
+
dateOfBirth: new Date(Date.UTC(parseInt(y), (0, utils_1.monthIndex)(month), parseInt(d))),
|
|
388
|
+
cityOfBirth: m[3],
|
|
389
|
+
countryOfBirth: m[4],
|
|
390
|
+
jobTitle: m[5],
|
|
391
|
+
employer: m[6],
|
|
392
|
+
ownDomain: m[7],
|
|
393
|
+
foreignDomain: m[8],
|
|
394
|
+
picture: m[9],
|
|
395
|
+
verificationMethod: m[10],
|
|
396
|
+
confidence: m[11] ? parseFloat(m[11]) : undefined,
|
|
397
|
+
reliabilityPolicy: m[12]
|
|
398
|
+
};
|
|
399
|
+
};
|
|
400
|
+
exports.parsePersonVerification = parsePersonVerification;
|
|
401
|
+
const buildVoteContent = ({ pollHash, poll, vote }) => {
|
|
402
|
+
const content = "\n" +
|
|
403
|
+
"\t" + "Type: Vote" + "\n" +
|
|
404
|
+
"\t" + "Poll id: " + pollHash + "\n" +
|
|
405
|
+
"\t" + "Poll: " + poll + "\n" +
|
|
406
|
+
"\t" + "Option: " + vote + "\n" +
|
|
407
|
+
"";
|
|
408
|
+
return content;
|
|
409
|
+
};
|
|
410
|
+
exports.buildVoteContent = buildVoteContent;
|
|
411
|
+
const parseVote = (s) => {
|
|
412
|
+
const voteRegex = new RegExp(''
|
|
413
|
+
+ /^\n\tType: Vote\n/.source
|
|
414
|
+
+ /\tPoll id: (?<pollHash>[^\n]+?)\n/.source
|
|
415
|
+
+ /\tPoll: (?<poll>[^\n]+?)\n/.source
|
|
416
|
+
+ /\tOption: (?<vote>[^\n]+?)\n/.source
|
|
417
|
+
+ /$/.source);
|
|
418
|
+
const m = s.match(voteRegex);
|
|
419
|
+
if (!m)
|
|
420
|
+
throw new Error("Invalid vote format: " + s);
|
|
421
|
+
return {
|
|
422
|
+
pollHash: m[1],
|
|
423
|
+
poll: m[2],
|
|
424
|
+
vote: m[3]
|
|
425
|
+
};
|
|
426
|
+
};
|
|
427
|
+
exports.parseVote = parseVote;
|
|
428
|
+
const buildDisputeAuthenticityContent = ({ hash, confidence, reliabilityPolicy }) => {
|
|
429
|
+
const content = "\n" +
|
|
430
|
+
"\t" + "Type: Dispute statement authenticity" + "\n" +
|
|
431
|
+
"\t" + "Description: We think that the referenced statement is not authentic.\n" +
|
|
432
|
+
"\t" + "Hash of referenced statement: " + hash + "\n" +
|
|
433
|
+
(confidence ? "\t" + "Confidence: " + confidence + "\n" : "") +
|
|
434
|
+
(reliabilityPolicy ? "\t" + "Reliability policy: " + reliabilityPolicy + "\n" : "") +
|
|
435
|
+
"";
|
|
436
|
+
return content;
|
|
437
|
+
};
|
|
438
|
+
exports.buildDisputeAuthenticityContent = buildDisputeAuthenticityContent;
|
|
439
|
+
const parseDisputeAuthenticity = (s) => {
|
|
440
|
+
const disputeRegex = new RegExp(''
|
|
441
|
+
+ /^\n\tType: Dispute statement authenticity\n/.source
|
|
442
|
+
+ /\tDescription: We think that the referenced statement is not authentic.\n/.source
|
|
443
|
+
+ /\tHash of referenced statement: (?<hash>[^\n]+?)\n/.source
|
|
444
|
+
+ /(?:\tConfidence: (?<confidence>[^\n]*?)\n)?/.source
|
|
445
|
+
+ /(?:\tReliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source
|
|
446
|
+
+ /$/.source);
|
|
447
|
+
const m = s.match(disputeRegex);
|
|
448
|
+
if (!m)
|
|
449
|
+
throw new Error("Invalid dispute authenticity format: " + s);
|
|
450
|
+
return {
|
|
451
|
+
hash: m[1],
|
|
452
|
+
confidence: m[2] ? parseFloat(m[2]) : undefined,
|
|
453
|
+
reliabilityPolicy: m[3]
|
|
454
|
+
};
|
|
455
|
+
};
|
|
456
|
+
exports.parseDisputeAuthenticity = parseDisputeAuthenticity;
|
|
457
|
+
const buildDisputeContentContent = ({ hash, confidence, reliabilityPolicy }) => {
|
|
458
|
+
const content = "\n" +
|
|
459
|
+
"\t" + "Type: Dispute statement content" + "\n" +
|
|
460
|
+
"\t" + "Description: We think that the content of the referenced statement is false.\n" +
|
|
461
|
+
"\t" + "Hash of referenced statement: " + hash + "\n" +
|
|
462
|
+
(confidence ? "\t" + "Confidence: " + confidence + "\n" : "") +
|
|
463
|
+
(reliabilityPolicy ? "\t" + "Reliability policy: " + reliabilityPolicy + "\n" : "") +
|
|
464
|
+
"";
|
|
465
|
+
return content;
|
|
466
|
+
};
|
|
467
|
+
exports.buildDisputeContentContent = buildDisputeContentContent;
|
|
468
|
+
const parseDisputeContent = (s) => {
|
|
469
|
+
const disputeRegex = new RegExp(''
|
|
470
|
+
+ /^\n\tType: Dispute statement content\n/.source
|
|
471
|
+
+ /\tDescription: We think that the content of the referenced statement is false.\n/.source
|
|
472
|
+
+ /\tHash of referenced statement: (?<hash>[^\n]+?)\n/.source
|
|
473
|
+
+ /(?:\tConfidence: (?<confidence>[^\n]*?)\n)?/.source
|
|
474
|
+
+ /(?:\tReliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source
|
|
475
|
+
+ /$/.source);
|
|
476
|
+
const m = s.match(disputeRegex);
|
|
477
|
+
if (!m)
|
|
478
|
+
throw new Error("Invalid dispute content format: " + s);
|
|
479
|
+
return {
|
|
480
|
+
hash: m[1],
|
|
481
|
+
confidence: m[2] ? parseFloat(m[2]) : undefined,
|
|
482
|
+
reliabilityPolicy: m[3]
|
|
483
|
+
};
|
|
484
|
+
};
|
|
485
|
+
exports.parseDisputeContent = parseDisputeContent;
|
|
486
|
+
const buildResponseContent = ({ hash, response }) => {
|
|
487
|
+
const content = "\n" +
|
|
488
|
+
"\t" + "Type: Response" + "\n" +
|
|
489
|
+
"\t" + "Hash of referenced statement: " + hash + "\n" +
|
|
490
|
+
"\t" + "Response: " + response + "\n" +
|
|
491
|
+
"";
|
|
492
|
+
return content;
|
|
493
|
+
};
|
|
494
|
+
exports.buildResponseContent = buildResponseContent;
|
|
495
|
+
const parseResponseContent = (s) => {
|
|
496
|
+
const disputeRegex = new RegExp(''
|
|
497
|
+
+ /^\n\tType: Response\n/.source
|
|
498
|
+
+ /\tHash of referenced statement: (?<hash>[^\n]+?)\n/.source
|
|
499
|
+
+ /\tResponse: (?<response>[^\n]*?)\n/.source
|
|
500
|
+
+ /$/.source);
|
|
501
|
+
const m = s.match(disputeRegex);
|
|
502
|
+
if (!m)
|
|
503
|
+
throw new Error("Invalid response content format: " + s);
|
|
504
|
+
return {
|
|
505
|
+
hash: m[1],
|
|
506
|
+
response: m[2]
|
|
507
|
+
};
|
|
508
|
+
};
|
|
509
|
+
exports.parseResponseContent = parseResponseContent;
|
|
510
|
+
const buildPDFSigningContent = ({ hash }) => {
|
|
511
|
+
const content = "\n" +
|
|
512
|
+
"\t" + "Type: Sign PDF" + "\n" +
|
|
513
|
+
"\t" + "Description: We hereby digitally sign the referenced PDF file.\n" +
|
|
514
|
+
"\t" + "PDF file hash: " + hash + "\n" +
|
|
515
|
+
"";
|
|
516
|
+
return content;
|
|
517
|
+
};
|
|
518
|
+
exports.buildPDFSigningContent = buildPDFSigningContent;
|
|
519
|
+
const parsePDFSigning = (s) => {
|
|
520
|
+
const signingRegex = new RegExp(''
|
|
521
|
+
+ /^\n\tType: Sign PDF\n/.source
|
|
522
|
+
+ /\tDescription: We hereby digitally sign the referenced PDF file.\n/.source
|
|
523
|
+
+ /\tPDF file hash: (?<hash>[^\n]+?)\n/.source
|
|
524
|
+
+ /$/.source);
|
|
525
|
+
const m = s.match(signingRegex);
|
|
526
|
+
if (!m)
|
|
527
|
+
throw new Error("Invalid PDF signing format: " + s);
|
|
528
|
+
return {
|
|
529
|
+
hash: m[1]
|
|
530
|
+
};
|
|
531
|
+
};
|
|
532
|
+
exports.parsePDFSigning = parsePDFSigning;
|
|
533
|
+
const buildRating = ({ subjectName, subjectType, subjectReference, documentFileHash, rating, quality, comment }) => {
|
|
534
|
+
if (![1, 2, 3, 4, 5].includes(rating))
|
|
535
|
+
throw new Error("Invalid rating: " + rating);
|
|
536
|
+
const content = "\n" +
|
|
537
|
+
"\t" + "Type: Rating" + "\n" +
|
|
538
|
+
(subjectType ? "\t" + "Subject type: " + subjectType + "\n" : "") +
|
|
539
|
+
"\t" + "Subject name: " + subjectName + "\n" +
|
|
540
|
+
(subjectReference ? "\t" + "URL that identifies the subject: " + subjectReference + "\n" : "") +
|
|
541
|
+
(documentFileHash ? "\t" + "Document file hash: " + documentFileHash + "\n" : "") +
|
|
542
|
+
(quality ? "\t" + "Rated quality: " + quality + "\n" : "") +
|
|
543
|
+
"\t" + "Our rating: " + rating + "/5 Stars\n" +
|
|
544
|
+
(comment ? "\t" + "Comment: " + comment + "\n" : "") +
|
|
545
|
+
"";
|
|
546
|
+
return content;
|
|
547
|
+
};
|
|
548
|
+
exports.buildRating = buildRating;
|
|
549
|
+
const parseRating = (s) => {
|
|
550
|
+
const ratingRegex = new RegExp(''
|
|
551
|
+
+ /^\n\tType: Rating\n/.source
|
|
552
|
+
+ /(?:\tSubject type: (?<subjectType>[^\n]*?)\n)?/.source
|
|
553
|
+
+ /\tSubject name: (?<subjectName>[^\n]*?)\n/.source
|
|
554
|
+
+ /(?:\tURL that identifies the subject: (?<subjectReference>[^\n]*?)\n)?/.source
|
|
555
|
+
+ /(?:\tDocument file hash: (?<documentFileHash>[^\n]*?)\n)?/.source
|
|
556
|
+
+ /(?:\tRated quality: (?<quality>[^\n]*?)\n)?/.source
|
|
557
|
+
+ /\tOur rating: (?<rating>[1-5])\/5 Stars\n/.source
|
|
558
|
+
+ /(?:\tComment: (?<comment>[\s\S]+?)\n)?/.source
|
|
559
|
+
+ /$/.source);
|
|
560
|
+
const m = s.match(ratingRegex);
|
|
561
|
+
if (!m)
|
|
562
|
+
throw new Error("Invalid rating format: " + s);
|
|
563
|
+
const rating = parseInt(m[6]);
|
|
564
|
+
if (![1, 2, 3, 4, 5].includes(rating))
|
|
565
|
+
throw new Error("Invalid rating: " + m[6]);
|
|
566
|
+
if (m[1] && !['Organisation', 'Policy proposal', 'Regulation',
|
|
567
|
+
'Treaty draft', 'Product', 'Research publication'].includes(m[1]))
|
|
568
|
+
throw new Error("Invalid subject type: " + m[1]);
|
|
569
|
+
if (!m[2])
|
|
570
|
+
throw new Error("Missing subject name");
|
|
571
|
+
return {
|
|
572
|
+
subjectType: m[1],
|
|
573
|
+
subjectName: m[2],
|
|
574
|
+
subjectReference: m[3],
|
|
575
|
+
documentFileHash: m[4],
|
|
576
|
+
quality: m[5],
|
|
577
|
+
rating,
|
|
578
|
+
comment: m[7]
|
|
579
|
+
};
|
|
580
|
+
};
|
|
581
|
+
exports.parseRating = parseRating;
|
|
582
|
+
const buildBounty = ({ motivation, bounty, reward, judge, judgePay }) => {
|
|
583
|
+
const content = "\n" +
|
|
584
|
+
"\t" + "Type: Bounty" + "\n" +
|
|
585
|
+
(motivation ? "\t" + "In order to: " + motivation + "\n" : "") +
|
|
586
|
+
"\t" + "We will reward any entity that: " + bounty + "\n" +
|
|
587
|
+
"\t" + "The reward is: " + reward + "\n" +
|
|
588
|
+
"\t" + "In case of dispute, bounty claims are judged by: " + judge + "\n" +
|
|
589
|
+
(judgePay ? "\t" + "The judge will be paid per investigated case with a maxium of: " + judgePay + "\n" : "") +
|
|
590
|
+
"";
|
|
591
|
+
return content;
|
|
592
|
+
};
|
|
593
|
+
exports.buildBounty = buildBounty;
|
|
594
|
+
const parseBounty = (s) => {
|
|
595
|
+
const bountyRegex = new RegExp(''
|
|
596
|
+
+ /^\n\tType: Bounty\n/.source
|
|
597
|
+
+ /(?:\tIn order to: (?<motivation>[^\n]*?)\n)?/.source
|
|
598
|
+
+ /\tWe will reward any entity that: (?<bounty>[^\n]*?)\n/.source
|
|
599
|
+
+ /\tThe reward is: (?<reward>[^\n]*?)\n/.source
|
|
600
|
+
+ /\tIn case of dispute, bounty claims are judged by: (?<judge>[^\n]*?)\n/.source
|
|
601
|
+
+ /(?:\tThe judge will be paid per investigated case with a maxium of: (?<judgePay>[^\n]*?)\n)?/.source
|
|
602
|
+
+ /$/.source);
|
|
603
|
+
const m = s.match(bountyRegex);
|
|
604
|
+
if (!m)
|
|
605
|
+
throw new Error("Invalid bounty format: " + s);
|
|
606
|
+
return {
|
|
607
|
+
motivation: m[1],
|
|
608
|
+
bounty: m[2],
|
|
609
|
+
reward: m[3],
|
|
610
|
+
judge: m[4],
|
|
611
|
+
judgePay: m[5]
|
|
612
|
+
};
|
|
613
|
+
};
|
|
614
|
+
exports.parseBounty = parseBounty;
|
|
615
|
+
const buildObservation = ({ approach, confidence, reliabilityPolicy, subject, subjectReference, observationReference, property, value }) => {
|
|
616
|
+
const content = "\n" +
|
|
617
|
+
"\t" + "Type: Observation" + "\n" +
|
|
618
|
+
(approach ? "\t" + "Approach: " + approach + "\n" : "") +
|
|
619
|
+
(confidence ? "\t" + "Confidence: " + confidence + "\n" : "") +
|
|
620
|
+
(reliabilityPolicy ? "\t" + "Reliability policy: " + reliabilityPolicy + "\n" : "") +
|
|
621
|
+
"\t" + "Subject: " + subject + "\n" +
|
|
622
|
+
(subjectReference ? "\t" + "Subject identity reference: " + subjectReference + "\n" : "") +
|
|
623
|
+
(observationReference ? "\t" + "Observation reference: " + observationReference + "\n" : "") +
|
|
624
|
+
"\t" + "Observed property: " + property + "\n" +
|
|
625
|
+
(value ? "\t" + "Observed value: " + value + "\n" : "") +
|
|
626
|
+
"";
|
|
627
|
+
return content;
|
|
628
|
+
};
|
|
629
|
+
exports.buildObservation = buildObservation;
|
|
630
|
+
const parseObservation = (s) => {
|
|
631
|
+
const observationRegex = new RegExp(''
|
|
632
|
+
+ /^\n\tType: Observation\n/.source
|
|
633
|
+
+ /(?:\tApproach: (?<approach>[^\n]*?)\n)?/.source
|
|
634
|
+
+ /(?:\tConfidence: (?<confidence>[^\n]*?)\n)?/.source
|
|
635
|
+
+ /(?:\tReliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source
|
|
636
|
+
+ /\tSubject: (?<subject>[^\n]*?)\n/.source
|
|
637
|
+
+ /(?:\tSubject identity reference: (?<subjectReference>[^\n]*?)\n)?/.source
|
|
638
|
+
+ /(?:\tObservation reference: (?<observationReference>[^\n]*?)\n)?/.source
|
|
639
|
+
+ /\tObserved property: (?<property>[^\n]*?)\n/.source
|
|
640
|
+
+ /(?:\tObserved value: (?<value>[\s\S]+?)\n)?/.source
|
|
641
|
+
+ /$/.source);
|
|
642
|
+
const m = s.match(observationRegex);
|
|
643
|
+
if (!m)
|
|
644
|
+
throw new Error("Invalid observation format: " + s);
|
|
645
|
+
return {
|
|
646
|
+
approach: m[1],
|
|
647
|
+
confidence: m[2] ? parseFloat(m[2]) : undefined,
|
|
648
|
+
reliabilityPolicy: m[3],
|
|
649
|
+
subject: m[4],
|
|
650
|
+
subjectReference: m[5],
|
|
651
|
+
observationReference: m[6],
|
|
652
|
+
property: m[7],
|
|
653
|
+
value: m[8]
|
|
654
|
+
};
|
|
655
|
+
};
|
|
656
|
+
exports.parseObservation = parseObservation;
|
|
657
|
+
const buildBoycott = ({ description, subject, subjectReference }) => {
|
|
658
|
+
const content = "\n" +
|
|
659
|
+
"\t" + "Type: Boycott" + "\n" +
|
|
660
|
+
(description ? "\t" + "Description: " + description + "\n" : "") +
|
|
661
|
+
"\t" + "Subject: " + subject + "\n" +
|
|
662
|
+
(subjectReference ? "\t" + "Subject identity reference: " + subjectReference + "\n" : "") +
|
|
663
|
+
"";
|
|
664
|
+
return content;
|
|
665
|
+
};
|
|
666
|
+
exports.buildBoycott = buildBoycott;
|
|
667
|
+
const parseBoycott = (s) => {
|
|
668
|
+
const observationRegex = new RegExp(''
|
|
669
|
+
+ /^\n\tType: Boycott\n/.source
|
|
670
|
+
+ /(?:\tDescription: (?<description>[^\n]*?)\n)?/.source
|
|
671
|
+
+ /\tSubject: (?<subject>[^\n]*?)\n/.source
|
|
672
|
+
+ /(?:\tSubject identity reference: (?<subjectReference>[^\n]*?)\n)?/.source
|
|
673
|
+
+ /$/.source);
|
|
674
|
+
const m = s.match(observationRegex);
|
|
675
|
+
if (!m)
|
|
676
|
+
throw new Error("Invalid observation format: " + s);
|
|
677
|
+
return {
|
|
678
|
+
description: m[1],
|
|
679
|
+
subject: m[2],
|
|
680
|
+
subjectReference: m[3],
|
|
681
|
+
};
|
|
682
|
+
};
|
|
683
|
+
exports.parseBoycott = parseBoycott;
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
export type StatementTypeValue = 'statement' | 'quotation' | 'organisation_verification' | 'person_verification' | 'poll' | 'vote' | 'response' | 'dispute_statement_content' | 'dispute_statement_authenticity' | 'boycott' | 'observation' | 'rating' | 'sign_pdf' | 'bounty';
|
|
2
|
+
export type Statement = {
|
|
3
|
+
domain: string;
|
|
4
|
+
author: string;
|
|
5
|
+
time: Date;
|
|
6
|
+
tags?: string[];
|
|
7
|
+
content: string;
|
|
8
|
+
representative?: string;
|
|
9
|
+
supersededStatement?: string;
|
|
10
|
+
formatVersion?: string;
|
|
11
|
+
};
|
|
12
|
+
export type Quotation = {
|
|
13
|
+
originalAuthor: string;
|
|
14
|
+
authorVerification: string;
|
|
15
|
+
originalTime?: string;
|
|
16
|
+
source?: string;
|
|
17
|
+
quotation?: string;
|
|
18
|
+
paraphrasedStatement?: string;
|
|
19
|
+
picture?: string;
|
|
20
|
+
confidence?: string;
|
|
21
|
+
};
|
|
22
|
+
export type Poll = {
|
|
23
|
+
country: string | undefined;
|
|
24
|
+
city: string | undefined;
|
|
25
|
+
legalEntity: string | undefined;
|
|
26
|
+
domainScope: string[] | undefined;
|
|
27
|
+
judges?: string;
|
|
28
|
+
deadline: Date | undefined;
|
|
29
|
+
poll: string;
|
|
30
|
+
scopeDescription?: string;
|
|
31
|
+
scopeQueryLink?: string;
|
|
32
|
+
options: string[];
|
|
33
|
+
allowArbitraryVote?: boolean;
|
|
34
|
+
requiredProperty?: string;
|
|
35
|
+
requiredPropertyValue?: string;
|
|
36
|
+
requiredPropertyObserver?: string;
|
|
37
|
+
requiredMinConfidence?: number;
|
|
38
|
+
};
|
|
39
|
+
export type OrganisationVerification = {
|
|
40
|
+
name: string;
|
|
41
|
+
englishName?: string;
|
|
42
|
+
country: string;
|
|
43
|
+
city: string;
|
|
44
|
+
province: string;
|
|
45
|
+
legalForm: string;
|
|
46
|
+
department?: string;
|
|
47
|
+
domain: string;
|
|
48
|
+
foreignDomain: string;
|
|
49
|
+
serialNumber: string;
|
|
50
|
+
confidence?: number;
|
|
51
|
+
reliabilityPolicy?: string;
|
|
52
|
+
employeeCount?: string;
|
|
53
|
+
pictureHash?: string;
|
|
54
|
+
latitude?: number;
|
|
55
|
+
longitude?: number;
|
|
56
|
+
population?: string;
|
|
57
|
+
};
|
|
58
|
+
export type withOwnDomain = {
|
|
59
|
+
ownDomain: string;
|
|
60
|
+
foreignDomain?: string;
|
|
61
|
+
};
|
|
62
|
+
export type withForeignDomain = {
|
|
63
|
+
foreignDomain: string;
|
|
64
|
+
ownDomain?: string;
|
|
65
|
+
};
|
|
66
|
+
export type PersonVerification = {
|
|
67
|
+
name: string;
|
|
68
|
+
countryOfBirth: string;
|
|
69
|
+
cityOfBirth: string;
|
|
70
|
+
dateOfBirth: Date;
|
|
71
|
+
jobTitle?: string;
|
|
72
|
+
employer?: string;
|
|
73
|
+
verificationMethod?: string;
|
|
74
|
+
confidence?: number;
|
|
75
|
+
picture?: string;
|
|
76
|
+
reliabilityPolicy?: string;
|
|
77
|
+
} & (withOwnDomain | withForeignDomain);
|
|
78
|
+
export type Vote = {
|
|
79
|
+
pollHash: string;
|
|
80
|
+
poll: string;
|
|
81
|
+
vote: string;
|
|
82
|
+
};
|
|
83
|
+
export type DisputeAuthenticity = {
|
|
84
|
+
hash: string;
|
|
85
|
+
confidence?: number;
|
|
86
|
+
reliabilityPolicy?: string;
|
|
87
|
+
};
|
|
88
|
+
export type DisputeContent = {
|
|
89
|
+
hash: string;
|
|
90
|
+
confidence?: number;
|
|
91
|
+
reliabilityPolicy?: string;
|
|
92
|
+
};
|
|
93
|
+
export type ResponseContent = {
|
|
94
|
+
hash: string;
|
|
95
|
+
response: string;
|
|
96
|
+
};
|
|
97
|
+
export type PDFSigning = {
|
|
98
|
+
hash: string;
|
|
99
|
+
};
|
|
100
|
+
export type RatingSubjectTypeValue = 'Organisation' | 'Policy proposal' | 'Treaty draft' | 'Research publication' | 'Regulation' | 'Product';
|
|
101
|
+
export type Rating = {
|
|
102
|
+
subjectType?: RatingSubjectTypeValue;
|
|
103
|
+
subjectName: string;
|
|
104
|
+
subjectReference?: string;
|
|
105
|
+
documentFileHash?: string;
|
|
106
|
+
rating: number;
|
|
107
|
+
quality?: string;
|
|
108
|
+
comment?: string;
|
|
109
|
+
};
|
|
110
|
+
export type Bounty = {
|
|
111
|
+
motivation?: string;
|
|
112
|
+
bounty: string;
|
|
113
|
+
reward: string;
|
|
114
|
+
judge: string;
|
|
115
|
+
judgePay?: string;
|
|
116
|
+
};
|
|
117
|
+
export type Observation = {
|
|
118
|
+
description?: string;
|
|
119
|
+
approach?: string;
|
|
120
|
+
confidence?: number;
|
|
121
|
+
reliabilityPolicy?: string;
|
|
122
|
+
subject: string;
|
|
123
|
+
subjectReference?: string;
|
|
124
|
+
observationReference?: string;
|
|
125
|
+
property: string;
|
|
126
|
+
value?: string;
|
|
127
|
+
};
|
|
128
|
+
export type PollV3 = {
|
|
129
|
+
country: string | undefined;
|
|
130
|
+
city: string | undefined;
|
|
131
|
+
legalEntity: string | undefined;
|
|
132
|
+
domainScope: string[] | undefined;
|
|
133
|
+
judges?: string;
|
|
134
|
+
deadline: Date;
|
|
135
|
+
poll: string;
|
|
136
|
+
scopeDescription?: string;
|
|
137
|
+
scopeQueryLink?: string;
|
|
138
|
+
scopeProperty?: string;
|
|
139
|
+
propertyScopeObserver?: string;
|
|
140
|
+
pollType?: string;
|
|
141
|
+
options: string[];
|
|
142
|
+
};
|
|
143
|
+
export type Boycott = {
|
|
144
|
+
description?: string;
|
|
145
|
+
reliabilityPolicy?: string;
|
|
146
|
+
subject: string;
|
|
147
|
+
subjectReference?: string;
|
|
148
|
+
};
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
package/dist/utils.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.birthDateFormat = exports.monthIndex = exports.minPeopleCountToRange = void 0;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
const minPeopleCountToRange = (n) => {
|
|
6
|
+
if (n >= 10000000)
|
|
7
|
+
return constants_1.peopleCountBuckets["10000000"];
|
|
8
|
+
if (n >= 1000000)
|
|
9
|
+
return constants_1.peopleCountBuckets["1000000"];
|
|
10
|
+
if (n >= 100000)
|
|
11
|
+
return constants_1.peopleCountBuckets["100000"];
|
|
12
|
+
if (n >= 10000)
|
|
13
|
+
return constants_1.peopleCountBuckets["10000"];
|
|
14
|
+
if (n >= 1000)
|
|
15
|
+
return constants_1.peopleCountBuckets["1000"];
|
|
16
|
+
if (n >= 100)
|
|
17
|
+
return constants_1.peopleCountBuckets["100"];
|
|
18
|
+
if (n >= 10)
|
|
19
|
+
return constants_1.peopleCountBuckets["10"];
|
|
20
|
+
if (n >= 0)
|
|
21
|
+
return constants_1.peopleCountBuckets["0"];
|
|
22
|
+
};
|
|
23
|
+
exports.minPeopleCountToRange = minPeopleCountToRange;
|
|
24
|
+
const monthIndex = (month) => ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"]
|
|
25
|
+
.indexOf(month.toLowerCase().substr(0, 3));
|
|
26
|
+
exports.monthIndex = monthIndex;
|
|
27
|
+
exports.birthDateFormat = /(?<d>\d{1,2})\s(?<month>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?<y>\d{4})/;
|
package/dist/v3.d.ts
ADDED
package/dist/v3.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parsePollV3 = void 0;
|
|
4
|
+
const constants_1 = require("./constants");
|
|
5
|
+
const parsePollV3 = (s, version) => {
|
|
6
|
+
const pollRegex = new RegExp(''
|
|
7
|
+
+ /^\n\tType: Poll\n/.source
|
|
8
|
+
+ /(?:\tPoll type: (?<pollType>[^\n]+?)\n)?/.source
|
|
9
|
+
+ /(?:\tWho can vote: (?<scopeDescription>[^\n]+?)\n)?/.source
|
|
10
|
+
+ /(?:\tLink to query defining who can vote: (?<scopeQueryLink>[^\n]+?)\n)?/.source
|
|
11
|
+
+ /(?:\tCountry scope: (?<country>[^\n]+?)\n)?/.source
|
|
12
|
+
+ /(?:\tCity scope: (?<city>[^\n]+?)\n)?/.source
|
|
13
|
+
+ /(?:\tLegal form scope: (?<legalEntity>[^\n]+?)\n)?/.source
|
|
14
|
+
+ /(?:\tDomain scope: (?<domainScope>[^\n]+?)\n)?/.source
|
|
15
|
+
+ /(?:\tThe decision is finalized when the following nodes agree: (?<judges>[^\n]+?)\n)?/.source
|
|
16
|
+
+ /(?:\tVoting deadline: (?<deadline>[^\n]+?)\n)?/.source
|
|
17
|
+
+ /\tPoll: (?<poll>[^\n]+?)\n/.source
|
|
18
|
+
+ /(?:\tOption 1: (?<option1>[^\n]+?)\n)?/.source
|
|
19
|
+
+ /(?:\tOption 2: (?<option2>[^\n]+?)\n)?/.source
|
|
20
|
+
+ /(?:\tOption 3: (?<option3>[^\n]+?)\n)?/.source
|
|
21
|
+
+ /(?:\tOption 4: (?<option4>[^\n]+?)\n)?/.source
|
|
22
|
+
+ /(?:\tOption 5: (?<option5>[^\n]+?)\n)?/.source
|
|
23
|
+
+ /$/.source);
|
|
24
|
+
const match = s.match(pollRegex);
|
|
25
|
+
if (!match)
|
|
26
|
+
throw new Error("Invalid poll format: " + s);
|
|
27
|
+
const m = {
|
|
28
|
+
pollType: match[1],
|
|
29
|
+
scopeDescription: match[2],
|
|
30
|
+
scopeQueryLink: match[3],
|
|
31
|
+
country: match[4],
|
|
32
|
+
city: match[5],
|
|
33
|
+
legalEntity: match[6],
|
|
34
|
+
domainScope: match[7],
|
|
35
|
+
judges: match[8],
|
|
36
|
+
deadline: match[9],
|
|
37
|
+
poll: match[10],
|
|
38
|
+
option1: match[11],
|
|
39
|
+
option2: match[12],
|
|
40
|
+
option3: match[13],
|
|
41
|
+
option4: match[14],
|
|
42
|
+
option5: match[15]
|
|
43
|
+
};
|
|
44
|
+
const options = [m.option1, m.option2, m.option3, m.option4, m.option5].filter(o => o);
|
|
45
|
+
const domainScope = m.domainScope?.split(', ');
|
|
46
|
+
const deadlineStr = m.deadline;
|
|
47
|
+
if (!deadlineStr.match(constants_1.UTCFormat))
|
|
48
|
+
throw new Error("Invalid poll, deadline must be in UTC: " + deadlineStr);
|
|
49
|
+
return {
|
|
50
|
+
pollType: m['pollType'],
|
|
51
|
+
country: m['country'],
|
|
52
|
+
scopeDescription: m['scopeDescription'],
|
|
53
|
+
scopeQueryLink: m['scopeQueryLink'],
|
|
54
|
+
city: m['city'],
|
|
55
|
+
legalEntity: m['legalEntity'],
|
|
56
|
+
domainScope: (domainScope && domainScope.length > 0) ? domainScope : undefined,
|
|
57
|
+
judges: m['judges'],
|
|
58
|
+
deadline: new Date(deadlineStr),
|
|
59
|
+
poll: m['poll'],
|
|
60
|
+
options
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
exports.parsePollV3 = parsePollV3;
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "stated-protocol-parser",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Parser and formatter for the Stated protocol - a decentralized statement verification system",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "jest",
|
|
10
|
+
"prepublishOnly": "npm run build"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"stated",
|
|
14
|
+
"protocol",
|
|
15
|
+
"parser",
|
|
16
|
+
"formatter",
|
|
17
|
+
"verification",
|
|
18
|
+
"decentralized",
|
|
19
|
+
"statements"
|
|
20
|
+
],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/jest": "^29.5.0",
|
|
25
|
+
"@types/node": "^20.0.0",
|
|
26
|
+
"jest": "^29.5.0",
|
|
27
|
+
"ts-jest": "^29.1.0",
|
|
28
|
+
"typescript": "^5.0.0"
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "https://github.com/c-riq/stated"
|
|
38
|
+
}
|
|
39
|
+
}
|