@abapify/adt-plugin-gcts 0.4.33 → 0.4.36
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 +14 -45
- package/dist/index.d.mts +94 -90
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +292 -110
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
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 =
|
|
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
|
-
|
|
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 =
|
|
788
|
-
|
|
789
|
-
path: metadataFile,
|
|
819
|
+
const metadataFile = {
|
|
820
|
+
path: resolveMetadataFileName(definition, object, objectName, type),
|
|
790
821
|
content: buildMetadataFile(metadata)
|
|
791
|
-
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
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: (
|
|
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
|
|
1054
|
-
const oi = content
|
|
1055
|
-
const vi = content
|
|
1127
|
+
const ti = content?.typeInformation;
|
|
1128
|
+
const oi = content?.outputInformation;
|
|
1129
|
+
const vi = content?.valueInformation;
|
|
1056
1130
|
const format = {
|
|
1057
|
-
dataType: ti
|
|
1058
|
-
length: ti
|
|
1131
|
+
dataType: affDataType(ti?.datatype ?? "CHAR"),
|
|
1132
|
+
length: ti?.length ?? 1
|
|
1059
1133
|
};
|
|
1060
|
-
if (typeof ti
|
|
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
|
|
1071
|
-
if (typeof oi
|
|
1072
|
-
if (oi
|
|
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
|
|
1075
|
-
if (vtRef
|
|
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
|
-
|
|
1118
|
-
|
|
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
|
-
])
|
|
1148
|
-
|
|
1149
|
-
|
|
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,42 @@ 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
|
+
(data.language ?? data.masterLanguage ?? "").toLowerCase();
|
|
1432
|
+
const meta = {
|
|
1433
|
+
formatVersion: "1",
|
|
1434
|
+
header: { description: func.description ?? data.description ?? "" },
|
|
1435
|
+
processingType: data.processingType ?? "normal",
|
|
1436
|
+
includeNumber: data.includeNumber ?? "0000"
|
|
1437
|
+
};
|
|
1438
|
+
if (data.rfcProperties && typeof data.rfcProperties === "object") meta.rfcProperties = data.rfcProperties;
|
|
1439
|
+
if (data.updateProperties && typeof data.updateProperties === "object") meta.updateProperties = data.updateProperties;
|
|
1440
|
+
if (typeof data.releaseState === "string") meta.releaseState = data.releaseState;
|
|
1441
|
+
if (typeof data.global === "boolean") meta.global = data.global;
|
|
1442
|
+
if (typeof data.exceptionClasses === "boolean") meta.exceptionClasses = data.exceptionClasses;
|
|
1443
|
+
return meta;
|
|
1444
|
+
},
|
|
1445
|
+
getSource: (func) => typeof func.getSource === "function" ? func.getSource() : "",
|
|
1446
|
+
fromMetadata: (meta) => ({
|
|
1447
|
+
name: "",
|
|
1448
|
+
description: meta.header.description,
|
|
1449
|
+
language: meta.header.originalLanguage?.toUpperCase(),
|
|
1450
|
+
masterLanguage: meta.header.originalLanguage?.toUpperCase(),
|
|
1451
|
+
processingType: meta.processingType,
|
|
1452
|
+
includeNumber: meta.includeNumber
|
|
1453
|
+
})
|
|
1454
|
+
});
|
|
1455
|
+
|
|
1339
1456
|
// src/lib/handlers/objects/ddls.ts
|
|
1340
1457
|
/**
|
|
1341
1458
|
* DDLS (CDS view) handler for gCTS / AFF format.
|
|
@@ -1351,6 +1468,56 @@ const functionGroupHandler = createHandler(AdkFunctionGroup, {
|
|
|
1351
1468
|
* parentName?: string
|
|
1352
1469
|
* }
|
|
1353
1470
|
*/
|
|
1471
|
+
const languageVersions = {
|
|
1472
|
+
standard: true,
|
|
1473
|
+
keyUser: true,
|
|
1474
|
+
cloudDevelopment: true
|
|
1475
|
+
};
|
|
1476
|
+
const sourceOrigins = {
|
|
1477
|
+
abapDevelopmentTools: true,
|
|
1478
|
+
customCdsViews: true,
|
|
1479
|
+
customAnalyticalQueries: true,
|
|
1480
|
+
customBusinessObject: true,
|
|
1481
|
+
customCodeList: true,
|
|
1482
|
+
customCdsViewsVariantConfg: true,
|
|
1483
|
+
customFields: true,
|
|
1484
|
+
extensionsForDataSources: true,
|
|
1485
|
+
customSearchModeler: true,
|
|
1486
|
+
serviceConsumptionModel: true
|
|
1487
|
+
};
|
|
1488
|
+
const sourceTypes = {
|
|
1489
|
+
ddicBasedView: true,
|
|
1490
|
+
viewEntity: true,
|
|
1491
|
+
viewExtend: true,
|
|
1492
|
+
viewEntityExtend: true,
|
|
1493
|
+
tableFunction: true,
|
|
1494
|
+
tableEntity: true,
|
|
1495
|
+
abstractEntity: true,
|
|
1496
|
+
customEntity: true,
|
|
1497
|
+
hierarchy: true,
|
|
1498
|
+
projectionView: true,
|
|
1499
|
+
externalEntity: true,
|
|
1500
|
+
unknown: true
|
|
1501
|
+
};
|
|
1502
|
+
/**
|
|
1503
|
+
* ADK exposes these fields as open strings, so the compile-time enum types do
|
|
1504
|
+
* not protect the serialized output. Reject values outside the AFF enum.
|
|
1505
|
+
* Non-strings are rejected before property lookup: an array such as
|
|
1506
|
+
* `['viewEntity']` would otherwise coerce to a valid key and be emitted.
|
|
1507
|
+
*/
|
|
1508
|
+
function isAffEnumValue(allowed, value) {
|
|
1509
|
+
return typeof value === "string" && Object.hasOwn(allowed, value);
|
|
1510
|
+
}
|
|
1511
|
+
function mismatchDetail(value) {
|
|
1512
|
+
if (typeof value === "string") return value;
|
|
1513
|
+
if (value === null) return "null";
|
|
1514
|
+
if (Array.isArray(value)) return "array";
|
|
1515
|
+
return typeof value;
|
|
1516
|
+
}
|
|
1517
|
+
function affEnum(allowed, field, value) {
|
|
1518
|
+
if (isAffEnumValue(allowed, value)) return value;
|
|
1519
|
+
throw new Error(`Unsupported AFF DDLS ${field}: ${mismatchDetail(value)}`);
|
|
1520
|
+
}
|
|
1354
1521
|
const ddlSourceHandler = createHandler("DDLS", {
|
|
1355
1522
|
toMetadata(obj) {
|
|
1356
1523
|
const lang = (obj.originalLanguage ?? "").toLowerCase();
|
|
@@ -1359,10 +1526,10 @@ const ddlSourceHandler = createHandler("DDLS", {
|
|
|
1359
1526
|
header: {
|
|
1360
1527
|
description: obj.description ?? obj.name ?? "",
|
|
1361
1528
|
originalLanguage: lang,
|
|
1362
|
-
...obj.abapLanguageVersion ? { abapLanguageVersion: obj.abapLanguageVersion } : {}
|
|
1529
|
+
...obj.abapLanguageVersion ? { abapLanguageVersion: affEnum(languageVersions, "abapLanguageVersion", obj.abapLanguageVersion) } : {}
|
|
1363
1530
|
},
|
|
1364
|
-
sourceOrigin: obj.sourceOrigin ?? "abapDevelopmentTools",
|
|
1365
|
-
sourceType: obj.sourceType ?? "unknown"
|
|
1531
|
+
sourceOrigin: affEnum(sourceOrigins, "sourceOrigin", obj.sourceOrigin ?? "abapDevelopmentTools"),
|
|
1532
|
+
sourceType: affEnum(sourceTypes, "sourceType", obj.sourceType ?? "unknown")
|
|
1366
1533
|
};
|
|
1367
1534
|
},
|
|
1368
1535
|
getSource: (obj) => typeof obj.getSource === "function" ? obj.getSource() : "",
|
|
@@ -1703,6 +1870,67 @@ function abapLangVerToAdt(code) {
|
|
|
1703
1870
|
return ABAP_LANG_VER_TO_ADT[code] ?? code;
|
|
1704
1871
|
}
|
|
1705
1872
|
/**
|
|
1873
|
+
* Register one `.json` file in the object index.
|
|
1874
|
+
*
|
|
1875
|
+
* Packages are NOT deployed (same convention as abapGit's `package.devc.xml`)
|
|
1876
|
+
* — they must exist on target. `{name}.{type}.docu.json` is a DOCU
|
|
1877
|
+
* companion, not a second metadata anchor — without this it can overwrite
|
|
1878
|
+
* metadataFile depending on glob order. Other suffixed `.json` companions
|
|
1879
|
+
* (LIMU sub-object metadata, `{sub}.{stype}`) flow through the source
|
|
1880
|
+
* pipeline with an explicit `json` ext marker.
|
|
1881
|
+
*/
|
|
1882
|
+
function registerJsonAnchor(jsonPath, objectMap, supportedTypes) {
|
|
1883
|
+
const filename = jsonPath.split("/").pop();
|
|
1884
|
+
if (filename === "package.devc.json") return;
|
|
1885
|
+
const parsed = parseGctsFilename(filename);
|
|
1886
|
+
if (!parsed) return;
|
|
1887
|
+
if (parsed.extension !== "json") return;
|
|
1888
|
+
if (!supportedTypes.has(parsed.type.toLowerCase())) return;
|
|
1889
|
+
const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
|
|
1890
|
+
if (!objectMap.has(key)) objectMap.set(key, {
|
|
1891
|
+
name: parsed.name.toUpperCase(),
|
|
1892
|
+
type: parsed.type.toUpperCase(),
|
|
1893
|
+
sourceFiles: [],
|
|
1894
|
+
propertyFiles: []
|
|
1895
|
+
});
|
|
1896
|
+
const entry = objectMap.get(key);
|
|
1897
|
+
if (parsed.suffix === "docu") entry.docuFile = jsonPath;
|
|
1898
|
+
else if (parsed.suffix) entry.sourceFiles.push({
|
|
1899
|
+
path: jsonPath,
|
|
1900
|
+
suffix: parsed.suffix,
|
|
1901
|
+
ext: "json"
|
|
1902
|
+
});
|
|
1903
|
+
else entry.metadataFile = jsonPath;
|
|
1904
|
+
}
|
|
1905
|
+
/**
|
|
1906
|
+
* Register a `.properties` translation companion — routed into
|
|
1907
|
+
* `data.properties` so it round-trips through metadata, not source staging.
|
|
1908
|
+
*/
|
|
1909
|
+
function registerPropertyFile(path, objectMap) {
|
|
1910
|
+
const filename = path.split("/").pop();
|
|
1911
|
+
const parsed = parseGctsFilename(filename);
|
|
1912
|
+
if (!parsed) return;
|
|
1913
|
+
const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
|
|
1914
|
+
objectMap.get(key)?.propertyFiles.push({
|
|
1915
|
+
path,
|
|
1916
|
+
suffix: parsed.suffix
|
|
1917
|
+
});
|
|
1918
|
+
}
|
|
1919
|
+
/** Register a source file (.abap/.asddls/.asdcls) with its object group. */
|
|
1920
|
+
function registerSourceFile(path, objectMap) {
|
|
1921
|
+
const filename = path.split("/").pop();
|
|
1922
|
+
const parsed = parseGctsFilename(filename);
|
|
1923
|
+
if (!parsed) return;
|
|
1924
|
+
const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
|
|
1925
|
+
const obj = objectMap.get(key);
|
|
1926
|
+
if (!obj) return;
|
|
1927
|
+
obj.sourceFiles.push({
|
|
1928
|
+
path,
|
|
1929
|
+
suffix: parsed.suffix,
|
|
1930
|
+
ext: parsed.extension
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
/**
|
|
1706
1934
|
* Deserialise a gCTS/AFF file tree into `AdkObject` instances.
|
|
1707
1935
|
*
|
|
1708
1936
|
* @param fileTree Virtual FS abstraction (checkin supplies a real-fs impl).
|
|
@@ -1716,56 +1944,10 @@ async function* deserialize(fileTree, client, options) {
|
|
|
1716
1944
|
const jsonFiles = await fileTree.glob("**/*.json");
|
|
1717
1945
|
const supportedTypes = new Set(getSupportedTypes().map((t) => t.toLowerCase()));
|
|
1718
1946
|
const objectMap = /* @__PURE__ */ new Map();
|
|
1719
|
-
for (const jsonPath of jsonFiles)
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
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
|
-
}
|
|
1947
|
+
for (const jsonPath of jsonFiles) registerJsonAnchor(jsonPath, objectMap, supportedTypes);
|
|
1948
|
+
for (const path of await fileTree.glob("**/*.properties")) registerPropertyFile(path, objectMap);
|
|
1949
|
+
const pathsByExtension = await Promise.all(Array.from(SOURCE_EXTENSIONS).map((ext) => fileTree.glob(`**/*.${ext}`)));
|
|
1950
|
+
for (const paths of pathsByExtension) for (const path of paths) registerSourceFile(path, objectMap);
|
|
1769
1951
|
const readThrottled = throttledReader(fileTree);
|
|
1770
1952
|
const entries = [...objectMap.values()];
|
|
1771
1953
|
const pending = /* @__PURE__ */ new Map();
|