Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
import { assert } from '../assertion/assertion.js';
/**
* ISO-4217 currency codes.
*/
const CURRENCY_CODES = ['USD', 'EUR', 'CAD', 'GBP'] as const;
export type CurrencyCode = (typeof CURRENCY_CODES)[number];
export function isCurrencyCode(value: string): value is CurrencyCode {
return (CURRENCY_CODES as readonly string[]).includes(value);
}
export function currencyCode(value: string): CurrencyCode {
assert(isCurrencyCode(value), `Unsupported currency code: ${value}`);
return value;
}
const CURRENCY_SCALES = [2] as const;
/**
* Represents the scale of the currency.
*
* - `2`: The minor unit is 1/100 of the major unit.
*/
type CurrencyScale = (typeof CURRENCY_SCALES)[number];
export function isCurrencyScale(value: number): value is CurrencyScale {
return (CURRENCY_SCALES as readonly number[]).includes(value);
}
export function currencyScale(value: number): CurrencyScale {
assert(isCurrencyScale(value), `Unsupported currency scale: ${value}`);
return value;
}
type CurrencyMap = {
[K in CurrencyCode]: Currency;
};
/**
* Represents a currency with decimal precision.
*
* To add support for a currency:
* 1. Add the new currency code to the {@link CURRENCY_CODES} array.
* 2. Create a corresponding mapping in the {@link SUPPORTED_CURRENCIES} map.
*/
export class Currency {
private static readonly SUPPORTED_CURRENCIES: CurrencyMap = {
USD: new Currency('USD', 2),
EUR: new Currency('EUR', 2),
CAD: new Currency('CAD', 2),
GBP: new Currency('GBP', 2),
};
private readonly _code: CurrencyCode;
private readonly _scale: CurrencyScale;
constructor(code: string | CurrencyCode, scale: number | CurrencyScale) {
this._code = currencyCode(code);
this._scale = currencyScale(scale);
}
get code() {
return this._code;
}
get scale() {
return this._scale;
}
static of(code: string | CurrencyCode) {
assert(isCurrencyCode(code), `Unsupported currency code: ${code}`);
const currency = Currency.SUPPORTED_CURRENCIES[code];
if (currency === undefined) {
throw Error(`${code} currency is not supported`);
}
return currency;
}
}

View File

@@ -0,0 +1,118 @@
// SPDX-FileCopyrightText: 2025 Contributors to the CitrineOS Project
//
// SPDX-License-Identifier: Apache-2.0
/* eslint-disable @typescript-eslint/no-unused-vars */
import type { CurrencyCode } from './Currency.js';
import { Currency } from './Currency.js';
import { Big } from 'big.js';
import { assert, notNull } from '../assertion/assertion.js';
export type CurrencySource = string | CurrencyCode | Currency;
export class Money {
private readonly _amount: Big;
private readonly _currency: Currency;
private constructor(amount: number | string | Big, currency: CurrencySource) {
assert(notNull(amount), 'Amount has to be defined');
assert(notNull(currency), 'Currency has to be defined');
try {
this._amount = new Big(amount);
} catch (error) {
throw new Error(`Invalid money amount: ${amount}`);
}
this._currency = typeof currency === 'string' ? Currency.of(currency) : currency;
}
get amount(): Big {
return this._amount;
}
get currency(): Currency {
return this._currency;
}
static of(amount: number | string | Big, currency: CurrencySource): Money {
return new Money(amount, currency);
}
static USD(amount: number | string | Big) {
return new Money(amount, 'USD');
}
toNumber(): number {
return this._amount.toNumber();
}
/**
* Rounds the amount down to match the currency's defined scale.
* This method could be used when converting an amount to its final monetary value.
*
* @returns {Money} A new Money instance with the amount rounded down to the currency's scale.
*/
roundToCurrencyScale(): Money {
const newAmount = this._amount.round(
this.currency.scale,
0, // RoundDown
);
return this.withAmount(newAmount);
}
multiply(multiplier: number | string | Big): Money {
return this.withAmount(this.amount.times(multiplier));
}
add(money: Money): Money {
this.requireSameCurrency(money);
return this.withAmount(this.amount.plus(money.amount));
}
subtract(money: Money): Money {
this.requireSameCurrency(money);
return this.withAmount(this.amount.minus(money.amount));
}
equals(money: Money): boolean {
return this._currency === money._currency && this.amount.eq(money.amount);
}
greaterThan(money: Money): boolean {
this.requireSameCurrency(money);
return this.amount.gt(money.amount);
}
greaterThanOrEqual(money: Money): boolean {
this.requireSameCurrency(money);
return this.amount.gte(money.amount);
}
lessThan(money: Money): boolean {
this.requireSameCurrency(money);
return this.amount.lt(money.amount);
}
lessThanOrEqual(money: Money): boolean {
this.requireSameCurrency(money);
return this.amount.lte(money.amount);
}
isZero(): boolean {
return this.amount.eq(0);
}
isPositive(): boolean {
return this.amount.gt(0);
}
isNegative(): boolean {
return this.amount.lt(0);
}
private withAmount(amount: Big): Money {
return new Money(amount, this._currency);
}
private requireSameCurrency(money: Money) {
assert(this.currency.code === money.currency.code, 'Currency mismatch');
}
}