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
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# beancount
|
|
2
2
|
|
|
3
|
+
[](https://github.com/Boelensman1/node-beancount/actions/workflows/ci.yml)
|
|
4
|
+
|
|
3
5
|
A parser and editor for Beancount accounting files with full type safety.
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
@@ -11,16 +13,18 @@ npm install beancount
|
|
|
11
13
|
## Features
|
|
12
14
|
|
|
13
15
|
- **Full Beancount Support** - All directives supported: transactions, open/close, balance, pad, note, document, price, event, query, custom, commodity, include, option, plugin, pushtag/poptag
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
+
- **Full Transaction Support** - Tags, links, metadata, costs, price annotations, and postings
|
|
17
|
+
- **Type-Safe** - Complete TypeScript types
|
|
18
|
+
- **Platform Agnostic** - Works in Node.js, browsers, Deno, and other JavaScript runtimes
|
|
16
19
|
- **Round-Trip Parsing** - Parse to objects and serialize back to text
|
|
17
|
-
- **
|
|
20
|
+
- **Recursive File Parsing** - Option to automatically follow and merge `include` directives with circular reference protection
|
|
21
|
+
- **Formatted Output** - Column-aligned output with `toFormattedString()`
|
|
18
22
|
- **CLI Formatter** - Command-line tool `beancount-format` for formatting files with auto-aligned columns
|
|
19
23
|
|
|
20
24
|
## Quick Start
|
|
21
25
|
|
|
22
26
|
```typescript
|
|
23
|
-
import { parse
|
|
27
|
+
import { parse } from './main.mjs'
|
|
24
28
|
|
|
25
29
|
const beancountContent = `
|
|
26
30
|
2024-01-01 open Assets:Checking USD
|
|
@@ -32,22 +36,21 @@ const beancountContent = `
|
|
|
32
36
|
|
|
33
37
|
const result = parse(beancountContent)
|
|
34
38
|
|
|
35
|
-
// Access parsed
|
|
36
|
-
console.log(result.
|
|
37
|
-
|
|
38
|
-
// Convert back to string
|
|
39
|
-
console.log(result.toString())
|
|
39
|
+
// Access parsed directives
|
|
40
|
+
console.log(result.nodes.length) // 5
|
|
41
|
+
console.log(result.nodes)
|
|
40
42
|
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
// Edit parsed directives
|
|
44
|
+
result.transactions[0].narration = 'Trip to the supermarket'
|
|
45
|
+
result.transactions[0].postings.forEach((p) => (p.currency = 'EUR'))
|
|
44
46
|
|
|
45
|
-
//
|
|
46
|
-
console.log(ParseResult.fromJSON(result))
|
|
47
|
-
|
|
48
|
-
// Or with formatted output (aligned columns)
|
|
49
|
-
// only partially implemented at this point
|
|
47
|
+
// Output formatted
|
|
50
48
|
console.log(result.toFormattedString())
|
|
49
|
+
/* outputs:
|
|
50
|
+
2024-01-15 * "Grocery Store" "Trip to the supermarket"
|
|
51
|
+
Assets:Checking -50.00 EUR
|
|
52
|
+
Expenses:Food 50.00 EUR
|
|
53
|
+
*/
|
|
51
54
|
```
|
|
52
55
|
|
|
53
56
|
## Parsing Files
|
|
@@ -64,7 +67,37 @@ const result = await parseFile('/path/to/ledger.beancount')
|
|
|
64
67
|
const result = await parseFile('/path/to/main.beancount', { recurse: true })
|
|
65
68
|
```
|
|
66
69
|
|
|
67
|
-
When `recurse: true`, the parser follows all `include` directives and merges the
|
|
70
|
+
When `recurse: true`, the parser follows all `include` directives and merges the directives from included files into the result. Circular includes are handled gracefully (each file is only parsed once).
|
|
71
|
+
|
|
72
|
+
## Browser Usage
|
|
73
|
+
|
|
74
|
+
The library works in browsers and other non-Node.js environments. The core `parse()` function works everywhere. For `parseFile()`, provide custom file system helpers:
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
import { parseFile, type FileSystemHelpers } from 'beancount'
|
|
78
|
+
|
|
79
|
+
const browserFS: FileSystemHelpers = {
|
|
80
|
+
readFile: async (path) => {
|
|
81
|
+
const response = await fetch(path)
|
|
82
|
+
return response.text()
|
|
83
|
+
},
|
|
84
|
+
resolvePath: (path) => new URL(path, window.location.origin).pathname,
|
|
85
|
+
resolveRelative: (base, rel) => {
|
|
86
|
+
const baseDir = base.substring(0, base.lastIndexOf('/') + 1)
|
|
87
|
+
return new URL(rel, window.location.origin + baseDir).pathname
|
|
88
|
+
},
|
|
89
|
+
dirname: (path) => path.substring(0, path.lastIndexOf('/')),
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const result = await parseFile('/api/ledger.beancount', {
|
|
93
|
+
recurse: true,
|
|
94
|
+
fs: browserFS,
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
Full API documentation is available at https://Boelensman1.github.io/node-beancount/
|
|
68
101
|
|
|
69
102
|
## CLI Usage
|
|
70
103
|
|
|
@@ -102,10 +135,6 @@ beancount-format -w income.beancount expenses.beancount
|
|
|
102
135
|
beancount-format --currency-column 60 ledger.beancount
|
|
103
136
|
```
|
|
104
137
|
|
|
105
|
-
## Documentation
|
|
106
|
-
|
|
107
|
-
Full API documentation is available at https://Boelensman1.github.io/node-beancount/
|
|
108
|
-
|
|
109
138
|
## Contributing
|
|
110
139
|
|
|
111
140
|
This project uses Make for task orchestration. Common commands:
|
package/build/src/benchmark.mjs
CHANGED
|
@@ -25,4 +25,4 @@ console.log(`Average parse time: ${avgDuration.toFixed(3)} ms`);
|
|
|
25
25
|
console.log(`Min: ${minDuration.toFixed(3)} ms, Max: ${maxDuration.toFixed(3)} ms`);
|
|
26
26
|
console.log(`Average throughput: ${(fileSizeKB / avgDurationSeconds / 1000).toFixed(2)} MB/s`);
|
|
27
27
|
console.log('---');
|
|
28
|
-
console.log(`Parsed ${lastResult.
|
|
28
|
+
console.log(`Parsed ${lastResult.nodes.length} items`);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
import { Node } from './Node.mjs';
|
|
3
|
+
import { Value } from './Value.mjs';
|
|
4
|
+
import type { DatedDirectiveNodeType } from '../nodeTypeToClass.mjs';
|
|
5
|
+
/**
|
|
6
|
+
* Abstract base class for all nodes that correspond to dated Beancount directives
|
|
7
|
+
* like transaction and open.
|
|
8
|
+
*
|
|
9
|
+
* Child classes must implement static `fromGenericParseResult` method
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class DatedNode extends Node {
|
|
12
|
+
/** The type of this dated node */
|
|
13
|
+
abstract type: DatedDirectiveNodeType;
|
|
14
|
+
/** The date of this node as a Temporal.PlainDate object */
|
|
15
|
+
date: Temporal.PlainDate;
|
|
16
|
+
/** Optional metadata key-value pairs associated with this node */
|
|
17
|
+
metadata?: Record<string, Value>;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new DatedNode instance.
|
|
20
|
+
* @param obj - Object containing node properties
|
|
21
|
+
* @param obj.date - The date string in YYYY-MM-DD format
|
|
22
|
+
*/
|
|
23
|
+
constructor(obj: {
|
|
24
|
+
date: string | Temporal.PlainDate;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Returns the common prefix for all DatedNode toString methods.
|
|
29
|
+
* Format: "YYYY-MM-DD <type>"
|
|
30
|
+
* @returns The formatted date and type prefix string
|
|
31
|
+
*/
|
|
32
|
+
protected getDateTypePrefix(): string;
|
|
33
|
+
/**
|
|
34
|
+
* Converts metadata and comment to a formatted string.
|
|
35
|
+
* If metadata exists, each key-value pair is formatted on separate indented lines.
|
|
36
|
+
*
|
|
37
|
+
* @returns The formatted metadata and comment string, or empty string if neither exists
|
|
38
|
+
*/
|
|
39
|
+
getMetaDataString(): string;
|
|
40
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Temporal } from '@js-temporal/polyfill';
|
|
2
|
+
import { Node } from './Node.mjs';
|
|
3
|
+
import { Value } from './Value.mjs';
|
|
4
|
+
/**
|
|
5
|
+
* Abstract base class for all nodes that correspond to dated Beancount directives
|
|
6
|
+
* like transaction and open.
|
|
7
|
+
*
|
|
8
|
+
* Child classes must implement static `fromGenericParseResult` method
|
|
9
|
+
*/
|
|
10
|
+
export class DatedNode extends Node {
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new DatedNode instance.
|
|
13
|
+
* @param obj - Object containing node properties
|
|
14
|
+
* @param obj.date - The date string in YYYY-MM-DD format
|
|
15
|
+
*/
|
|
16
|
+
constructor(obj) {
|
|
17
|
+
const { date, metadata, ...props } = obj;
|
|
18
|
+
super(props);
|
|
19
|
+
if (date) {
|
|
20
|
+
if (date instanceof Temporal.PlainDate) {
|
|
21
|
+
this.date = date;
|
|
22
|
+
}
|
|
23
|
+
else if (typeof date === 'string') {
|
|
24
|
+
this.date = Temporal.PlainDate.from(date, { overflow: 'reject' });
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
throw new Error('Could not parse date, should be either string of Temporal.PlainDate');
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (metadata) {
|
|
31
|
+
this.metadata = Object.fromEntries(Object.entries(metadata).map(([key, val]) => [
|
|
32
|
+
key,
|
|
33
|
+
new Value(val),
|
|
34
|
+
]));
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Returns the common prefix for all DatedNode toString methods.
|
|
39
|
+
* Format: "YYYY-MM-DD <type>"
|
|
40
|
+
* @returns The formatted date and type prefix string
|
|
41
|
+
*/
|
|
42
|
+
getDateTypePrefix() {
|
|
43
|
+
return `${this.date.toJSON()} ${this.type}`;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Converts metadata and comment to a formatted string.
|
|
47
|
+
* If metadata exists, each key-value pair is formatted on separate indented lines.
|
|
48
|
+
*
|
|
49
|
+
* @returns The formatted metadata and comment string, or empty string if neither exists
|
|
50
|
+
*/
|
|
51
|
+
getMetaDataString() {
|
|
52
|
+
const comment = this.comment ? ` ; ${this.comment}` : '';
|
|
53
|
+
if (!this.metadata) {
|
|
54
|
+
return comment;
|
|
55
|
+
}
|
|
56
|
+
return (`${comment}\n` +
|
|
57
|
+
Object.entries(this.metadata)
|
|
58
|
+
.map(([key, val]) => ` ${key}: ${val.toString()}`)
|
|
59
|
+
.join('\n'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { BeancountDirectiveNodeType } from '../nodeTypeToClass.mjs';
|
|
2
|
+
import { genericParse } from '../genericParse.mjs';
|
|
3
|
+
import { FormatOptions } from './ParseResult.mjs';
|
|
4
|
+
/**
|
|
5
|
+
* Type helper for Node class constructors that enforce the static factory methods.
|
|
6
|
+
* Child classes must implement static fromGenericParseResult and fromObject methods to create instances.
|
|
7
|
+
* Note: The constructor is protected, so only the static factory methods are part of the public API.
|
|
8
|
+
*/
|
|
9
|
+
export interface NodeConstructor<T extends Node> {
|
|
10
|
+
/**
|
|
11
|
+
* Creates an Node instance from a generic parse result.
|
|
12
|
+
* @param parsedStart - The result from genericParse containing parsed node data
|
|
13
|
+
* @returns A new instance of the Node subclass
|
|
14
|
+
*/
|
|
15
|
+
fromGenericParseResult(parsedStart: ReturnType<typeof genericParse>): T;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Abstract base class for all nodes.
|
|
19
|
+
*
|
|
20
|
+
* Child classes must implement static `fromGenericParseResult` method
|
|
21
|
+
*/
|
|
22
|
+
export declare abstract class Node {
|
|
23
|
+
/** Optional comment text associated with this node */
|
|
24
|
+
comment?: string;
|
|
25
|
+
/** Internal metadata key-value pairs associated with this node.
|
|
26
|
+
* These can be anything, are not used in the output, and are meant to be used
|
|
27
|
+
* to allow your pipeline to keep track of an internal property */
|
|
28
|
+
internalMetadata: Record<string, unknown>;
|
|
29
|
+
/** The type of this node (e.g., 'open', 'close', 'transaction', 'comment', 'blankline') */
|
|
30
|
+
abstract type: BeancountDirectiveNodeType | 'comment' | 'blankline';
|
|
31
|
+
/**
|
|
32
|
+
* Creates a new Node instance.
|
|
33
|
+
* @param obj - Object containing node properties
|
|
34
|
+
*/
|
|
35
|
+
constructor(obj: Record<string, unknown>);
|
|
36
|
+
/**
|
|
37
|
+
* Creates an Node instance from a Beancount string.
|
|
38
|
+
* Parses the input string and constructs the appropriate Node subclass.
|
|
39
|
+
*
|
|
40
|
+
* @param input - A single unparsed node as a string
|
|
41
|
+
* @returns A new instance of the Node subclass
|
|
42
|
+
*/
|
|
43
|
+
static fromString<T extends Node>(this: NodeConstructor<T>, input: string): T;
|
|
44
|
+
/**
|
|
45
|
+
* Creates an Node instance from JSON data.
|
|
46
|
+
* Calls fromJSONData to allow subclasses to transform the data before construction.
|
|
47
|
+
*
|
|
48
|
+
* @param jsonString - JSON data representing an node
|
|
49
|
+
* @returns A new instance of the Node subclass
|
|
50
|
+
* @remarks **Warning:** No validation is performed on the JSON input. We assume the JSON is valid and well-formed.
|
|
51
|
+
*/
|
|
52
|
+
static fromJSON<T extends Node>(this: new (obj: any) => T, jsonString: string): T;
|
|
53
|
+
/**
|
|
54
|
+
* Creates an Node instance from JSON data.
|
|
55
|
+
* Calls fromJSONData to allow subclasses to transform the data before construction.
|
|
56
|
+
*
|
|
57
|
+
* @param jsonData - object representing an node
|
|
58
|
+
* @returns A new instance of the Node subclass
|
|
59
|
+
* @remarks **Warning:** No validation is performed on the input. We assume the input is valid and well-formed.
|
|
60
|
+
*/
|
|
61
|
+
static fromJSONData<T extends Node>(this: new (obj: any) => T, jsonData: Record<string, unknown>): T;
|
|
62
|
+
/**
|
|
63
|
+
* Converts this node to a formatted string with aligned columns.
|
|
64
|
+
* Default implementation delegates to toString(). Subclasses can override for custom formatting.
|
|
65
|
+
*
|
|
66
|
+
* @param _formatOptions - Formatting options (unused in base implementation)
|
|
67
|
+
* @returns The formatted string representation of this node
|
|
68
|
+
*/
|
|
69
|
+
toFormattedString(_formatOptions?: FormatOptions): string;
|
|
70
|
+
/**
|
|
71
|
+
* Transforms JSON data before creating an Node instance.
|
|
72
|
+
* Default implementation returns the input unchanged.
|
|
73
|
+
* Subclasses can override this to handle custom deserialization logic
|
|
74
|
+
* (e.g., converting nested objects, handling dates, etc.).
|
|
75
|
+
*
|
|
76
|
+
* @param json - The JSON data to transform
|
|
77
|
+
* @returns The transformed data ready for the constructor
|
|
78
|
+
*/
|
|
79
|
+
protected parseJSONData(json: Record<string, unknown>): Record<string, unknown>;
|
|
80
|
+
/**
|
|
81
|
+
* Converts an node to a JSON-serializable object.
|
|
82
|
+
* @returns A JSON-serializable representation of this node
|
|
83
|
+
*/
|
|
84
|
+
toJSON(): Record<string, unknown>;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Type assertion helper to ensure a class conforms to NodeConstructor.
|
|
88
|
+
* Usage: assertNodeConstructor(MyNodeClass)
|
|
89
|
+
* @param _ctor - The constructor to validate (unused at runtime)
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export declare function assertNodeConstructor<T extends Node>(_ctor: NodeConstructor<T>): void;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { genericParse } from '../genericParse.mjs';
|
|
2
|
+
import { stringAwareSplitLine } from '../utils/stringAwareSplitLine.mjs';
|
|
3
|
+
import { defaultFormatOptions } from './ParseResult.mjs';
|
|
4
|
+
/**
|
|
5
|
+
* Abstract base class for all nodes.
|
|
6
|
+
*
|
|
7
|
+
* Child classes must implement static `fromGenericParseResult` method
|
|
8
|
+
*/
|
|
9
|
+
export class Node {
|
|
10
|
+
/**
|
|
11
|
+
* Creates a new Node instance.
|
|
12
|
+
* @param obj - Object containing node properties
|
|
13
|
+
*/
|
|
14
|
+
constructor(obj) {
|
|
15
|
+
/** Internal metadata key-value pairs associated with this node.
|
|
16
|
+
* These can be anything, are not used in the output, and are meant to be used
|
|
17
|
+
* to allow your pipeline to keep track of an internal property */
|
|
18
|
+
this.internalMetadata = {};
|
|
19
|
+
Object.assign(this, obj);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Creates an Node instance from a Beancount string.
|
|
23
|
+
* Parses the input string and constructs the appropriate Node subclass.
|
|
24
|
+
*
|
|
25
|
+
* @param input - A single unparsed node as a string
|
|
26
|
+
* @returns A new instance of the Node subclass
|
|
27
|
+
*/
|
|
28
|
+
static fromString(input) {
|
|
29
|
+
const sourceFragment = stringAwareSplitLine(input);
|
|
30
|
+
const genericParseResult = genericParse(sourceFragment);
|
|
31
|
+
const result = this.fromGenericParseResult(genericParseResult);
|
|
32
|
+
if (result.type !== genericParseResult.type) {
|
|
33
|
+
console.warn('Parse result type is not equal to requested object type, make sure the correct class is initiated');
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Creates an Node instance from JSON data.
|
|
39
|
+
* Calls fromJSONData to allow subclasses to transform the data before construction.
|
|
40
|
+
*
|
|
41
|
+
* @param jsonString - JSON data representing an node
|
|
42
|
+
* @returns A new instance of the Node subclass
|
|
43
|
+
* @remarks **Warning:** No validation is performed on the JSON input. We assume the JSON is valid and well-formed.
|
|
44
|
+
*/
|
|
45
|
+
static fromJSON(jsonString) {
|
|
46
|
+
const json = JSON.parse(jsonString);
|
|
47
|
+
// @ts-expect-error Not sure how to type this correctly
|
|
48
|
+
return this.fromJSONData(json); // eslint-disable-line
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Creates an Node instance from JSON data.
|
|
52
|
+
* Calls fromJSONData to allow subclasses to transform the data before construction.
|
|
53
|
+
*
|
|
54
|
+
* @param jsonData - object representing an node
|
|
55
|
+
* @returns A new instance of the Node subclass
|
|
56
|
+
* @remarks **Warning:** No validation is performed on the input. We assume the input is valid and well-formed.
|
|
57
|
+
*/
|
|
58
|
+
static fromJSONData(jsonData) {
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
const instance = new this({});
|
|
61
|
+
const transformedData = instance.parseJSONData(jsonData);
|
|
62
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
63
|
+
return new this(transformedData);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Converts this node to a formatted string with aligned columns.
|
|
67
|
+
* Default implementation delegates to toString(). Subclasses can override for custom formatting.
|
|
68
|
+
*
|
|
69
|
+
* @param _formatOptions - Formatting options (unused in base implementation)
|
|
70
|
+
* @returns The formatted string representation of this node
|
|
71
|
+
*/
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
73
|
+
toFormattedString(_formatOptions = defaultFormatOptions) {
|
|
74
|
+
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
|
75
|
+
return this.toString();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Transforms JSON data before creating an Node instance.
|
|
79
|
+
* Default implementation returns the input unchanged.
|
|
80
|
+
* Subclasses can override this to handle custom deserialization logic
|
|
81
|
+
* (e.g., converting nested objects, handling dates, etc.).
|
|
82
|
+
*
|
|
83
|
+
* @param json - The JSON data to transform
|
|
84
|
+
* @returns The transformed data ready for the constructor
|
|
85
|
+
*/
|
|
86
|
+
parseJSONData(json) {
|
|
87
|
+
return json;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Converts an node to a JSON-serializable object.
|
|
91
|
+
* @returns A JSON-serializable representation of this node
|
|
92
|
+
*/
|
|
93
|
+
toJSON() {
|
|
94
|
+
return {
|
|
95
|
+
...this,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Type assertion helper to ensure a class conforms to NodeConstructor.
|
|
101
|
+
* Usage: assertNodeConstructor(MyNodeClass)
|
|
102
|
+
* @param _ctor - The constructor to validate (unused at runtime)
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
export function assertNodeConstructor(
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
107
|
+
_ctor) { }
|