beancount 0.1.0 → 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 +15 -16
- 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 +2 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { Transaction } from './Transaction/index.mjs';
|
|
2
|
+
export { Balance } from './Balance.mjs';
|
|
3
|
+
export { Blankline } from './Blankline.mjs';
|
|
4
|
+
export { Close } from './Close.mjs';
|
|
5
|
+
export { Comment } from './Comment.mjs';
|
|
6
|
+
export { Commodity } from './Commodity.mjs';
|
|
7
|
+
export { Custom } from './Custom.mjs';
|
|
8
|
+
export { Document } from './Document.mjs';
|
|
9
|
+
export { Event } from './Event.mjs';
|
|
10
|
+
export { Include } from './Include.mjs';
|
|
11
|
+
export { Note } from './Note.mjs';
|
|
12
|
+
export { Open } from './Open.mjs';
|
|
13
|
+
export { Option } from './Option.mjs';
|
|
14
|
+
export { Pad } from './Pad.mjs';
|
|
15
|
+
export { Plugin } from './Plugin.mjs';
|
|
16
|
+
export { Price } from './Price.mjs';
|
|
17
|
+
export { Poptag } from './Poptag.mjs';
|
|
18
|
+
export { Pushtag } from './Pushtag.mjs';
|
|
19
|
+
export { Query } from './Query.mjs';
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export { Transaction } from './Transaction/index.mjs';
|
|
2
|
+
export { Balance } from './Balance.mjs';
|
|
3
|
+
export { Blankline } from './Blankline.mjs';
|
|
4
|
+
export { Close } from './Close.mjs';
|
|
5
|
+
export { Comment } from './Comment.mjs';
|
|
6
|
+
export { Commodity } from './Commodity.mjs';
|
|
7
|
+
export { Custom } from './Custom.mjs';
|
|
8
|
+
export { Document } from './Document.mjs';
|
|
9
|
+
export { Event } from './Event.mjs';
|
|
10
|
+
export { Include } from './Include.mjs';
|
|
11
|
+
export { Note } from './Note.mjs';
|
|
12
|
+
export { Open } from './Open.mjs';
|
|
13
|
+
export { Option } from './Option.mjs';
|
|
14
|
+
export { Pad } from './Pad.mjs';
|
|
15
|
+
export { Plugin } from './Plugin.mjs';
|
|
16
|
+
export { Price } from './Price.mjs';
|
|
17
|
+
export { Poptag } from './Poptag.mjs';
|
|
18
|
+
export { Pushtag } from './Pushtag.mjs';
|
|
19
|
+
export { Query } from './Query.mjs';
|
package/build/src/cli.mjs
CHANGED
|
@@ -36,7 +36,7 @@ Examples:
|
|
|
36
36
|
* @param filePath Path to the file to format
|
|
37
37
|
* @param write Whether to write the formatted content back to the file
|
|
38
38
|
* @param currencyColumn Currency column number, or null to auto-calculate
|
|
39
|
-
* @param force Wether to also format files
|
|
39
|
+
* @param force Wether to also format files without any Beancount directives, defaults to false
|
|
40
40
|
* @returns Resolves to true if successful, false if an error occurred
|
|
41
41
|
*/
|
|
42
42
|
async function formatFile(filePath, write, currencyColumn, force = false) {
|
|
@@ -49,11 +49,11 @@ async function formatFile(filePath, write, currencyColumn, force = false) {
|
|
|
49
49
|
}
|
|
50
50
|
// Read and parse the beancount file
|
|
51
51
|
const parseResult = await parseFile(filePath);
|
|
52
|
-
// check if we have any
|
|
52
|
+
// check if we have any Beancount directives
|
|
53
53
|
if (!force &&
|
|
54
|
-
parseResult.
|
|
54
|
+
parseResult.nodes.length ===
|
|
55
55
|
parseResult.blankline.length + parseResult.comment.length) {
|
|
56
|
-
console.error(`Error processing ${filePath}: does not seem to be a beancount file, it has no
|
|
56
|
+
console.error(`Error processing ${filePath}: does not seem to be a beancount file, it has no Beancount directives`);
|
|
57
57
|
return false;
|
|
58
58
|
}
|
|
59
59
|
// Determine currency column
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Node } from './classes/Node.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 declare function
|
|
36
|
+
export declare function deserializeNode(nodeData: Record<string, unknown>): Node;
|
|
37
37
|
/**
|
|
38
|
-
* Deserializes a single
|
|
38
|
+
* Deserializes a single node from a JSON string.
|
|
39
39
|
*
|
|
40
|
-
* This function parses a JSON string containing an
|
|
41
|
-
* and reconstructs the appropriate
|
|
40
|
+
* This function parses a JSON string containing an node object
|
|
41
|
+
* and reconstructs the appropriate Node subclass instance.
|
|
42
42
|
*
|
|
43
|
-
* @param jsonString - JSON string containing an
|
|
44
|
-
* @returns An
|
|
45
|
-
* @throws {Error} If the JSON is invalid or
|
|
43
|
+
* @param jsonString - JSON string containing an node object
|
|
44
|
+
* @returns An Node instance of the appropriate subclass
|
|
45
|
+
* @throws {Error} If the JSON is invalid or node cannot be deserialized:
|
|
46
46
|
* - Invalid JSON syntax
|
|
47
47
|
* - JSON does not contain an object
|
|
48
|
-
* -
|
|
48
|
+
* - Node validation errors (see deserializeNode)
|
|
49
49
|
*
|
|
50
50
|
* @example
|
|
51
51
|
* Deserializing from a JSON string:
|
|
52
52
|
* ```typescript
|
|
53
53
|
* const json = '{"type":"open","date":"2024-01-01","account":"Assets:Checking"}'
|
|
54
|
-
* const
|
|
55
|
-
* console.log(
|
|
54
|
+
* const node = deserializeNodeFromString(json)
|
|
55
|
+
* console.log(node.type) // 'open'
|
|
56
56
|
* ```
|
|
57
57
|
*
|
|
58
58
|
* @example
|
|
@@ -60,34 +60,34 @@ export declare function deserializeEntry(entryData: Record<string, unknown>): En
|
|
|
60
60
|
* ```typescript
|
|
61
61
|
* const original = Open.fromString('2024-01-01 open Assets:Checking')
|
|
62
62
|
* const json = JSON.stringify(original.toJSON())
|
|
63
|
-
* const deserialized =
|
|
63
|
+
* const deserialized = deserializeNodeFromString(json)
|
|
64
64
|
* // deserialized equals original
|
|
65
65
|
* ```
|
|
66
66
|
*/
|
|
67
|
-
export declare function
|
|
67
|
+
export declare function deserializeNodeFromString(jsonString: string): Node;
|
|
68
68
|
/**
|
|
69
|
-
* Deserializes an array of
|
|
69
|
+
* Deserializes an array of nodes from their JSON representations.
|
|
70
70
|
*
|
|
71
71
|
* This function takes an array of plain JavaScript objects (typically from JSON.parse)
|
|
72
|
-
* and reconstructs each as the appropriate
|
|
73
|
-
* the input and provides helpful error messages, including the index of any
|
|
72
|
+
* and reconstructs each as the appropriate Node subclass instance. It validates
|
|
73
|
+
* the input and provides helpful error messages, including the index of any node
|
|
74
74
|
* that fails to deserialize.
|
|
75
75
|
*
|
|
76
|
-
* @param
|
|
77
|
-
* @returns Array of
|
|
78
|
-
* @throws {Error} If the input is invalid or
|
|
76
|
+
* @param nodesData - Array of plain objects containing node data
|
|
77
|
+
* @returns Array of Node instances
|
|
78
|
+
* @throws {Error} If the input is invalid or nodes cannot be deserialized:
|
|
79
79
|
* - Input is not an array
|
|
80
|
-
* - Any
|
|
80
|
+
* - Any node fails validation (see deserializeNode)
|
|
81
81
|
*
|
|
82
82
|
* @example
|
|
83
|
-
* Deserializing an array of
|
|
83
|
+
* Deserializing an array of nodes:
|
|
84
84
|
* ```typescript
|
|
85
|
-
* const
|
|
85
|
+
* const nodesData = [
|
|
86
86
|
* { type: 'open', date: '2024-01-01', account: 'Assets:Checking' },
|
|
87
87
|
* { type: 'balance', date: '2024-01-02', account: 'Assets:Checking', amount: '100', currency: 'USD' }
|
|
88
88
|
* ]
|
|
89
|
-
* const
|
|
90
|
-
* console.log(
|
|
89
|
+
* const nodes = deserializeNodes(nodesData)
|
|
90
|
+
* console.log(nodes.length) // 2
|
|
91
91
|
* ```
|
|
92
92
|
*
|
|
93
93
|
* @example
|
|
@@ -96,35 +96,35 @@ export declare function deserializeEntryFromString(jsonString: string): Entry;
|
|
|
96
96
|
* const original = [Open.fromString('2024-01-01 open Assets:Checking')]
|
|
97
97
|
* const json = JSON.stringify(original.map(e => e.toJSON()))
|
|
98
98
|
* const parsed = JSON.parse(json)
|
|
99
|
-
* const deserialized =
|
|
99
|
+
* const deserialized = deserializeNodes(parsed)
|
|
100
100
|
* // deserialized equals original
|
|
101
101
|
* ```
|
|
102
102
|
*/
|
|
103
|
-
export declare function
|
|
103
|
+
export declare function deserializeNodes(nodesData: Record<string, unknown>[]): Node[];
|
|
104
104
|
/**
|
|
105
|
-
* Deserializes an array of
|
|
105
|
+
* Deserializes an array of nodes from a JSON string.
|
|
106
106
|
*
|
|
107
|
-
* This function parses a JSON string containing an array of
|
|
108
|
-
* and reconstructs each
|
|
107
|
+
* This function parses a JSON string containing an array of node objects
|
|
108
|
+
* and reconstructs each node as the appropriate Node subclass instance.
|
|
109
109
|
* It validates the input and provides helpful error messages, including
|
|
110
|
-
* the index of any
|
|
110
|
+
* the index of any node that fails to deserialize.
|
|
111
111
|
*
|
|
112
|
-
* @param jsonString - JSON string containing an array of
|
|
113
|
-
* @returns Array of
|
|
114
|
-
* @throws {Error} If the JSON is invalid or
|
|
112
|
+
* @param jsonString - JSON string containing an array of node objects
|
|
113
|
+
* @returns Array of Node instances
|
|
114
|
+
* @throws {Error} If the JSON is invalid or nodes cannot be deserialized:
|
|
115
115
|
* - Invalid JSON syntax
|
|
116
116
|
* - JSON does not contain an array
|
|
117
|
-
* - Any
|
|
117
|
+
* - Any node fails validation (see deserializeNode)
|
|
118
118
|
*
|
|
119
119
|
* @example
|
|
120
|
-
* Deserializing multiple
|
|
120
|
+
* Deserializing multiple nodes:
|
|
121
121
|
* ```typescript
|
|
122
122
|
* const json = '[
|
|
123
123
|
* {"type": "open", "date": "2024-01-01", "account": "Assets:Checking"},
|
|
124
124
|
* {"type": "balance", "date": "2024-01-02", "account": "Assets:Checking", "amount": "100", "currency": "USD"}
|
|
125
125
|
* ]'
|
|
126
|
-
* const
|
|
127
|
-
* console.log(
|
|
126
|
+
* const nodes = deserializeNodes(json)
|
|
127
|
+
* console.log(nodes.length) // 2
|
|
128
128
|
* ```
|
|
129
129
|
*
|
|
130
130
|
* @example
|
|
@@ -133,9 +133,9 @@ export declare function deserializeEntries(entriesData: Record<string, unknown>[
|
|
|
133
133
|
* import { parse } from 'beancount'
|
|
134
134
|
*
|
|
135
135
|
* const original = parse('2024-01-01 open Assets:Checking')
|
|
136
|
-
* const json = JSON.stringify(original.
|
|
137
|
-
* const deserialized =
|
|
138
|
-
* // deserialized equals original.
|
|
136
|
+
* const json = JSON.stringify(original.nodes.map(e => e.toJSON()))
|
|
137
|
+
* const deserialized = deserializeNodes(json)
|
|
138
|
+
* // deserialized equals original.nodes
|
|
139
139
|
* ```
|
|
140
140
|
*/
|
|
141
|
-
export declare function
|
|
141
|
+
export declare function deserializeNodesFromString(jsonString: string): Node[];
|
|
@@ -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
|
+
];
|