Skip to content
This repository has been archived by the owner on Aug 30, 2023. It is now read-only.

Commit

Permalink
Merge pull request #113 from ehn-dcc-development/feature/dob
Browse files Browse the repository at this point in the history
[CertLogic] add operation for dealing with (partial) DOBs
  • Loading branch information
dslmeinte authored Mar 31, 2022
2 parents 2ea6f36 + 20df20c commit 0c00612
Show file tree
Hide file tree
Showing 33 changed files with 897 additions and 177 deletions.
23 changes: 22 additions & 1 deletion certlogic/certlogic-js/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,31 @@
# Change log

## 1.2.0

* Add a `dccDateOfBirth` operation to convert date of birth (DOB) values in the EU DCC to a date.
Such DOBs may be “partial dates” of the form YYYY or YYYY-MM.
See [the specification](../specification/README.md#) for more details.

* Changed desugaring of `"or"` (in the `misc` sub package) to align semantically with that of the `"and"` operation:
the first truthy operand is returned, or the last operand (which is then falsy).
This replaces the semantics where a desugared `"or"` always returned a boolean value, due to the use of [De Morgan's laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
(Also: an `"or"` with a single operand reduces to that operand.)

* Build improvement: perform deduplication of (nested) dependencies.

* Added the following to the `internals`:
* The concept of “boolsiness” (internally) by means of a type `Boolsiness` and a function `boolsiness`.
* A `CertlogicLiteral` type, and a corresponding type guard function.

These can be imported (until they're re-exported by `index.ts`) as `import { ... } from "certlogic-js/dist/internals"`.


## 1.1.2

* Improve types in source of `renderAsCompactText`
* (fix:) Really prevent emission of all source map files, not just for the `.d.ts`-files
* Replace use of `Object.keys(...)` with equivalent use of `Object.entries(...)` - shorter code; maybe some performance improvement?
* Replace use of `Object.keys(...)` with equivalent use of `Object.entries(...)`.
Advantage: shorter code, and maybe some performance improvement?


## 1.1.1
Expand Down
2 changes: 1 addition & 1 deletion certlogic/certlogic-js/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
It is a [specified](https://github.com/ehn-dcc-development/dgc-business-rules/blob/main/certlogic/specification/README.md) subset of [JsonLogic](https://jsonlogic.com/), extended with necessary custom operations - e.g. for working with dates.
It's part of the efforts surrounding the [Digital COVID Certificate](https://ec.europa.eu/info/live-work-travel-eu/coronavirus-response/safe-covid-19-vaccines-europeans/eu-digital-covid-certificate_en), and as such serves as the basis for defining _interchangeable_ validation rules on top of the DCC.

This NPM package consists of an implementation of CertLogic in JavaScript(/TypeScript) which is compatible with version **1.2.4** of [the specification](https://github.com/ehn-dcc-development/dgc-business-rules/tree/main/certlogic/specification/README.md).
This NPM package consists of an implementation of CertLogic in JavaScript(/TypeScript) which is compatible with version **1.3.0** of [the specification](https://github.com/ehn-dcc-development/dgc-business-rules/tree/main/certlogic/specification/README.md).


## API
Expand Down
1 change: 1 addition & 0 deletions certlogic/certlogic-js/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ set -e

npm run clean
npm install
npm dedupe # also deduplicate dependencies
npm test # also builds the source

# check for circular dependencies, and exit in case one's present:
Expand Down
113 changes: 92 additions & 21 deletions certlogic/certlogic-js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions certlogic/certlogic-js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "certlogic-js",
"version": "1.1.2",
"version": "1.2.0",
"description": "Implementation of CertLogic in TypeScript",
"keywords": [
"json",
Expand Down Expand Up @@ -44,10 +44,12 @@
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/mocha": "^9.1.0",
"@types/node": "^17.0.14",
"@types/node": "^17.0.17",
"@types/semver": "^7.3.9",
"chai": "^4.3.6",
"dpdm": "^3.8.0",
"mocha": "^9.2.0",
"semver": "^7.3.5",
"typescript": "^4.5.5"
}
}
52 changes: 28 additions & 24 deletions certlogic/certlogic-js/src/evaluator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { CertLogicExpression, TimeUnit, timeUnits } from "./typings"
import {
access,
extractFromUVCI,
isFalsy,
access, boolsiness, dccDateOfBirth,
extractFromUVCI, isCertLogicLiteral,
isInt,
isTruthy,
plusTime
} from "./internals"

Expand All @@ -28,13 +26,11 @@ const evaluateIf = (guard: CertLogicExpression, then: CertLogicExpression, else_
throw new Error(`an if-operation must have an else (argument #3)`)
}
const evalGuard = evaluate(guard, data)
if (isTruthy(evalGuard)) {
return evaluate(then, data)
switch (boolsiness(evalGuard)) {
case true: return evaluate(then, data)
case false: return evaluate(else_, data)
case undefined: throw new Error(`if-guard evaluates to something neither truthy, nor falsy: ${evalGuard}`)
}
if (isFalsy(evalGuard)) {
return evaluate(else_, data)
}
throw new Error(`if-guard evaluates to something neither truthy, nor falsy: ${evalGuard}`)
}


Expand Down Expand Up @@ -111,13 +107,11 @@ const evaluateInfix = (operator: string, values: CertLogicExpression[], data: an
}
case "and": return values.reduce(
(acc: any, current: CertLogicExpression) => {
if (isFalsy(acc)) {
return acc
}
if (isTruthy(acc)) {
return evaluate(current, data)
switch (boolsiness(acc)) {
case false: return acc
case true: return evaluate(current, data)
case undefined: throw new Error(`all operands of an "and" operation must be either truthy or falsy`)
}
throw new Error(`all operands of an "and" operation must be either truthy or falsy`)
},
true
)
Expand Down Expand Up @@ -146,13 +140,11 @@ const evaluateInfix = (operator: string, values: CertLogicExpression[], data: an

const evaluateNot = (operand: CertLogicExpression, data: any): any => {
const evalOperand = evaluate(operand, data)
if (isFalsy(evalOperand)) {
return true
}
if (isTruthy(evalOperand)) {
return false
switch (boolsiness(evalOperand)) {
case false: return true
case true: return false
case undefined: throw new Error(`operand of ! evaluates to something neither truthy, nor falsy: ${evalOperand}`)
}
throw new Error(`operand of ! evaluates to something neither truthy, nor falsy: ${evalOperand}`)
}


Expand All @@ -165,7 +157,7 @@ const evaluatePlusTime = (dateOperand: CertLogicExpression, amount: CertLogicExp
}
const dateTimeStr = evaluate(dateOperand, data)
if (typeof dateTimeStr !== "string") {
throw new Error(`date argument of "plusTime" must be a string`)
throw new Error(`date argument (#1) of "plusTime" must be a string`)
}
return plusTime(dateTimeStr, amount, unit)
}
Expand Down Expand Up @@ -200,8 +192,17 @@ const evaluateExtractFromUVCI = (operand: CertLogicExpression, index: number, da
}


const evaluateDccDateOfBirth = (operand: CertLogicExpression, data: any): Date => {
const evalOperand = evaluate(operand, data)
if (!(typeof evalOperand === "string")) {
throw new Error(`operand of "dccDateOfBirth" must be a string`)
}
return dccDateOfBirth(evalOperand)
}


export const evaluate = (expr: CertLogicExpression, data: any): any => {
if (typeof expr === "string" || isInt(expr) || typeof expr === "boolean") {
if (isCertLogicLiteral(expr)) {
return expr
}
if (expr === null) {
Expand Down Expand Up @@ -241,6 +242,9 @@ export const evaluate = (expr: CertLogicExpression, data: any): any => {
if (operator === "extractFromUVCI") {
return evaluateExtractFromUVCI(values[0], values[1], data)
}
if (operator === "dccDateOfBirth") {
return evaluateDccDateOfBirth(values[0], data)
}
throw new Error(`unrecognised operator: "${operator}"`)
}
throw new Error(`invalid CertLogic expression: ${expr}`)
Expand Down
3 changes: 3 additions & 0 deletions certlogic/certlogic-js/src/factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,6 @@ export const reduce_ = (operand: CertLogicExpression, lambda: CertLogicExpressio
export const extractFromUVCI_ = (operand: CertLogicExpression, index: number): CertLogicOperation =>
({ "extractFromUVCI": [ operand, index ] })

export const dccDateOfBirth_ = (operand: CertLogicExpression): CertLogicOperation =>
({ "dccDateOfBirth": [ operand ] })

Loading

0 comments on commit 0c00612

Please sign in to comment.