beancount 0.0.31 → 0.2.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 +51 -22
- package/build/src/benchmark.mjs +1 -1
- package/build/src/classes/DatedNode.d.mts +40 -0
- package/build/src/classes/DatedNode.mjs +61 -0
- package/build/src/classes/Node.d.mts +92 -0
- package/build/src/classes/Node.mjs +107 -0
- package/build/src/classes/ParseResult.d.mts +75 -75
- package/build/src/classes/ParseResult.mjs +96 -98
- package/build/src/classes/nodes/Balance.d.mts +32 -0
- package/build/src/classes/nodes/Balance.mjs +50 -0
- package/build/src/classes/nodes/Blankline.d.mts +23 -0
- package/build/src/classes/nodes/Blankline.mjs +37 -0
- package/build/src/classes/nodes/Close.d.mts +20 -0
- package/build/src/classes/nodes/Close.mjs +31 -0
- package/build/src/classes/nodes/Comment.d.mts +25 -0
- package/build/src/classes/nodes/Comment.mjs +42 -0
- package/build/src/classes/nodes/Commodity.d.mts +20 -0
- package/build/src/classes/nodes/Commodity.mjs +31 -0
- package/build/src/classes/nodes/Custom.d.mts +23 -0
- package/build/src/classes/nodes/Custom.mjs +38 -0
- package/build/src/classes/nodes/Document.d.mts +22 -0
- package/build/src/classes/nodes/Document.mjs +34 -0
- package/build/src/classes/nodes/Event.d.mts +23 -0
- package/build/src/classes/nodes/Event.mjs +34 -0
- package/build/src/classes/nodes/Include.d.mts +20 -0
- package/build/src/classes/nodes/Include.mjs +31 -0
- package/build/src/classes/nodes/Note.d.mts +22 -0
- package/build/src/classes/nodes/Note.mjs +34 -0
- package/build/src/classes/nodes/Open.d.mts +27 -0
- package/build/src/classes/nodes/Open.mjs +66 -0
- package/build/src/classes/nodes/Option.d.mts +23 -0
- package/build/src/classes/nodes/Option.mjs +32 -0
- package/build/src/classes/nodes/Pad.d.mts +22 -0
- package/build/src/classes/nodes/Pad.mjs +33 -0
- package/build/src/classes/nodes/Plugin.d.mts +22 -0
- package/build/src/classes/nodes/Plugin.mjs +36 -0
- package/build/src/classes/nodes/Poptag.d.mts +21 -0
- package/build/src/classes/nodes/Poptag.mjs +34 -0
- package/build/src/classes/nodes/Price.d.mts +32 -0
- package/build/src/classes/nodes/Price.mjs +57 -0
- package/build/src/classes/nodes/Pushtag.d.mts +21 -0
- package/build/src/classes/nodes/Pushtag.mjs +34 -0
- package/build/src/classes/nodes/Query.d.mts +22 -0
- package/build/src/classes/nodes/Query.mjs +34 -0
- package/build/src/classes/nodes/Transaction/Posting.d.mts +59 -0
- package/build/src/classes/nodes/Transaction/Posting.mjs +97 -0
- package/build/src/classes/nodes/Transaction/Tag.d.mts +28 -0
- package/build/src/classes/nodes/Transaction/Tag.mjs +28 -0
- package/build/src/classes/nodes/Transaction/index.d.mts +70 -0
- package/build/src/classes/nodes/Transaction/index.mjs +193 -0
- package/build/src/classes/nodes/index.d.mts +19 -0
- package/build/src/classes/nodes/index.mjs +19 -0
- package/build/src/cli.mjs +4 -4
- package/build/src/deserialize.d.mts +54 -54
- package/build/src/deserialize.mjs +89 -89
- package/build/src/directiveTypes.d.mts +10 -0
- package/build/src/directiveTypes.mjs +29 -0
- package/build/src/genericParse.d.mts +27 -20
- package/build/src/genericParse.mjs +30 -30
- package/build/src/main.d.mts +30 -31
- package/build/src/main.mjs +30 -30
- package/build/src/nodeTypeToClass.d.mts +81 -0
- package/build/src/nodeTypeToClass.mjs +37 -0
- package/build/src/parse.d.mts +16 -16
- package/build/src/parse.mjs +37 -37
- package/build/src/parseFile.d.mts +2 -2
- package/build/src/parseFile.mjs +11 -11
- package/build/src/utils/splitStringIntoSourceFragments.d.ts +14 -0
- package/build/src/utils/splitStringIntoSourceFragments.js +48 -0
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +7 -7
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { nodeTypeToClass } from './nodeTypeToClass.mjs';
|
|
2
2
|
/**
|
|
3
|
-
* Deserializes a single
|
|
3
|
+
* Deserializes a single node from its JSON representation.
|
|
4
4
|
*
|
|
5
5
|
* This function takes a plain JavaScript object (typically from JSON.parse)
|
|
6
|
-
* and reconstructs the appropriate
|
|
6
|
+
* and reconstructs the appropriate Node subclass instance. It validates
|
|
7
7
|
* the input and provides helpful error messages for common issues.
|
|
8
8
|
*
|
|
9
|
-
* @param
|
|
10
|
-
* @returns An
|
|
11
|
-
* @throws {Error} If the
|
|
9
|
+
* @param nodeData - Plain object containing node data with a 'type' field
|
|
10
|
+
* @returns An Node instance of the appropriate subclass
|
|
11
|
+
* @throws {Error} If the node data is invalid:
|
|
12
12
|
* - Missing or invalid 'type' field
|
|
13
|
-
* - Unknown
|
|
14
|
-
* - Invalid
|
|
13
|
+
* - Unknown node type
|
|
14
|
+
* - Invalid node structure (errors from Node.fromJSONData)
|
|
15
15
|
*
|
|
16
16
|
* @example
|
|
17
|
-
* Deserializing a simple
|
|
17
|
+
* Deserializing a simple node:
|
|
18
18
|
* ```typescript
|
|
19
|
-
* const
|
|
19
|
+
* const nodeData = {
|
|
20
20
|
* type: 'open',
|
|
21
21
|
* date: '2024-01-01',
|
|
22
22
|
* account: 'Assets:Checking'
|
|
23
23
|
* }
|
|
24
|
-
* const
|
|
25
|
-
* console.log(
|
|
24
|
+
* const node = deserializeNode(nodeData)
|
|
25
|
+
* console.log(node.type) // 'open'
|
|
26
26
|
* ```
|
|
27
27
|
*
|
|
28
28
|
* @example
|
|
29
29
|
* Deserializing from JSON.parse:
|
|
30
30
|
* ```typescript
|
|
31
31
|
* const json = '{"type":"balance","date":"2024-01-02","account":"Assets:Checking","amount":"100","currency":"USD"}'
|
|
32
|
-
* const
|
|
33
|
-
* const
|
|
32
|
+
* const nodeData = JSON.parse(json)
|
|
33
|
+
* const node = deserializeNode(nodeData)
|
|
34
34
|
* ```
|
|
35
35
|
*/
|
|
36
|
-
export function
|
|
36
|
+
export function deserializeNode(nodeData) {
|
|
37
37
|
// Validate input is an object
|
|
38
|
-
if (!
|
|
39
|
-
throw new Error(`Invalid
|
|
38
|
+
if (!nodeData || typeof nodeData !== 'object') {
|
|
39
|
+
throw new Error(`Invalid node data: expected an object but received ${typeof nodeData}`);
|
|
40
40
|
}
|
|
41
41
|
// Validate 'type' field exists
|
|
42
|
-
if (!('type' in
|
|
43
|
-
throw new Error('Invalid
|
|
44
|
-
'
|
|
42
|
+
if (!('type' in nodeData)) {
|
|
43
|
+
throw new Error('Invalid node data: missing required "type" field. ' +
|
|
44
|
+
'Node data must include a "type" property indicating the node type.');
|
|
45
45
|
}
|
|
46
46
|
// Validate 'type' is a string
|
|
47
|
-
if (typeof
|
|
48
|
-
throw new Error(`Invalid
|
|
47
|
+
if (typeof nodeData.type !== 'string') {
|
|
48
|
+
throw new Error(`Invalid node data: "type" field must be a string, but received ${typeof nodeData.type}`);
|
|
49
49
|
}
|
|
50
|
-
const
|
|
51
|
-
// Validate
|
|
52
|
-
const
|
|
53
|
-
if (!
|
|
54
|
-
throw new Error(`Unknown
|
|
55
|
-
`Valid
|
|
50
|
+
const nodeType = nodeData.type;
|
|
51
|
+
// Validate node type is recognized
|
|
52
|
+
const NodeClass = nodeTypeToClass[nodeType];
|
|
53
|
+
if (!NodeClass) {
|
|
54
|
+
throw new Error(`Unknown node type: "${nodeType}". ` +
|
|
55
|
+
`Valid node types are: ${Object.keys(nodeTypeToClass).join(', ')}`);
|
|
56
56
|
}
|
|
57
|
-
// Attempt to deserialize the
|
|
57
|
+
// Attempt to deserialize the node
|
|
58
58
|
try {
|
|
59
|
-
return
|
|
59
|
+
return NodeClass.fromJSONData(nodeData);
|
|
60
60
|
}
|
|
61
61
|
catch (error) {
|
|
62
62
|
// Wrap errors from fromJSONData with additional context
|
|
63
63
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
64
|
-
throw new Error(`Failed to deserialize ${
|
|
64
|
+
throw new Error(`Failed to deserialize ${nodeType} node: ${errorMessage}`);
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
|
-
* Deserializes a single
|
|
68
|
+
* Deserializes a single node from a JSON string.
|
|
69
69
|
*
|
|
70
|
-
* This function parses a JSON string containing an
|
|
71
|
-
* and reconstructs the appropriate
|
|
70
|
+
* This function parses a JSON string containing an node object
|
|
71
|
+
* and reconstructs the appropriate Node subclass instance.
|
|
72
72
|
*
|
|
73
|
-
* @param jsonString - JSON string containing an
|
|
74
|
-
* @returns An
|
|
75
|
-
* @throws {Error} If the JSON is invalid or
|
|
73
|
+
* @param jsonString - JSON string containing an node object
|
|
74
|
+
* @returns An Node instance of the appropriate subclass
|
|
75
|
+
* @throws {Error} If the JSON is invalid or node cannot be deserialized:
|
|
76
76
|
* - Invalid JSON syntax
|
|
77
77
|
* - JSON does not contain an object
|
|
78
|
-
* -
|
|
78
|
+
* - Node validation errors (see deserializeNode)
|
|
79
79
|
*
|
|
80
80
|
* @example
|
|
81
81
|
* Deserializing from a JSON string:
|
|
82
82
|
* ```typescript
|
|
83
83
|
* const json = '{"type":"open","date":"2024-01-01","account":"Assets:Checking"}'
|
|
84
|
-
* const
|
|
85
|
-
* console.log(
|
|
84
|
+
* const node = deserializeNodeFromString(json)
|
|
85
|
+
* console.log(node.type) // 'open'
|
|
86
86
|
* ```
|
|
87
87
|
*
|
|
88
88
|
* @example
|
|
@@ -90,56 +90,56 @@ export function deserializeEntry(entryData) {
|
|
|
90
90
|
* ```typescript
|
|
91
91
|
* const original = Open.fromString('2024-01-01 open Assets:Checking')
|
|
92
92
|
* const json = JSON.stringify(original.toJSON())
|
|
93
|
-
* const deserialized =
|
|
93
|
+
* const deserialized = deserializeNodeFromString(json)
|
|
94
94
|
* // deserialized equals original
|
|
95
95
|
* ```
|
|
96
96
|
*/
|
|
97
|
-
export function
|
|
97
|
+
export function deserializeNodeFromString(jsonString) {
|
|
98
98
|
// Validate input
|
|
99
99
|
if (typeof jsonString !== 'string') {
|
|
100
100
|
throw new Error(`Invalid input: expected a JSON string but received ${typeof jsonString}`);
|
|
101
101
|
}
|
|
102
102
|
// Parse JSON with error handling
|
|
103
|
-
let
|
|
103
|
+
let nodeData;
|
|
104
104
|
try {
|
|
105
|
-
|
|
105
|
+
nodeData = JSON.parse(jsonString);
|
|
106
106
|
}
|
|
107
107
|
catch (error) {
|
|
108
108
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
109
109
|
throw new Error(`Failed to parse JSON: ${errorMessage}`);
|
|
110
110
|
}
|
|
111
111
|
// Validate parsed data is an object (not array or null)
|
|
112
|
-
if (
|
|
113
|
-
throw new Error(`Invalid JSON structure: expected an object but received ${
|
|
112
|
+
if (nodeData === null || typeof nodeData !== 'object') {
|
|
113
|
+
throw new Error(`Invalid JSON structure: expected an object but received ${nodeData === null ? 'null' : typeof nodeData}`);
|
|
114
114
|
}
|
|
115
|
-
if (Array.isArray(
|
|
115
|
+
if (Array.isArray(nodeData)) {
|
|
116
116
|
throw new Error('Invalid JSON structure: expected an object but received an array');
|
|
117
117
|
}
|
|
118
|
-
return
|
|
118
|
+
return deserializeNode(nodeData);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
|
-
* Deserializes an array of
|
|
121
|
+
* Deserializes an array of nodes from their JSON representations.
|
|
122
122
|
*
|
|
123
123
|
* This function takes an array of plain JavaScript objects (typically from JSON.parse)
|
|
124
|
-
* and reconstructs each as the appropriate
|
|
125
|
-
* the input and provides helpful error messages, including the index of any
|
|
124
|
+
* and reconstructs each as the appropriate Node subclass instance. It validates
|
|
125
|
+
* the input and provides helpful error messages, including the index of any node
|
|
126
126
|
* that fails to deserialize.
|
|
127
127
|
*
|
|
128
|
-
* @param
|
|
129
|
-
* @returns Array of
|
|
130
|
-
* @throws {Error} If the input is invalid or
|
|
128
|
+
* @param nodesData - Array of plain objects containing node data
|
|
129
|
+
* @returns Array of Node instances
|
|
130
|
+
* @throws {Error} If the input is invalid or nodes cannot be deserialized:
|
|
131
131
|
* - Input is not an array
|
|
132
|
-
* - Any
|
|
132
|
+
* - Any node fails validation (see deserializeNode)
|
|
133
133
|
*
|
|
134
134
|
* @example
|
|
135
|
-
* Deserializing an array of
|
|
135
|
+
* Deserializing an array of nodes:
|
|
136
136
|
* ```typescript
|
|
137
|
-
* const
|
|
137
|
+
* const nodesData = [
|
|
138
138
|
* { type: 'open', date: '2024-01-01', account: 'Assets:Checking' },
|
|
139
139
|
* { type: 'balance', date: '2024-01-02', account: 'Assets:Checking', amount: '100', currency: 'USD' }
|
|
140
140
|
* ]
|
|
141
|
-
* const
|
|
142
|
-
* console.log(
|
|
141
|
+
* const nodes = deserializeNodes(nodesData)
|
|
142
|
+
* console.log(nodes.length) // 2
|
|
143
143
|
* ```
|
|
144
144
|
*
|
|
145
145
|
* @example
|
|
@@ -148,52 +148,52 @@ export function deserializeEntryFromString(jsonString) {
|
|
|
148
148
|
* const original = [Open.fromString('2024-01-01 open Assets:Checking')]
|
|
149
149
|
* const json = JSON.stringify(original.map(e => e.toJSON()))
|
|
150
150
|
* const parsed = JSON.parse(json)
|
|
151
|
-
* const deserialized =
|
|
151
|
+
* const deserialized = deserializeNodes(parsed)
|
|
152
152
|
* // deserialized equals original
|
|
153
153
|
* ```
|
|
154
154
|
*/
|
|
155
|
-
export function
|
|
155
|
+
export function deserializeNodes(nodesData) {
|
|
156
156
|
// Validate input is an array
|
|
157
|
-
if (!Array.isArray(
|
|
158
|
-
throw new Error(`Invalid input: expected an array but received ${typeof
|
|
157
|
+
if (!Array.isArray(nodesData)) {
|
|
158
|
+
throw new Error(`Invalid input: expected an array but received ${typeof nodesData}`);
|
|
159
159
|
}
|
|
160
|
-
// Deserialize each
|
|
161
|
-
const
|
|
162
|
-
for (let i = 0; i <
|
|
160
|
+
// Deserialize each node with error context
|
|
161
|
+
const nodes = [];
|
|
162
|
+
for (let i = 0; i < nodesData.length; i++) {
|
|
163
163
|
try {
|
|
164
|
-
|
|
164
|
+
nodes.push(deserializeNode(nodesData[i]));
|
|
165
165
|
}
|
|
166
166
|
catch (error) {
|
|
167
167
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
168
|
-
throw new Error(`Failed to deserialize
|
|
168
|
+
throw new Error(`Failed to deserialize node at index ${i}: ${errorMessage}`);
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
return
|
|
171
|
+
return nodes;
|
|
172
172
|
}
|
|
173
173
|
/**
|
|
174
|
-
* Deserializes an array of
|
|
174
|
+
* Deserializes an array of nodes from a JSON string.
|
|
175
175
|
*
|
|
176
|
-
* This function parses a JSON string containing an array of
|
|
177
|
-
* and reconstructs each
|
|
176
|
+
* This function parses a JSON string containing an array of node objects
|
|
177
|
+
* and reconstructs each node as the appropriate Node subclass instance.
|
|
178
178
|
* It validates the input and provides helpful error messages, including
|
|
179
|
-
* the index of any
|
|
179
|
+
* the index of any node that fails to deserialize.
|
|
180
180
|
*
|
|
181
|
-
* @param jsonString - JSON string containing an array of
|
|
182
|
-
* @returns Array of
|
|
183
|
-
* @throws {Error} If the JSON is invalid or
|
|
181
|
+
* @param jsonString - JSON string containing an array of node objects
|
|
182
|
+
* @returns Array of Node instances
|
|
183
|
+
* @throws {Error} If the JSON is invalid or nodes cannot be deserialized:
|
|
184
184
|
* - Invalid JSON syntax
|
|
185
185
|
* - JSON does not contain an array
|
|
186
|
-
* - Any
|
|
186
|
+
* - Any node fails validation (see deserializeNode)
|
|
187
187
|
*
|
|
188
188
|
* @example
|
|
189
|
-
* Deserializing multiple
|
|
189
|
+
* Deserializing multiple nodes:
|
|
190
190
|
* ```typescript
|
|
191
191
|
* const json = '[
|
|
192
192
|
* {"type": "open", "date": "2024-01-01", "account": "Assets:Checking"},
|
|
193
193
|
* {"type": "balance", "date": "2024-01-02", "account": "Assets:Checking", "amount": "100", "currency": "USD"}
|
|
194
194
|
* ]'
|
|
195
|
-
* const
|
|
196
|
-
* console.log(
|
|
195
|
+
* const nodes = deserializeNodes(json)
|
|
196
|
+
* console.log(nodes.length) // 2
|
|
197
197
|
* ```
|
|
198
198
|
*
|
|
199
199
|
* @example
|
|
@@ -202,28 +202,28 @@ export function deserializeEntries(entriesData) {
|
|
|
202
202
|
* import { parse } from 'beancount'
|
|
203
203
|
*
|
|
204
204
|
* const original = parse('2024-01-01 open Assets:Checking')
|
|
205
|
-
* const json = JSON.stringify(original.
|
|
206
|
-
* const deserialized =
|
|
207
|
-
* // deserialized equals original.
|
|
205
|
+
* const json = JSON.stringify(original.nodes.map(e => e.toJSON()))
|
|
206
|
+
* const deserialized = deserializeNodes(json)
|
|
207
|
+
* // deserialized equals original.nodes
|
|
208
208
|
* ```
|
|
209
209
|
*/
|
|
210
|
-
export function
|
|
210
|
+
export function deserializeNodesFromString(jsonString) {
|
|
211
211
|
// Validate input
|
|
212
212
|
if (typeof jsonString !== 'string') {
|
|
213
213
|
throw new Error(`Invalid input: expected a JSON string but received ${typeof jsonString}`);
|
|
214
214
|
}
|
|
215
215
|
// Parse JSON with error handling
|
|
216
|
-
let
|
|
216
|
+
let nodesData;
|
|
217
217
|
try {
|
|
218
|
-
|
|
218
|
+
nodesData = JSON.parse(jsonString);
|
|
219
219
|
}
|
|
220
220
|
catch (error) {
|
|
221
221
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
222
222
|
throw new Error(`Failed to parse JSON: ${errorMessage}`);
|
|
223
223
|
}
|
|
224
224
|
// Validate parsed data is an array
|
|
225
|
-
if (!Array.isArray(
|
|
226
|
-
throw new Error(`Invalid JSON structure: expected an array but received ${typeof
|
|
225
|
+
if (!Array.isArray(nodesData)) {
|
|
226
|
+
throw new Error(`Invalid JSON structure: expected an array but received ${typeof nodesData}`);
|
|
227
227
|
}
|
|
228
|
-
return
|
|
228
|
+
return deserializeNodes(nodesData);
|
|
229
229
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Array of all Beancount directive types that start with a date (YYYY-MM-DD format).
|
|
3
|
+
* These directives follow the pattern: `YYYY-MM-DD <type> ...`
|
|
4
|
+
*/
|
|
5
|
+
export declare const DATED_DIRECTIVE_TYPES: readonly ["balance", "close", "commodity", "custom", "document", "event", "note", "open", "pad", "price", "query", "transaction"];
|
|
6
|
+
/**
|
|
7
|
+
* Array of all Beancount directive types that do NOT start with a date.
|
|
8
|
+
* These directives follow the pattern: `<type> ...`
|
|
9
|
+
*/
|
|
10
|
+
export declare const NON_DATED_DIRECTIVE_TYPES: readonly ["include", "option", "plugin", "poptag", "pushtag"];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Array of all Beancount directive types that start with a date (YYYY-MM-DD format).
|
|
3
|
+
* These directives follow the pattern: `YYYY-MM-DD <type> ...`
|
|
4
|
+
*/
|
|
5
|
+
export const DATED_DIRECTIVE_TYPES = [
|
|
6
|
+
'balance',
|
|
7
|
+
'close',
|
|
8
|
+
'commodity',
|
|
9
|
+
'custom',
|
|
10
|
+
'document',
|
|
11
|
+
'event',
|
|
12
|
+
'note',
|
|
13
|
+
'open',
|
|
14
|
+
'pad',
|
|
15
|
+
'price',
|
|
16
|
+
'query',
|
|
17
|
+
'transaction',
|
|
18
|
+
];
|
|
19
|
+
/**
|
|
20
|
+
* Array of all Beancount directive types that do NOT start with a date.
|
|
21
|
+
* These directives follow the pattern: `<type> ...`
|
|
22
|
+
*/
|
|
23
|
+
export const NON_DATED_DIRECTIVE_TYPES = [
|
|
24
|
+
'include',
|
|
25
|
+
'option',
|
|
26
|
+
'plugin',
|
|
27
|
+
'poptag',
|
|
28
|
+
'pushtag',
|
|
29
|
+
];
|
|
@@ -1,27 +1,34 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BeancountDirectiveNodeType, SyntheticNodeType } from './nodeTypeToClass.mjs';
|
|
2
2
|
import { type Metadata } from './utils/parseMetadata.mjs';
|
|
3
3
|
/**
|
|
4
|
-
* The basic result structure from generic parsing of a Beancount
|
|
5
|
-
* Contains the
|
|
4
|
+
* The basic result structure from generic parsing of a Beancount directive.
|
|
5
|
+
* Contains the directive type, header line content, and any properties like comments.
|
|
6
6
|
*/
|
|
7
7
|
export interface GenericParseResult {
|
|
8
|
-
/** The type of Beancount
|
|
9
|
-
type:
|
|
10
|
-
/** The main header content from the first line of the
|
|
8
|
+
/** The type of Beancount directive (e.g., 'open', 'close', 'balance') */
|
|
9
|
+
type: BeancountDirectiveNodeType;
|
|
10
|
+
/** The main header content from the first line of the directive */
|
|
11
11
|
header: string;
|
|
12
|
-
/** Properties extracted from the
|
|
12
|
+
/** Properties extracted from the directive */
|
|
13
13
|
props: {
|
|
14
14
|
/** Optional comment text following a semicolon */
|
|
15
15
|
comment?: string;
|
|
16
16
|
};
|
|
17
|
-
|
|
17
|
+
synthetic?: false;
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Generic parse result for synthetic (non-directive) nodes.
|
|
21
|
+
* These represent content that doesn't correspond to actual Beancount directives,
|
|
22
|
+
* such as comments and blank lines, which are preserved to maintain file structure.
|
|
23
|
+
*/
|
|
24
|
+
export interface GenericParseResultSyntheticNode extends Omit<GenericParseResult, 'synthetic' | 'type'> {
|
|
25
|
+
/** The synthetic node type (e.g., 'comment', 'blankline') */
|
|
26
|
+
type: SyntheticNodeType;
|
|
27
|
+
/** Always true to distinguish synthetic nodes from real Beancount directives */
|
|
28
|
+
synthetic: true;
|
|
22
29
|
}
|
|
23
30
|
/**
|
|
24
|
-
* Generic parse result for
|
|
31
|
+
* Generic parse result for directives that include a date field.
|
|
25
32
|
* Extends the base result with date and metadata properties.
|
|
26
33
|
*/
|
|
27
34
|
export interface GenericParseResultWithDate extends GenericParseResult {
|
|
@@ -34,7 +41,7 @@ export interface GenericParseResultWithDate extends GenericParseResult {
|
|
|
34
41
|
};
|
|
35
42
|
}
|
|
36
43
|
/**
|
|
37
|
-
* Generic parse result specifically for transaction
|
|
44
|
+
* Generic parse result specifically for transaction directives.
|
|
38
45
|
* Extends the dated result with transaction-specific fields like body lines and flags.
|
|
39
46
|
*/
|
|
40
47
|
export interface GenericParseResultTransaction extends Omit<GenericParseResultWithDate, 'metadata'> {
|
|
@@ -51,16 +58,16 @@ export interface GenericParseResultTransaction extends Omit<GenericParseResultWi
|
|
|
51
58
|
};
|
|
52
59
|
}
|
|
53
60
|
/**
|
|
54
|
-
* Performs generic parsing on
|
|
61
|
+
* Performs generic parsing on a source fragment to extract common fields.
|
|
55
62
|
*
|
|
56
63
|
* This function:
|
|
57
|
-
* - Detects if the
|
|
58
|
-
* - Identifies the
|
|
64
|
+
* - Detects if the directive has a date (YYYY-MM-DD format)
|
|
65
|
+
* - Identifies the directive type
|
|
59
66
|
* - Extracts header content and comments
|
|
60
67
|
* - Handles transaction-specific parsing (flags, body lines)
|
|
61
|
-
* - Parses metadata for dated
|
|
68
|
+
* - Parses metadata for dated directives
|
|
62
69
|
*
|
|
63
|
-
* @param
|
|
64
|
-
* @returns A generic parse result object appropriate for the
|
|
70
|
+
* @param sourceFragment - Array of strings that should be parsed to a single node
|
|
71
|
+
* @returns A generic parse result object appropriate for the node type
|
|
65
72
|
*/
|
|
66
|
-
export declare const genericParse: (
|
|
73
|
+
export declare const genericParse: (sourceFragment: string[]) => GenericParseResult | GenericParseResultTransaction | GenericParseResultWithDate | GenericParseResultSyntheticNode;
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DATED_DIRECTIVE_TYPES, NON_DATED_DIRECTIVE_TYPES, } from './directiveTypes.mjs';
|
|
2
2
|
import { parseMetadata } from './utils/parseMetadata.mjs';
|
|
3
3
|
/**
|
|
4
|
-
* Compiles a regex pattern that validates both date format AND
|
|
4
|
+
* Compiles a regex pattern that validates both date format AND directive type.
|
|
5
5
|
*
|
|
6
6
|
* The generated pattern matches lines starting with:
|
|
7
7
|
* - Date in YYYY-MM-DD format
|
|
8
8
|
* - Followed by one or more whitespace characters
|
|
9
9
|
* - Followed by either:
|
|
10
|
-
* - A valid dated
|
|
10
|
+
* - A valid dated node type keyword from {@link DATED_DIRECTIVE_TYPES}
|
|
11
11
|
* - A transaction flag (* or !)
|
|
12
12
|
* - The transaction alias 'txn'
|
|
13
13
|
* - Followed by a word boundary to prevent partial matches
|
|
14
14
|
*
|
|
15
|
-
* This ensures that only valid Beancount directives with correct
|
|
16
|
-
* are recognized. Invalid
|
|
15
|
+
* This ensures that only valid Beancount directives with correct node types
|
|
16
|
+
* are recognized. Invalid directive types will be treated as comments.
|
|
17
17
|
*
|
|
18
18
|
* Pattern: `^YYYY-MM-DD\s+(validType|[*!]|txn)\b`
|
|
19
19
|
*
|
|
20
|
-
* @returns A RegExp that validates dated
|
|
20
|
+
* @returns A RegExp that validates dated node lines
|
|
21
21
|
*/
|
|
22
|
-
function
|
|
23
|
-
// Join all non dated
|
|
24
|
-
const
|
|
25
|
-
// Join all dated
|
|
26
|
-
const
|
|
27
|
-
...
|
|
22
|
+
function compileDirectivePattern() {
|
|
23
|
+
// Join all non dated directive types with | for regex alternation
|
|
24
|
+
const nonDatedDirectivesPattern = NON_DATED_DIRECTIVE_TYPES.join('|');
|
|
25
|
+
// Join all dated directive types with | for regex alternation
|
|
26
|
+
const datedDirectivesTypePattern = [
|
|
27
|
+
...DATED_DIRECTIVE_TYPES,
|
|
28
28
|
'txn',
|
|
29
29
|
'[^ ]' /* flag */,
|
|
30
30
|
].join('|');
|
|
31
31
|
const datePattern = `\\d{4}-\\d{2}-\\d{2}`;
|
|
32
|
-
const
|
|
33
|
-
const pattern = `^(?:${
|
|
32
|
+
const datedDirectivesPattern = `${datePattern} +(?:${datedDirectivesTypePattern})`;
|
|
33
|
+
const pattern = `^(?:${nonDatedDirectivesPattern})|(?:^${datedDirectivesPattern}) `;
|
|
34
34
|
return new RegExp(pattern);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Regex pattern to identify Beancount
|
|
38
|
-
* Generated from {@link
|
|
37
|
+
* Regex pattern to identify Beancount directives that start with a date.
|
|
38
|
+
* Generated from {@link NON_DATED_DIRECTIVE_TYPES} and {@link DATED_DIRECTIVE_TYPES} to ensure validation of directive types.
|
|
39
39
|
*/
|
|
40
|
-
const
|
|
40
|
+
const beanCountDirectiveRegex = compileDirectivePattern();
|
|
41
41
|
/**
|
|
42
|
-
* Performs generic parsing on
|
|
42
|
+
* Performs generic parsing on a source fragment to extract common fields.
|
|
43
43
|
*
|
|
44
44
|
* This function:
|
|
45
|
-
* - Detects if the
|
|
46
|
-
* - Identifies the
|
|
45
|
+
* - Detects if the directive has a date (YYYY-MM-DD format)
|
|
46
|
+
* - Identifies the directive type
|
|
47
47
|
* - Extracts header content and comments
|
|
48
48
|
* - Handles transaction-specific parsing (flags, body lines)
|
|
49
|
-
* - Parses metadata for dated
|
|
49
|
+
* - Parses metadata for dated directives
|
|
50
50
|
*
|
|
51
|
-
* @param
|
|
52
|
-
* @returns A generic parse result object appropriate for the
|
|
51
|
+
* @param sourceFragment - Array of strings that should be parsed to a single node
|
|
52
|
+
* @returns A generic parse result object appropriate for the node type
|
|
53
53
|
*/
|
|
54
|
-
export const genericParse = (
|
|
55
|
-
const [firstLine, ...rest] =
|
|
54
|
+
export const genericParse = (sourceFragment) => {
|
|
55
|
+
const [firstLine, ...rest] = sourceFragment;
|
|
56
56
|
if (firstLine.trim() === '') {
|
|
57
|
-
return { type: 'blankline', header: '', props: {},
|
|
57
|
+
return { type: 'blankline', header: '', props: {}, synthetic: true };
|
|
58
58
|
}
|
|
59
|
-
if (!
|
|
60
|
-
// not a valid beancount
|
|
59
|
+
if (!beanCountDirectiveRegex.test(firstLine)) {
|
|
60
|
+
// not a valid beancount directive, return it as a comment
|
|
61
61
|
return {
|
|
62
62
|
type: 'comment',
|
|
63
|
-
header:
|
|
63
|
+
header: sourceFragment.join('\n'),
|
|
64
64
|
props: {},
|
|
65
|
-
|
|
65
|
+
synthetic: true,
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
const splitFirstLine = firstLine.split(' ');
|
package/build/src/main.d.mts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* @remarks
|
|
5
5
|
* The primary function you'll use is {@link parse}, which parses a complete Beancount file
|
|
6
|
-
* and returns a {@link ParseResult} containing
|
|
6
|
+
* and returns a {@link ParseResult} containing parsed nodes.
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
@@ -17,43 +17,42 @@
|
|
|
17
17
|
* `
|
|
18
18
|
*
|
|
19
19
|
* const result = parse(beancountContent)
|
|
20
|
-
* console.log(result.
|
|
20
|
+
* console.log(result.nodes) // Array of parsed Node objects
|
|
21
21
|
* ```
|
|
22
22
|
*
|
|
23
23
|
* @module
|
|
24
24
|
*/
|
|
25
|
-
export { parse,
|
|
26
|
-
export {
|
|
25
|
+
export { parse, parseSourceFragment } from './parse.mjs';
|
|
26
|
+
export { deserializeNode, deserializeNodeFromString, deserializeNodes, deserializeNodesFromString, } from './deserialize.mjs';
|
|
27
27
|
export { parseFile, type ParseFileOptions, type FileSystemHelpers, } from './parseFile.mjs';
|
|
28
28
|
export type { GenericParseResult, GenericParseResultWithDate, GenericParseResultTransaction, } from './genericParse.mjs';
|
|
29
29
|
export type { Metadata } from './utils/parseMetadata.mjs';
|
|
30
30
|
export { ParseResult, type ParseResultObj, type FormatOptions, type CalculateCurrencyColumnOptions, } from './classes/ParseResult.mjs';
|
|
31
|
-
export {
|
|
32
|
-
export {
|
|
33
|
-
export type { BeancountDateEntryType } from './classes/DateEntry.mjs';
|
|
31
|
+
export { Node, assertNodeConstructor } from './classes/Node.mjs';
|
|
32
|
+
export { DatedNode } from './classes/DatedNode.mjs';
|
|
34
33
|
export { Value } from './classes/Value.mjs';
|
|
35
34
|
export type { ValueType } from './classes/Value.mjs';
|
|
36
|
-
export { Balance } from './classes/
|
|
37
|
-
export { Blankline } from './classes/
|
|
38
|
-
export { Close } from './classes/
|
|
39
|
-
export { Comment } from './classes/
|
|
40
|
-
export { Commodity } from './classes/
|
|
41
|
-
export { Custom } from './classes/
|
|
42
|
-
export { Document } from './classes/
|
|
43
|
-
export { Event } from './classes/
|
|
44
|
-
export { Include } from './classes/
|
|
45
|
-
export { Note } from './classes/
|
|
46
|
-
export { Open } from './classes/
|
|
47
|
-
export { Option } from './classes/
|
|
48
|
-
export { Pad } from './classes/
|
|
49
|
-
export { Plugin } from './classes/
|
|
50
|
-
export { Poptag } from './classes/
|
|
51
|
-
export { Price } from './classes/
|
|
52
|
-
export { Pushtag } from './classes/
|
|
53
|
-
export { Query } from './classes/
|
|
54
|
-
export { Transaction, type PostingComment, } from './classes/
|
|
55
|
-
export { Posting } from './classes/
|
|
56
|
-
export { Tag } from './classes/
|
|
57
|
-
export type {
|
|
58
|
-
export {
|
|
59
|
-
export {
|
|
35
|
+
export { Balance } from './classes/nodes/Balance.mjs';
|
|
36
|
+
export { Blankline } from './classes/nodes/Blankline.mjs';
|
|
37
|
+
export { Close } from './classes/nodes/Close.mjs';
|
|
38
|
+
export { Comment } from './classes/nodes/Comment.mjs';
|
|
39
|
+
export { Commodity } from './classes/nodes/Commodity.mjs';
|
|
40
|
+
export { Custom } from './classes/nodes/Custom.mjs';
|
|
41
|
+
export { Document } from './classes/nodes/Document.mjs';
|
|
42
|
+
export { Event } from './classes/nodes/Event.mjs';
|
|
43
|
+
export { Include } from './classes/nodes/Include.mjs';
|
|
44
|
+
export { Note } from './classes/nodes/Note.mjs';
|
|
45
|
+
export { Open } from './classes/nodes/Open.mjs';
|
|
46
|
+
export { Option } from './classes/nodes/Option.mjs';
|
|
47
|
+
export { Pad } from './classes/nodes/Pad.mjs';
|
|
48
|
+
export { Plugin } from './classes/nodes/Plugin.mjs';
|
|
49
|
+
export { Poptag } from './classes/nodes/Poptag.mjs';
|
|
50
|
+
export { Price } from './classes/nodes/Price.mjs';
|
|
51
|
+
export { Pushtag } from './classes/nodes/Pushtag.mjs';
|
|
52
|
+
export { Query } from './classes/nodes/Query.mjs';
|
|
53
|
+
export { Transaction, type PostingComment, } from './classes/nodes/Transaction/index.mjs';
|
|
54
|
+
export { Posting } from './classes/nodes/Transaction/Posting.mjs';
|
|
55
|
+
export { Tag } from './classes/nodes/Transaction/Tag.mjs';
|
|
56
|
+
export type { BeancountDirectiveNodeType, NodeType, SyntheticNodeType, DatedDirectiveNodeType, NonDatedDirectiveNodeType, } from './nodeTypeToClass.mjs';
|
|
57
|
+
export { beancountDirectiveNodeTypeToClass, nodeTypeToClass, } from './nodeTypeToClass.mjs';
|
|
58
|
+
export { DATED_DIRECTIVE_TYPES, NON_DATED_DIRECTIVE_TYPES, } from './directiveTypes.mjs';
|