configforge 1.5.0 → 1.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 +307 -217
- package/dist/core/BatchProcessor.d.ts.map +1 -1
- package/dist/core/BatchProcessor.js +9 -0
- package/dist/core/BatchProcessor.js.map +1 -1
- package/dist/core/ConversionResult.d.ts +81 -18
- package/dist/core/ConversionResult.d.ts.map +1 -1
- package/dist/core/ConversionResult.js +227 -56
- package/dist/core/ConversionResult.js.map +1 -1
- package/dist/core/Converter.d.ts +60 -3
- package/dist/core/Converter.d.ts.map +1 -1
- package/dist/core/Converter.js +538 -13
- package/dist/core/Converter.js.map +1 -1
- package/dist/core/IncrementalProcessor.d.ts.map +1 -1
- package/dist/core/IncrementalProcessor.js +9 -0
- package/dist/core/IncrementalProcessor.js.map +1 -1
- package/dist/core/Mapper.d.ts +1 -1
- package/dist/core/Mapper.d.ts.map +1 -1
- package/dist/core/Mapper.js +8 -1
- package/dist/core/Mapper.js.map +1 -1
- package/dist/core/MultiFileProcessor.d.ts.map +1 -1
- package/dist/core/MultiFileProcessor.js +9 -0
- package/dist/core/MultiFileProcessor.js.map +1 -1
- package/dist/core/pipeline/PipelineSteps.d.ts.map +1 -1
- package/dist/core/pipeline/PipelineSteps.js +21 -1
- package/dist/core/pipeline/PipelineSteps.js.map +1 -1
- package/dist/parsers/Parser.d.ts.map +1 -1
- package/dist/parsers/Parser.js +1 -3
- package/dist/parsers/Parser.js.map +1 -1
- package/dist/parsers/yaml.d.ts.map +1 -1
- package/dist/parsers/yaml.js +7 -3
- package/dist/parsers/yaml.js.map +1 -1
- package/dist/types/index.d.ts +35 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1244,235 +1244,300 @@ console.log('Backup created:', result.context?.backupPath);
|
|
|
1244
1244
|
|
|
1245
1245
|
### Example 10: Multi-File Processing ⭐ NEW!
|
|
1246
1246
|
|
|
1247
|
-
ConfigForge
|
|
1247
|
+
ConfigForge makes it easy to work with multiple files at once. Think of it like organizing your music collection - you might have individual song files that you want to combine into a playlist, or a big playlist that you want to split into smaller themed playlists.
|
|
1248
1248
|
|
|
1249
1249
|
```javascript
|
|
1250
1250
|
const { forge } = require('configforge');
|
|
1251
1251
|
|
|
1252
|
-
// Example:
|
|
1253
|
-
//
|
|
1254
|
-
// - NPCCoinshop.yml, NPCCosmetics.yml, Welcome.yml, etc.
|
|
1255
|
-
// CMI stores all holograms in a single file
|
|
1252
|
+
// Example 1: Combining Multiple Files (Many-to-One)
|
|
1253
|
+
// Like combining individual recipe cards into a cookbook
|
|
1256
1254
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1255
|
+
// You have separate recipe files:
|
|
1256
|
+
const recipeFiles = [
|
|
1257
|
+
{
|
|
1258
|
+
filename: 'chocolate-cake.yml',
|
|
1259
|
+
content: `
|
|
1260
|
+
name: Chocolate Cake
|
|
1261
|
+
category: dessert
|
|
1262
|
+
servings: 8
|
|
1263
|
+
ingredients:
|
|
1264
|
+
- flour: 2 cups
|
|
1265
|
+
- sugar: 1.5 cups
|
|
1266
|
+
- cocoa: 0.5 cups
|
|
1267
|
+
cookTime: 45
|
|
1268
|
+
difficulty: medium
|
|
1269
|
+
`,
|
|
1270
|
+
},
|
|
1271
|
+
{
|
|
1272
|
+
filename: 'pasta-salad.yml',
|
|
1273
|
+
content: `
|
|
1274
|
+
name: Pasta Salad
|
|
1275
|
+
category: main
|
|
1276
|
+
servings: 6
|
|
1277
|
+
ingredients:
|
|
1278
|
+
- pasta: 1 lb
|
|
1279
|
+
- tomatoes: 2 cups
|
|
1280
|
+
- cheese: 1 cup
|
|
1281
|
+
cookTime: 20
|
|
1282
|
+
difficulty: easy
|
|
1283
|
+
`,
|
|
1284
|
+
},
|
|
1285
|
+
{
|
|
1286
|
+
filename: 'fruit-smoothie.yml',
|
|
1287
|
+
content: `
|
|
1288
|
+
name: Fruit Smoothie
|
|
1289
|
+
category: drink
|
|
1290
|
+
servings: 2
|
|
1291
|
+
ingredients:
|
|
1292
|
+
- banana: 1
|
|
1293
|
+
- berries: 1 cup
|
|
1294
|
+
- yogurt: 0.5 cups
|
|
1295
|
+
cookTime: 5
|
|
1296
|
+
difficulty: easy
|
|
1297
|
+
`,
|
|
1298
|
+
},
|
|
1299
|
+
];
|
|
1298
1300
|
|
|
1299
|
-
|
|
1301
|
+
// Create a converter to combine recipes into a cookbook
|
|
1302
|
+
const cookbookConverter = forge()
|
|
1303
|
+
.from('*.yml')
|
|
1304
|
+
.to('cookbook.yml')
|
|
1305
|
+
// Use filename as the recipe key (removes .yml automatically)
|
|
1306
|
+
.useFilenameAsKey()
|
|
1307
|
+
// Map recipe fields to cookbook format
|
|
1308
|
+
.map('name', 'title')
|
|
1309
|
+
.map('category', 'type')
|
|
1310
|
+
.map('servings', 'serves')
|
|
1311
|
+
.map('ingredients', 'ingredientList')
|
|
1312
|
+
.map('cookTime', 'prepTime')
|
|
1313
|
+
.map('difficulty', 'skillLevel')
|
|
1314
|
+
// Add some defaults for the cookbook
|
|
1300
1315
|
.defaults({
|
|
1301
|
-
|
|
1316
|
+
tested: true,
|
|
1317
|
+
addedDate: () => new Date().toISOString().split('T')[0], // Just the date
|
|
1302
1318
|
});
|
|
1303
1319
|
|
|
1304
|
-
// Convert
|
|
1305
|
-
const
|
|
1306
|
-
'holograms/NPCCoinshop.yml',
|
|
1307
|
-
'holograms/NPCCosmetics.yml',
|
|
1308
|
-
'holograms/Welcome.yml',
|
|
1309
|
-
'holograms/CrateCommon.yml',
|
|
1310
|
-
];
|
|
1311
|
-
|
|
1312
|
-
const result = await decentToCmiConverter.convertMany(inputFiles, {
|
|
1313
|
-
mergeStrategy: 'merge',
|
|
1314
|
-
preserveFileNames: true,
|
|
1315
|
-
keyExtractor: filePath => {
|
|
1316
|
-
// Extract hologram name from filename
|
|
1317
|
-
return path.basename(filePath, path.extname(filePath));
|
|
1318
|
-
},
|
|
1319
|
-
});
|
|
1320
|
+
// Convert all recipe files into one cookbook
|
|
1321
|
+
const cookbook = await cookbookConverter.convert(recipeFiles);
|
|
1320
1322
|
|
|
1321
|
-
console.log(
|
|
1322
|
-
|
|
1323
|
+
console.log(
|
|
1324
|
+
'📚 Created cookbook with',
|
|
1325
|
+
Object.keys(cookbook.data).length,
|
|
1326
|
+
'recipes'
|
|
1327
|
+
);
|
|
1328
|
+
console.log(cookbook.data);
|
|
1323
1329
|
// {
|
|
1324
|
-
//
|
|
1325
|
-
//
|
|
1326
|
-
//
|
|
1327
|
-
//
|
|
1328
|
-
//
|
|
1330
|
+
// 'chocolate-cake': {
|
|
1331
|
+
// title: 'Chocolate Cake',
|
|
1332
|
+
// type: 'dessert',
|
|
1333
|
+
// serves: 8,
|
|
1334
|
+
// ingredientList: [{ flour: '2 cups' }, { sugar: '1.5 cups' }, { cocoa: '0.5 cups' }],
|
|
1335
|
+
// prepTime: 45,
|
|
1336
|
+
// skillLevel: 'medium',
|
|
1337
|
+
// tested: true,
|
|
1338
|
+
// addedDate: '2024-01-22'
|
|
1329
1339
|
// },
|
|
1330
|
-
//
|
|
1331
|
-
//
|
|
1332
|
-
//
|
|
1333
|
-
//
|
|
1334
|
-
//
|
|
1340
|
+
// 'pasta-salad': {
|
|
1341
|
+
// title: 'Pasta Salad',
|
|
1342
|
+
// type: 'main',
|
|
1343
|
+
// serves: 6,
|
|
1344
|
+
// ingredientList: [{ pasta: '1 lb' }, { tomatoes: '2 cups' }, { cheese: '1 cup' }],
|
|
1345
|
+
// prepTime: 20,
|
|
1346
|
+
// skillLevel: 'easy',
|
|
1347
|
+
// tested: true,
|
|
1348
|
+
// addedDate: '2024-01-22'
|
|
1335
1349
|
// },
|
|
1336
|
-
//
|
|
1350
|
+
// 'fruit-smoothie': {
|
|
1351
|
+
// title: 'Fruit Smoothie',
|
|
1352
|
+
// type: 'drink',
|
|
1353
|
+
// serves: 2,
|
|
1354
|
+
// ingredientList: [{ banana: 1 }, { berries: '1 cup' }, { yogurt: '0.5 cups' }],
|
|
1355
|
+
// prepTime: 5,
|
|
1356
|
+
// skillLevel: 'easy',
|
|
1357
|
+
// tested: true,
|
|
1358
|
+
// addedDate: '2024-01-22'
|
|
1359
|
+
// }
|
|
1337
1360
|
// }
|
|
1338
1361
|
|
|
1339
|
-
//
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1362
|
+
// Example 2: Splitting One File into Many (One-to-Many)
|
|
1363
|
+
// Like taking a big address book and creating separate contact cards
|
|
1364
|
+
|
|
1365
|
+
const addressBookData = {
|
|
1366
|
+
filename: 'contacts.yml',
|
|
1367
|
+
content: `
|
|
1368
|
+
contacts:
|
|
1369
|
+
john-doe:
|
|
1370
|
+
name: John Doe
|
|
1371
|
+
email: john@example.com
|
|
1372
|
+
phone: 555-0123
|
|
1373
|
+
category: friend
|
|
1374
|
+
city: New York
|
|
1375
|
+
jane-smith:
|
|
1376
|
+
name: Jane Smith
|
|
1377
|
+
email: jane@company.com
|
|
1378
|
+
phone: 555-0456
|
|
1379
|
+
category: work
|
|
1380
|
+
city: Boston
|
|
1381
|
+
mom:
|
|
1382
|
+
name: Mary Johnson
|
|
1383
|
+
email: mom@family.com
|
|
1384
|
+
phone: 555-0789
|
|
1385
|
+
category: family
|
|
1386
|
+
city: Chicago
|
|
1387
|
+
`,
|
|
1388
|
+
};
|
|
1357
1389
|
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1390
|
+
// Create converter to split contacts into individual cards
|
|
1391
|
+
const contactConverter = forge()
|
|
1392
|
+
.from('*.yml')
|
|
1393
|
+
.to('json')
|
|
1394
|
+
// Transform each contact
|
|
1395
|
+
.map('name', 'fullName')
|
|
1396
|
+
.map('email', 'emailAddress')
|
|
1397
|
+
.map('phone', 'phoneNumber')
|
|
1398
|
+
.map('category', 'group')
|
|
1399
|
+
.map('city', 'location')
|
|
1400
|
+
// Add some useful defaults
|
|
1401
|
+
.defaults({
|
|
1402
|
+
favorite: false,
|
|
1403
|
+
lastContacted: null,
|
|
1361
1404
|
})
|
|
1405
|
+
// Split the contacts into separate files
|
|
1406
|
+
.split(data => {
|
|
1407
|
+
const result = {};
|
|
1408
|
+
|
|
1409
|
+
// Take each contact and make it a separate file
|
|
1410
|
+
if (data.contacts) {
|
|
1411
|
+
for (const [contactId, contactInfo] of Object.entries(data.contacts)) {
|
|
1412
|
+
// Create filename based on contact name and category
|
|
1413
|
+
const filename = `${contactInfo.category}-${contactId}.yml`;
|
|
1414
|
+
result[filename] = contactInfo;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1362
1417
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1418
|
+
return result;
|
|
1419
|
+
});
|
|
1365
1420
|
|
|
1366
|
-
|
|
1367
|
-
.map('Lines', 'pages', lines => {
|
|
1368
|
-
if (!Array.isArray(lines)) return [];
|
|
1421
|
+
const splitContacts = await contactConverter.convert([addressBookData]);
|
|
1369
1422
|
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
}));
|
|
1423
|
+
// Get the individual contact files
|
|
1424
|
+
const contactFiles = splitContacts.toFiles();
|
|
1425
|
+
console.log(`📇 Split into ${contactFiles.length} contact cards:`);
|
|
1374
1426
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
},
|
|
1380
|
-
];
|
|
1381
|
-
})
|
|
1427
|
+
contactFiles.forEach(file => {
|
|
1428
|
+
console.log(`📄 ${file.filename}`);
|
|
1429
|
+
console.log(file.content.substring(0, 100) + '...');
|
|
1430
|
+
});
|
|
1382
1431
|
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1432
|
+
// Output:
|
|
1433
|
+
// 📇 Split into 3 contact cards:
|
|
1434
|
+
// 📄 friend-john-doe.yml
|
|
1435
|
+
// fullName: John Doe
|
|
1436
|
+
// emailAddress: john@example.com
|
|
1437
|
+
// phoneNumber: 555-0123
|
|
1438
|
+
// group: friend
|
|
1439
|
+
// location: New York...
|
|
1440
|
+
//
|
|
1441
|
+
// 📄 work-jane-smith.yml
|
|
1442
|
+
// fullName: Jane Smith
|
|
1443
|
+
// emailAddress: jane@company.com
|
|
1444
|
+
// phoneNumber: 555-0456
|
|
1445
|
+
// group: work
|
|
1446
|
+
// location: Boston...
|
|
1447
|
+
//
|
|
1448
|
+
// 📄 family-mom.yml
|
|
1449
|
+
// fullName: Mary Johnson
|
|
1450
|
+
// emailAddress: mom@family.com
|
|
1451
|
+
// phoneNumber: 555-0789
|
|
1452
|
+
// group: family
|
|
1453
|
+
// location: Chicago...
|
|
1389
1454
|
|
|
1390
|
-
//
|
|
1391
|
-
|
|
1392
|
-
const result = {};
|
|
1455
|
+
// Example 3: Handling Conflicts (When Files Have Same Names)
|
|
1456
|
+
// Like when you have two recipes both called "cake.yml"
|
|
1393
1457
|
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
}
|
|
1458
|
+
const conflictingFiles = [
|
|
1459
|
+
{
|
|
1460
|
+
filename: 'cake.yml',
|
|
1461
|
+
content: 'name: Chocolate Cake\ntype: dessert\nrating: 5',
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
filename: 'cake.yml', // Same filename!
|
|
1465
|
+
content: 'name: Vanilla Cake\ntype: dessert\nrating: 4',
|
|
1466
|
+
},
|
|
1467
|
+
];
|
|
1399
1468
|
|
|
1400
|
-
|
|
1401
|
-
|
|
1469
|
+
// Option 1: Merge conflicts (combine the values)
|
|
1470
|
+
const mergeConverter = forge()
|
|
1471
|
+
.from('*.yml')
|
|
1472
|
+
.to('json')
|
|
1473
|
+
.useFilenameAsKey()
|
|
1474
|
+
.onKeyConflict('merge'); // Combine conflicting values into arrays
|
|
1402
1475
|
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1476
|
+
const mergedResult = await mergeConverter.convert(conflictingFiles);
|
|
1477
|
+
console.log('🔀 Merged conflicts:', mergedResult.data);
|
|
1478
|
+
// {
|
|
1479
|
+
// cake: {
|
|
1480
|
+
// name: ['Chocolate Cake', 'Vanilla Cake'], // Both names in an array
|
|
1481
|
+
// type: 'dessert', // Same value, no conflict
|
|
1482
|
+
// rating: [5, 4] // Both ratings in an array
|
|
1483
|
+
// }
|
|
1484
|
+
// }
|
|
1408
1485
|
|
|
1409
|
-
|
|
1486
|
+
// Option 2: Error on conflicts (be strict)
|
|
1487
|
+
const strictConverter = forge()
|
|
1488
|
+
.from('*.yml')
|
|
1489
|
+
.to('json')
|
|
1490
|
+
.useFilenameAsKey()
|
|
1491
|
+
.onKeyConflict('error'); // Stop and report the problem
|
|
1410
1492
|
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1493
|
+
try {
|
|
1494
|
+
await strictConverter.convert(conflictingFiles);
|
|
1495
|
+
} catch (error) {
|
|
1496
|
+
console.log('⚠️ Conflict detected:', error.message);
|
|
1497
|
+
// "Key conflict detected: 'cake' appears in multiple files"
|
|
1415
1498
|
}
|
|
1416
1499
|
|
|
1417
|
-
//
|
|
1418
|
-
const
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
};
|
|
1429
|
-
|
|
1430
|
-
inputs.forEach((data, index) => {
|
|
1431
|
-
const fileName = path.basename(filePaths[index], '.yml');
|
|
1500
|
+
// Real-world example: Simple server config merger
|
|
1501
|
+
const serverConfigs = [
|
|
1502
|
+
{
|
|
1503
|
+
filename: 'database.yml',
|
|
1504
|
+
content: 'host: db.example.com\nport: 5432\nname: myapp',
|
|
1505
|
+
},
|
|
1506
|
+
{
|
|
1507
|
+
filename: 'cache.yml',
|
|
1508
|
+
content: 'host: cache.example.com\nport: 6379\nttl: 3600',
|
|
1509
|
+
},
|
|
1510
|
+
];
|
|
1432
1511
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1512
|
+
const serverConverter = forge()
|
|
1513
|
+
.from('*.yml')
|
|
1514
|
+
.to('config.yml')
|
|
1515
|
+
.useFilenameAsKey()
|
|
1516
|
+
.map('host', 'hostname')
|
|
1517
|
+
.map('port', 'port')
|
|
1518
|
+
.defaults({
|
|
1519
|
+
enabled: true,
|
|
1520
|
+
timeout: 30,
|
|
1440
1521
|
});
|
|
1441
1522
|
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
const groupedResult = await customMergeConverter.convertMany(inputFiles, {
|
|
1446
|
-
mergeStrategy: 'custom',
|
|
1447
|
-
customMerger: customMerger,
|
|
1448
|
-
});
|
|
1449
|
-
|
|
1450
|
-
console.log(groupedResult.data);
|
|
1523
|
+
const serverConfig = await serverConverter.convert(serverConfigs);
|
|
1524
|
+
console.log('🖥️ Server configuration:', serverConfig.data);
|
|
1451
1525
|
// {
|
|
1452
|
-
//
|
|
1453
|
-
//
|
|
1454
|
-
//
|
|
1455
|
-
//
|
|
1456
|
-
//
|
|
1457
|
-
//
|
|
1526
|
+
// database: {
|
|
1527
|
+
// hostname: 'db.example.com',
|
|
1528
|
+
// port: 5432,
|
|
1529
|
+
// name: 'myapp',
|
|
1530
|
+
// enabled: true,
|
|
1531
|
+
// timeout: 30
|
|
1458
1532
|
// },
|
|
1459
|
-
//
|
|
1460
|
-
//
|
|
1533
|
+
// cache: {
|
|
1534
|
+
// hostname: 'cache.example.com',
|
|
1535
|
+
// port: 6379,
|
|
1536
|
+
// ttl: 3600,
|
|
1537
|
+
// enabled: true,
|
|
1538
|
+
// timeout: 30
|
|
1461
1539
|
// }
|
|
1462
1540
|
// }
|
|
1463
|
-
|
|
1464
|
-
// Multi-file processing options:
|
|
1465
|
-
//
|
|
1466
|
-
// mergeStrategy: 'merge' (default) - Merge objects using file names as keys
|
|
1467
|
-
// mergeStrategy: 'array' - Combine all inputs into an array
|
|
1468
|
-
// mergeStrategy: 'custom' - Use custom merger function
|
|
1469
|
-
//
|
|
1470
|
-
// preserveFileNames: true (default) - Use filenames as object keys
|
|
1471
|
-
// preserveFileNames: false - Simple deep merge without keys
|
|
1472
|
-
//
|
|
1473
|
-
// keyExtractor: function - Custom function to extract keys from file paths
|
|
1474
|
-
// continueOnError: true (default) - Continue processing other files if one fails
|
|
1475
|
-
// rootKey: string - Wrap merged data in a root key
|
|
1476
1541
|
```
|
|
1477
1542
|
|
|
1478
1543
|
### Example 11: Batch Processing and Performance Features
|
|
@@ -1737,6 +1802,9 @@ cli.parse();
|
|
|
1737
1802
|
- ✅ **Simple API**: Just map fields and convert
|
|
1738
1803
|
- ✅ **String Input Support**: Convert raw YAML/JSON strings directly with `convertString()` ⭐ NEW!
|
|
1739
1804
|
- ✅ **Multi-File Processing**: Process multiple input files into single output (many-to-one) or split single input into multiple outputs (one-to-many) ⭐ NEW!
|
|
1805
|
+
- ✅ **Split Functionality**: Break single input files into multiple outputs with configurable split functions ⭐ NEW!
|
|
1806
|
+
- ✅ **Conflict Resolution**: Handle field conflicts in multi-file processing with configurable strategies (error, overwrite, merge, suffix) ⭐ NEW!
|
|
1807
|
+
- ✅ **Enhanced Result Handling**: Comprehensive result objects with `getSummary()`, `toFiles()`, and enhanced `print()` methods ⭐ NEW!
|
|
1740
1808
|
- ✅ **Pipeline Architecture**: Robust internal processing with configurable steps and error handling
|
|
1741
1809
|
- ✅ **No direct Mapper usage needed**: The `convert()` method handles everything
|
|
1742
1810
|
- ✅ **Nested object support**: Use dot notation like `user.profile.name`
|
|
@@ -1765,7 +1833,11 @@ cli.parse();
|
|
|
1765
1833
|
- Nested object and array access
|
|
1766
1834
|
- Value transformations
|
|
1767
1835
|
- **String input support with `convertString()` and `convert()` with `isRawContent` option** ⭐ NEW!
|
|
1836
|
+
- **Enhanced result handling with `getSummary()`, `toFiles()`, and improved `print()` methods** ⭐ NEW!
|
|
1768
1837
|
- **Multi-file processing with `convertMany()` (many-to-one) and `convertSplit()` (one-to-many)** ⭐ NEW!
|
|
1838
|
+
- **Complete pipeline integration with multi-file processing** ⭐ NEW!
|
|
1839
|
+
- **Multi-file conflict resolution with configurable strategies (error, overwrite, merge, suffix)** ⭐ NEW!
|
|
1840
|
+
- **Split functionality with `split()` method for one-to-many processing** ⭐ NEW!
|
|
1769
1841
|
- **Default values with `defaults()`** ⭐ ENHANCED!
|
|
1770
1842
|
- **Array/object processing with `forEach()` and `mapToObject()`** ⭐ ENHANCED!
|
|
1771
1843
|
- **Conditional mapping with `when()`**
|
|
@@ -1824,31 +1896,49 @@ cli.parse();
|
|
|
1824
1896
|
34. **Use `forEach()` with `{ output: 'object' }` to transform arrays into keyed objects** - perfect for converting indexed arrays to UUID-keyed objects
|
|
1825
1897
|
35. **`forEach()` with object output merges returned objects** - return `{ [key]: value }` to create dynamic keys from your data
|
|
1826
1898
|
36. **Filter with `forEach()`** - return `null` from the mapping function to exclude items from the result
|
|
1827
|
-
37. **
|
|
1828
|
-
38. **
|
|
1829
|
-
39. **
|
|
1830
|
-
40. **
|
|
1831
|
-
41. **
|
|
1832
|
-
42. **
|
|
1833
|
-
43. **
|
|
1834
|
-
44. **
|
|
1835
|
-
45. **
|
|
1836
|
-
46. **
|
|
1837
|
-
47. **
|
|
1838
|
-
48. **
|
|
1839
|
-
49. **
|
|
1840
|
-
50. **
|
|
1841
|
-
51. **Use
|
|
1842
|
-
52. **
|
|
1843
|
-
53. **
|
|
1844
|
-
54. **
|
|
1845
|
-
55. **
|
|
1846
|
-
56. **
|
|
1847
|
-
57. **
|
|
1848
|
-
58. **
|
|
1849
|
-
59. **
|
|
1850
|
-
60. **
|
|
1851
|
-
61. **
|
|
1899
|
+
37. **Use `result.getSummary()`** - get detailed statistics about conversion success, file counts, errors, and duration
|
|
1900
|
+
38. **Use `result.toFiles()`** - convert any result to FileObject arrays for consistent multi-file handling
|
|
1901
|
+
39. **Enhanced `print()` methods** - result printing now includes emojis and better formatting for easier debugging
|
|
1902
|
+
40. **Multi-file results provide file-specific statistics** - track success/failure per file in batch operations
|
|
1903
|
+
41. **Split results include generated file lists** - `getSummary().generatedFiles` shows all files created from split operations
|
|
1904
|
+
42. **Pipeline integration works seamlessly with multi-file processing** - all pipeline steps (parse, map, transform, validate, hooks) work correctly across multiple files
|
|
1905
|
+
43. **Multi-file context is available in all pipeline steps** - access filename, fileIndex, and other multi-file metadata in transforms and hooks
|
|
1906
|
+
44. **Error collection spans multiple files** - validation errors and processing errors are collected across all files with proper context
|
|
1907
|
+
45. **Choose forEach output type** - use `{ output: 'array' }` (default) to maintain structure, `{ output: 'object' }` to create keyed objects
|
|
1908
|
+
46. **Track progress** - provide `progressCallback` to monitor batch processing progress in real-time
|
|
1909
|
+
47. **Cache management** - use `IncrementalProcessor.getCacheStats()` and `cleanupCache()` to manage incremental processing cache
|
|
1910
|
+
48. **Save batch results** - use `BatchProcessor.saveBatch()` to save all conversion results to an output directory
|
|
1911
|
+
49. **Use forge() with options** - pass `ForgeOptions` to `forge({ strict: true, parallel: true })` to configure converter behavior globally
|
|
1912
|
+
50. **Use convertString() for raw content** - when you have YAML or JSON as a string, use `convertString()` instead of `convert()` ⭐ NEW!
|
|
1913
|
+
51. **Use convert() with isRawContent option** - alternatively, use `convert(stringContent, { isRawContent: true })` for string input ⭐ NEW!
|
|
1914
|
+
52. **Format auto-detection works with strings** - ConfigForge automatically detects YAML vs JSON format in string content ⭐ NEW!
|
|
1915
|
+
53. **String input handles parsing errors gracefully** - malformed YAML/JSON strings will produce helpful error messages ⭐ NEW!
|
|
1916
|
+
54. **forEach field tracking is automatic** - when you access fields inside forEach callbacks, they're automatically marked as mapped in statistics ⭐ NEW!
|
|
1917
|
+
55. **forEach with target renaming** - use `forEach('source', 'target', mapFn)` to rename arrays/objects in output: `forEach('npc', 'npcs', mapFn)` ⭐ NEW!
|
|
1918
|
+
56. **Array indices are always numbers** - in forEach for arrays, the index parameter is guaranteed to be a number, so `index + 1` works correctly ⭐ NEW!
|
|
1919
|
+
57. **Object keys in forEach** - for objects, forEach passes the key as the second parameter for backward compatibility ⭐ NEW!
|
|
1920
|
+
58. **Access object keys in context** - when processing objects with forEach, the key is also available in `context.metadata.objectKey` ⭐ NEW!
|
|
1921
|
+
59. **Use convertMany() for many-to-one processing** - merge multiple input files into a single output with `convertMany(inputPaths, options)` ⭐ NEW!
|
|
1922
|
+
60. **Use convertSplit() for one-to-many processing** - split a single input file into multiple outputs with `convertSplit(inputPath, splitFn)` ⭐ NEW!
|
|
1923
|
+
61. **Choose merge strategies wisely** - use `'merge'` for object merging, `'array'` for simple arrays, or `'custom'` for complex logic ⭐ NEW!
|
|
1924
|
+
62. **Custom key extractors for file naming** - use `keyExtractor: (filePath) => customKey` to control how filenames become object keys ⭐ NEW!
|
|
1925
|
+
63. **Multi-file processing is fully tested and stable** - both `convertMany()` and `convertSplit()` have comprehensive test coverage and error handling ⭐ ENHANCED!
|
|
1926
|
+
64. **Handle file errors gracefully** - set `continueOnError: true` to process all files even if some fail, or `false` to stop on first error ⭐ NEW!
|
|
1927
|
+
65. **Perfect for plugin conversions** - multi-file processing is ideal for converting between plugin formats like DecentHolograms ↔ CMI ⭐ NEW!
|
|
1928
|
+
66. **Use rootKey for wrapping** - set `rootKey: 'holograms'` to wrap merged data in a parent object ⭐ NEW!
|
|
1929
|
+
67. **Check fileResults for debugging** - `result.fileResults` shows success/failure status for each processed file ⭐ NEW!
|
|
1930
|
+
68. **Monitor failed files** - `result.failedFiles` contains paths of files that couldn't be processed ⭐ NEW!
|
|
1931
|
+
69. **Split functions control output structure** - return `{ key1: data1, key2: data2 }` from split functions to create multiple output files ⭐ NEW!
|
|
1932
|
+
70. **Handle field conflicts in multi-file processing** - use `onKeyConflict()` to configure how to handle conflicting field names across files ⭐ NEW!
|
|
1933
|
+
71. **Choose conflict resolution strategy** - use `'error'` to fail on conflicts, `'overwrite'` for last-wins, `'merge'` to combine into arrays, or `'suffix'` to add unique suffixes ⭐ NEW!
|
|
1934
|
+
72. **Merge strategy combines conflicting fields** - when using `onKeyConflict('merge')`, fields with the same name across files are combined into arrays ⭐ NEW!
|
|
1935
|
+
73. **Custom conflict suffixes** - use `onKeyConflict('suffix', '_backup')` to customize the suffix added to conflicting field names ⭐ NEW!
|
|
1936
|
+
74. **Force same key for conflict testing** - use `useKey('fixedKey')` to force all files to use the same key, creating conflicts for testing resolution strategies ⭐ NEW!
|
|
1937
|
+
75. **Use split() for one-to-many processing** - break single input files into multiple outputs with `split(data => ({ file1: data.part1, file2: data.part2 }))` ⭐ NEW!
|
|
1938
|
+
76. **Split functions control output structure** - return an object where keys become filenames and values become file content ⭐ NEW!
|
|
1939
|
+
77. **Split works with all mappings and transforms** - apply field mappings, transformations, defaults, and hooks to each split output ⭐ NEW!
|
|
1940
|
+
78. **Split handles errors gracefully** - if split function fails or individual conversions error, detailed error information is provided ⭐ NEW!
|
|
1941
|
+
79. **Combine split with filename mapping** - use `mapFilename()` to include source filename information in each split output ⭐ NEW!
|
|
1852
1942
|
|
|
1853
1943
|
---
|
|
1854
1944
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BatchProcessor.d.ts","sourceRoot":"","sources":["../../src/core/BatchProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EAEX,gBAAgB,EAGjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxC;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAyB;gBAE5B,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB;IAU5D;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAyDrD;;OAEG;YACW,mBAAmB;IA2CjC;;OAEG;YACW,iBAAiB;IA4E/B;;OAEG;YACW,WAAW;
|
|
1
|
+
{"version":3,"file":"BatchProcessor.d.ts","sourceRoot":"","sources":["../../src/core/BatchProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,aAAa,EACb,WAAW,EAEX,gBAAgB,EAGjB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAKxC;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAyB;gBAE5B,SAAS,EAAE,SAAS,EAAE,OAAO,GAAE,YAAiB;IAU5D;;OAEG;IACG,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAyDrD;;OAEG;YACW,mBAAmB;IA2CjC;;OAEG;YACW,iBAAiB;IA4E/B;;OAEG;YACW,WAAW;IAiDzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAczB;;OAEG;IACH,OAAO,CAAC,UAAU;IAQlB;;OAEG;IACG,SAAS,CACb,OAAO,EAAE,gBAAgB,EAAE,EAC3B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,IAAI,CAAC;IAyBhB;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM;IAcvD;;OAEG;IACH,OAAO,CAAC,iBAAiB;CAK1B"}
|
|
@@ -191,7 +191,16 @@ class BatchProcessor {
|
|
|
191
191
|
save: async () => { },
|
|
192
192
|
toJSON: () => '{}',
|
|
193
193
|
toYAML: () => '{}',
|
|
194
|
+
toFiles: () => [{ filename: 'error.yml', content: '{}' }], // ⭐ NEW! Required method
|
|
194
195
|
print: () => { },
|
|
196
|
+
getSummary: () => ({
|
|
197
|
+
success: false,
|
|
198
|
+
fileCount: 1,
|
|
199
|
+
errorCount: 1,
|
|
200
|
+
warningCount: 0,
|
|
201
|
+
unmappedCount: 0,
|
|
202
|
+
duration: 0,
|
|
203
|
+
}),
|
|
195
204
|
};
|
|
196
205
|
}
|
|
197
206
|
}
|