xml-disassembler 1.10.10 → 1.10.12

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/dist/index.cjs CHANGED
@@ -6,12 +6,12 @@ var posix = require('node:path/posix');
6
6
  var node_fs = require('node:fs');
7
7
  var node_path = require('node:path');
8
8
  var ignore = require('ignore');
9
- var node_crypto = require('node:crypto');
10
9
  var fastXmlParser = require('fast-xml-parser');
11
10
  var json5 = require('json5');
12
11
  var smolToml = require('smol-toml');
13
12
  var ini = require('ini');
14
13
  var yaml = require('yaml');
14
+ var node_crypto = require('node:crypto');
15
15
  var promises$1 = require('fs/promises');
16
16
 
17
17
  /******************************************************************************
@@ -227,35 +227,6 @@ class ReassembleXMLFileHandler {
227
227
  }
228
228
  }
229
229
 
230
- function parseUniqueIdElement(element, uniqueIdElements) {
231
- if (uniqueIdElements === undefined) {
232
- return createShortHash(element);
233
- }
234
- const uniqueIdElementsArray = uniqueIdElements.split(",");
235
- for (const fieldName of uniqueIdElementsArray) {
236
- if (element[fieldName] !== undefined) {
237
- if (typeof element[fieldName] === "string") {
238
- return element[fieldName];
239
- }
240
- }
241
- }
242
- for (const key in element) {
243
- if (typeof element[key] === "object" && element[key] !== null) {
244
- const childFieldName = parseUniqueIdElement(element[key], uniqueIdElements);
245
- if (childFieldName !== undefined) {
246
- return childFieldName;
247
- }
248
- }
249
- }
250
- return createShortHash(element);
251
- }
252
- function createShortHash(element) {
253
- const hash = node_crypto.createHash("sha256");
254
- hash.update(JSON.stringify(element));
255
- const fullHash = hash.digest("hex");
256
- return fullHash.slice(0, 8);
257
- }
258
-
259
230
  function buildXMLString(element) {
260
231
  const xmlBuilder = new fastXmlParser.XMLBuilder(JSON_PARSER_OPTION);
261
232
  return xmlBuilder.build(element).trimEnd();
@@ -309,189 +280,182 @@ function getTransformer(format) {
309
280
  }
310
281
  }
311
282
 
312
- function buildNestedFile(element, disassembledPath, uniqueIdElements, rootElementName, rootAttributes, parentKey, format, xmlDeclaration) {
313
- return __awaiter(this, void 0, void 0, function* () {
314
- const fieldName = parseUniqueIdElement(element, uniqueIdElements);
315
- const outputDirectory = posix.join(disassembledPath, parentKey);
316
- const outputFileName = `${fieldName}.${parentKey}-meta.${format}`;
317
- const outputPath = posix.join(outputDirectory, outputFileName);
318
- yield promises.mkdir(outputDirectory, { recursive: true });
319
- let finalXml = {
320
- [rootElementName]: Object.assign(Object.assign({}, rootAttributes), { [parentKey]: element }),
321
- };
322
- if (typeof xmlDeclaration === "object" && xmlDeclaration !== null) {
323
- finalXml = Object.assign({ "?xml": xmlDeclaration }, finalXml);
324
- }
325
- let nestedString;
326
- const transformer = getTransformer(format);
327
- if (transformer) {
328
- nestedString = yield transformer(finalXml);
329
- }
330
- else {
331
- nestedString = buildXMLString(finalXml);
283
+ function parseUniqueIdElement(element, uniqueIdElements) {
284
+ var _a, _b;
285
+ if (!uniqueIdElements) {
286
+ return createShortHash(element);
287
+ }
288
+ const id = (_b = (_a = findDirectFieldMatch(element, uniqueIdElements.split(","))) !== null && _a !== void 0 ? _a : findNestedFieldMatch(element, uniqueIdElements)) !== null && _b !== void 0 ? _b : createShortHash(element);
289
+ return id;
290
+ }
291
+ function findDirectFieldMatch(element, fieldNames) {
292
+ for (const name of fieldNames) {
293
+ const value = element[name];
294
+ if (typeof value === "string") {
295
+ return value;
332
296
  }
333
- yield promises.writeFile(outputPath, nestedString);
334
- logger.debug(`Created disassembled file: ${outputPath}`);
335
- });
297
+ }
336
298
  }
337
-
338
- function parseElement$1(params) {
339
- return __awaiter(this, void 0, void 0, function* () {
340
- const { element, disassembledPath, uniqueIdElements, rootElementName, rootAttributes, key, leafCount, hasNestedElements, format, xmlDeclaration, } = params;
341
- if (typeof element === "object" && element !== null) {
342
- yield buildNestedFile(element, disassembledPath, uniqueIdElements, rootElementName, rootAttributes, key, format, xmlDeclaration);
343
- return [{}, leafCount, true];
299
+ function findNestedFieldMatch(element, uniqueIdElements) {
300
+ for (const key in element) {
301
+ const child = element[key];
302
+ if (typeof child === "object" && child !== null) {
303
+ const result = parseUniqueIdElement(child, uniqueIdElements);
304
+ if (result)
305
+ return result;
344
306
  }
345
- const leafContent = {
346
- [key]: [element],
347
- };
348
- return [leafContent, leafCount + 1, hasNestedElements];
349
- });
307
+ }
308
+ }
309
+ function createShortHash(element) {
310
+ const hash = node_crypto.createHash("sha256")
311
+ .update(JSON.stringify(element))
312
+ .digest("hex");
313
+ return hash.slice(0, 8);
350
314
  }
351
315
 
352
- function buildLeafFile(leafContent, disassembledPath, baseName, rootElementName, rootAttributes, format, xmlDeclaration) {
353
- return __awaiter(this, void 0, void 0, function* () {
354
- const leafOutputPath = posix.join(disassembledPath, `${baseName}.${format}`);
355
- yield promises.mkdir(disassembledPath, { recursive: true });
316
+ function buildDisassembledFile(_a) {
317
+ return __awaiter(this, arguments, void 0, function* ({ content, disassembledPath, outputFileName, subdirectory, wrapKey, isGroupedArray = false, rootElementName, rootAttributes, xmlDeclaration, format, uniqueIdElements, }) {
318
+ const targetDirectory = subdirectory
319
+ ? posix.join(disassembledPath, subdirectory)
320
+ : disassembledPath;
321
+ let fileName = outputFileName;
322
+ if (!fileName && wrapKey && !isGroupedArray && typeof content === "object") {
323
+ const fieldName = parseUniqueIdElement(content, uniqueIdElements);
324
+ fileName = `${fieldName}.${wrapKey}-meta.${format}`;
325
+ }
326
+ const outputPath = posix.join(targetDirectory, fileName);
327
+ yield promises.mkdir(targetDirectory, { recursive: true });
356
328
  let wrappedXml = {
357
- [rootElementName]: Object.assign(Object.assign({}, rootAttributes), leafContent),
329
+ [rootElementName]: Object.assign(Object.assign({}, rootAttributes), (wrapKey
330
+ ? { [wrapKey]: isGroupedArray ? content : content }
331
+ : content)),
358
332
  };
359
333
  if (typeof xmlDeclaration === "object" && xmlDeclaration !== null) {
360
334
  wrappedXml = Object.assign({ "?xml": xmlDeclaration }, wrappedXml);
361
335
  }
362
- let leafString;
363
336
  const transformer = getTransformer(format);
364
- if (transformer) {
365
- leafString = yield transformer(wrappedXml);
366
- }
367
- else {
368
- leafString = buildXMLString(wrappedXml);
369
- }
370
- yield promises.writeFile(leafOutputPath, leafString);
371
- logger.debug(`Created disassembled file: ${leafOutputPath}`);
337
+ const outputString = transformer
338
+ ? yield transformer(wrappedXml)
339
+ : buildXMLString(wrappedXml);
340
+ yield promises.writeFile(outputPath, outputString);
341
+ logger.debug(`Created disassembled file: ${outputPath}`);
372
342
  });
373
343
  }
374
344
 
375
- function extractRootAttributes(rootElement) {
376
- const attributesOnly = {};
377
- for (const [attrKey, attrValue] of Object.entries(rootElement)) {
378
- if (attrKey.startsWith("@")) {
379
- attributesOnly[attrKey] = attrValue;
345
+ function extractRootAttributes(element) {
346
+ const attributes = {};
347
+ for (const [key, value] of Object.entries(element)) {
348
+ if (key.startsWith("@") && typeof value === "string") {
349
+ attributes[key] = value;
380
350
  }
381
351
  }
382
- return attributesOnly;
352
+ return attributes;
383
353
  }
384
354
 
385
- function buildDisassembledFiles$1(filePath, disassembledPath, uniqueIdElements, baseName, postPurge, format) {
355
+ function parseElementUnified(params) {
386
356
  return __awaiter(this, void 0, void 0, function* () {
387
- var _a;
388
- const parsedXml = yield parseXML(filePath);
389
- if (parsedXml === undefined)
390
- return;
391
- const rawDeclaration = parsedXml["?xml"];
392
- const xmlDeclaration = typeof rawDeclaration === "object" && rawDeclaration !== null
393
- ? rawDeclaration
394
- : undefined;
395
- const rootElementName = Object.keys(parsedXml).find((k) => k !== "?xml");
396
- const rootElement = parsedXml[rootElementName];
397
- const rootAttributes = extractRootAttributes(rootElement);
398
- let leafContent = {};
399
- let leafCount = 0;
400
- let hasNestedElements = false;
401
- for (const key of Object.keys(rootElement).filter((k) => !k.startsWith("@"))) {
402
- const elements = Array.isArray(rootElement[key])
403
- ? rootElement[key]
404
- : [rootElement[key]];
405
- for (const element of elements) {
406
- const [parsedLeafContent, updatedLeafCount, updatedHasNestedElements] = yield parseElement$1({
407
- element,
408
- disassembledPath,
409
- uniqueIdElements,
410
- rootElementName,
411
- rootAttributes,
412
- key,
413
- leafCount,
414
- hasNestedElements,
415
- format,
416
- xmlDeclaration,
417
- });
418
- const newContent = parsedLeafContent[key];
419
- if (newContent !== undefined) {
420
- leafContent[key] = [
421
- ...((_a = leafContent[key]) !== null && _a !== void 0 ? _a : []),
422
- ...newContent,
423
- ];
424
- }
425
- leafCount = updatedLeafCount;
426
- hasNestedElements = updatedHasNestedElements;
427
- }
428
- }
429
- if (!hasNestedElements) {
430
- logger.error(`The XML file ${filePath} only has leaf elements. This file will not be disassembled.`);
431
- return;
432
- }
433
- if (leafCount > 0) {
434
- yield buildLeafFile(leafContent, disassembledPath, baseName, rootElementName, rootAttributes, format, xmlDeclaration);
435
- }
436
- if (postPurge) {
437
- yield promises.unlink(filePath);
438
- }
439
- });
440
- }
441
-
442
- function parseElement(params) {
443
- return __awaiter(this, void 0, void 0, function* () {
444
- const { element, key, hasNestedElements } = params;
445
- const nestedGroups = {};
357
+ const { element, disassembledPath, uniqueIdElements, rootElementName, rootAttributes, key, leafCount, hasNestedElements, format, xmlDeclaration, strategy, } = params;
446
358
  const isArray = Array.isArray(element);
447
359
  const isNestedObject = typeof element === "object" &&
448
360
  element !== null &&
449
361
  Object.keys(element).some((k) => !k.startsWith("#"));
450
362
  const isNested = isArray || isNestedObject;
451
363
  if (isNested) {
452
- nestedGroups[key] = [element];
453
- return {
454
- leafContent: {},
455
- leafCount: params.leafCount,
456
- hasNestedElements: true,
457
- nestedGroups,
458
- };
364
+ if (strategy === "grouped-by-tag") {
365
+ return {
366
+ leafContent: {},
367
+ leafCount,
368
+ hasNestedElements: true,
369
+ nestedGroups: { [key]: [element] },
370
+ };
371
+ }
372
+ else {
373
+ yield buildDisassembledFile({
374
+ content: element,
375
+ disassembledPath,
376
+ subdirectory: key,
377
+ wrapKey: key,
378
+ rootElementName,
379
+ rootAttributes,
380
+ xmlDeclaration,
381
+ format,
382
+ uniqueIdElements,
383
+ });
384
+ return {
385
+ leafContent: {},
386
+ leafCount,
387
+ hasNestedElements: true,
388
+ };
389
+ }
459
390
  }
460
- const leafContent = {
461
- [key]: [element],
462
- };
463
391
  return {
464
- leafContent,
465
- leafCount: params.leafCount + 1,
392
+ leafContent: {
393
+ [key]: [element],
394
+ },
395
+ leafCount: leafCount + 1,
466
396
  hasNestedElements,
467
- nestedGroups,
468
397
  };
469
398
  });
470
399
  }
471
400
 
472
- function buildGroupedNestedFile(tag, elements, disassembledPath, rootElementName, rootAttributes, format, xmlDeclaration) {
473
- return __awaiter(this, void 0, void 0, function* () {
474
- const outputPath = posix.join(disassembledPath, `${tag}.${format}`);
475
- yield promises.mkdir(disassembledPath, { recursive: true });
476
- let rootElement = {
477
- [rootElementName]: Object.assign(Object.assign({}, rootAttributes), { [tag]: elements }),
478
- };
479
- if (typeof xmlDeclaration === "object" && xmlDeclaration !== null) {
480
- rootElement = Object.assign({ "?xml": xmlDeclaration }, rootElement);
401
+ function buildDisassembledFilesUnified(_a) {
402
+ return __awaiter(this, arguments, void 0, function* ({ filePath, disassembledPath, baseName, postPurge, format, uniqueIdElements, strategy, }) {
403
+ const parsedXml = yield parseXML(filePath);
404
+ if (!parsedXml)
405
+ return;
406
+ const { rootElementName, rootElement, xmlDeclaration } = getRootInfo(parsedXml);
407
+ const rootAttributes = extractRootAttributes(rootElement);
408
+ const keyOrder = Object.keys(rootElement).filter((k) => !k.startsWith("@"));
409
+ const { leafContent, nestedGroups, leafCount, hasNestedElements } = yield disassembleElementKeys({
410
+ rootElement,
411
+ keyOrder,
412
+ disassembledPath,
413
+ rootElementName,
414
+ rootAttributes,
415
+ xmlDeclaration,
416
+ uniqueIdElements,
417
+ strategy,
418
+ format,
419
+ });
420
+ if (!hasNestedElements && leafCount > 0) {
421
+ logger.error(`The XML file ${filePath} only has leaf elements. This file will not be disassembled.`);
422
+ return;
481
423
  }
482
- let nestedString;
483
- const transformer = getTransformer(format);
484
- if (transformer) {
485
- nestedString = yield transformer(rootElement);
424
+ yield writeNestedGroups(nestedGroups, strategy, {
425
+ disassembledPath,
426
+ rootElementName,
427
+ rootAttributes,
428
+ xmlDeclaration,
429
+ format,
430
+ });
431
+ if (leafCount > 0) {
432
+ const finalLeafContent = strategy === "grouped-by-tag"
433
+ ? orderXmlElementKeys(leafContent, keyOrder)
434
+ : leafContent;
435
+ yield buildDisassembledFile({
436
+ content: finalLeafContent,
437
+ disassembledPath,
438
+ outputFileName: `${baseName}.${format}`,
439
+ rootElementName,
440
+ rootAttributes,
441
+ xmlDeclaration,
442
+ format,
443
+ });
486
444
  }
487
- else {
488
- nestedString = buildXMLString(rootElement);
445
+ if (postPurge) {
446
+ yield promises.unlink(filePath);
489
447
  }
490
- yield promises.writeFile(outputPath, nestedString);
491
- logger.debug(`Created disassembled file: ${outputPath}`);
492
448
  });
493
449
  }
494
-
450
+ function getRootInfo(parsedXml) {
451
+ const rawDeclaration = parsedXml["?xml"];
452
+ const xmlDeclaration = typeof rawDeclaration === "object" && rawDeclaration !== null
453
+ ? rawDeclaration
454
+ : undefined;
455
+ const rootElementName = Object.keys(parsedXml).find((k) => k !== "?xml");
456
+ const rootElement = parsedXml[rootElementName];
457
+ return { rootElementName, rootElement, xmlDeclaration };
458
+ }
495
459
  function orderXmlElementKeys(content, keyOrder) {
496
460
  const ordered = {};
497
461
  for (const key of keyOrder) {
@@ -501,65 +465,68 @@ function orderXmlElementKeys(content, keyOrder) {
501
465
  }
502
466
  return ordered;
503
467
  }
504
- function buildDisassembledFiles(filePath, disassembledPath, baseName, postPurge, format) {
505
- return __awaiter(this, void 0, void 0, function* () {
506
- var _a;
507
- const parsedXml = yield parseXML(filePath);
508
- if (parsedXml === undefined)
509
- return;
510
- const rawDeclaration = parsedXml["?xml"];
511
- const xmlDeclaration = typeof rawDeclaration === "object" && rawDeclaration !== null
512
- ? rawDeclaration
513
- : undefined;
514
- const rootElementName = Object.keys(parsedXml).find((k) => k !== "?xml");
515
- const rootElement = parsedXml[rootElementName];
516
- const rootAttributes = extractRootAttributes(rootElement);
468
+ function disassembleElementKeys(_a) {
469
+ return __awaiter(this, arguments, void 0, function* ({ rootElement, keyOrder, disassembledPath, rootElementName, rootAttributes, xmlDeclaration, uniqueIdElements, strategy, format, }) {
470
+ var _b, _c;
517
471
  let leafContent = {};
472
+ let nestedGroups = {};
518
473
  let leafCount = 0;
519
474
  let hasNestedElements = false;
520
- const nestedGroups = {};
521
- const keyOrder = Object.keys(rootElement).filter((k) => !k.startsWith("@"));
522
475
  for (const key of keyOrder) {
523
476
  const elements = Array.isArray(rootElement[key])
524
477
  ? rootElement[key]
525
478
  : [rootElement[key]];
526
479
  for (const element of elements) {
527
- const result = yield parseElement({
480
+ const result = yield parseElementUnified({
528
481
  element,
482
+ disassembledPath,
483
+ uniqueIdElements,
484
+ rootElementName,
485
+ rootAttributes,
529
486
  key,
530
487
  leafCount,
531
- hasNestedElements});
532
- if (Object.keys(result.leafContent).length > 0) {
533
- const newContent = result.leafContent[key];
534
- if (newContent !== undefined) {
535
- leafContent[key] = [
536
- ...((_a = leafContent[key]) !== null && _a !== void 0 ? _a : []),
537
- ...newContent,
488
+ hasNestedElements,
489
+ format,
490
+ xmlDeclaration,
491
+ strategy,
492
+ });
493
+ if (result.leafContent[key]) {
494
+ leafContent[key] = [
495
+ ...((_b = leafContent[key]) !== null && _b !== void 0 ? _b : []),
496
+ ...result.leafContent[key],
497
+ ];
498
+ }
499
+ if (strategy === "grouped-by-tag" && result.nestedGroups) {
500
+ for (const tag in result.nestedGroups) {
501
+ nestedGroups[tag] = [
502
+ ...((_c = nestedGroups[tag]) !== null && _c !== void 0 ? _c : []),
503
+ ...result.nestedGroups[tag],
538
504
  ];
539
505
  }
540
506
  }
541
507
  leafCount = result.leafCount;
542
508
  hasNestedElements = result.hasNestedElements;
543
- for (const tag in result.nestedGroups) {
544
- if (!nestedGroups[tag])
545
- nestedGroups[tag] = [];
546
- nestedGroups[tag].push(...result.nestedGroups[tag]);
547
- }
548
509
  }
549
510
  }
550
- if (!hasNestedElements && leafCount > 0) {
551
- logger.error(`The XML file ${filePath} only has leaf elements. This file will not be disassembled.`);
511
+ return { leafContent, nestedGroups, leafCount, hasNestedElements };
512
+ });
513
+ }
514
+ function writeNestedGroups(nestedGroups, strategy, options) {
515
+ return __awaiter(this, void 0, void 0, function* () {
516
+ if (strategy !== "grouped-by-tag")
552
517
  return;
553
- }
554
518
  for (const tag in nestedGroups) {
555
- yield buildGroupedNestedFile(tag, nestedGroups[tag], disassembledPath, rootElementName, rootAttributes, format, xmlDeclaration);
556
- }
557
- if (leafCount > 0) {
558
- const orderedLeafContent = orderXmlElementKeys(leafContent, keyOrder);
559
- yield buildLeafFile(orderedLeafContent, disassembledPath, baseName, rootElementName, rootAttributes, format, xmlDeclaration);
560
- }
561
- if (postPurge) {
562
- yield promises.unlink(filePath);
519
+ yield buildDisassembledFile({
520
+ content: nestedGroups[tag],
521
+ disassembledPath: options.disassembledPath,
522
+ outputFileName: `${tag}.${options.format}`,
523
+ wrapKey: tag,
524
+ isGroupedArray: true,
525
+ rootElementName: options.rootElementName,
526
+ rootAttributes: options.rootAttributes,
527
+ xmlDeclaration: options.xmlDeclaration,
528
+ format: options.format,
529
+ });
563
530
  }
564
531
  });
565
532
  }
@@ -570,7 +537,11 @@ class DisassembleXMLFileHandler {
570
537
  }
571
538
  disassemble(xmlAttributes) {
572
539
  return __awaiter(this, void 0, void 0, function* () {
573
- const { filePath, uniqueIdElements, strategy = "unique-id", prePurge = false, postPurge = false, ignorePath = ".xmldisassemblerignore", format = "xml", } = xmlAttributes;
540
+ let { filePath, uniqueIdElements, strategy = "unique-id", prePurge = false, postPurge = false, ignorePath = ".xmldisassemblerignore", format = "xml", } = xmlAttributes;
541
+ if (!["unique-id", "grouped-by-tag"].includes(strategy)) {
542
+ logger.warn(`Unsupported strategy "${strategy}", defaulting to "unique-id".`);
543
+ strategy = "unique-id";
544
+ }
574
545
  const resolvedIgnorePath = node_path.resolve(ignorePath);
575
546
  if (node_fs.existsSync(resolvedIgnorePath)) {
576
547
  const content = yield promises.readFile(resolvedIgnorePath);
@@ -633,12 +604,15 @@ class DisassembleXMLFileHandler {
633
604
  outputPath = node_path.join(dirPath, baseName);
634
605
  if (prePurge && node_fs.existsSync(outputPath))
635
606
  yield promises.rm(outputPath, { recursive: true });
636
- if (strategy === "grouped-by-tag") {
637
- yield buildDisassembledFiles(filePath, outputPath, fullName, postPurge, format);
638
- }
639
- else {
640
- yield buildDisassembledFiles$1(filePath, outputPath, uniqueIdElements, fullName, postPurge, format);
641
- }
607
+ yield buildDisassembledFilesUnified({
608
+ filePath,
609
+ disassembledPath: outputPath,
610
+ uniqueIdElements,
611
+ baseName: fullName,
612
+ postPurge,
613
+ format,
614
+ strategy,
615
+ });
642
616
  });
643
617
  }
644
618
  posixPath(path) {