@luca-financial/luca-schema 2.2.0 → 2.3.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/dist/esm/index.d.ts +0 -10
- package/dist/esm/index.js +19 -2
- package/dist/esm/lucaValidator.js +158 -2
- package/dist/esm/schemas/transaction.json +0 -7
- package/dist/index.d.ts +0 -10
- package/package.json +1 -1
package/dist/esm/index.d.ts
CHANGED
|
@@ -553,7 +553,6 @@ export type Transaction = Common5 & {
|
|
|
553
553
|
| 'DISPUTED'
|
|
554
554
|
| 'REFUNDED'
|
|
555
555
|
| 'DELETED';
|
|
556
|
-
deletedAt?: DeletedAt;
|
|
557
556
|
};
|
|
558
557
|
/**
|
|
559
558
|
* UUID for the item
|
|
@@ -623,10 +622,6 @@ export type StatementID = string | null;
|
|
|
623
622
|
* Identifier for this transaction in a financial data aggregation service.
|
|
624
623
|
*/
|
|
625
624
|
export type AggregationServiceID1 = string | null;
|
|
626
|
-
/**
|
|
627
|
-
* Timestamp when the transaction was soft-deleted, if applicable (UTC).
|
|
628
|
-
*/
|
|
629
|
-
export type DeletedAt = string | null;
|
|
630
625
|
/**
|
|
631
626
|
* Defines a split within a transaction.
|
|
632
627
|
*/
|
|
@@ -1040,7 +1035,6 @@ export type Transaction = Common & {
|
|
|
1040
1035
|
| 'DISPUTED'
|
|
1041
1036
|
| 'REFUNDED'
|
|
1042
1037
|
| 'DELETED';
|
|
1043
|
-
deletedAt?: DeletedAt;
|
|
1044
1038
|
};
|
|
1045
1039
|
/**
|
|
1046
1040
|
* UUID for the item
|
|
@@ -1110,10 +1104,6 @@ export type StatementID = string | null;
|
|
|
1110
1104
|
* Identifier for this transaction in a financial data aggregation service.
|
|
1111
1105
|
*/
|
|
1112
1106
|
export type AggregationServiceID = string | null;
|
|
1113
|
-
/**
|
|
1114
|
-
* Timestamp when the transaction was soft-deleted, if applicable (UTC).
|
|
1115
|
-
*/
|
|
1116
|
-
export type DeletedAt = string | null;
|
|
1117
1107
|
|
|
1118
1108
|
/**
|
|
1119
1109
|
* Common properties for all schemas
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
import * as schemaIndex from './schemas/index.js';
|
|
2
2
|
import { enums, LucaSchemas } from './enums.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
applyDefaults,
|
|
5
|
+
getRequiredFields,
|
|
6
|
+
getValidFields,
|
|
7
|
+
stripInvalidFields,
|
|
8
|
+
validate,
|
|
9
|
+
validateCollection
|
|
10
|
+
} from './lucaValidator.js';
|
|
4
11
|
|
|
5
12
|
const schemas = { ...schemaIndex, enums: schemaIndex.enums };
|
|
6
13
|
|
|
@@ -14,5 +21,15 @@ export const recurringTransactionEventSchema =
|
|
|
14
21
|
export const transactionSchema = schemas.transaction;
|
|
15
22
|
export const transactionSplitSchema = schemas.transactionSplit;
|
|
16
23
|
|
|
17
|
-
export {
|
|
24
|
+
export {
|
|
25
|
+
enums,
|
|
26
|
+
LucaSchemas,
|
|
27
|
+
schemas,
|
|
28
|
+
validate,
|
|
29
|
+
validateCollection,
|
|
30
|
+
getValidFields,
|
|
31
|
+
getRequiredFields,
|
|
32
|
+
stripInvalidFields,
|
|
33
|
+
applyDefaults
|
|
34
|
+
};
|
|
18
35
|
export default schemas;
|
|
@@ -25,6 +25,8 @@ const schemas = {
|
|
|
25
25
|
const supportSchemas = [commonSchemaJson, enumsSchemaJson];
|
|
26
26
|
|
|
27
27
|
let sharedAjv;
|
|
28
|
+
const validFieldsCache = new Map();
|
|
29
|
+
const requiredFieldsCache = new Map();
|
|
28
30
|
|
|
29
31
|
function getValidator() {
|
|
30
32
|
if (sharedAjv) return sharedAjv;
|
|
@@ -46,14 +48,168 @@ function getValidator() {
|
|
|
46
48
|
return sharedAjv;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
|
|
50
|
-
const ajv = getValidator();
|
|
51
|
+
function getSchema(schemaKey) {
|
|
51
52
|
const schema = schemas[schemaKey];
|
|
52
53
|
if (!schema) {
|
|
53
54
|
throw new Error(`Unknown schema: ${schemaKey}`);
|
|
54
55
|
}
|
|
56
|
+
return schema;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function usesCommonSchema(schema) {
|
|
60
|
+
if (!Array.isArray(schema?.allOf)) return false;
|
|
61
|
+
return schema.allOf.some(entry => {
|
|
62
|
+
if (!entry || typeof entry !== 'object') return false;
|
|
63
|
+
if (typeof entry.$ref !== 'string') return false;
|
|
64
|
+
return entry.$ref.includes('common.json');
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function getSchemaProperties(schema) {
|
|
69
|
+
const properties = schema?.properties ?? {};
|
|
70
|
+
if (!usesCommonSchema(schema)) return properties;
|
|
71
|
+
return {
|
|
72
|
+
...commonSchemaJson.properties,
|
|
73
|
+
...properties
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getSchemaRequired(schema) {
|
|
78
|
+
const required = Array.isArray(schema?.required) ? schema.required : [];
|
|
79
|
+
if (!usesCommonSchema(schema)) return required;
|
|
80
|
+
const commonRequired = Array.isArray(commonSchemaJson.required)
|
|
81
|
+
? commonSchemaJson.required
|
|
82
|
+
: [];
|
|
83
|
+
return [...commonRequired, ...required];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function isPlainObject(value) {
|
|
87
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) return false;
|
|
88
|
+
const proto = Object.getPrototypeOf(value);
|
|
89
|
+
return proto === Object.prototype || proto === null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function cloneDefault(value) {
|
|
93
|
+
if (typeof structuredClone === 'function') return structuredClone(value);
|
|
94
|
+
if (value && typeof value === 'object') {
|
|
95
|
+
return JSON.parse(JSON.stringify(value));
|
|
96
|
+
}
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function validate(schemaKey, data) {
|
|
101
|
+
const ajv = getValidator();
|
|
102
|
+
const schema = getSchema(schemaKey);
|
|
55
103
|
const isValid = ajv.validate(schema, data);
|
|
56
104
|
return { valid: isValid, errors: ajv.errors ?? [] };
|
|
57
105
|
}
|
|
58
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Returns a cached Set of valid field names for the given schema key.
|
|
109
|
+
* Treat the returned Set as read-only.
|
|
110
|
+
* @param {string} schemaKey
|
|
111
|
+
* @returns {Set<string>}
|
|
112
|
+
*/
|
|
113
|
+
export function getValidFields(schemaKey) {
|
|
114
|
+
if (validFieldsCache.has(schemaKey)) {
|
|
115
|
+
return validFieldsCache.get(schemaKey);
|
|
116
|
+
}
|
|
117
|
+
const schema = getSchema(schemaKey);
|
|
118
|
+
const properties = getSchemaProperties(schema);
|
|
119
|
+
const fields = new Set(Object.keys(properties));
|
|
120
|
+
validFieldsCache.set(schemaKey, fields);
|
|
121
|
+
return fields;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Returns a cached Set of required field names for the given schema key.
|
|
126
|
+
* Treat the returned Set as read-only.
|
|
127
|
+
* @param {string} schemaKey
|
|
128
|
+
* @returns {Set<string>}
|
|
129
|
+
*/
|
|
130
|
+
export function getRequiredFields(schemaKey) {
|
|
131
|
+
if (requiredFieldsCache.has(schemaKey)) {
|
|
132
|
+
return requiredFieldsCache.get(schemaKey);
|
|
133
|
+
}
|
|
134
|
+
const schema = getSchema(schemaKey);
|
|
135
|
+
const required = getSchemaRequired(schema);
|
|
136
|
+
const fields = new Set(required);
|
|
137
|
+
requiredFieldsCache.set(schemaKey, fields);
|
|
138
|
+
return fields;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Returns a new object containing only fields defined in the schema.
|
|
143
|
+
* @param {string} schemaKey
|
|
144
|
+
* @param {object | null | undefined} data
|
|
145
|
+
* @returns {object}
|
|
146
|
+
*/
|
|
147
|
+
export function stripInvalidFields(schemaKey, data) {
|
|
148
|
+
if (data === null || data === undefined) return {};
|
|
149
|
+
if (!isPlainObject(data)) {
|
|
150
|
+
throw new TypeError('Expected a plain object for data');
|
|
151
|
+
}
|
|
152
|
+
const validFields = getValidFields(schemaKey);
|
|
153
|
+
const cleaned = {};
|
|
154
|
+
for (const [key, value] of Object.entries(data)) {
|
|
155
|
+
if (validFields.has(key)) cleaned[key] = value;
|
|
156
|
+
}
|
|
157
|
+
return cleaned;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Returns a new object with top-level schema defaults applied for missing fields.
|
|
162
|
+
* @param {string} schemaKey
|
|
163
|
+
* @param {object | null | undefined} data
|
|
164
|
+
* @returns {object}
|
|
165
|
+
*/
|
|
166
|
+
export function applyDefaults(schemaKey, data) {
|
|
167
|
+
if (data === null || data === undefined) return {};
|
|
168
|
+
if (!isPlainObject(data)) {
|
|
169
|
+
throw new TypeError('Expected a plain object for data');
|
|
170
|
+
}
|
|
171
|
+
const schema = getSchema(schemaKey);
|
|
172
|
+
const properties = getSchemaProperties(schema);
|
|
173
|
+
const next = { ...data };
|
|
174
|
+
for (const [key, definition] of Object.entries(properties)) {
|
|
175
|
+
if (next[key] !== undefined) continue;
|
|
176
|
+
if (
|
|
177
|
+
definition &&
|
|
178
|
+
Object.prototype.hasOwnProperty.call(definition, 'default')
|
|
179
|
+
) {
|
|
180
|
+
next[key] = cloneDefault(definition.default);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return next;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Validates an array of entities efficiently and returns structured errors.
|
|
188
|
+
* @param {string} schemaKey
|
|
189
|
+
* @param {Array<any>} arrayOfEntities
|
|
190
|
+
* @returns {{ valid: boolean, errors: Array<{ index: number, entity: any, errors: Array<any> }> }}
|
|
191
|
+
*/
|
|
192
|
+
export function validateCollection(schemaKey, arrayOfEntities) {
|
|
193
|
+
if (!Array.isArray(arrayOfEntities)) {
|
|
194
|
+
throw new TypeError('Expected an array of entities');
|
|
195
|
+
}
|
|
196
|
+
const ajv = getValidator();
|
|
197
|
+
const schema = getSchema(schemaKey);
|
|
198
|
+
const validateFn = ajv.getSchema(schema.$id) ?? ajv.compile(schema);
|
|
199
|
+
const errors = [];
|
|
200
|
+
|
|
201
|
+
arrayOfEntities.forEach((entity, index) => {
|
|
202
|
+
const isValid = validateFn(entity);
|
|
203
|
+
if (!isValid) {
|
|
204
|
+
errors.push({
|
|
205
|
+
index,
|
|
206
|
+
entity,
|
|
207
|
+
errors: validateFn.errors ?? []
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
return { valid: errors.length === 0, errors };
|
|
213
|
+
}
|
|
214
|
+
|
|
59
215
|
export { schemas };
|
|
@@ -84,13 +84,6 @@
|
|
|
84
84
|
"title": "Transaction State",
|
|
85
85
|
"$ref": "./enums.json#/$defs/TransactionState",
|
|
86
86
|
"description": "The current state of the transaction."
|
|
87
|
-
},
|
|
88
|
-
"deletedAt": {
|
|
89
|
-
"type": ["string", "null"],
|
|
90
|
-
"title": "Deleted At",
|
|
91
|
-
"format": "date-time",
|
|
92
|
-
"pattern": "Z$",
|
|
93
|
-
"description": "Timestamp when the transaction was soft-deleted, if applicable (UTC)."
|
|
94
87
|
}
|
|
95
88
|
},
|
|
96
89
|
"required": ["accountId", "date", "amount", "description", "transactionState"]
|
package/dist/index.d.ts
CHANGED
|
@@ -553,7 +553,6 @@ export type Transaction = Common5 & {
|
|
|
553
553
|
| 'DISPUTED'
|
|
554
554
|
| 'REFUNDED'
|
|
555
555
|
| 'DELETED';
|
|
556
|
-
deletedAt?: DeletedAt;
|
|
557
556
|
};
|
|
558
557
|
/**
|
|
559
558
|
* UUID for the item
|
|
@@ -623,10 +622,6 @@ export type StatementID = string | null;
|
|
|
623
622
|
* Identifier for this transaction in a financial data aggregation service.
|
|
624
623
|
*/
|
|
625
624
|
export type AggregationServiceID1 = string | null;
|
|
626
|
-
/**
|
|
627
|
-
* Timestamp when the transaction was soft-deleted, if applicable (UTC).
|
|
628
|
-
*/
|
|
629
|
-
export type DeletedAt = string | null;
|
|
630
625
|
/**
|
|
631
626
|
* Defines a split within a transaction.
|
|
632
627
|
*/
|
|
@@ -1040,7 +1035,6 @@ export type Transaction = Common & {
|
|
|
1040
1035
|
| 'DISPUTED'
|
|
1041
1036
|
| 'REFUNDED'
|
|
1042
1037
|
| 'DELETED';
|
|
1043
|
-
deletedAt?: DeletedAt;
|
|
1044
1038
|
};
|
|
1045
1039
|
/**
|
|
1046
1040
|
* UUID for the item
|
|
@@ -1110,10 +1104,6 @@ export type StatementID = string | null;
|
|
|
1110
1104
|
* Identifier for this transaction in a financial data aggregation service.
|
|
1111
1105
|
*/
|
|
1112
1106
|
export type AggregationServiceID = string | null;
|
|
1113
|
-
/**
|
|
1114
|
-
* Timestamp when the transaction was soft-deleted, if applicable (UTC).
|
|
1115
|
-
*/
|
|
1116
|
-
export type DeletedAt = string | null;
|
|
1117
1107
|
|
|
1118
1108
|
/**
|
|
1119
1109
|
* Common properties for all schemas
|