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
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a tag associated with a transaction.
|
|
3
|
+
* Tags can be specified inline in the transaction or inherited from a tag stack (pushtag/poptag).
|
|
4
|
+
*/
|
|
5
|
+
export declare class Tag {
|
|
6
|
+
/** The tag name/content (without the '#' prefix) */
|
|
7
|
+
content: string;
|
|
8
|
+
/** Whether this tag comes from the tag stack (pushtag) or is inline */
|
|
9
|
+
fromStack: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new Tag instance.
|
|
12
|
+
* @param obj - Object containing tag content and source information
|
|
13
|
+
* @param obj.content - The tag name/content
|
|
14
|
+
* @param obj.fromStack - Whether this tag is from the tag stack
|
|
15
|
+
*/
|
|
16
|
+
constructor(obj: {
|
|
17
|
+
content: string;
|
|
18
|
+
fromStack: boolean;
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Converts this tag to its string representation.
|
|
22
|
+
* Tags from the stack return an empty string (they're implicit),
|
|
23
|
+
* while inline tags return '#tagname' format.
|
|
24
|
+
*
|
|
25
|
+
* @returns The tag string with '#' prefix, or empty string if from stack
|
|
26
|
+
*/
|
|
27
|
+
toString(): string;
|
|
28
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a tag associated with a transaction.
|
|
3
|
+
* Tags can be specified inline in the transaction or inherited from a tag stack (pushtag/poptag).
|
|
4
|
+
*/
|
|
5
|
+
export class Tag {
|
|
6
|
+
/**
|
|
7
|
+
* Creates a new Tag instance.
|
|
8
|
+
* @param obj - Object containing tag content and source information
|
|
9
|
+
* @param obj.content - The tag name/content
|
|
10
|
+
* @param obj.fromStack - Whether this tag is from the tag stack
|
|
11
|
+
*/
|
|
12
|
+
constructor(obj) {
|
|
13
|
+
Object.assign(this, obj);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Converts this tag to its string representation.
|
|
17
|
+
* Tags from the stack return an empty string (they're implicit),
|
|
18
|
+
* while inline tags return '#tagname' format.
|
|
19
|
+
*
|
|
20
|
+
* @returns The tag string with '#' prefix, or empty string if from stack
|
|
21
|
+
*/
|
|
22
|
+
toString() {
|
|
23
|
+
if (this.fromStack) {
|
|
24
|
+
return '';
|
|
25
|
+
}
|
|
26
|
+
return `#${this.content}`;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
import type { GenericParseResultTransaction } from '../../../genericParse.mjs';
|
|
3
|
+
import { DatedNode } from '../../DatedNode.mjs';
|
|
4
|
+
import { Posting } from './Posting.mjs';
|
|
5
|
+
import { Tag } from './Tag.mjs';
|
|
6
|
+
import { FormatOptions } from '../../ParseResult.mjs';
|
|
7
|
+
export interface PostingComment {
|
|
8
|
+
order: number;
|
|
9
|
+
comment: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Represents a Beancount transaction node.
|
|
13
|
+
* Transactions record financial movements between accounts with postings.
|
|
14
|
+
*/
|
|
15
|
+
export declare class Transaction extends DatedNode {
|
|
16
|
+
/** @inheritdoc */
|
|
17
|
+
type: "transaction";
|
|
18
|
+
/** The payee of the transaction */
|
|
19
|
+
payee: string;
|
|
20
|
+
/** Optional narration/description of the transaction */
|
|
21
|
+
narration?: string;
|
|
22
|
+
/** Optional transaction flag (e.g., '*' for cleared, '!' for pending) */
|
|
23
|
+
flag?: string;
|
|
24
|
+
/** Array of postings (account movements) in this transaction */
|
|
25
|
+
postings: Posting[];
|
|
26
|
+
/** Array of comments under this transaction (mixed in with the postings) */
|
|
27
|
+
postingComments: PostingComment[];
|
|
28
|
+
/** Set of link identifiers associated with this transaction */
|
|
29
|
+
links: Set<string>;
|
|
30
|
+
/** Array of tags associated with this transaction (from inline tags and tag stack) */
|
|
31
|
+
tags: Tag[];
|
|
32
|
+
/**
|
|
33
|
+
* @inheritdoc
|
|
34
|
+
*/
|
|
35
|
+
constructor(obj: {
|
|
36
|
+
date: string | Temporal.PlainDate;
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Creates a Transaction instance from a generic parse result.
|
|
41
|
+
* Parses payee, narration, links, tags, postings, and metadata.
|
|
42
|
+
*
|
|
43
|
+
* @param genericParseResult - The parsed transaction data
|
|
44
|
+
* @returns A new Transaction instance
|
|
45
|
+
*/
|
|
46
|
+
static fromGenericParseResult(genericParseResult: GenericParseResultTransaction): Transaction;
|
|
47
|
+
/** @inheritdoc */
|
|
48
|
+
toString(): string;
|
|
49
|
+
/** @inheritdoc */
|
|
50
|
+
toFormattedString(formatOptions?: FormatOptions): string;
|
|
51
|
+
/**
|
|
52
|
+
* Converts this transaction to a JSON-serializable object.
|
|
53
|
+
* Ensures the links Set is properly serialized as an array.
|
|
54
|
+
*
|
|
55
|
+
* @returns A JSON-serializable representation of this transaction
|
|
56
|
+
*/
|
|
57
|
+
toJSON(): Record<string, unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Transforms JSON data before creating a Transaction instance.
|
|
60
|
+
* Deserializes transaction-specific properties including postings, tags, links, and metadata.
|
|
61
|
+
*
|
|
62
|
+
* @param json - The JSON data to transform
|
|
63
|
+
* @returns The transformed data with:
|
|
64
|
+
* - postings converted to Posting instances
|
|
65
|
+
* - tags converted to Tag instances
|
|
66
|
+
* - links converted from array to Set<string>
|
|
67
|
+
* - metadata values converted to Value instances
|
|
68
|
+
*/
|
|
69
|
+
protected parseJSONData(json: Record<string, unknown>): Record<string, unknown>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { assertNodeConstructor } from '../../Node.mjs';
|
|
2
|
+
import { DatedNode } from '../../DatedNode.mjs';
|
|
3
|
+
import { stringAwareParseLine } from '../../../utils/stringAwareParseLine.mjs';
|
|
4
|
+
import { parseString, Value } from '../../Value.mjs';
|
|
5
|
+
import { parseMetadata } from '../../../utils/parseMetadata.mjs';
|
|
6
|
+
import { Posting } from './Posting.mjs';
|
|
7
|
+
import { Tag } from './Tag.mjs';
|
|
8
|
+
import { defaultFormatOptions } from '../../ParseResult.mjs';
|
|
9
|
+
/**
|
|
10
|
+
* Valid Beancount account type prefixes.
|
|
11
|
+
* @internal
|
|
12
|
+
*/
|
|
13
|
+
const AccountTypes = ['Assets', 'Liabilities', 'Equity', 'Income', 'Expenses'];
|
|
14
|
+
/**
|
|
15
|
+
* Parses a string to extract narration/payee, links, and tags.
|
|
16
|
+
* Links are prefixed with '^' and tags with '#'.
|
|
17
|
+
*
|
|
18
|
+
* @param input - The string to parse (may contain narration in quotes, links, and tags)
|
|
19
|
+
* @returns An object containing extracted links, tags, and the remaining string (narration/payee)
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
const getStringLinksAndTags = (input) => {
|
|
23
|
+
let links = new Set();
|
|
24
|
+
let tags = [];
|
|
25
|
+
// default if no narration
|
|
26
|
+
let strRemaining = '';
|
|
27
|
+
let linksAndTags = input;
|
|
28
|
+
// check for narration
|
|
29
|
+
const match = /^(".*")(.*)/.exec(input);
|
|
30
|
+
if (match) {
|
|
31
|
+
// strRemaining = narration
|
|
32
|
+
strRemaining = match[1];
|
|
33
|
+
linksAndTags = match[2];
|
|
34
|
+
}
|
|
35
|
+
const linksMatch = linksAndTags.matchAll(/\^([\w-_.]*)/g);
|
|
36
|
+
if (linksMatch) {
|
|
37
|
+
links = new Set(linksMatch.map((m) => m[1]));
|
|
38
|
+
}
|
|
39
|
+
const tagsMatch = linksAndTags.matchAll(/#([\w-_.]*)/g);
|
|
40
|
+
if (tagsMatch) {
|
|
41
|
+
tags = tagsMatch
|
|
42
|
+
.map((m) => new Tag({ content: m[1], fromStack: false }))
|
|
43
|
+
.toArray();
|
|
44
|
+
}
|
|
45
|
+
return { links, tags, string: strRemaining };
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Represents a Beancount transaction node.
|
|
49
|
+
* Transactions record financial movements between accounts with postings.
|
|
50
|
+
*/
|
|
51
|
+
export class Transaction extends DatedNode {
|
|
52
|
+
/**
|
|
53
|
+
* @inheritdoc
|
|
54
|
+
*/
|
|
55
|
+
constructor(obj) {
|
|
56
|
+
/*
|
|
57
|
+
* This constructor exists to provide a default value for some values.
|
|
58
|
+
* Class field initializers (e.g., `postingComments = []`) run after
|
|
59
|
+
* `super()` returns, which would overwrite values set by `Object.assign`
|
|
60
|
+
* in the parent constructor.
|
|
61
|
+
*/
|
|
62
|
+
super(obj);
|
|
63
|
+
/** @inheritdoc */
|
|
64
|
+
this.type = 'transaction';
|
|
65
|
+
this.postingComments ??= [];
|
|
66
|
+
this.postings ??= [];
|
|
67
|
+
this.links ??= new Set();
|
|
68
|
+
this.tags ??= [];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Creates a Transaction instance from a generic parse result.
|
|
72
|
+
* Parses payee, narration, links, tags, postings, and metadata.
|
|
73
|
+
*
|
|
74
|
+
* @param genericParseResult - The parsed transaction data
|
|
75
|
+
* @returns A new Transaction instance
|
|
76
|
+
*/
|
|
77
|
+
static fromGenericParseResult(genericParseResult) {
|
|
78
|
+
// eslint-disable-next-line prefer-const
|
|
79
|
+
let [payee, ...rest] = stringAwareParseLine(genericParseResult.header);
|
|
80
|
+
let links = new Set();
|
|
81
|
+
let tags = [];
|
|
82
|
+
let narration;
|
|
83
|
+
if (rest.length === 0) {
|
|
84
|
+
// no narration
|
|
85
|
+
const payeeParsed = getStringLinksAndTags(payee);
|
|
86
|
+
payee = payeeParsed.string;
|
|
87
|
+
links = payeeParsed.links;
|
|
88
|
+
tags = payeeParsed.tags;
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
const payeeParsed = getStringLinksAndTags(rest.join(' '));
|
|
92
|
+
narration = payeeParsed.string;
|
|
93
|
+
links = payeeParsed.links;
|
|
94
|
+
tags = payeeParsed.tags;
|
|
95
|
+
}
|
|
96
|
+
const unparsedPostings = [];
|
|
97
|
+
const unparsedMetadata = [];
|
|
98
|
+
const postingComments = [];
|
|
99
|
+
genericParseResult.body.forEach((line) => {
|
|
100
|
+
// V remove flag, V get account type
|
|
101
|
+
const accountType = line.replace(/^[^ ] /, '').split(':')[0];
|
|
102
|
+
if (AccountTypes.includes(accountType)) {
|
|
103
|
+
unparsedPostings.push(line);
|
|
104
|
+
}
|
|
105
|
+
else if (line.startsWith(';')) {
|
|
106
|
+
postingComments.push({
|
|
107
|
+
comment: line,
|
|
108
|
+
order: unparsedPostings.length + postingComments.length,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
unparsedMetadata.push(line);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
const postings = unparsedPostings.map((p) => Posting.fromString(p));
|
|
116
|
+
const metadata = parseMetadata(unparsedMetadata);
|
|
117
|
+
return new Transaction({
|
|
118
|
+
...genericParseResult.props,
|
|
119
|
+
payee: parseString(payee),
|
|
120
|
+
narration: narration ? parseString(narration) : undefined,
|
|
121
|
+
postings,
|
|
122
|
+
postingComments,
|
|
123
|
+
metadata,
|
|
124
|
+
links,
|
|
125
|
+
tags,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** @inheritdoc */
|
|
129
|
+
toString() {
|
|
130
|
+
return this.toFormattedString({ currencyColumn: 0 });
|
|
131
|
+
}
|
|
132
|
+
/** @inheritdoc */
|
|
133
|
+
toFormattedString(formatOptions = defaultFormatOptions) {
|
|
134
|
+
const firstLine = [
|
|
135
|
+
this.date.toJSON(),
|
|
136
|
+
this.flag ?? 'txn',
|
|
137
|
+
`"${this.payee}"`,
|
|
138
|
+
];
|
|
139
|
+
if (this.narration !== undefined) {
|
|
140
|
+
firstLine.push(`"${this.narration}"`);
|
|
141
|
+
}
|
|
142
|
+
firstLine.push(...this.links.values().map((l) => `^${l}`));
|
|
143
|
+
firstLine.push(...this.tags.map((t) => t.toString()));
|
|
144
|
+
const lines = [firstLine.join(' ') + this.getMetaDataString()];
|
|
145
|
+
const postingLines = this.postings.map((p) => ` ${p.toFormattedString(formatOptions)}`);
|
|
146
|
+
this.postingComments.forEach((comment) => {
|
|
147
|
+
postingLines.splice(comment.order, 0, ` ${comment.comment}`);
|
|
148
|
+
});
|
|
149
|
+
lines.push(...postingLines);
|
|
150
|
+
return lines.join('\n');
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Converts this transaction to a JSON-serializable object.
|
|
154
|
+
* Ensures the links Set is properly serialized as an array.
|
|
155
|
+
*
|
|
156
|
+
* @returns A JSON-serializable representation of this transaction
|
|
157
|
+
*/
|
|
158
|
+
toJSON() {
|
|
159
|
+
return {
|
|
160
|
+
...this,
|
|
161
|
+
links: Array.from(this.links),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Transforms JSON data before creating a Transaction instance.
|
|
166
|
+
* Deserializes transaction-specific properties including postings, tags, links, and metadata.
|
|
167
|
+
*
|
|
168
|
+
* @param json - The JSON data to transform
|
|
169
|
+
* @returns The transformed data with:
|
|
170
|
+
* - postings converted to Posting instances
|
|
171
|
+
* - tags converted to Tag instances
|
|
172
|
+
* - links converted from array to Set<string>
|
|
173
|
+
* - metadata values converted to Value instances
|
|
174
|
+
*/
|
|
175
|
+
parseJSONData(json) {
|
|
176
|
+
const { postings, postingComments, tags, links, metadata, ...rest } = json;
|
|
177
|
+
return {
|
|
178
|
+
...rest,
|
|
179
|
+
postings: postings?.map((p) => new Posting(p)),
|
|
180
|
+
postingComments: postingComments ?? [],
|
|
181
|
+
tags: tags?.map((t) => new Tag(t)),
|
|
182
|
+
links: links ? new Set(links) : new Set(),
|
|
183
|
+
metadata: metadata
|
|
184
|
+
? Object.fromEntries(Object.entries(metadata).map(([key, val]) => [
|
|
185
|
+
key,
|
|
186
|
+
new Value(val),
|
|
187
|
+
]))
|
|
188
|
+
: undefined,
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Ensure class conforms to NodeConstructor pattern
|
|
193
|
+
assertNodeConstructor(Transaction);
|
|
@@ -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[];
|