@abapify/adt-plugin-gcts 0.4.34 → 0.4.37

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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-CNh9ExCG.mjs";
2
2
  import { createPlugin, registerFormatPlugin } from "@abapify/adt-plugin";
3
- import { AdkClass, AdkDataElement, AdkDomain, AdkFunctionGroup, AdkInterface, AdkPackage, AdkProgram, AdkTable, AdkTableType, createAdk, getMainType, getTypeForKind } from "@abapify/adk";
3
+ import { AdkClass, AdkDataElement, AdkDomain, AdkFunctionGroup, AdkFunctionModule, AdkInterface, AdkPackage, AdkProgram, AdkTable, AdkTableType, createAdk, getMainType, getTypeForKind } from "@abapify/adk";
4
4
  import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
5
5
  import { dirname, join, resolve, sep } from "node:path";
6
6
  import { fileURLToPath } from "node:url";
@@ -385,7 +385,7 @@ function affHeaderProps(ref) {
385
385
  if (error instanceof Error && error.message.startsWith("No AFF schema")) return [];
386
386
  throw error;
387
387
  }
388
- const header = (schema.properties ?? {}).header;
388
+ const header = schema.properties?.header;
389
389
  return Object.keys(header && typeof header === "object" && header.properties ? header.properties : {});
390
390
  }
391
391
  const ajv = new Ajv2020({
@@ -744,6 +744,56 @@ function companionFiles(object, type, objectName, emitted, suffixToSourceKey) {
744
744
  ...propertyCompanionFiles(payload, objectName, typeLower)
745
745
  ].filter((f) => !emitted.has(f.path));
746
746
  }
747
+ /**
748
+ * Register a handler for an ADK class (preferred — `type` is derived from
749
+ * the static `kind`) or an explicit type string (for types without an ADK
750
+ * class, e.g. DOMA/DTEL).
751
+ */
752
+ async function resolveSource(entry) {
753
+ return await (typeof entry.content === "function" ? entry.content() : entry.content);
754
+ }
755
+ /** Resolve the metadata file name for an object (custom hook or default). */
756
+ function resolveMetadataFileName(definition, object, objectName, type) {
757
+ if (typeof definition.metadataFileName === "function") return definition.metadataFileName(object);
758
+ return definition.metadataFileName ?? gctsFilename(objectName, type, "metadata");
759
+ }
760
+ /**
761
+ * Definition source entries → serialized files. Skips empty sources;
762
+ * entries are resolved through the lazy `GctsSourceEntry` contract.
763
+ */
764
+ async function serializeSourceFiles(object, definition, type, objectName) {
765
+ const files = [];
766
+ if (definition.getSources) for (const entry of definition.getSources(object)) {
767
+ const content = await resolveSource(entry);
768
+ if (!content) continue;
769
+ files.push({
770
+ path: gctsFilename(objectName, type, "source", entry.suffix, entry.ext),
771
+ content
772
+ });
773
+ }
774
+ else if (definition.getSource) {
775
+ const content = await definition.getSource(object);
776
+ if (content) files.push({
777
+ path: gctsFilename(objectName, type, "source"),
778
+ content
779
+ });
780
+ }
781
+ return files;
782
+ }
783
+ /** Extra files (e.g. FUGR per-function-module files) → serialized files. */
784
+ async function serializeExtraFiles(object, definition) {
785
+ if (!definition.getExtraFiles) return [];
786
+ const files = [];
787
+ for (const extra of await definition.getExtraFiles(object)) {
788
+ const content = await resolveSource(extra);
789
+ if (!content) continue;
790
+ files.push({
791
+ path: extra.path,
792
+ content
793
+ });
794
+ }
795
+ return files;
796
+ }
747
797
  function createHandler(adkClassOrType, definition) {
748
798
  let type;
749
799
  if (typeof adkClassOrType === "string") type = adkClassOrType;
@@ -754,9 +804,6 @@ function createHandler(adkClassOrType, definition) {
754
804
  type = derived;
755
805
  }
756
806
  const fileExtension = getMainType(type).toLowerCase();
757
- async function resolveSource(entry) {
758
- return await (typeof entry.content === "function" ? entry.content() : entry.content);
759
- }
760
807
  const handler = {
761
808
  type,
762
809
  fileExtension,
@@ -766,41 +813,20 @@ function createHandler(adkClassOrType, definition) {
766
813
  },
767
814
  suffixToSourceKey: definition.suffixToSourceKey,
768
815
  async serialize(object) {
769
- const files = [];
770
816
  const objectName = (object.name ?? "").toLowerCase();
771
- if (definition.getSources) for (const entry of definition.getSources(object)) {
772
- const content = await resolveSource(entry);
773
- if (!content) continue;
774
- files.push({
775
- path: gctsFilename(objectName, type, "source", entry.suffix, entry.ext),
776
- content
777
- });
778
- }
779
- else if (definition.getSource) {
780
- const content = await definition.getSource(object);
781
- if (content) files.push({
782
- path: gctsFilename(objectName, type, "source"),
783
- content
784
- });
785
- }
817
+ const files = await serializeSourceFiles(object, definition, type, objectName);
786
818
  const metadata = definition.toMetadata(object);
787
- const metadataFile = typeof definition.metadataFileName === "function" ? definition.metadataFileName(object) : definition.metadataFileName ?? gctsFilename(objectName, type, "metadata");
788
- files.push({
789
- path: metadataFile,
819
+ const metadataFile = {
820
+ path: resolveMetadataFileName(definition, object, objectName, type),
790
821
  content: buildMetadataFile(metadata)
791
- });
792
- if (definition.getExtraFiles) {
793
- const extras = await definition.getExtraFiles(object);
794
- for (const extra of extras) {
795
- const content = await resolveSource(extra);
796
- if (!content) continue;
797
- files.push({
798
- path: extra.path,
799
- content
800
- });
801
- }
802
- }
803
- files.push(...companionFiles(object, type, objectName, new Set(files.map((f) => f.path)), definition.suffixToSourceKey));
822
+ };
823
+ const extraFiles = await serializeExtraFiles(object, definition);
824
+ const emitted = /* @__PURE__ */ new Set([
825
+ ...files.map((f) => f.path),
826
+ metadataFile.path,
827
+ ...extraFiles.map((f) => f.path)
828
+ ]);
829
+ files.push(metadataFile, ...extraFiles, ...companionFiles(object, type, objectName, emitted, definition.suffixToSourceKey));
804
830
  return files;
805
831
  },
806
832
  fromAbapGit: definition.fromMetadata ? (values) => definition.fromMetadata(values) : void 0,
@@ -950,7 +976,6 @@ const interfaceHandler = createHandler(AdkInterface, {
950
976
  * generalInformation: { programType, programStatus, fixPointArithmetic?, ... }
951
977
  * }
952
978
  */
953
- /** ADK sourceObjectStatus → AFF programStatus */
954
979
  const STATUS_TO_AFF = {
955
980
  SAPStandardProduction: "sapProductionProgram",
956
981
  customerProduction: "customerProductionProgram",
@@ -977,7 +1002,7 @@ const programHandler = createHandler(AdkProgram, {
977
1002
  generalInformation
978
1003
  };
979
1004
  },
980
- getSource: (obj) => obj.getSource(),
1005
+ getSource: (prog) => prog.getSource(),
981
1006
  fromMetadata: (meta) => ({
982
1007
  name: "",
983
1008
  type: "PROG/P",
@@ -1031,6 +1056,55 @@ const packageHandler = createHandler(AdkPackage, {
1031
1056
  })
1032
1057
  });
1033
1058
 
1059
+ // src/lib/handlers/objects/ddic-data-type.ts
1060
+ const dataTypes = {
1061
+ ACCP: true,
1062
+ CHAR: true,
1063
+ CLNT: true,
1064
+ CUKY: true,
1065
+ CURR: true,
1066
+ DF16_DEC: true,
1067
+ DF16_RAW: true,
1068
+ DF16_SCL: true,
1069
+ DECFLOAT16: true,
1070
+ DF34_DEC: true,
1071
+ DF34_RAW: true,
1072
+ DF34_SCL: true,
1073
+ DECFLOAT34: true,
1074
+ DATS: true,
1075
+ DATN: true,
1076
+ DEC: true,
1077
+ FLTP: true,
1078
+ GEOM_EWKB: true,
1079
+ INT1: true,
1080
+ INT2: true,
1081
+ INT4: true,
1082
+ INT8: true,
1083
+ LANG: true,
1084
+ LCHR: true,
1085
+ LRAW: true,
1086
+ NUMC: true,
1087
+ PREC: true,
1088
+ QUAN: true,
1089
+ RAW: true,
1090
+ RAWSTRING: true,
1091
+ SSTRING: true,
1092
+ STRING: true,
1093
+ TIMS: true,
1094
+ TIMN: true,
1095
+ UNIT: true,
1096
+ UTCLONG: true,
1097
+ VARC: true
1098
+ };
1099
+ /** Validate the open ADT type code before writing the narrower AFF enum. */
1100
+ function affDataType(value) {
1101
+ if (isAffDataType(value)) return value;
1102
+ throw new Error(`Unsupported AFF DDIC data type: ${String(value)}`);
1103
+ }
1104
+ function isAffDataType(value) {
1105
+ return typeof value === "string" && Object.hasOwn(dataTypes, value);
1106
+ }
1107
+
1034
1108
  // src/lib/handlers/objects/doma.ts
1035
1109
  /**
1036
1110
  * DOMA (domain) handler for gCTS / AFF format.
@@ -1048,16 +1122,16 @@ const packageHandler = createHandler(AdkPackage, {
1048
1122
  const domainHandler = createHandler(AdkDomain, {
1049
1123
  toMetadata(doma) {
1050
1124
  const data = doma.dataSync;
1051
- const content = data.content ?? {};
1125
+ const content = data.content;
1052
1126
  const lang = (data.language ?? data.masterLanguage ?? "").toLowerCase();
1053
- const ti = content.typeInformation ?? {};
1054
- const oi = content.outputInformation ?? {};
1055
- const vi = content.valueInformation ?? {};
1127
+ const ti = content?.typeInformation;
1128
+ const oi = content?.outputInformation;
1129
+ const vi = content?.valueInformation;
1056
1130
  const format = {
1057
- dataType: ti.datatype ?? "CHAR",
1058
- length: ti.length ?? 1
1131
+ dataType: affDataType(ti?.datatype ?? "CHAR"),
1132
+ length: ti?.length ?? 1
1059
1133
  };
1060
- if (typeof ti.decimals === "number") format.decimals = ti.decimals;
1134
+ if (typeof ti?.decimals === "number") format.decimals = ti.decimals;
1061
1135
  const result = {
1062
1136
  formatVersion: "1",
1063
1137
  header: {
@@ -1067,12 +1141,12 @@ const domainHandler = createHandler(AdkDomain, {
1067
1141
  format
1068
1142
  };
1069
1143
  const outChars = {};
1070
- if (typeof oi.length === "number") outChars.length = oi.length;
1071
- if (typeof oi.lowercase === "boolean") outChars.caseSensitive = !oi.lowercase;
1072
- if (oi.conversionExit) outChars.conversionRoutine = oi.conversionExit;
1144
+ if (typeof oi?.length === "number") outChars.length = oi.length;
1145
+ if (typeof oi?.lowercase === "boolean") outChars.caseSensitive = !oi.lowercase;
1146
+ if (oi?.conversionExit) outChars.conversionRoutine = oi.conversionExit;
1073
1147
  if (Object.keys(outChars).length > 0) result.outputCharacteristics = outChars;
1074
- const vtRef = vi.valueTableRef ?? {};
1075
- if (vtRef.name) result.valueTable = { name: vtRef.name };
1148
+ const vtRef = vi?.valueTableRef;
1149
+ if (vtRef?.name) result.valueTable = { name: vtRef.name };
1076
1150
  return result;
1077
1151
  },
1078
1152
  fromMetadata: (meta) => {
@@ -1112,10 +1186,13 @@ const domainHandler = createHandler(AdkDomain, {
1112
1186
  * }
1113
1187
  */
1114
1188
  function buildDataTypeInformation(data) {
1115
- if (data.typeKind === "domain" && data.typeName) return { domainName: data.typeName };
1189
+ if (data.typeKind === "domain" && typeof data.typeName === "string" && data.typeName) return { domainName: data.typeName };
1116
1190
  if (data.dataType) {
1117
- const predefinedType = { dataType: data.dataType };
1118
- if (typeof data.dataTypeLength === "number") predefinedType.length = data.dataTypeLength;
1191
+ if (typeof data.dataTypeLength !== "number") throw new TypeError("AFF predefined DDIC type requires a length");
1192
+ const predefinedType = {
1193
+ dataType: affDataType(data.dataType),
1194
+ length: data.dataTypeLength
1195
+ };
1119
1196
  if (typeof data.dataTypeDecimals === "number") predefinedType.decimals = data.dataTypeDecimals;
1120
1197
  return { predefinedType };
1121
1198
  }
@@ -1144,9 +1221,13 @@ function buildFieldLabels(data) {
1144
1221
  "heading",
1145
1222
  "headingFieldLength"
1146
1223
  ]
1147
- ]) if (data[src]) {
1148
- labels[dst] = data[src];
1149
- if (typeof data[lenKey] === "number") labels[`${dst}Length`] = data[lenKey];
1224
+ ]) {
1225
+ const label = data[src];
1226
+ const length = data[lenKey];
1227
+ if (typeof label === "string" && label) {
1228
+ labels[dst] = label;
1229
+ if (typeof length === "number") labels[`${dst}Length`] = length;
1230
+ }
1150
1231
  }
1151
1232
  return labels;
1152
1233
  }
@@ -1336,6 +1417,41 @@ const functionGroupHandler = createHandler(AdkFunctionGroup, {
1336
1417
  })
1337
1418
  });
1338
1419
 
1420
+ // src/lib/handlers/objects/func.ts
1421
+ /**
1422
+ * FUNC (function module) handler for gCTS / AFF format.
1423
+ *
1424
+ * Projects ADK function module data to the AFF func-v1.json schema shape.
1425
+ * A function module is a child of a function group, but it can also be
1426
+ * serialized as its own ADK object (FUNC) for the gCTS file format.
1427
+ */
1428
+ const functionModuleHandler = createHandler(AdkFunctionModule, {
1429
+ toMetadata(func) {
1430
+ const data = func.dataSync ?? {};
1431
+ const meta = {
1432
+ formatVersion: "1",
1433
+ header: { description: func.description ?? data.description ?? "" },
1434
+ processingType: data.processingType ?? "normal",
1435
+ includeNumber: data.includeNumber ?? "0000"
1436
+ };
1437
+ if (data.rfcProperties && typeof data.rfcProperties === "object") meta.rfcProperties = data.rfcProperties;
1438
+ if (data.updateProperties && typeof data.updateProperties === "object") meta.updateProperties = data.updateProperties;
1439
+ if (typeof data.releaseState === "string") meta.releaseState = data.releaseState;
1440
+ if (typeof data.global === "boolean") meta.global = data.global;
1441
+ if (typeof data.exceptionClasses === "boolean") meta.exceptionClasses = data.exceptionClasses;
1442
+ return meta;
1443
+ },
1444
+ getSource: (func) => typeof func.getSource === "function" ? func.getSource() : "",
1445
+ fromMetadata: (meta) => ({
1446
+ name: "",
1447
+ description: meta.header.description,
1448
+ language: meta.header.originalLanguage?.toUpperCase(),
1449
+ masterLanguage: meta.header.originalLanguage?.toUpperCase(),
1450
+ processingType: meta.processingType,
1451
+ includeNumber: meta.includeNumber
1452
+ })
1453
+ });
1454
+
1339
1455
  // src/lib/handlers/objects/ddls.ts
1340
1456
  /**
1341
1457
  * DDLS (CDS view) handler for gCTS / AFF format.
@@ -1351,6 +1467,56 @@ const functionGroupHandler = createHandler(AdkFunctionGroup, {
1351
1467
  * parentName?: string
1352
1468
  * }
1353
1469
  */
1470
+ const languageVersions = {
1471
+ standard: true,
1472
+ keyUser: true,
1473
+ cloudDevelopment: true
1474
+ };
1475
+ const sourceOrigins = {
1476
+ abapDevelopmentTools: true,
1477
+ customCdsViews: true,
1478
+ customAnalyticalQueries: true,
1479
+ customBusinessObject: true,
1480
+ customCodeList: true,
1481
+ customCdsViewsVariantConfg: true,
1482
+ customFields: true,
1483
+ extensionsForDataSources: true,
1484
+ customSearchModeler: true,
1485
+ serviceConsumptionModel: true
1486
+ };
1487
+ const sourceTypes = {
1488
+ ddicBasedView: true,
1489
+ viewEntity: true,
1490
+ viewExtend: true,
1491
+ viewEntityExtend: true,
1492
+ tableFunction: true,
1493
+ tableEntity: true,
1494
+ abstractEntity: true,
1495
+ customEntity: true,
1496
+ hierarchy: true,
1497
+ projectionView: true,
1498
+ externalEntity: true,
1499
+ unknown: true
1500
+ };
1501
+ /**
1502
+ * ADK exposes these fields as open strings, so the compile-time enum types do
1503
+ * not protect the serialized output. Reject values outside the AFF enum.
1504
+ * Non-strings are rejected before property lookup: an array such as
1505
+ * `['viewEntity']` would otherwise coerce to a valid key and be emitted.
1506
+ */
1507
+ function isAffEnumValue(allowed, value) {
1508
+ return typeof value === "string" && Object.hasOwn(allowed, value);
1509
+ }
1510
+ function mismatchDetail(value) {
1511
+ if (typeof value === "string") return value;
1512
+ if (value === null) return "null";
1513
+ if (Array.isArray(value)) return "array";
1514
+ return typeof value;
1515
+ }
1516
+ function affEnum(allowed, field, value) {
1517
+ if (isAffEnumValue(allowed, value)) return value;
1518
+ throw new Error(`Unsupported AFF DDLS ${field}: ${mismatchDetail(value)}`);
1519
+ }
1354
1520
  const ddlSourceHandler = createHandler("DDLS", {
1355
1521
  toMetadata(obj) {
1356
1522
  const lang = (obj.originalLanguage ?? "").toLowerCase();
@@ -1359,10 +1525,10 @@ const ddlSourceHandler = createHandler("DDLS", {
1359
1525
  header: {
1360
1526
  description: obj.description ?? obj.name ?? "",
1361
1527
  originalLanguage: lang,
1362
- ...obj.abapLanguageVersion ? { abapLanguageVersion: obj.abapLanguageVersion } : {}
1528
+ ...obj.abapLanguageVersion ? { abapLanguageVersion: affEnum(languageVersions, "abapLanguageVersion", obj.abapLanguageVersion) } : {}
1363
1529
  },
1364
- sourceOrigin: obj.sourceOrigin ?? "abapDevelopmentTools",
1365
- sourceType: obj.sourceType ?? "unknown"
1530
+ sourceOrigin: affEnum(sourceOrigins, "sourceOrigin", obj.sourceOrigin ?? "abapDevelopmentTools"),
1531
+ sourceType: affEnum(sourceTypes, "sourceType", obj.sourceType ?? "unknown")
1366
1532
  };
1367
1533
  },
1368
1534
  getSource: (obj) => typeof obj.getSource === "function" ? obj.getSource() : "",
@@ -1703,6 +1869,67 @@ function abapLangVerToAdt(code) {
1703
1869
  return ABAP_LANG_VER_TO_ADT[code] ?? code;
1704
1870
  }
1705
1871
  /**
1872
+ * Register one `.json` file in the object index.
1873
+ *
1874
+ * Packages are NOT deployed (same convention as abapGit's `package.devc.xml`)
1875
+ * — they must exist on target. `{name}.{type}.docu.json` is a DOCU
1876
+ * companion, not a second metadata anchor — without this it can overwrite
1877
+ * metadataFile depending on glob order. Other suffixed `.json` companions
1878
+ * (LIMU sub-object metadata, `{sub}.{stype}`) flow through the source
1879
+ * pipeline with an explicit `json` ext marker.
1880
+ */
1881
+ function registerJsonAnchor(jsonPath, objectMap, supportedTypes) {
1882
+ const filename = jsonPath.split("/").pop();
1883
+ if (filename === "package.devc.json") return;
1884
+ const parsed = parseGctsFilename(filename);
1885
+ if (!parsed) return;
1886
+ if (parsed.extension !== "json") return;
1887
+ if (!supportedTypes.has(parsed.type.toLowerCase())) return;
1888
+ const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
1889
+ if (!objectMap.has(key)) objectMap.set(key, {
1890
+ name: parsed.name.toUpperCase(),
1891
+ type: parsed.type.toUpperCase(),
1892
+ sourceFiles: [],
1893
+ propertyFiles: []
1894
+ });
1895
+ const entry = objectMap.get(key);
1896
+ if (parsed.suffix === "docu") entry.docuFile = jsonPath;
1897
+ else if (parsed.suffix) entry.sourceFiles.push({
1898
+ path: jsonPath,
1899
+ suffix: parsed.suffix,
1900
+ ext: "json"
1901
+ });
1902
+ else entry.metadataFile = jsonPath;
1903
+ }
1904
+ /**
1905
+ * Register a `.properties` translation companion — routed into
1906
+ * `data.properties` so it round-trips through metadata, not source staging.
1907
+ */
1908
+ function registerPropertyFile(path, objectMap) {
1909
+ const filename = path.split("/").pop();
1910
+ const parsed = parseGctsFilename(filename);
1911
+ if (!parsed) return;
1912
+ const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
1913
+ objectMap.get(key)?.propertyFiles.push({
1914
+ path,
1915
+ suffix: parsed.suffix
1916
+ });
1917
+ }
1918
+ /** Register a source file (.abap/.asddls/.asdcls) with its object group. */
1919
+ function registerSourceFile(path, objectMap) {
1920
+ const filename = path.split("/").pop();
1921
+ const parsed = parseGctsFilename(filename);
1922
+ if (!parsed) return;
1923
+ const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
1924
+ const obj = objectMap.get(key);
1925
+ if (!obj) return;
1926
+ obj.sourceFiles.push({
1927
+ path,
1928
+ suffix: parsed.suffix,
1929
+ ext: parsed.extension
1930
+ });
1931
+ }
1932
+ /**
1706
1933
  * Deserialise a gCTS/AFF file tree into `AdkObject` instances.
1707
1934
  *
1708
1935
  * @param fileTree Virtual FS abstraction (checkin supplies a real-fs impl).
@@ -1716,56 +1943,10 @@ async function* deserialize(fileTree, client, options) {
1716
1943
  const jsonFiles = await fileTree.glob("**/*.json");
1717
1944
  const supportedTypes = new Set(getSupportedTypes().map((t) => t.toLowerCase()));
1718
1945
  const objectMap = /* @__PURE__ */ new Map();
1719
- for (const jsonPath of jsonFiles) {
1720
- const filename = jsonPath.split("/").pop();
1721
- if (filename === "package.devc.json") continue;
1722
- const parsed = parseGctsFilename(filename);
1723
- if (!parsed) continue;
1724
- if (parsed.extension !== "json") continue;
1725
- if (!supportedTypes.has(parsed.type.toLowerCase())) continue;
1726
- const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
1727
- if (!objectMap.has(key)) objectMap.set(key, {
1728
- name: parsed.name.toUpperCase(),
1729
- type: parsed.type.toUpperCase(),
1730
- sourceFiles: [],
1731
- propertyFiles: []
1732
- });
1733
- if (parsed.suffix === "docu") objectMap.get(key).docuFile = jsonPath;
1734
- else if (parsed.suffix) {
1735
- objectMap.get(key).sourceFiles.push({
1736
- path: jsonPath,
1737
- suffix: parsed.suffix,
1738
- ext: "json"
1739
- });
1740
- continue;
1741
- } else objectMap.get(key).metadataFile = jsonPath;
1742
- }
1743
- for (const path of await fileTree.glob("**/*.properties")) {
1744
- const filename = path.split("/").pop();
1745
- const parsed = parseGctsFilename(filename);
1746
- if (!parsed) continue;
1747
- const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
1748
- objectMap.get(key)?.propertyFiles.push({
1749
- path,
1750
- suffix: parsed.suffix
1751
- });
1752
- }
1753
- for (const ext of SOURCE_EXTENSIONS) {
1754
- const paths = await fileTree.glob(`**/*.${ext}`);
1755
- for (const path of paths) {
1756
- const filename = path.split("/").pop();
1757
- const parsed = parseGctsFilename(filename);
1758
- if (!parsed) continue;
1759
- const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
1760
- const obj = objectMap.get(key);
1761
- if (!obj) continue;
1762
- obj.sourceFiles.push({
1763
- path,
1764
- suffix: parsed.suffix,
1765
- ext: parsed.extension
1766
- });
1767
- }
1768
- }
1946
+ for (const jsonPath of jsonFiles) registerJsonAnchor(jsonPath, objectMap, supportedTypes);
1947
+ for (const path of await fileTree.glob("**/*.properties")) registerPropertyFile(path, objectMap);
1948
+ const pathsByExtension = await Promise.all(Array.from(SOURCE_EXTENSIONS).map((ext) => fileTree.glob(`**/*.${ext}`)));
1949
+ for (const paths of pathsByExtension) for (const path of paths) registerSourceFile(path, objectMap);
1769
1950
  const readThrottled = throttledReader(fileTree);
1770
1951
  const entries = [...objectMap.values()];
1771
1952
  const pending = /* @__PURE__ */ new Map();