@herb-tools/printer 0.6.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 +123 -0
- package/bin/herb-print +3 -0
- package/dist/cli.js +190 -0
- package/dist/cli.js.map +1 -0
- package/dist/herb-print.js +17200 -0
- package/dist/herb-print.js.map +1 -0
- package/dist/identity-printer.js +13 -0
- package/dist/identity-printer.js.map +1 -0
- package/dist/index.cjs +436 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.js +431 -0
- package/dist/index.js.map +1 -0
- package/dist/print-context.js +92 -0
- package/dist/print-context.js.map +1 -0
- package/dist/printer.js +325 -0
- package/dist/printer.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/cli.d.ts +6 -0
- package/dist/types/herb-print.d.ts +2 -0
- package/dist/types/identity-printer.d.ts +12 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/print-context.d.ts +54 -0
- package/dist/types/printer.d.ts +75 -0
- package/package.json +50 -0
- package/src/cli.ts +226 -0
- package/src/herb-print.ts +6 -0
- package/src/identity-printer.ts +14 -0
- package/src/index.ts +4 -0
- package/src/print-context.ts +104 -0
- package/src/printer.ts +438 -0
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Herb Syntax Tree Printer
|
|
2
|
+
|
|
3
|
+
**Package:** [`@herb-tools/printer`](https://www.npmjs.com/package/@herb-tools/printer)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
AST printer infrastructure for lossless HTML+ERB reconstruction and AST-to-source code conversion for the Herb Parser Syntax Tree.
|
|
8
|
+
|
|
9
|
+
### Installation
|
|
10
|
+
|
|
11
|
+
:::code-group
|
|
12
|
+
```shell [npm]
|
|
13
|
+
npm add @herb-tools/printer
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```shell [pnpm]
|
|
17
|
+
pnpm add @herb-tools/printer
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
```shell [yarn]
|
|
21
|
+
yarn add @herb-tools/printer
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```shell [bun]
|
|
25
|
+
bun add @herb-tools/printer
|
|
26
|
+
```
|
|
27
|
+
:::
|
|
28
|
+
|
|
29
|
+
### Usage
|
|
30
|
+
|
|
31
|
+
#### IdentityPrinter (Provides lossless reconstruction of the original source)
|
|
32
|
+
|
|
33
|
+
For lossless reconstruction of the original source:
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
import { IdentityPrinter } from '@herb-tools/printer'
|
|
37
|
+
import { Herb } from '@herb-tools/node-wasm'
|
|
38
|
+
|
|
39
|
+
await Herb.load()
|
|
40
|
+
|
|
41
|
+
const parseResult = Herb.parse(
|
|
42
|
+
'<div class="hello" > Hello </div>',
|
|
43
|
+
{ track_whitespace: true }
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
const printer = new IdentityPrinter()
|
|
47
|
+
const output = printer.print(parseResult.value)
|
|
48
|
+
|
|
49
|
+
// output === '<div class="hello" > Hello </div>' (exact preservation)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
#### Custom Printers
|
|
53
|
+
|
|
54
|
+
Create custom printers by extending the base `Printer` class and override specific visitors for custom behavior:
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
import { Printer } from "@herb-tools/printer"
|
|
58
|
+
import { HTMLAttributeNode } from "@herb-tools/core"
|
|
59
|
+
|
|
60
|
+
class CustomPrinter extends Printer {
|
|
61
|
+
protected write(content: string) {
|
|
62
|
+
super.write(content.toUpperCase())
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
protected visitHTMLAttributeNode(node: HTMLAttributeNode) {
|
|
66
|
+
// do nothing to strip attributes
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
and then printing the result using `print`
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
import { Herb } from "@herb-tools/node-wasm"
|
|
75
|
+
|
|
76
|
+
await Herb.load()
|
|
77
|
+
|
|
78
|
+
const parseResult = Herb.parse(
|
|
79
|
+
'<div class="hello"> Hello </div>',
|
|
80
|
+
{ track_whitespace: true }
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
const printer = new CustomPrinter()
|
|
84
|
+
const output = printer.print(parseResult.value)
|
|
85
|
+
|
|
86
|
+
// output === '<div > HELLO </div>'
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### Print Options
|
|
90
|
+
|
|
91
|
+
The printer supports options to control how nodes are printed:
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { IdentityPrinter, DEFAULT_PRINT_OPTIONS } from "@herb-tools/printer"
|
|
95
|
+
import type { PrintOptions } from "@herb-tools/printer"
|
|
96
|
+
|
|
97
|
+
const printer = new IdentityPrinter()
|
|
98
|
+
|
|
99
|
+
// Will throw error if node has parse errors (default behavior)
|
|
100
|
+
const output1 = printer.print(nodeWithErrors)
|
|
101
|
+
|
|
102
|
+
// Will print the node despite parse errors
|
|
103
|
+
const output2 = printer.print(nodeWithErrors, { ignoreErrors: true })
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
When `ignoreErrors` is `false` (default), the printer will throw an error if you attempt to print a node that contains parse errors. Set `ignoreErrors` to `true` to print nodes with errors, which can be useful for debugging or partial AST reconstruction.
|
|
107
|
+
|
|
108
|
+
:::warning Important
|
|
109
|
+
The Printer expects the source to be parsed using the `track_whitespace: true` parser option for accurate source reconstruction.
|
|
110
|
+
:::
|
|
111
|
+
|
|
112
|
+
#### CLI Usage
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Basic round-trip printing
|
|
116
|
+
herb-print input.html.erb > output.html.erb
|
|
117
|
+
|
|
118
|
+
# Verify parser accuracy
|
|
119
|
+
herb-print input.html.erb --verify
|
|
120
|
+
|
|
121
|
+
# Show parsing statistics
|
|
122
|
+
herb-print input.html.erb --stats
|
|
123
|
+
```
|
package/bin/herb-print
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import dedent from "dedent";
|
|
3
|
+
import { readFileSync, writeFileSync } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
import { glob } from "glob";
|
|
6
|
+
import { Herb } from "@herb-tools/node-wasm";
|
|
7
|
+
import { IdentityPrinter } from "./index.js";
|
|
8
|
+
export class CLI {
|
|
9
|
+
parseArgs(args) {
|
|
10
|
+
const options = {};
|
|
11
|
+
for (let i = 2; i < args.length; i++) {
|
|
12
|
+
const arg = args[i];
|
|
13
|
+
switch (arg) {
|
|
14
|
+
case '-i':
|
|
15
|
+
case '--input':
|
|
16
|
+
options.input = args[++i];
|
|
17
|
+
break;
|
|
18
|
+
case '-o':
|
|
19
|
+
case '--output':
|
|
20
|
+
options.output = args[++i];
|
|
21
|
+
break;
|
|
22
|
+
case '--verify':
|
|
23
|
+
options.verify = true;
|
|
24
|
+
break;
|
|
25
|
+
case '--stats':
|
|
26
|
+
options.stats = true;
|
|
27
|
+
break;
|
|
28
|
+
case '--glob':
|
|
29
|
+
options.glob = true;
|
|
30
|
+
break;
|
|
31
|
+
case '-h':
|
|
32
|
+
case '--help':
|
|
33
|
+
options.help = true;
|
|
34
|
+
break;
|
|
35
|
+
default:
|
|
36
|
+
if (!arg.startsWith('-') && !options.input) {
|
|
37
|
+
options.input = arg;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return options;
|
|
42
|
+
}
|
|
43
|
+
showHelp() {
|
|
44
|
+
console.log(dedent `
|
|
45
|
+
herb-print - Print HTML+ERB AST back to source code
|
|
46
|
+
|
|
47
|
+
This tool parses HTML+ERB templates and prints them back, preserving the original
|
|
48
|
+
formatting as closely as possible. Useful for testing parser accuracy and as a
|
|
49
|
+
baseline for other transformations.
|
|
50
|
+
|
|
51
|
+
Usage:
|
|
52
|
+
herb-print [options] <input-file-or-pattern>
|
|
53
|
+
herb-print -i <input-file> -o <output-file>
|
|
54
|
+
|
|
55
|
+
Options:
|
|
56
|
+
-i, --input <file> Input file path
|
|
57
|
+
-o, --output <file> Output file path (defaults to stdout)
|
|
58
|
+
--verify Verify that output matches input exactly
|
|
59
|
+
--stats Show parsing and printing statistics
|
|
60
|
+
--glob Treat input as glob pattern (default: **/*.html.erb)
|
|
61
|
+
-h, --help Show this help message
|
|
62
|
+
|
|
63
|
+
Examples:
|
|
64
|
+
# Single file
|
|
65
|
+
herb-print input.html.erb > output.html.erb
|
|
66
|
+
herb-print -i input.html.erb -o output.html.erb --verify
|
|
67
|
+
herb-print input.html.erb --stats
|
|
68
|
+
|
|
69
|
+
# Glob patterns (batch verification)
|
|
70
|
+
herb-print --glob --verify # All .html.erb files
|
|
71
|
+
herb-print "app/views/**/*.html.erb" --glob --verify --stats
|
|
72
|
+
herb-print "*.erb" --glob --verify
|
|
73
|
+
herb-print "/path/to/templates" --glob --verify # Directory (auto-appends /**/*.html.erb)
|
|
74
|
+
herb-print "/path/to/templates/**/*.html.erb" --glob --verify
|
|
75
|
+
|
|
76
|
+
# The --verify flag is useful to test parser fidelity:
|
|
77
|
+
herb-print input.html.erb --verify
|
|
78
|
+
# Checks if parsing and printing results in identical content
|
|
79
|
+
`);
|
|
80
|
+
}
|
|
81
|
+
async run() {
|
|
82
|
+
const options = this.parseArgs(process.argv);
|
|
83
|
+
if (options.help || (!options.input && !options.glob)) {
|
|
84
|
+
this.showHelp();
|
|
85
|
+
process.exit(0);
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
await Herb.load();
|
|
89
|
+
if (options.glob) {
|
|
90
|
+
const pattern = options.input || "**/*.html.erb";
|
|
91
|
+
const files = await glob(pattern);
|
|
92
|
+
if (files.length === 0) {
|
|
93
|
+
console.error(`No files found matching pattern: ${pattern}`);
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
let totalFiles = 0;
|
|
97
|
+
let failedFiles = 0;
|
|
98
|
+
let verificationFailures = 0;
|
|
99
|
+
let totalBytes = 0;
|
|
100
|
+
console.log(`Processing ${files.length} files...\n`);
|
|
101
|
+
for (const file of files) {
|
|
102
|
+
try {
|
|
103
|
+
const input = readFileSync(file, 'utf-8');
|
|
104
|
+
const parseResult = Herb.parse(input, { track_whitespace: true });
|
|
105
|
+
if (parseResult.errors.length > 0) {
|
|
106
|
+
console.error(`\x1b[31m✗\x1b[0m \x1b[1m${file}\x1b[0m: \x1b[1m\x1b[31mFailed\x1b[0m to parse`);
|
|
107
|
+
failedFiles++;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const printer = new IdentityPrinter();
|
|
111
|
+
const output = printer.print(parseResult.value);
|
|
112
|
+
totalFiles++;
|
|
113
|
+
totalBytes += input.length;
|
|
114
|
+
if (options.verify) {
|
|
115
|
+
if (input === output) {
|
|
116
|
+
console.log(`\x1b[32m✓\x1b[0m \x1b[1m${file}\x1b[0m: \x1b[32mPerfect match\x1b[0m`);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
console.error(`\x1b[31m✗\x1b[0m \x1b[1m${file}\x1b[0m: \x1b[1m\x1b[31mVerification failed\x1b[0m - differences detected`);
|
|
120
|
+
verificationFailures++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
console.log(`\x1b[32m✓\x1b[0m \x1b[1m${file}\x1b[0m: \x1b[32mProcessed\x1b[0m`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch (error) {
|
|
128
|
+
console.error(`\x1b[31m✗\x1b[0m \x1b[1m${file}\x1b[0m: \x1b[1m\x1b[31mError\x1b[0m - ${error}`);
|
|
129
|
+
failedFiles++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
console.log(`\nSummary:`);
|
|
133
|
+
console.log(` Files processed: ${totalFiles}`);
|
|
134
|
+
console.log(` Files failed: ${failedFiles}`);
|
|
135
|
+
if (options.verify) {
|
|
136
|
+
console.log(` Verifications: ${totalFiles - verificationFailures} passed, ${verificationFailures} failed`);
|
|
137
|
+
}
|
|
138
|
+
if (options.stats) {
|
|
139
|
+
console.log(` Total bytes: ${totalBytes}`);
|
|
140
|
+
}
|
|
141
|
+
process.exit(failedFiles > 0 || verificationFailures > 0 ? 1 : 0);
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
const inputPath = resolve(options.input);
|
|
145
|
+
const input = readFileSync(inputPath, 'utf-8');
|
|
146
|
+
const parseResult = Herb.parse(input, { track_whitespace: true });
|
|
147
|
+
if (parseResult.errors.length > 0) {
|
|
148
|
+
console.error('Parse errors:', parseResult.errors.map(e => e.message).join(', '));
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
const printer = new IdentityPrinter();
|
|
152
|
+
const output = printer.print(parseResult.value);
|
|
153
|
+
if (options.output) {
|
|
154
|
+
const outputPath = resolve(options.output);
|
|
155
|
+
writeFileSync(outputPath, output, 'utf-8');
|
|
156
|
+
console.log(`Output written to: ${outputPath}`);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
console.log(output);
|
|
160
|
+
}
|
|
161
|
+
if (options.verify) {
|
|
162
|
+
if (input === output) {
|
|
163
|
+
console.error('\x1b[32m✓ Verification passed\x1b[0m - output matches input exactly');
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.error('\x1b[31m✗ Verification failed\x1b[0m - output differs from input');
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (options.stats) {
|
|
171
|
+
const errors = parseResult.errors?.length || 0;
|
|
172
|
+
const warnings = parseResult.warnings?.length || 0;
|
|
173
|
+
console.error(dedent `
|
|
174
|
+
Printing Statistics:
|
|
175
|
+
Input size: ${input.length} bytes
|
|
176
|
+
Output size: ${output.length} bytes
|
|
177
|
+
Parse errors: ${errors}
|
|
178
|
+
Parse warnings: ${warnings}
|
|
179
|
+
Round-trip: ${input === output ? 'Perfect' : 'Differences detected'}
|
|
180
|
+
`);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.error('Error:', error instanceof Error ? error.message : error);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,MAAM,MAAM,QAAQ,CAAA;AAE3B,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,IAAI,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAE3B,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAW5C,MAAM,OAAO,GAAG;IACN,SAAS,CAAC,IAAc;QAC9B,MAAM,OAAO,GAAe,EAAE,CAAA;QAE9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YAEnB,QAAQ,GAAG,EAAE,CAAC;gBACZ,KAAK,IAAI,CAAC;gBACV,KAAK,SAAS;oBACZ,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;oBACzB,MAAK;gBACP,KAAK,IAAI,CAAC;gBACV,KAAK,UAAU;oBACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;oBAC1B,MAAK;gBACP,KAAK,UAAU;oBACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAA;oBACrB,MAAK;gBACP,KAAK,SAAS;oBACZ,OAAO,CAAC,KAAK,GAAG,IAAI,CAAA;oBACpB,MAAK;gBACP,KAAK,QAAQ;oBACX,OAAO,CAAC,IAAI,GAAG,IAAI,CAAA;oBACnB,MAAK;gBACP,KAAK,IAAI,CAAC;gBACV,KAAK,QAAQ;oBACX,OAAO,CAAC,IAAI,GAAG,IAAI,CAAA;oBACnB,MAAK;gBACP;oBACE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;wBAC3C,OAAO,CAAC,KAAK,GAAG,GAAG,CAAA;oBACrB,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAA;IAChB,CAAC;IAEO,QAAQ;QACd,OAAO,CAAC,GAAG,CAAC,MAAM,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAmCjB,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,GAAG;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QAE5C,IAAI,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,QAAQ,EAAE,CAAA;YACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,IAAI,EAAE,CAAA;YAEjB,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;gBACjB,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,eAAe,CAAA;gBAChD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,CAAA;gBAEjC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACvB,OAAO,CAAC,KAAK,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAA;oBAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBACjB,CAAC;gBAED,IAAI,UAAU,GAAG,CAAC,CAAA;gBAClB,IAAI,WAAW,GAAG,CAAC,CAAA;gBACnB,IAAI,oBAAoB,GAAG,CAAC,CAAA;gBAC5B,IAAI,UAAU,GAAG,CAAC,CAAA;gBAElB,OAAO,CAAC,GAAG,CAAC,cAAc,KAAK,CAAC,MAAM,aAAa,CAAC,CAAA;gBAEpD,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,IAAI,CAAC;wBACH,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;wBACzC,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAA;wBAEjE,IAAI,WAAW,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BAClC,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,gDAAgD,CAAC,CAAA;4BAC9F,WAAW,EAAE,CAAA;4BACb,SAAQ;wBACV,CAAC;wBAED,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;wBACrC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;wBAE/C,UAAU,EAAE,CAAA;wBACZ,UAAU,IAAI,KAAK,CAAC,MAAM,CAAA;wBAE1B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;4BACnB,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;gCACrB,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,uCAAuC,CAAC,CAAA;4BACrF,CAAC;iCAAM,CAAC;gCACN,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,2EAA2E,CAAC,CAAA;gCACzH,oBAAoB,EAAE,CAAA;4BACxB,CAAC;wBACH,CAAC;6BAAM,CAAC;4BACN,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,mCAAmC,CAAC,CAAA;wBACjF,CAAC;oBAEH,CAAC;oBAAC,OAAO,KAAK,EAAE,CAAC;wBACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,IAAI,0CAA0C,KAAK,EAAE,CAAC,CAAA;wBAC/F,WAAW,EAAE,CAAA;oBACf,CAAC;gBACH,CAAC;gBAED,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAA;gBACzB,OAAO,CAAC,GAAG,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAA;gBAC/C,OAAO,CAAC,GAAG,CAAC,sBAAsB,WAAW,EAAE,CAAC,CAAA;gBAEhD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;oBACnB,OAAO,CAAC,GAAG,CAAC,uBAAuB,UAAU,GAAG,oBAAoB,YAAY,oBAAoB,SAAS,CAAC,CAAA;gBAChH,CAAC;gBAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,OAAO,CAAC,GAAG,CAAC,uBAAuB,UAAU,EAAE,CAAC,CAAA;gBAClD,CAAC;gBAED,OAAO,CAAC,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,oBAAoB,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAEnE,CAAC;iBAAM,CAAC;gBACN,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,KAAM,CAAC,CAAA;gBACzC,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;gBAE9C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC,CAAA;gBAEjE,IAAI,WAAW,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBAClC,OAAO,CAAC,KAAK,CAAC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;oBACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;gBACjB,CAAC;gBAED,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAA;gBACrC,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;gBAE/C,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;oBACnB,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;oBAC1C,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,CAAA;oBAE1C,OAAO,CAAC,GAAG,CAAC,sBAAsB,UAAU,EAAE,CAAC,CAAA;gBACjD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;gBACrB,CAAC;gBAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;oBACnB,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;wBACrB,OAAO,CAAC,KAAK,CAAC,qEAAqE,CAAC,CAAA;oBACtF,CAAC;yBAAM,CAAC;wBACN,OAAO,CAAC,KAAK,CAAC,kEAAkE,CAAC,CAAA;wBACjF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;oBACjB,CAAC;gBACH,CAAC;gBAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;oBAClB,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAA;oBAC9C,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAA;oBAElD,OAAO,CAAC,KAAK,CAAC,MAAM,CAAA;;gCAEE,KAAK,CAAC,MAAM;gCACZ,MAAM,CAAC,MAAM;gCACb,MAAM;gCACN,QAAQ;gCACR,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB;WAC1E,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;QAEH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;IACH,CAAC;CACF"}
|