@ts-graphviz/ast 3.0.4 → 3.0.5-next-11f7126347816f64f7892c8608b5e3bf1a826670
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/CHANGELOG.md +120 -0
- package/README.md +36 -7
- package/lib/ast.d.ts +41 -0
- package/lib/ast.js +78 -6
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,125 @@
|
|
|
1
1
|
# @ts-graphviz/ast
|
|
2
2
|
|
|
3
|
+
## 3.0.5-next-11f7126347816f64f7892c8608b5e3bf1a826670
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1533](https://github.com/ts-graphviz/ts-graphviz/pull/1533) [`ed770be`](https://github.com/ts-graphviz/ts-graphviz/commit/ed770be7fffc93b9171198c9a84270df7477185d) Thanks [@kamiazya](https://github.com/kamiazya)! - Add memory exhaustion protection with input size and AST node count limits
|
|
8
|
+
|
|
9
|
+
Addresses security vulnerability where extremely large inputs or inputs with excessive elements could cause memory exhaustion, leading to application crashes and potential DoS attacks.
|
|
10
|
+
|
|
11
|
+
## Security Enhancements
|
|
12
|
+
|
|
13
|
+
### Input Size Limit
|
|
14
|
+
|
|
15
|
+
- Added `maxInputSize` option to `parse()` function (default: 10MB)
|
|
16
|
+
- Validates input size before parsing to prevent memory exhaustion from extremely large DOT files
|
|
17
|
+
- Configurable limit allows flexibility for legitimate large graphs
|
|
18
|
+
- Can be disabled by setting to 0 (not recommended for untrusted inputs)
|
|
19
|
+
|
|
20
|
+
### AST Node Count Limit
|
|
21
|
+
|
|
22
|
+
- Added `maxASTNodes` option to `parse()` function (default: 100,000 nodes)
|
|
23
|
+
- Tracks and limits the number of AST nodes created during parsing
|
|
24
|
+
- Prevents memory exhaustion from inputs with excessive elements
|
|
25
|
+
- Configurable limit for complex graphs when needed
|
|
26
|
+
- Can be disabled by setting to 0 (not recommended for untrusted inputs)
|
|
27
|
+
|
|
28
|
+
## Changes
|
|
29
|
+
|
|
30
|
+
### API Updates
|
|
31
|
+
|
|
32
|
+
- `CommonParseOptions` interface extended with `maxInputSize` and `maxASTNodes` options
|
|
33
|
+
- `Builder` class enhanced with node counting and validation
|
|
34
|
+
- `parse()` function validates input size before parsing
|
|
35
|
+
- Parser grammar updated to pass limits to Builder
|
|
36
|
+
|
|
37
|
+
### Error Handling
|
|
38
|
+
|
|
39
|
+
- Input size violations throw `DotSyntaxError` with descriptive messages
|
|
40
|
+
- AST node count violations throw `DotSyntaxError` with actionable guidance
|
|
41
|
+
- Error messages include current values and suggestions for resolution
|
|
42
|
+
|
|
43
|
+
### Testing
|
|
44
|
+
|
|
45
|
+
- Comprehensive test coverage for both limits
|
|
46
|
+
- Tests for normal usage, boundary conditions, and limit violations
|
|
47
|
+
- Tests for custom limit values and disabling limits
|
|
48
|
+
- All 62 parser tests passing
|
|
49
|
+
|
|
50
|
+
### Documentation
|
|
51
|
+
|
|
52
|
+
- Updated `SECURITY.md` with detailed security protection information
|
|
53
|
+
- Added usage examples and best practices
|
|
54
|
+
- Documented recommendations for untrusted input handling
|
|
55
|
+
|
|
56
|
+
## Security Impact
|
|
57
|
+
|
|
58
|
+
- Prevents DoS attacks via extremely large DOT files (hundreds of MB)
|
|
59
|
+
- Prevents memory exhaustion from inputs with tens of thousands of elements
|
|
60
|
+
- Default limits protect normal use cases while allowing customization
|
|
61
|
+
- Complements existing protections (HTML nesting depth, edge chain depth)
|
|
62
|
+
- Provides defense-in-depth security strategy
|
|
63
|
+
|
|
64
|
+
- [#1532](https://github.com/ts-graphviz/ts-graphviz/pull/1532) [`dc3ef34`](https://github.com/ts-graphviz/ts-graphviz/commit/dc3ef34316f5642c416711cb6a50704dbef7bb64) Thanks [@dependabot](https://github.com/apps/dependabot)! - build(deps-dev): bump vite from 7.0.2 to 7.0.8 in the npm_and_yarn group across 1 directory
|
|
65
|
+
|
|
66
|
+
- [#1535](https://github.com/ts-graphviz/ts-graphviz/pull/1535) [`11f7126`](https://github.com/ts-graphviz/ts-graphviz/commit/11f7126347816f64f7892c8608b5e3bf1a826670) Thanks [@kamiazya](https://github.com/kamiazya)! - Fix comment injection vulnerability in block comments
|
|
67
|
+
|
|
68
|
+
Addresses security vulnerability where malicious `*/` sequences in comment content could break out of block comment context and inject arbitrary DOT syntax.
|
|
69
|
+
|
|
70
|
+
## Security Enhancement
|
|
71
|
+
|
|
72
|
+
### Comment Content Escaping
|
|
73
|
+
|
|
74
|
+
- Added `escapeComment()` utility function to sanitize comment content
|
|
75
|
+
- Block comments: Breaks up `*/` sequences using zero-width space (U+200B) to prevent early comment termination
|
|
76
|
+
- All comment types: Removes null bytes that could cause parsing issues
|
|
77
|
+
- Follows C/C++ and DOT language specifications where block comments cannot be nested
|
|
78
|
+
|
|
79
|
+
## Changes
|
|
80
|
+
|
|
81
|
+
### New Utility Function
|
|
82
|
+
|
|
83
|
+
- `escapeComment()` in `packages/ast/src/dot-shim/printer/plugins/utils/escape-comment.ts`
|
|
84
|
+
- Prevents comment injection by inserting zero-width space between `*` and `/`
|
|
85
|
+
- Maintains visual appearance while preventing syntax injection
|
|
86
|
+
- Verified to work with Graphviz 13.1.1
|
|
87
|
+
|
|
88
|
+
### Updated Components
|
|
89
|
+
|
|
90
|
+
- `CommentPrintPlugin` now applies escaping before outputting comment content
|
|
91
|
+
- All comment values are sanitized at print time, not at creation time
|
|
92
|
+
- Maintains backward compatibility with existing AST structures
|
|
93
|
+
|
|
94
|
+
### Testing
|
|
95
|
+
|
|
96
|
+
- 11 unit tests for `escapeComment()` function covering:
|
|
97
|
+
- Block comment injection prevention
|
|
98
|
+
- Multiple `*/` sequence handling
|
|
99
|
+
- Null byte removal
|
|
100
|
+
- Normal content preservation
|
|
101
|
+
- Integration tests in `stringify.test.ts` for end-to-end verification
|
|
102
|
+
- All existing tests continue to pass
|
|
103
|
+
|
|
104
|
+
## Security Impact
|
|
105
|
+
|
|
106
|
+
- Prevents DOT syntax injection via malicious comment content
|
|
107
|
+
- Blocks attempts to escape comment context and inject arbitrary graph definitions
|
|
108
|
+
- Protects against parser manipulation through crafted comment values
|
|
109
|
+
- Zero-width space approach is standards-compliant and validated with official Graphviz parser
|
|
110
|
+
|
|
111
|
+
## Technical Details
|
|
112
|
+
|
|
113
|
+
According to C/C++ and DOT language specifications, block comments (`/* */`) cannot be nested and there is no escape sequence for the closing delimiter within comments. The standard workaround is to insert a zero-width space (U+200B) between `*` and `/`, which:
|
|
114
|
+
|
|
115
|
+
- Prevents early comment termination
|
|
116
|
+
- Preserves visual appearance (zero-width character is invisible)
|
|
117
|
+
- Is correctly handled by Graphviz parser (tested with version 13.1.1)
|
|
118
|
+
- Follows industry best practices for comment sanitization
|
|
119
|
+
|
|
120
|
+
- Updated dependencies [[`dc3ef34`](https://github.com/ts-graphviz/ts-graphviz/commit/dc3ef34316f5642c416711cb6a50704dbef7bb64)]:
|
|
121
|
+
- @ts-graphviz/common@3.0.4-next-11f7126347816f64f7892c8608b5e3bf1a826670
|
|
122
|
+
|
|
3
123
|
## 3.0.4
|
|
4
124
|
|
|
5
125
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -73,18 +73,47 @@ The `parse` function accepts an optional second argument for configuration:
|
|
|
73
73
|
```ts
|
|
74
74
|
import { parse } from "@ts-graphviz/ast";
|
|
75
75
|
|
|
76
|
-
// Parse with custom
|
|
76
|
+
// Parse with custom security limits
|
|
77
77
|
const ast = parse(dotString, {
|
|
78
|
-
startRule: 'Dot',
|
|
79
|
-
maxHtmlNestingDepth: 200
|
|
78
|
+
startRule: 'Dot', // Specify the starting rule (default: 'Dot')
|
|
79
|
+
maxHtmlNestingDepth: 200, // Maximum HTML nesting depth (default: 100)
|
|
80
|
+
maxEdgeChainDepth: 2000, // Maximum edge chain depth (default: 1000)
|
|
81
|
+
maxInputSize: 20971520, // Maximum input size in bytes (default: 10MB)
|
|
82
|
+
maxASTNodes: 200000 // Maximum AST nodes (default: 100,000)
|
|
80
83
|
});
|
|
81
84
|
```
|
|
82
85
|
|
|
86
|
+
**Available Options**:
|
|
87
|
+
|
|
88
|
+
| Option | Default | Description |
|
|
89
|
+
|--------|---------|-------------|
|
|
90
|
+
| `startRule` | `'Dot'` | Starting grammar rule for parsing |
|
|
91
|
+
| `maxHtmlNestingDepth` | `100` | Maximum depth of nested HTML-like structures |
|
|
92
|
+
| `maxEdgeChainDepth` | `1000` | Maximum depth of chained edges (e.g., `a -> b -> c -> ...`) |
|
|
93
|
+
| `maxInputSize` | `10485760` (10MB) | Maximum input size in bytes |
|
|
94
|
+
| `maxASTNodes` | `100000` | Maximum number of AST nodes to create |
|
|
95
|
+
|
|
83
96
|
**Security Note**:
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
-
|
|
97
|
+
|
|
98
|
+
These limits protect against denial-of-service attacks:
|
|
99
|
+
|
|
100
|
+
- **`maxHtmlNestingDepth`**: Prevents stack overflow from deeply nested HTML-like structures
|
|
101
|
+
- Normal use cases: typically <10 levels
|
|
102
|
+
- HTML-like labels are GraphViz DOT syntax, not browser HTML
|
|
103
|
+
|
|
104
|
+
- **`maxEdgeChainDepth`**: Prevents stack overflow from deeply chained edges
|
|
105
|
+
- Example dangerous input: `a -> b -> c -> ... -> z (1000+ nodes)`
|
|
106
|
+
|
|
107
|
+
- **`maxInputSize`**: Prevents memory exhaustion from extremely large files
|
|
108
|
+
- Default 10MB is sufficient for most legitimate graphs
|
|
109
|
+
- Can be increased for known large graphs or disabled with `0` (not recommended for untrusted input)
|
|
110
|
+
|
|
111
|
+
- **`maxASTNodes`**: Prevents memory exhaustion from inputs with excessive elements
|
|
112
|
+
- Each DOT element creates multiple AST nodes
|
|
113
|
+
- Example: A single node statement (`node1;`) creates ~2-3 AST nodes
|
|
114
|
+
- Can be disabled with `0` (not recommended for untrusted input)
|
|
115
|
+
|
|
116
|
+
**Important**: When processing untrusted DOT files (e.g., user uploads), keep these limits enabled with conservative values appropriate for your environment. For additional validation of untrusted content, see the validation guide in [@ts-graphviz/adapter documentation](../adapter/README.md#security-considerations).
|
|
88
117
|
|
|
89
118
|
### Generating DOT Language
|
|
90
119
|
|
package/lib/ast.d.ts
CHANGED
|
@@ -66,6 +66,23 @@ export declare interface ASTCommonPropaties {
|
|
|
66
66
|
*/
|
|
67
67
|
export declare type ASTNode = LiteralASTNode | DotASTNode | GraphASTNode | AttributeASTNode | CommentASTNode | AttributeListASTNode | NodeRefASTNode | NodeRefGroupASTNode | EdgeASTNode | NodeASTNode | SubgraphASTNode;
|
|
68
68
|
|
|
69
|
+
/**
|
|
70
|
+
* Error thrown when the AST node count exceeds the maximum allowed limit.
|
|
71
|
+
* This error is thrown during parsing to prevent memory exhaustion attacks.
|
|
72
|
+
*
|
|
73
|
+
* @group Create AST
|
|
74
|
+
*/
|
|
75
|
+
export declare class ASTNodeCountExceededError extends Error {
|
|
76
|
+
nodeCount: number;
|
|
77
|
+
maxNodes: number;
|
|
78
|
+
/**
|
|
79
|
+
* Constructor
|
|
80
|
+
* @param nodeCount - The current node count when the limit was exceeded
|
|
81
|
+
* @param maxNodes - The maximum allowed node count
|
|
82
|
+
*/
|
|
83
|
+
constructor(nodeCount: number, maxNodes: number);
|
|
84
|
+
}
|
|
85
|
+
|
|
69
86
|
/**
|
|
70
87
|
* ASTToModel is a type that determines a model type from an AST.
|
|
71
88
|
*
|
|
@@ -115,6 +132,8 @@ export declare interface AttributeListASTPropaties extends ASTCommonPropaties {
|
|
|
115
132
|
*/
|
|
116
133
|
export declare class Builder implements ASTBuilder {
|
|
117
134
|
private options?;
|
|
135
|
+
private nodeCount;
|
|
136
|
+
private maxNodes;
|
|
118
137
|
/* Excluded from this release type: getLocation */
|
|
119
138
|
/**
|
|
120
139
|
* Constructor of Builder
|
|
@@ -128,8 +147,10 @@ export declare class Builder implements ASTBuilder {
|
|
|
128
147
|
* @param props - Properties of the {@link ASTNode}
|
|
129
148
|
* @param children - Children of the {@link ASTNode}
|
|
130
149
|
* @returns An {@link ASTNode}
|
|
150
|
+
* @throws {ASTNodeCountExceededError} if the maximum number of AST nodes is exceeded
|
|
131
151
|
*/
|
|
132
152
|
createElement<T extends ASTNode>(type: T['type'], props: any, children?: ASTChildNode<T>[]): T;
|
|
153
|
+
/* Excluded from this release type: resetNodeCount */
|
|
133
154
|
}
|
|
134
155
|
|
|
135
156
|
/**
|
|
@@ -143,6 +164,12 @@ export declare interface BuilderOptions {
|
|
|
143
164
|
* It is used to specify the location of the builder.
|
|
144
165
|
*/
|
|
145
166
|
locationFunction: () => FileRange;
|
|
167
|
+
/**
|
|
168
|
+
* Maximum allowed number of AST nodes to create.
|
|
169
|
+
* Default is 100000. Set to 0 to disable this limit.
|
|
170
|
+
* @default 100000
|
|
171
|
+
*/
|
|
172
|
+
maxASTNodes?: number;
|
|
146
173
|
}
|
|
147
174
|
|
|
148
175
|
/**
|
|
@@ -201,6 +228,20 @@ export declare interface CommonParseOptions {
|
|
|
201
228
|
* @default 1000
|
|
202
229
|
*/
|
|
203
230
|
maxEdgeChainDepth?: number;
|
|
231
|
+
/**
|
|
232
|
+
* maxInputSize (optional): Maximum allowed input size in bytes.
|
|
233
|
+
* Default is 10MB (10485760 bytes). This limit prevents memory exhaustion from extremely large inputs.
|
|
234
|
+
* Set to 0 to disable this limit (not recommended for untrusted inputs).
|
|
235
|
+
* @default 10485760
|
|
236
|
+
*/
|
|
237
|
+
maxInputSize?: number;
|
|
238
|
+
/**
|
|
239
|
+
* maxASTNodes (optional): Maximum allowed number of AST nodes to create during parsing.
|
|
240
|
+
* Default is 100000. This limit prevents memory exhaustion from inputs with excessive elements.
|
|
241
|
+
* Set to 0 to disable this limit (not recommended for untrusted inputs).
|
|
242
|
+
* @default 100000
|
|
243
|
+
*/
|
|
244
|
+
maxASTNodes?: number;
|
|
204
245
|
}
|
|
205
246
|
|
|
206
247
|
/**
|
package/lib/ast.js
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
import { isNodeModel, isForwardRefNode, createModelsContext } from "@ts-graphviz/common";
|
|
2
|
+
class ASTNodeCountExceededError extends Error {
|
|
3
|
+
/**
|
|
4
|
+
* Constructor
|
|
5
|
+
* @param nodeCount - The current node count when the limit was exceeded
|
|
6
|
+
* @param maxNodes - The maximum allowed node count
|
|
7
|
+
*/
|
|
8
|
+
constructor(nodeCount, maxNodes) {
|
|
9
|
+
super(
|
|
10
|
+
`AST node count (${nodeCount}) exceeds maximum allowed (${maxNodes}). Consider increasing 'maxASTNodes' option or simplifying the input.`
|
|
11
|
+
);
|
|
12
|
+
this.nodeCount = nodeCount;
|
|
13
|
+
this.maxNodes = maxNodes;
|
|
14
|
+
this.name = "ASTNodeCountExceededError";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
const DEFAULT_MAX_AST_NODES = 1e5;
|
|
2
18
|
class Builder {
|
|
3
19
|
/**
|
|
4
20
|
* Constructor of Builder
|
|
@@ -6,7 +22,10 @@ class Builder {
|
|
|
6
22
|
*/
|
|
7
23
|
constructor(options) {
|
|
8
24
|
this.options = options;
|
|
25
|
+
this.maxNodes = options?.maxASTNodes ?? DEFAULT_MAX_AST_NODES;
|
|
9
26
|
}
|
|
27
|
+
nodeCount = 0;
|
|
28
|
+
maxNodes;
|
|
10
29
|
/**
|
|
11
30
|
* Get the current file range or null
|
|
12
31
|
* @internal
|
|
@@ -21,8 +40,13 @@ class Builder {
|
|
|
21
40
|
* @param props - Properties of the {@link ASTNode}
|
|
22
41
|
* @param children - Children of the {@link ASTNode}
|
|
23
42
|
* @returns An {@link ASTNode}
|
|
43
|
+
* @throws {ASTNodeCountExceededError} if the maximum number of AST nodes is exceeded
|
|
24
44
|
*/
|
|
25
45
|
createElement(type, props, children = []) {
|
|
46
|
+
this.nodeCount++;
|
|
47
|
+
if (this.maxNodes > 0 && this.nodeCount > this.maxNodes) {
|
|
48
|
+
throw new ASTNodeCountExceededError(this.nodeCount, this.maxNodes);
|
|
49
|
+
}
|
|
26
50
|
return {
|
|
27
51
|
location: this.getLocation(),
|
|
28
52
|
...props,
|
|
@@ -30,6 +54,13 @@ class Builder {
|
|
|
30
54
|
children
|
|
31
55
|
};
|
|
32
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Reset the node count. Used internally by the parser between parse invocations.
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
resetNodeCount() {
|
|
62
|
+
this.nodeCount = 0;
|
|
63
|
+
}
|
|
33
64
|
}
|
|
34
65
|
const createElement = Builder.prototype.createElement.bind(new Builder());
|
|
35
66
|
class peg$SyntaxError extends SyntaxError {
|
|
@@ -2718,8 +2749,16 @@ function peg$parse(input, options) {
|
|
|
2718
2749
|
let htmlNestingDepth = 0;
|
|
2719
2750
|
let edgeChainDepth = 0;
|
|
2720
2751
|
const b = new Builder({
|
|
2721
|
-
locationFunction: location
|
|
2752
|
+
locationFunction: location,
|
|
2753
|
+
maxASTNodes: options.maxASTNodes
|
|
2722
2754
|
});
|
|
2755
|
+
function resetState() {
|
|
2756
|
+
b.resetNodeCount();
|
|
2757
|
+
htmlNestingDepth = 0;
|
|
2758
|
+
edgeChainDepth = 0;
|
|
2759
|
+
edgeops.length = 0;
|
|
2760
|
+
}
|
|
2761
|
+
resetState();
|
|
2723
2762
|
peg$result = peg$startRuleFunction();
|
|
2724
2763
|
const peg$success = peg$result !== peg$FAILED && peg$currPos === input.length;
|
|
2725
2764
|
function peg$throw() {
|
|
@@ -2752,14 +2791,32 @@ function peg$parse(input, options) {
|
|
|
2752
2791
|
peg$throw();
|
|
2753
2792
|
}
|
|
2754
2793
|
}
|
|
2794
|
+
const DEFAULT_MAX_INPUT_SIZE = 10 * 1024 * 1024;
|
|
2755
2795
|
function parse(input, options) {
|
|
2756
|
-
const {
|
|
2796
|
+
const {
|
|
2797
|
+
startRule,
|
|
2798
|
+
filename,
|
|
2799
|
+
maxHtmlNestingDepth,
|
|
2800
|
+
maxEdgeChainDepth,
|
|
2801
|
+
maxInputSize,
|
|
2802
|
+
maxASTNodes
|
|
2803
|
+
} = options ?? {};
|
|
2804
|
+
const inputSizeLimit = maxInputSize ?? DEFAULT_MAX_INPUT_SIZE;
|
|
2805
|
+
if (inputSizeLimit > 0) {
|
|
2806
|
+
const inputBytes = new TextEncoder().encode(input).length;
|
|
2807
|
+
if (inputBytes > inputSizeLimit) {
|
|
2808
|
+
throw new DotSyntaxError(
|
|
2809
|
+
`Input size (${inputBytes} bytes) exceeds maximum allowed size (${inputSizeLimit} bytes). Consider increasing 'maxInputSize' option or reducing the input size.`
|
|
2810
|
+
);
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2757
2813
|
try {
|
|
2758
2814
|
return peg$parse(input, {
|
|
2759
2815
|
startRule,
|
|
2760
2816
|
filename,
|
|
2761
2817
|
maxHtmlNestingDepth,
|
|
2762
|
-
maxEdgeChainDepth
|
|
2818
|
+
maxEdgeChainDepth,
|
|
2819
|
+
maxASTNodes
|
|
2763
2820
|
});
|
|
2764
2821
|
} catch (e) {
|
|
2765
2822
|
if (e instanceof peg$SyntaxError) {
|
|
@@ -2767,6 +2824,11 @@ function parse(input, options) {
|
|
|
2767
2824
|
cause: e
|
|
2768
2825
|
});
|
|
2769
2826
|
}
|
|
2827
|
+
if (e instanceof ASTNodeCountExceededError) {
|
|
2828
|
+
throw new DotSyntaxError(e.message, {
|
|
2829
|
+
cause: e
|
|
2830
|
+
});
|
|
2831
|
+
}
|
|
2770
2832
|
throw new Error("Unexpected parse error", {
|
|
2771
2833
|
cause: e
|
|
2772
2834
|
});
|
|
@@ -2803,6 +2865,14 @@ const AttributePrintPlugin = {
|
|
|
2803
2865
|
yield ";";
|
|
2804
2866
|
}
|
|
2805
2867
|
};
|
|
2868
|
+
const ZERO_WIDTH_SPACE = "";
|
|
2869
|
+
function escapeComment(value, kind) {
|
|
2870
|
+
let escaped = value.replace(/\0/g, "");
|
|
2871
|
+
if (kind === "Block") {
|
|
2872
|
+
escaped = escaped.replace(/\*\//g, `*${ZERO_WIDTH_SPACE}/`);
|
|
2873
|
+
}
|
|
2874
|
+
return escaped;
|
|
2875
|
+
}
|
|
2806
2876
|
const EOL_PATTERN = /\r?\n/;
|
|
2807
2877
|
const paddingMap = {
|
|
2808
2878
|
Block: " * ",
|
|
@@ -2818,7 +2888,8 @@ const CommentPrintPlugin = {
|
|
|
2818
2888
|
if (ast.kind === "Block") {
|
|
2819
2889
|
yield* ["/**", context.EOL];
|
|
2820
2890
|
}
|
|
2821
|
-
const
|
|
2891
|
+
const escapedValue = escapeComment(ast.value, ast.kind);
|
|
2892
|
+
const lines = escapedValue.split(EOL_PATTERN);
|
|
2822
2893
|
const lineLength = lines.length;
|
|
2823
2894
|
for (let i = 0; i < lineLength; i++) {
|
|
2824
2895
|
yield padding;
|
|
@@ -3108,7 +3179,7 @@ function convertComment(value, kind) {
|
|
|
3108
3179
|
}
|
|
3109
3180
|
function convertClusterChildren(context, model) {
|
|
3110
3181
|
return Array.from(
|
|
3111
|
-
function* () {
|
|
3182
|
+
(function* () {
|
|
3112
3183
|
for (const [key, value] of model.values) {
|
|
3113
3184
|
yield convertAttribute(key, value);
|
|
3114
3185
|
}
|
|
@@ -3138,7 +3209,7 @@ function convertClusterChildren(context, model) {
|
|
|
3138
3209
|
}
|
|
3139
3210
|
yield context.convert(edge);
|
|
3140
3211
|
}
|
|
3141
|
-
}()
|
|
3212
|
+
})()
|
|
3142
3213
|
);
|
|
3143
3214
|
}
|
|
3144
3215
|
const AttributeListPlugin = {
|
|
@@ -3605,6 +3676,7 @@ function toModel(ast, options) {
|
|
|
3605
3676
|
return new ToModelConverter(options).convert(ast);
|
|
3606
3677
|
}
|
|
3607
3678
|
export {
|
|
3679
|
+
ASTNodeCountExceededError,
|
|
3608
3680
|
Builder,
|
|
3609
3681
|
DotSyntaxError,
|
|
3610
3682
|
FromModelConverter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ts-graphviz/ast",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5-next-11f7126347816f64f7892c8608b5e3bf1a826670",
|
|
4
4
|
"description": "Graphviz AST(Abstract Syntax Tree) Utilities",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"homepage": "https://github.com/ts-graphviz/ts-graphviz#readme",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
"./package.json": "./package.json"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@ts-graphviz/common": "^3.0.
|
|
36
|
+
"@ts-graphviz/common": "^3.0.4-next-11f7126347816f64f7892c8608b5e3bf1a826670"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
39
|
"peggy": "^5.0.6",
|
|
40
40
|
"typescript": "^5.8.2",
|
|
41
|
-
"vite": "^7.0.
|
|
41
|
+
"vite": "^7.0.8",
|
|
42
42
|
"vite-plugin-dts": "^4.5.3"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|