brevit 0.1.1 → 0.1.3
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 +187 -27
- package/package.json +1 -1
- package/src/brevit.d.ts +22 -0
- package/src/brevit.js +182 -2
package/README.md
CHANGED
|
@@ -83,26 +83,26 @@ const optimized = await brevit.brevity(data);
|
|
|
83
83
|
### npm
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
npm install brevit
|
|
86
|
+
npm install brevit
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
### yarn
|
|
90
90
|
|
|
91
91
|
```bash
|
|
92
|
-
yarn add brevit
|
|
92
|
+
yarn add brevit
|
|
93
93
|
```
|
|
94
94
|
|
|
95
95
|
### pnpm
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
|
-
pnpm add brevit
|
|
98
|
+
pnpm add brevit
|
|
99
99
|
```
|
|
100
100
|
|
|
101
101
|
### CDN (Browser)
|
|
102
102
|
|
|
103
103
|
```html
|
|
104
104
|
<script type="module">
|
|
105
|
-
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'https://cdn.jsdelivr.net/npm/brevit
|
|
105
|
+
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'https://cdn.jsdelivr.net/npm/brevit@latest/src/brevit.js';
|
|
106
106
|
</script>
|
|
107
107
|
```
|
|
108
108
|
|
|
@@ -118,7 +118,7 @@ import {
|
|
|
118
118
|
BrevitConfig,
|
|
119
119
|
JsonOptimizationMode,
|
|
120
120
|
type BrevitConfigOptions,
|
|
121
|
-
} from 'brevit
|
|
121
|
+
} from 'brevit';
|
|
122
122
|
|
|
123
123
|
const config: BrevitConfigOptions = {
|
|
124
124
|
jsonMode: JsonOptimizationMode.Flatten,
|
|
@@ -137,7 +137,7 @@ Brevit.js supports three main data types: **JSON objects/strings**, **text files
|
|
|
137
137
|
#### Example 1.1: Simple JSON Object
|
|
138
138
|
|
|
139
139
|
```javascript
|
|
140
|
-
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'brevit
|
|
140
|
+
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'brevit';
|
|
141
141
|
|
|
142
142
|
const brevit = new BrevitClient(new BrevitConfig({
|
|
143
143
|
jsonMode: JsonOptimizationMode.Flatten
|
|
@@ -153,15 +153,59 @@ const data = {
|
|
|
153
153
|
|
|
154
154
|
// Method 1: Automatic optimization (recommended)
|
|
155
155
|
const optimized = await brevit.brevity(data);
|
|
156
|
-
// Output:
|
|
157
|
-
// user
|
|
158
|
-
//
|
|
159
|
-
//
|
|
156
|
+
// Output (with abbreviations enabled by default):
|
|
157
|
+
// @u=user
|
|
158
|
+
// @u.name:John Doe
|
|
159
|
+
// @u.email:john@example.com
|
|
160
|
+
// @u.age:30
|
|
160
161
|
|
|
161
162
|
// Method 2: Explicit optimization
|
|
162
163
|
const explicit = await brevit.optimize(data);
|
|
163
164
|
```
|
|
164
165
|
|
|
166
|
+
#### Example 1.1a: Abbreviation Feature (New in v0.1.2)
|
|
167
|
+
|
|
168
|
+
Brevit automatically creates abbreviations for frequently repeated prefixes, reducing token usage by 10-25%:
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
import { BrevitClient, BrevitConfig, JsonOptimizationMode } from 'brevit';
|
|
172
|
+
|
|
173
|
+
const brevit = new BrevitClient(new BrevitConfig({
|
|
174
|
+
jsonMode: JsonOptimizationMode.Flatten,
|
|
175
|
+
enableAbbreviations: true, // Enabled by default
|
|
176
|
+
abbreviationThreshold: 2 // Minimum occurrences to abbreviate
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
const data = {
|
|
180
|
+
user: {
|
|
181
|
+
name: "John Doe",
|
|
182
|
+
email: "john@example.com",
|
|
183
|
+
age: 30
|
|
184
|
+
},
|
|
185
|
+
order: {
|
|
186
|
+
id: "o-456",
|
|
187
|
+
status: "SHIPPED",
|
|
188
|
+
items: [
|
|
189
|
+
{ sku: "A-88", quantity: 1 }
|
|
190
|
+
]
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const optimized = await brevit.brevity(data);
|
|
195
|
+
// Output with abbreviations:
|
|
196
|
+
// @u=user
|
|
197
|
+
// @o=order
|
|
198
|
+
// @u.name:John Doe
|
|
199
|
+
// @u.email:john@example.com
|
|
200
|
+
// @u.age:30
|
|
201
|
+
// @o.id:o-456
|
|
202
|
+
// @o.status:SHIPPED
|
|
203
|
+
// @o.items[1]{quantity,sku}:
|
|
204
|
+
// 1,A-88
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Token Savings**: The abbreviation feature reduces tokens by replacing repeated prefixes like "user." and "order." with short aliases like "@u" and "@o", saving 10-25% on typical nested JSON structures.
|
|
208
|
+
|
|
165
209
|
#### Example 1.2: JSON String
|
|
166
210
|
|
|
167
211
|
```javascript
|
|
@@ -169,7 +213,23 @@ const jsonString = '{"order": {"id": "o-456", "status": "SHIPPED"}}';
|
|
|
169
213
|
|
|
170
214
|
// Brevit automatically detects JSON strings
|
|
171
215
|
const optimized = await brevit.brevity(jsonString);
|
|
172
|
-
// Output:
|
|
216
|
+
// Output (with abbreviations enabled by default):
|
|
217
|
+
// @o=order
|
|
218
|
+
// @o.id:o-456
|
|
219
|
+
// @o.status:SHIPPED
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
#### Example 1.2a: Abbreviations Disabled
|
|
223
|
+
|
|
224
|
+
```javascript
|
|
225
|
+
const brevitNoAbbr = new BrevitClient(new BrevitConfig({
|
|
226
|
+
jsonMode: JsonOptimizationMode.Flatten,
|
|
227
|
+
enableAbbreviations: false // Disable abbreviations
|
|
228
|
+
}));
|
|
229
|
+
|
|
230
|
+
const jsonString = '{"order": {"id": "o-456", "status": "SHIPPED"}}';
|
|
231
|
+
const optimized = await brevitNoAbbr.brevity(jsonString);
|
|
232
|
+
// Output (without abbreviations):
|
|
173
233
|
// order.id:o-456
|
|
174
234
|
// order.status:SHIPPED
|
|
175
235
|
```
|
|
@@ -205,7 +265,54 @@ const complexData = {
|
|
|
205
265
|
};
|
|
206
266
|
|
|
207
267
|
const optimized = await brevit.brevity(complexData);
|
|
208
|
-
// Output:
|
|
268
|
+
// Output (with abbreviations enabled by default):
|
|
269
|
+
// @c=context
|
|
270
|
+
// @c.task:Our favorite hikes together
|
|
271
|
+
// @c.location:Boulder
|
|
272
|
+
// @c.season:spring_2025
|
|
273
|
+
// friends[3]:ana,luis,sam
|
|
274
|
+
// hikes[2]{companion,distanceKm,elevationGain,id,name,wasSunny}:
|
|
275
|
+
// ana,7.5,320,1,Blue Lake Trail,true
|
|
276
|
+
// luis,9.2,540,2,Ridge Overlook,false
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Example 1.3a: Complex Data with Abbreviations Disabled
|
|
280
|
+
|
|
281
|
+
```javascript
|
|
282
|
+
const brevitNoAbbr = new BrevitClient(new BrevitConfig({
|
|
283
|
+
jsonMode: JsonOptimizationMode.Flatten,
|
|
284
|
+
enableAbbreviations: false // Disable abbreviations
|
|
285
|
+
}));
|
|
286
|
+
|
|
287
|
+
const complexData = {
|
|
288
|
+
context: {
|
|
289
|
+
task: "Our favorite hikes together",
|
|
290
|
+
location: "Boulder",
|
|
291
|
+
season: "spring_2025"
|
|
292
|
+
},
|
|
293
|
+
friends: ["ana", "luis", "sam"],
|
|
294
|
+
hikes: [
|
|
295
|
+
{
|
|
296
|
+
id: 1,
|
|
297
|
+
name: "Blue Lake Trail",
|
|
298
|
+
distanceKm: 7.5,
|
|
299
|
+
elevationGain: 320,
|
|
300
|
+
companion: "ana",
|
|
301
|
+
wasSunny: true
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
id: 2,
|
|
305
|
+
name: "Ridge Overlook",
|
|
306
|
+
distanceKm: 9.2,
|
|
307
|
+
elevationGain: 540,
|
|
308
|
+
companion: "luis",
|
|
309
|
+
wasSunny: false
|
|
310
|
+
}
|
|
311
|
+
]
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const optimized = await brevitNoAbbr.brevity(complexData);
|
|
315
|
+
// Output (without abbreviations):
|
|
209
316
|
// context.task:Our favorite hikes together
|
|
210
317
|
// context.location:Boulder
|
|
211
318
|
// context.season:spring_2025
|
|
@@ -573,7 +680,9 @@ const config = new BrevitConfig({
|
|
|
573
680
|
textMode: 'Clean', // Text optimization strategy
|
|
574
681
|
imageMode: 'Ocr', // Image optimization strategy
|
|
575
682
|
jsonPathsToKeep: [], // Paths to keep for Filter mode
|
|
576
|
-
longTextThreshold: 500
|
|
683
|
+
longTextThreshold: 500, // Character threshold for text optimization
|
|
684
|
+
enableAbbreviations: true, // Enable abbreviation feature (default: true)
|
|
685
|
+
abbreviationThreshold: 2 // Minimum occurrences to create abbreviation (default: 2)
|
|
577
686
|
});
|
|
578
687
|
```
|
|
579
688
|
|
|
@@ -614,7 +723,7 @@ import {
|
|
|
614
723
|
type BrevitClientOptions,
|
|
615
724
|
type TextOptimizerFunction,
|
|
616
725
|
type ImageOptimizerFunction,
|
|
617
|
-
} from 'brevit
|
|
726
|
+
} from 'brevit';
|
|
618
727
|
```
|
|
619
728
|
|
|
620
729
|
### Type-Safe Configuration
|
|
@@ -626,6 +735,8 @@ const config: BrevitConfigOptions = {
|
|
|
626
735
|
imageMode: ImageOptimizationMode.Ocr,
|
|
627
736
|
jsonPathsToKeep: ['user.name', 'order.orderId'],
|
|
628
737
|
longTextThreshold: 1000,
|
|
738
|
+
enableAbbreviations: true, // Default: true
|
|
739
|
+
abbreviationThreshold: 2 // Default: 2
|
|
629
740
|
};
|
|
630
741
|
|
|
631
742
|
const client = new BrevitClient(new BrevitConfig(config));
|
|
@@ -835,12 +946,15 @@ Consider alternatives when:
|
|
|
835
946
|
|
|
836
947
|
### Token Reduction
|
|
837
948
|
|
|
838
|
-
| Object Type | Original Tokens | Brevit
|
|
839
|
-
|
|
840
|
-
| Simple Object | 45 | 28 |
|
|
841
|
-
| Complex Object | 234 | 127 |
|
|
842
|
-
| Nested Arrays | 156 | 89 |
|
|
843
|
-
| API Response | 312 | 178 |
|
|
949
|
+
| Object Type | Original Tokens | Brevit (No Abbr) | Brevit (With Abbr) | Total Reduction |
|
|
950
|
+
|-------------|----------------|------------------|-------------------|-----------------|
|
|
951
|
+
| Simple Object | 45 | 28 | 26 | 42% |
|
|
952
|
+
| Complex Object | 234 | 127 | 105 | 55% |
|
|
953
|
+
| Nested Arrays | 156 | 89 | 75 | 52% |
|
|
954
|
+
| API Response | 312 | 178 | 145 | 54% |
|
|
955
|
+
| Deeply Nested | 95 | 78 | 65 | 32% |
|
|
956
|
+
|
|
957
|
+
**Note**: Abbreviations are enabled by default and provide additional 10-25% savings on top of base optimization.
|
|
844
958
|
|
|
845
959
|
### Performance
|
|
846
960
|
|
|
@@ -925,13 +1039,23 @@ const order = {
|
|
|
925
1039
|
};
|
|
926
1040
|
```
|
|
927
1041
|
|
|
928
|
-
**Output (with tabular optimization):**
|
|
1042
|
+
**Output (with tabular optimization and abbreviations enabled by default):**
|
|
1043
|
+
```
|
|
1044
|
+
orderId: o-456
|
|
1045
|
+
friends[3]: ana,luis,sam
|
|
1046
|
+
@i=items
|
|
1047
|
+
@i[2]{quantity,sku}:
|
|
1048
|
+
1,A-88
|
|
1049
|
+
2,T-22
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
**Output (with abbreviations disabled):**
|
|
929
1053
|
```
|
|
930
1054
|
orderId: o-456
|
|
931
1055
|
friends[3]: ana,luis,sam
|
|
932
1056
|
items[2]{quantity,sku}:
|
|
933
|
-
|
|
934
|
-
|
|
1057
|
+
1,A-88
|
|
1058
|
+
2,T-22
|
|
935
1059
|
```
|
|
936
1060
|
|
|
937
1061
|
**For non-uniform arrays (fallback):**
|
|
@@ -960,10 +1084,44 @@ items[2].quantity: 2
|
|
|
960
1084
|
- **Nested Objects**: Dot notation for nested properties
|
|
961
1085
|
- **Tabular Arrays**: Uniform object arrays automatically formatted in compact tabular format (`items[2]{field1,field2}:`)
|
|
962
1086
|
- **Primitive Arrays**: Comma-separated format (`friends[3]: ana,luis,sam`)
|
|
1087
|
+
- **Abbreviation System** (Default: Enabled): Automatically creates short aliases for repeated prefixes (`@u=user`, `@o=order`)
|
|
963
1088
|
- **Hybrid Approach**: Automatically detects optimal format, falls back to indexed format for mixed data
|
|
964
1089
|
- **Null Handling**: Explicit `null` values
|
|
965
1090
|
- **Type Preservation**: Numbers, booleans preserved as strings
|
|
966
1091
|
|
|
1092
|
+
### Abbreviation System (Default: Enabled)
|
|
1093
|
+
|
|
1094
|
+
Brevit automatically creates abbreviations for frequently repeated key prefixes, placing definitions at the top of the output:
|
|
1095
|
+
|
|
1096
|
+
**Example:**
|
|
1097
|
+
```
|
|
1098
|
+
@u=user
|
|
1099
|
+
@o=order
|
|
1100
|
+
@u.name:John Doe
|
|
1101
|
+
@u.email:john@example.com
|
|
1102
|
+
@o.id:o-456
|
|
1103
|
+
@o.status:SHIPPED
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
**Benefits:**
|
|
1107
|
+
- **10-25% additional token savings** on nested data
|
|
1108
|
+
- **Self-documenting**: Abbreviations are defined at the top
|
|
1109
|
+
- **LLM-friendly**: Models easily understand the mapping
|
|
1110
|
+
- **Configurable**: Can be disabled with `enableAbbreviations: false`
|
|
1111
|
+
|
|
1112
|
+
**When Abbreviations Help Most:**
|
|
1113
|
+
- Deeply nested JSON structures
|
|
1114
|
+
- Arrays of objects with repeated field names
|
|
1115
|
+
- API responses with consistent schemas
|
|
1116
|
+
- Data with many repeated prefixes (e.g., `user.profile.settings.theme`)
|
|
1117
|
+
|
|
1118
|
+
**Disable Abbreviations:**
|
|
1119
|
+
```javascript
|
|
1120
|
+
const config = new BrevitConfig({
|
|
1121
|
+
enableAbbreviations: false // Disable abbreviation feature
|
|
1122
|
+
});
|
|
1123
|
+
```
|
|
1124
|
+
|
|
967
1125
|
## API
|
|
968
1126
|
|
|
969
1127
|
### BrevitClient
|
|
@@ -1017,6 +1175,8 @@ class BrevitConfig {
|
|
|
1017
1175
|
imageMode: ImageOptimizationModeType;
|
|
1018
1176
|
jsonPathsToKeep: string[];
|
|
1019
1177
|
longTextThreshold: number;
|
|
1178
|
+
enableAbbreviations: boolean; // Default: true
|
|
1179
|
+
abbreviationThreshold: number; // Default: 2
|
|
1020
1180
|
}
|
|
1021
1181
|
```
|
|
1022
1182
|
|
|
@@ -1126,9 +1286,9 @@ Brevit is available in multiple languages:
|
|
|
1126
1286
|
|
|
1127
1287
|
| Language | Package | Status |
|
|
1128
1288
|
|----------|---------|--------|
|
|
1129
|
-
| JavaScript | `brevit
|
|
1130
|
-
| C# (.NET) | `Brevit
|
|
1131
|
-
| Python | `brevit
|
|
1289
|
+
| JavaScript | `brevit` | ✅ Stable (This) |
|
|
1290
|
+
| C# (.NET) | `Brevit` | ✅ Stable |
|
|
1291
|
+
| Python | `brevit` | ✅ Stable |
|
|
1132
1292
|
|
|
1133
1293
|
## Full Specification
|
|
1134
1294
|
|
|
@@ -1228,7 +1388,7 @@ MIT License - see LICENSE file for details.
|
|
|
1228
1388
|
## Support
|
|
1229
1389
|
|
|
1230
1390
|
- **Documentation**: [https://brevit.dev/docs](https://brevit.dev/docs)
|
|
1231
|
-
- **Issues**: [https://github.com/
|
|
1391
|
+
- **Issues**: [https://github.com/JavianDev/Brevit.js/issues](https://github.com/JavianDev/Brevit.js/issues)
|
|
1232
1392
|
- **Email**: support@javianpicardo.com
|
|
1233
1393
|
|
|
1234
1394
|
## Version History
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "brevit",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "A high-performance JavaScript library for semantically compressing and optimizing data before sending it to a Large Language Model (LLM).",
|
|
5
5
|
"main": "src/brevit.js",
|
|
6
6
|
"types": "src/brevit.d.ts",
|
package/src/brevit.d.ts
CHANGED
|
@@ -81,6 +81,18 @@ export interface BrevitConfigOptions {
|
|
|
81
81
|
* @default 500
|
|
82
82
|
*/
|
|
83
83
|
longTextThreshold?: number;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Enable abbreviation feature for frequently repeated key prefixes
|
|
87
|
+
* @default true
|
|
88
|
+
*/
|
|
89
|
+
enableAbbreviations?: boolean;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Minimum number of occurrences required to create an abbreviation
|
|
93
|
+
* @default 2
|
|
94
|
+
*/
|
|
95
|
+
abbreviationThreshold?: number;
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
/**
|
|
@@ -112,6 +124,16 @@ export class BrevitConfig {
|
|
|
112
124
|
*/
|
|
113
125
|
longTextThreshold: number;
|
|
114
126
|
|
|
127
|
+
/**
|
|
128
|
+
* Enable abbreviation feature
|
|
129
|
+
*/
|
|
130
|
+
enableAbbreviations: boolean;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Abbreviation threshold
|
|
134
|
+
*/
|
|
135
|
+
abbreviationThreshold: number;
|
|
136
|
+
|
|
115
137
|
/**
|
|
116
138
|
* Creates a new BrevitConfig instance
|
|
117
139
|
* @param options Configuration options
|
package/src/brevit.js
CHANGED
|
@@ -43,6 +43,8 @@ export class BrevitConfig {
|
|
|
43
43
|
* @param {string} options.imageMode - Strategy for Image optimization.
|
|
44
44
|
* @param {string[]} options.jsonPathsToKeep - Paths to keep for Filter mode.
|
|
45
45
|
* @param {number} options.longTextThreshold - Char count to trigger text optimization.
|
|
46
|
+
* @param {boolean} options.enableAbbreviations - Enable abbreviation feature for repeated prefixes.
|
|
47
|
+
* @param {number} options.abbreviationThreshold - Minimum occurrences to create abbreviation.
|
|
46
48
|
*/
|
|
47
49
|
constructor({
|
|
48
50
|
jsonMode = JsonOptimizationMode.Flatten,
|
|
@@ -50,12 +52,16 @@ export class BrevitConfig {
|
|
|
50
52
|
imageMode = ImageOptimizationMode.Ocr,
|
|
51
53
|
jsonPathsToKeep = [],
|
|
52
54
|
longTextThreshold = 500,
|
|
55
|
+
enableAbbreviations = true,
|
|
56
|
+
abbreviationThreshold = 2,
|
|
53
57
|
} = {}) {
|
|
54
58
|
this.jsonMode = jsonMode;
|
|
55
59
|
this.textMode = textMode;
|
|
56
60
|
this.imageMode = imageMode;
|
|
57
61
|
this.jsonPathsToKeep = jsonPathsToKeep;
|
|
58
62
|
this.longTextThreshold = longTextThreshold;
|
|
63
|
+
this.enableAbbreviations = enableAbbreviations;
|
|
64
|
+
this.abbreviationThreshold = abbreviationThreshold;
|
|
59
65
|
}
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -220,7 +226,131 @@ export class BrevitClient {
|
|
|
220
226
|
}
|
|
221
227
|
|
|
222
228
|
/**
|
|
223
|
-
*
|
|
229
|
+
* Generates abbreviations for frequently repeated prefixes.
|
|
230
|
+
* @param {Array<string>} paths - Array of flattened paths
|
|
231
|
+
* @returns {Object} Object with abbreviation map and definitions array
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
234
|
+
_generateAbbreviations(paths) {
|
|
235
|
+
if (!this._config.enableAbbreviations) {
|
|
236
|
+
return { map: new Map(), definitions: [] };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Count prefix frequencies
|
|
240
|
+
const prefixCounts = new Map();
|
|
241
|
+
|
|
242
|
+
paths.forEach(path => {
|
|
243
|
+
// Extract all prefixes (e.g., "user", "user.name", "order.items")
|
|
244
|
+
const parts = path.split('.');
|
|
245
|
+
for (let i = 1; i < parts.length; i++) {
|
|
246
|
+
const prefix = parts.slice(0, i).join('.');
|
|
247
|
+
prefixCounts.set(prefix, (prefixCounts.get(prefix) || 0) + 1);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// Filter prefixes that meet threshold
|
|
252
|
+
const frequentPrefixes = Array.from(prefixCounts.entries())
|
|
253
|
+
.filter(([prefix, count]) => count >= this._config.abbreviationThreshold)
|
|
254
|
+
.sort((a, b) => {
|
|
255
|
+
// Sort by: 1) count (desc), 2) length (asc) - prefer shorter, more frequent
|
|
256
|
+
if (b[1] !== a[1]) return b[1] - a[1];
|
|
257
|
+
return a[0].length - b[0].length;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Generate abbreviations
|
|
261
|
+
const abbreviationMap = new Map();
|
|
262
|
+
const definitions = [];
|
|
263
|
+
let abbrCounter = 0;
|
|
264
|
+
const usedAbbrs = new Set();
|
|
265
|
+
|
|
266
|
+
frequentPrefixes.forEach(([prefix, count]) => {
|
|
267
|
+
// Calculate savings: (prefix.length - abbr.length) * count
|
|
268
|
+
// Only abbreviate if it saves tokens
|
|
269
|
+
const abbr = this._generateAbbreviation(prefix, abbrCounter, usedAbbrs);
|
|
270
|
+
const definitionCost = prefix.length + abbr.length + 3; // "@x=prefix"
|
|
271
|
+
const savings = (prefix.length - abbr.length - 1) * count; // -1 for "@"
|
|
272
|
+
|
|
273
|
+
// Only create abbreviation if it saves tokens (accounting for definition)
|
|
274
|
+
if (savings > definitionCost) {
|
|
275
|
+
abbreviationMap.set(prefix, abbr);
|
|
276
|
+
definitions.push(`@${abbr}=${prefix}`);
|
|
277
|
+
abbrCounter++;
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
return { map: abbreviationMap, definitions };
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Generates a short abbreviation for a prefix.
|
|
286
|
+
* @param {string} prefix - The prefix to abbreviate
|
|
287
|
+
* @param {number} counter - Counter for fallback abbreviations
|
|
288
|
+
* @param {Set<string>} usedAbbrs - Set of already used abbreviations
|
|
289
|
+
* @returns {string} The abbreviation
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
292
|
+
_generateAbbreviation(prefix, counter, usedAbbrs) {
|
|
293
|
+
// Strategy 1: Use first letter if available and not used
|
|
294
|
+
const firstLetter = prefix.split('.')[0][0].toLowerCase();
|
|
295
|
+
if (!usedAbbrs.has(firstLetter)) {
|
|
296
|
+
usedAbbrs.add(firstLetter);
|
|
297
|
+
return firstLetter;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Strategy 2: Use first letter of each part (e.g., "order.items" -> "oi")
|
|
301
|
+
const parts = prefix.split('.');
|
|
302
|
+
if (parts.length > 1) {
|
|
303
|
+
const multiLetter = parts.map(p => p[0]).join('').toLowerCase();
|
|
304
|
+
if (!usedAbbrs.has(multiLetter) && multiLetter.length <= 3) {
|
|
305
|
+
usedAbbrs.add(multiLetter);
|
|
306
|
+
return multiLetter;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Strategy 3: Use counter-based abbreviation (a, b, c, ..., z, aa, ab, ...)
|
|
311
|
+
let abbr = '';
|
|
312
|
+
let num = counter;
|
|
313
|
+
do {
|
|
314
|
+
abbr = String.fromCharCode(97 + (num % 26)) + abbr; // 97 = 'a'
|
|
315
|
+
num = Math.floor(num / 26) - 1;
|
|
316
|
+
} while (num >= 0);
|
|
317
|
+
|
|
318
|
+
usedAbbrs.add(abbr);
|
|
319
|
+
return abbr;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Applies abbreviations to a path string.
|
|
324
|
+
* @param {string} path - The path to abbreviate
|
|
325
|
+
* @param {Map<string, string>} abbreviationMap - Map of prefix to abbreviation
|
|
326
|
+
* @returns {string} The abbreviated path
|
|
327
|
+
* @private
|
|
328
|
+
*/
|
|
329
|
+
_applyAbbreviations(path, abbreviationMap) {
|
|
330
|
+
if (!this._config.enableAbbreviations || abbreviationMap.size === 0) {
|
|
331
|
+
return path;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Find the longest matching prefix
|
|
335
|
+
let bestMatch = '';
|
|
336
|
+
let bestAbbr = '';
|
|
337
|
+
|
|
338
|
+
for (const [prefix, abbr] of abbreviationMap.entries()) {
|
|
339
|
+
if (path.startsWith(prefix + '.') && prefix.length > bestMatch.length) {
|
|
340
|
+
bestMatch = prefix;
|
|
341
|
+
bestAbbr = abbr;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
if (bestMatch) {
|
|
346
|
+
return `@${bestAbbr}.${path.substring(bestMatch.length + 1)}`;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
return path;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Flattens a JS object into a token-efficient string with tabular optimization and abbreviations.
|
|
224
354
|
* @param {object} obj - The object to flatten.
|
|
225
355
|
* @returns {string} The flattened string.
|
|
226
356
|
* @private
|
|
@@ -228,7 +358,57 @@ export class BrevitClient {
|
|
|
228
358
|
_flattenObject(obj) {
|
|
229
359
|
const output = [];
|
|
230
360
|
this._flatten(obj, '', output);
|
|
231
|
-
|
|
361
|
+
|
|
362
|
+
// Extract paths from output (before values)
|
|
363
|
+
const paths = output.map(line => {
|
|
364
|
+
const colonIndex = line.indexOf(':');
|
|
365
|
+
if (colonIndex > 0) {
|
|
366
|
+
const pathPart = line.substring(0, colonIndex);
|
|
367
|
+
// Handle tabular arrays: "key[count]{fields}:"
|
|
368
|
+
const bracketIndex = pathPart.indexOf('[');
|
|
369
|
+
if (bracketIndex > 0) {
|
|
370
|
+
return pathPart.substring(0, bracketIndex);
|
|
371
|
+
}
|
|
372
|
+
return pathPart;
|
|
373
|
+
}
|
|
374
|
+
return line.split(':')[0];
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// Generate abbreviations
|
|
378
|
+
const { map: abbreviationMap, definitions } = this._generateAbbreviations(paths);
|
|
379
|
+
|
|
380
|
+
// Apply abbreviations to output
|
|
381
|
+
const abbreviatedOutput = output.map(line => {
|
|
382
|
+
// Handle different line formats:
|
|
383
|
+
// 1. "key:value"
|
|
384
|
+
// 2. "key[count]:value1,value2"
|
|
385
|
+
// 3. "key[count]{fields}:\nrow1\nrow2"
|
|
386
|
+
|
|
387
|
+
const colonIndex = line.indexOf(':');
|
|
388
|
+
if (colonIndex === -1) return line;
|
|
389
|
+
|
|
390
|
+
const pathPart = line.substring(0, colonIndex);
|
|
391
|
+
const valuePart = line.substring(colonIndex);
|
|
392
|
+
|
|
393
|
+
// Handle tabular arrays - abbreviate the base path
|
|
394
|
+
const bracketIndex = pathPart.indexOf('[');
|
|
395
|
+
if (bracketIndex > 0) {
|
|
396
|
+
const basePath = pathPart.substring(0, bracketIndex);
|
|
397
|
+
const rest = pathPart.substring(bracketIndex);
|
|
398
|
+
const abbreviatedBase = this._applyAbbreviations(basePath, abbreviationMap);
|
|
399
|
+
return abbreviatedBase + rest + valuePart;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
const abbreviatedPath = this._applyAbbreviations(pathPart, abbreviationMap);
|
|
403
|
+
return abbreviatedPath + valuePart;
|
|
404
|
+
});
|
|
405
|
+
|
|
406
|
+
// Combine: definitions first, then abbreviated output
|
|
407
|
+
if (definitions.length > 0) {
|
|
408
|
+
return definitions.join('\n') + '\n' + abbreviatedOutput.join('\n');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return abbreviatedOutput.join('\n');
|
|
232
412
|
}
|
|
233
413
|
|
|
234
414
|
/**
|