@abapify/adt-plugin-gcts 0.4.0 → 0.4.1

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.
@@ -0,0 +1,156 @@
1
+ import { AdtPlugin, AdtPlugin as AdtPlugin$1, FormatHandler, FormatHandler as FormatHandler$1, FormatPlugin, FormatPlugin as FormatPlugin$1, ParsedFormatFilename, SerializedFile, SerializedFile as SerializedFile$1 } from "@abapify/adt-plugin";
2
+ import { AdkClass, AdkDataElement, AdkDomain, AdkFunctionGroup, AdkInterface, AdkKind, AdkObject, AdkPackage, AdkProgram, AdkTable, AdkTableType } from "@abapify/adk";
3
+
4
+ //#region src/lib/format/types.d.ts
5
+ /**
6
+ * gCTS / AFF format type definitions.
7
+ *
8
+ * The gCTS on-disk layout is essentially the layout documented by the AFF
9
+ * project (`SAP/abap-file-formats`): object-type subdirectory, JSON metadata,
10
+ * source files with AFF-specific extensions (`.abap`, `.acds`, ...).
11
+ *
12
+ * This plugin intentionally targets the AFF format so that a single plugin
13
+ * id (`gcts`) covers both gCTS-exported repos and AFF-exported repos. See
14
+ * `AGENTS.md` for the rationale and the open question tracked in
15
+ * `docs/roadmap/epics/e06-gcts-format-plugin.md`.
16
+ */
17
+ /** Header common to every AFF/gCTS metadata JSON file. */
18
+ interface GctsHeader {
19
+ /** AFF format version (e.g. `1.0`). */
20
+ formatVersion: string;
21
+ /** Description of the object. */
22
+ description?: string;
23
+ /** Master language (ISO code, lowercase — e.g. `en`). */
24
+ originalLanguage?: string;
25
+ /** ABAP language version (e.g. `standard`, `cloudDevelopment`). */
26
+ abapLanguageVersion?: string;
27
+ /** Indicates whether the object source is Unicode. */
28
+ [key: string]: unknown;
29
+ }
30
+ /**
31
+ * Top-level shape of an AFF/gCTS metadata JSON file.
32
+ *
33
+ * Concrete handlers tighten this with per-type payload shapes.
34
+ */
35
+ interface GctsMetadata<_TPayload extends object = object> {
36
+ /** Format header (mandatory on every file). */
37
+ header: GctsHeader;
38
+ /** Type-specific payload. Extended per ABAP object type. */
39
+ [payloadKey: string]: unknown;
40
+ }
41
+ /** Convenience helper for concrete metadata shapes. */
42
+ type WithHeader<TPayload extends object> = {
43
+ header: GctsHeader;
44
+ } & TPayload;
45
+ //#endregion
46
+ //#region src/lib/format/filename.d.ts
47
+ /** Metadata extension for all AFF/gCTS objects. */
48
+ declare const METADATA_EXTENSION = "json";
49
+ /** Fixed filename for package metadata (AFF / gCTS convention). */
50
+ declare const PACKAGE_FILENAME = "package.devc.json";
51
+ /**
52
+ * Build the AFF/gCTS on-disk filename for an object.
53
+ *
54
+ * @param name Object name (case preserved — AFF normalises to lowercase)
55
+ * @param type ABAP object type code (CLAS, INTF, ...)
56
+ * @param kind `"metadata"` (default) or `"source"`.
57
+ * @param suffix Optional sub-include suffix (e.g. `locals_def` for CLAS).
58
+ */
59
+ declare function gctsFilename(name: string, type: string, kind?: 'metadata' | 'source', suffix?: string): string;
60
+ /**
61
+ * Parse an AFF/gCTS filename back into its components.
62
+ *
63
+ * Returns `undefined` if the filename does not look like a known AFF/gCTS
64
+ * artefact — callers should skip unknown files (e.g. `README.md`).
65
+ */
66
+ declare function parseGctsFilename(filename: string): ParsedFormatFilename | undefined;
67
+ /**
68
+ * Translate an ADT object URI (e.g. `/sap/bc/adt/oo/classes/zcl_foo`) to
69
+ * the AFF/gCTS on-disk path (e.g. `zcl_foo/zcl_foo.clas.json`).
70
+ *
71
+ * Matches the `adtUriToAbapGitPath` helper in the abapGit plugin.
72
+ */
73
+ declare function adtUriToGctsPath(uri: string): string | undefined;
74
+ //#endregion
75
+ //#region src/lib/handlers/base.d.ts
76
+ type AbapObjectType = string;
77
+ type AdkObjectClass<T extends AdkObject = AdkObject> = {
78
+ new (...args: any[]): T;
79
+ readonly kind: AdkKind;
80
+ };
81
+ /**
82
+ * Lazy source entry.
83
+ *
84
+ * `content` may be a string, a promise, or a thunk returning either — the
85
+ * factory awaits whichever form the handler returns.
86
+ */
87
+ interface GctsSourceEntry {
88
+ suffix?: string;
89
+ content: string | Promise<string> | (() => string | Promise<string>);
90
+ }
91
+ /**
92
+ * Handler definition for a single ABAP object type.
93
+ *
94
+ * The shape intentionally mirrors the abapGit `HandlerDefinition` so that
95
+ * anyone familiar with the sister plugin can move between them with minimal
96
+ * friction. The `toMetadata` function is the only required hook: it maps an
97
+ * ADK object to the JSON metadata shape for the target type.
98
+ */
99
+ interface GctsHandlerDefinition<T extends AdkObject, M extends GctsMetadata = GctsMetadata> {
100
+ /** Map ADK object → JSON metadata payload (including the required `header`). */
101
+ toMetadata(object: T): M;
102
+ /** Optional: single primary source file. */
103
+ getSource?(object: T): string | Promise<string>;
104
+ /** Optional: multiple source files (e.g. CLAS includes). */
105
+ getSources?(object: T): GctsSourceEntry[];
106
+ /** Optional: custom metadata filename (e.g. `package.devc.json` for DEVC). */
107
+ metadataFileName?: string | ((object: T) => string);
108
+ /**
109
+ * Optional: inverse mapping used during deserialization.
110
+ *
111
+ * `fromMetadata` receives the parsed JSON payload and returns a partial
112
+ * ADK-data projection. `setSources` mirrors abapGit's behaviour: it stages
113
+ * source content on the ADK object for later deploy.
114
+ */
115
+ fromMetadata?(metadata: M): {
116
+ name: string;
117
+ } & Record<string, unknown>;
118
+ suffixToSourceKey?: Record<string, string>;
119
+ setSources?(object: T, sources: Record<string, string>): void;
120
+ }
121
+ /** Runtime shape of a gCTS handler after `createHandler` processing. */
122
+ interface GctsHandler<T extends AdkObject = AdkObject> extends FormatHandler$1 {
123
+ readonly type: AbapObjectType;
124
+ readonly fileExtension: string;
125
+ readonly schema: {
126
+ parse(raw: string): unknown;
127
+ build(data: unknown): string;
128
+ };
129
+ serialize(object: T): Promise<SerializedFile$1[]>;
130
+ fromAbapGit?(values: unknown): {
131
+ name: string;
132
+ } & Record<string, unknown>;
133
+ setSources?(object: T, sources: Record<string, string>): void;
134
+ }
135
+ /** Look up a handler (full-type first, then main-type fallback). */
136
+ declare function getHandler(type: AbapObjectType): GctsHandler | undefined;
137
+ /** `true` iff the given object type has a registered handler. */
138
+ declare function isSupported(type: AbapObjectType): boolean;
139
+ /** Snapshot of all registered object types. */
140
+ declare function getSupportedTypes(): AbapObjectType[];
141
+ /**
142
+ * Register a handler for an ADK class (preferred — `type` is derived from
143
+ * the static `kind`) or an explicit type string (for types without an ADK
144
+ * class, e.g. DOMA/DTEL).
145
+ */
146
+ declare function createHandler<T extends AdkObject, M extends GctsMetadata = GctsMetadata>(adkClass: AdkObjectClass<T>, definition: GctsHandlerDefinition<T, M>): GctsHandler<T>;
147
+ declare function createHandler<T extends AdkObject, M extends GctsMetadata = GctsMetadata>(type: AbapObjectType, definition: GctsHandlerDefinition<T, M>): GctsHandler<T>;
148
+ //#endregion
149
+ //#region src/lib/format/gcts-format.d.ts
150
+ declare const gctsFormatPlugin: FormatPlugin$1;
151
+ //#endregion
152
+ //#region src/lib/gcts-plugin.d.ts
153
+ declare const gctsPlugin: AdtPlugin$1;
154
+ //#endregion
155
+ export { type AdtPlugin, type FormatHandler, type FormatPlugin, type GctsHandler, type GctsHandlerDefinition, type GctsHeader, type GctsMetadata, gctsPlugin as GctsPlugin, gctsPlugin as default, gctsPlugin, type GctsSourceEntry, METADATA_EXTENSION, PACKAGE_FILENAME, type SerializedFile, type WithHeader, adtUriToGctsPath, createHandler, gctsFilename, gctsFormatPlugin, getHandler, getSupportedTypes, isSupported, parseGctsFilename };
156
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/lib/format/types.ts","../src/lib/format/filename.ts","../src/lib/handlers/base.ts","../src/lib/format/gcts-format.ts","../src/lib/gcts-plugin.ts"],"mappings":";;;;;;;;AAcA;;;;;;;;;UAAiB,UAAA;EAUH;EARZ,aAAA;EAgB2B;EAd3B,WAAA;EAgBkB;EAdlB,gBAAA;EAcA;EAZA,mBAAA;EAcC;EAAA,CAZA,GAAA;AAAA;AAgBH;;;;;AAAA,UARiB,YAAA;EASP;EAPR,MAAA,EAAQ,UAAA;EAQE;EAAA,CANT,UAAA;AAAA;;KAIS,UAAA;EACV,MAAA,EAAQ,UAAA;AAAA,IACN,QAAA;;;AAVJ;AAAA,cCCa,kBAAA;;cAGA,gBAAA;;;;;;;ADIb;;iBCMgB,YAAA,CACd,IAAA,UACA,IAAA,UACA,IAAA,0BACA,MAAA;;;;;;;iBAmBc,iBAAA,CACd,QAAA,WACC,oBAAA;;;;AAtCH;;;iBAuGgB,gBAAA,CAAiB,GAAA;;;KCpHrB,cAAA;AAAA,KAEA,cAAA,WAAyB,SAAA,GAAY,SAAA;EAAA,QACvC,IAAA,UAAc,CAAA;EAAA,SACb,IAAA,EAAM,OAAA;AAAA;;;;;AFgBjB;;UEPiB,eAAA;EACf,MAAA;EACA,OAAA,WAAkB,OAAA,2BAAkC,OAAA;AAAA;;;;;;;;ADFtD;UCaiB,qBAAA,WACL,SAAA,YACA,YAAA,GAAe,YAAA;;EAGzB,UAAA,CAAW,MAAA,EAAQ,CAAA,GAAI,CAAA;EDlBM;ECqB7B,SAAA,EAAW,MAAA,EAAQ,CAAA,YAAa,OAAA;EDlBL;ECqB3B,UAAA,EAAY,MAAA,EAAQ,CAAA,GAAI,eAAA;EDrBG;ECwB3B,gBAAA,cAA8B,MAAA,EAAQ,CAAA;EDdxB;;;;;;;ECuBd,YAAA,EAAc,QAAA,EAAU,CAAA;IAAM,IAAA;EAAA,IAAiB,MAAA;EAC/C,iBAAA,GAAoB,MAAA;EACpB,UAAA,EAAY,MAAA,EAAQ,CAAA,EAAG,OAAA,EAAS,MAAA;AAAA;;UAIjB,WAAA,WACL,SAAA,GAAY,SAAA,UACd,eAAA;EAAA,SACC,IAAA,EAAM,cAAA;EAAA,SACN,aAAA;EAAA,SACA,MAAA;IACP,KAAA,CAAM,GAAA;IACN,KAAA,CAAM,IAAA;EAAA;EAER,SAAA,CAAU,MAAA,EAAQ,CAAA,GAAI,OAAA,CAAQ,gBAAA;EAC9B,WAAA,EAAa,MAAA;IAAoB,IAAA;EAAA,IAAiB,MAAA;EAClD,UAAA,EAAY,MAAA,EAAQ,CAAA,EAAG,OAAA,EAAS,MAAA;AAAA;;iBAMlB,UAAA,CAAW,IAAA,EAAM,cAAA,GAAiB,WAAA;;iBAKlC,WAAA,CAAY,IAAA,EAAM,cAAA;;iBAKlB,iBAAA,CAAA,GAAqB,cAAA;;;;;;iBAsBrB,aAAA,WACJ,SAAA,YACA,YAAA,GAAe,YAAA,CAAA,CAEzB,QAAA,EAAU,cAAA,CAAe,CAAA,GACzB,UAAA,EAAY,qBAAA,CAAsB,CAAA,EAAG,CAAA,IACpC,WAAA,CAAY,CAAA;AAAA,iBACC,aAAA,WACJ,SAAA,YACA,YAAA,GAAe,YAAA,CAAA,CAEzB,IAAA,EAAM,cAAA,EACN,UAAA,EAAY,qBAAA,CAAsB,CAAA,EAAG,CAAA,IACpC,WAAA,CAAY,CAAA;;;cCvHF,gBAAA,EAAkB,cAAA;;;cCIlB,UAAA,EAAY,WAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,708 @@
1
+ import { createPlugin, registerFormatPlugin } from "@abapify/adt-plugin";
2
+ import { AdkClass, AdkDataElement, AdkDomain, AdkFunctionGroup, AdkInterface, AdkPackage, AdkProgram, AdkTable, AdkTableType, createAdk, getMainType, getTypeForKind } from "@abapify/adk";
3
+ import { mkdirSync, writeFileSync } from "fs";
4
+ import { dirname, join } from "path";
5
+
6
+ //#region src/lib/format/filename.ts
7
+ /**
8
+ * Extension used for the source-file part of each object type.
9
+ *
10
+ * Order of precedence: CDS types use AFF's `.asddls` / `.asdcls`; everything
11
+ * else uses `.abap`. Metadata is always `.json`.
12
+ */
13
+ const TYPE_TO_SOURCE_EXT = {
14
+ CLAS: "abap",
15
+ INTF: "abap",
16
+ PROG: "abap",
17
+ FUGR: "abap",
18
+ DDLS: "asddls",
19
+ DCLS: "asdcls"
20
+ };
21
+ /** Metadata extension for all AFF/gCTS objects. */
22
+ const METADATA_EXTENSION = "json";
23
+ /** Fixed filename for package metadata (AFF / gCTS convention). */
24
+ const PACKAGE_FILENAME = "package.devc.json";
25
+ /**
26
+ * Build the AFF/gCTS on-disk filename for an object.
27
+ *
28
+ * @param name Object name (case preserved — AFF normalises to lowercase)
29
+ * @param type ABAP object type code (CLAS, INTF, ...)
30
+ * @param kind `"metadata"` (default) or `"source"`.
31
+ * @param suffix Optional sub-include suffix (e.g. `locals_def` for CLAS).
32
+ */
33
+ function gctsFilename(name, type, kind = "metadata", suffix) {
34
+ const base = name.toLowerCase();
35
+ const typeLower = mainType(type).toLowerCase();
36
+ if (kind === "metadata") return `${base}.${typeLower}.${METADATA_EXTENSION}`;
37
+ const ext = TYPE_TO_SOURCE_EXT[mainType(type).toUpperCase()] ?? "abap";
38
+ return suffix ? `${base}.${typeLower}.${suffix}.${ext}` : `${base}.${typeLower}.${ext}`;
39
+ }
40
+ /**
41
+ * Parse an AFF/gCTS filename back into its components.
42
+ *
43
+ * Returns `undefined` if the filename does not look like a known AFF/gCTS
44
+ * artefact — callers should skip unknown files (e.g. `README.md`).
45
+ */
46
+ function parseGctsFilename(filename) {
47
+ if (filename === "package.devc.json") return {
48
+ name: "",
49
+ type: "DEVC",
50
+ extension: METADATA_EXTENSION
51
+ };
52
+ const parts = filename.split(".");
53
+ if (parts.length < 3) return;
54
+ const extension = parts.at(-1);
55
+ const nameParts = (parts.length >= 4 ? parts.at(-2) : void 0) ? parts.slice(0, -3) : parts.slice(0, -2);
56
+ if (nameParts.length === 0) return;
57
+ if (extension === "json") return {
58
+ name: nameParts.length === 0 ? "" : parts.slice(0, -2).join("."),
59
+ type: parts.at(-2).toUpperCase(),
60
+ extension
61
+ };
62
+ if (!new Set([
63
+ "abap",
64
+ "asddls",
65
+ "asdcls"
66
+ ]).has(extension)) return;
67
+ if (parts.length >= 4) return {
68
+ name: parts.slice(0, -3).join("."),
69
+ type: parts.at(-3).toUpperCase(),
70
+ suffix: parts.at(-2),
71
+ extension
72
+ };
73
+ return {
74
+ name: parts.slice(0, -2).join("."),
75
+ type: parts.at(-2).toUpperCase(),
76
+ extension
77
+ };
78
+ }
79
+ /**
80
+ * Translate an ADT object URI (e.g. `/sap/bc/adt/oo/classes/zcl_foo`) to
81
+ * the AFF/gCTS on-disk path (e.g. `zcl_foo/zcl_foo.clas.json`).
82
+ *
83
+ * Matches the `adtUriToAbapGitPath` helper in the abapGit plugin.
84
+ */
85
+ function adtUriToGctsPath(uri) {
86
+ if (!uri.startsWith("/sap/bc/adt/")) return void 0;
87
+ const tail = uri.slice(12);
88
+ if (tail.length === 0) return void 0;
89
+ for (const [pattern, type] of [
90
+ [/^oo\/classes\/([^/]+)$/, "CLAS"],
91
+ [/^oo\/interfaces\/([^/]+)$/, "INTF"],
92
+ [/^programs\/programs\/([^/]+)$/, "PROG"],
93
+ [/^functions\/groups\/([^/]+)$/, "FUGR"],
94
+ [/^packages\/([^/]+)$/, "DEVC"],
95
+ [/^ddic\/domains\/([^/]+)$/, "DOMA"],
96
+ [/^ddic\/dataelements\/([^/]+)$/, "DTEL"],
97
+ [/^ddic\/structures\/([^/]+)$/, "TABL"],
98
+ [/^ddic\/tables\/([^/]+)$/, "TABL"],
99
+ [/^ddic\/tabletypes\/([^/]+)$/, "TTYP"],
100
+ [/^ddic\/ddl\/sources\/([^/]+)$/, "DDLS"],
101
+ [/^acm\/dcls\/sources\/([^/]+)$/, "DCLS"]
102
+ ]) {
103
+ const m = pattern.exec(tail);
104
+ if (m) {
105
+ const name = m[1];
106
+ if (type === "DEVC") return `${name.toLowerCase()}/${PACKAGE_FILENAME}`;
107
+ return `${name.toLowerCase()}/${gctsFilename(name, type)}`;
108
+ }
109
+ }
110
+ }
111
+ function mainType(type) {
112
+ return type.split("/")[0];
113
+ }
114
+
115
+ //#endregion
116
+ //#region src/lib/handlers/base.ts
117
+ const handlerRegistry = /* @__PURE__ */ new Map();
118
+ /** Look up a handler (full-type first, then main-type fallback). */
119
+ function getHandler(type) {
120
+ return handlerRegistry.get(type) ?? handlerRegistry.get(getMainType(type));
121
+ }
122
+ /** `true` iff the given object type has a registered handler. */
123
+ function isSupported(type) {
124
+ return handlerRegistry.has(type) || handlerRegistry.has(getMainType(type));
125
+ }
126
+ /** Snapshot of all registered object types. */
127
+ function getSupportedTypes() {
128
+ return [...handlerRegistry.keys()];
129
+ }
130
+ /**
131
+ * Build a JSON metadata file for the object. JSON is pretty-printed (2-space
132
+ * indent) so the output is diff-friendly and matches AFF's own tooling.
133
+ */
134
+ function buildMetadataFile(meta) {
135
+ return JSON.stringify(meta, null, 2) + "\n";
136
+ }
137
+ function createHandler(adkClassOrType, definition) {
138
+ let type;
139
+ if (typeof adkClassOrType === "string") type = adkClassOrType;
140
+ else {
141
+ const kind = adkClassOrType.kind;
142
+ const derived = getTypeForKind(kind);
143
+ if (!derived) throw new Error(`Unknown ADK kind: ${kind}. Ensure the ADK class has a static 'kind' property.`);
144
+ type = derived;
145
+ }
146
+ const fileExtension = getMainType(type).toLowerCase();
147
+ async function resolveSource(entry) {
148
+ return await (typeof entry.content === "function" ? entry.content() : entry.content);
149
+ }
150
+ const handler = {
151
+ type,
152
+ fileExtension,
153
+ schema: {
154
+ parse: (raw) => JSON.parse(raw),
155
+ build: (data) => JSON.stringify(data, null, 2) + "\n"
156
+ },
157
+ suffixToSourceKey: definition.suffixToSourceKey,
158
+ async serialize(object) {
159
+ const files = [];
160
+ const objectName = (object.name ?? "").toLowerCase();
161
+ if (definition.getSources) for (const entry of definition.getSources(object)) {
162
+ const content = await resolveSource(entry);
163
+ if (!content) continue;
164
+ files.push({
165
+ path: gctsFilename(objectName, type, "source", entry.suffix),
166
+ content
167
+ });
168
+ }
169
+ else if (definition.getSource) {
170
+ const content = await definition.getSource(object);
171
+ if (content) files.push({
172
+ path: gctsFilename(objectName, type, "source"),
173
+ content
174
+ });
175
+ }
176
+ const metadata = definition.toMetadata(object);
177
+ const metadataFile = typeof definition.metadataFileName === "function" ? definition.metadataFileName(object) : definition.metadataFileName ?? gctsFilename(objectName, type, "metadata");
178
+ files.push({
179
+ path: metadataFile,
180
+ content: buildMetadataFile(metadata)
181
+ });
182
+ return files;
183
+ },
184
+ fromAbapGit: definition.fromMetadata ? (values) => definition.fromMetadata(values) : void 0,
185
+ setSources: definition.setSources
186
+ };
187
+ handlerRegistry.set(type, handler);
188
+ return handler;
189
+ }
190
+
191
+ //#endregion
192
+ //#region src/lib/handlers/objects/clas.ts
193
+ /**
194
+ * CLAS handler for gCTS / AFF format.
195
+ *
196
+ * Projects ADK class data to the AFF class-metadata shape:
197
+ *
198
+ * {
199
+ * header: { formatVersion, description, originalLanguage, ... },
200
+ * class: { category, visibility, final, abstract, ... }
201
+ * }
202
+ *
203
+ * Sources are emitted per include (main, definitions, implementations, ...).
204
+ * Abapgit suffix convention is reused for consistency — AFF does not
205
+ * standardise include filenames, but using the same suffixes as abapGit
206
+ * means downstream tooling (diff, round-trip) can treat both formats with
207
+ * the same suffix map.
208
+ */
209
+ const SUFFIX = {
210
+ main: void 0,
211
+ definitions: "locals_def",
212
+ implementations: "locals_imp",
213
+ localtypes: "locals_types",
214
+ macros: "macros",
215
+ testclasses: "testclasses"
216
+ };
217
+ const SUFFIX_TO_SOURCE_KEY = Object.fromEntries(Object.entries(SUFFIX).filter(([, v]) => v !== void 0).map(([k, v]) => [v, k]));
218
+ const classHandler = createHandler(AdkClass, {
219
+ suffixToSourceKey: SUFFIX_TO_SOURCE_KEY,
220
+ toMetadata(cls) {
221
+ const data = cls.dataSync;
222
+ return {
223
+ header: {
224
+ formatVersion: "1.0",
225
+ description: cls.description ?? data.description ?? "",
226
+ originalLanguage: data.language ?? data.masterLanguage,
227
+ abapLanguageVersion: data.abapLanguageVersion
228
+ },
229
+ class: {
230
+ category: data.category,
231
+ visibility: data.visibility ?? "public",
232
+ final: data.final === true,
233
+ abstract: data.abstract === true,
234
+ fixedPointArithmetic: data.fixPointArithmetic === true,
235
+ unicodeChecksActive: data.activeUnicodeCheck !== false,
236
+ sharedMemoryEnabled: data.sharedMemoryEnabled === true,
237
+ superClass: data.superClassRef?.name
238
+ }
239
+ };
240
+ },
241
+ getSources: (cls) => {
242
+ return (cls.dataSync.include ?? []).map((inc) => ({
243
+ suffix: SUFFIX[String(inc.includeType ?? "main")],
244
+ content: () => cls.getIncludeSource(String(inc.includeType ?? "main"))
245
+ }));
246
+ },
247
+ fromMetadata: (meta) => ({
248
+ name: (meta?.class?.name ?? "").toUpperCase(),
249
+ type: "CLAS/OC",
250
+ description: meta?.header?.description,
251
+ language: meta?.header?.originalLanguage,
252
+ masterLanguage: meta?.header?.originalLanguage,
253
+ category: meta?.class?.category,
254
+ visibility: meta?.class?.visibility,
255
+ final: meta?.class?.final === true,
256
+ abstract: meta?.class?.abstract === true,
257
+ abapLanguageVersion: meta?.header?.abapLanguageVersion
258
+ }),
259
+ setSources: (cls, sources) => {
260
+ cls._pendingSources = sources;
261
+ if (sources.main) cls._pendingSource = sources.main;
262
+ }
263
+ });
264
+
265
+ //#endregion
266
+ //#region src/lib/handlers/objects/intf.ts
267
+ /**
268
+ * INTF handler for gCTS / AFF format.
269
+ */
270
+ const interfaceHandler = createHandler(AdkInterface, {
271
+ toMetadata(intf) {
272
+ const data = intf.dataSync;
273
+ return {
274
+ header: {
275
+ formatVersion: "1.0",
276
+ description: intf.description ?? data.description ?? "",
277
+ originalLanguage: data.language ?? data.masterLanguage,
278
+ abapLanguageVersion: data.abapLanguageVersion
279
+ },
280
+ interface: { unicodeChecksActive: data.activeUnicodeCheck !== false }
281
+ };
282
+ },
283
+ getSource: (obj) => obj.getSource(),
284
+ fromMetadata: (meta) => ({
285
+ name: (meta?.interface?.name ?? "").toUpperCase(),
286
+ type: "INTF/OI",
287
+ description: meta?.header?.description,
288
+ language: meta?.header?.originalLanguage,
289
+ masterLanguage: meta?.header?.originalLanguage,
290
+ abapLanguageVersion: meta?.header?.abapLanguageVersion
291
+ }),
292
+ setSources: (intf, sources) => {
293
+ if (sources.main) intf._pendingSource = sources.main;
294
+ }
295
+ });
296
+
297
+ //#endregion
298
+ //#region src/lib/handlers/objects/prog.ts
299
+ /**
300
+ * PROG handler for gCTS / AFF format.
301
+ */
302
+ const programHandler = createHandler(AdkProgram, {
303
+ toMetadata(prog) {
304
+ const data = prog.dataSync;
305
+ return {
306
+ header: {
307
+ formatVersion: "1.0",
308
+ description: prog.description ?? data.description ?? "",
309
+ originalLanguage: data.language ?? data.masterLanguage,
310
+ abapLanguageVersion: data.abapLanguageVersion
311
+ },
312
+ program: {
313
+ programType: data.programType ?? "executableProgram",
314
+ fixedPointArithmetic: data.fixPointArithmetic === true,
315
+ unicodeChecksActive: data.activeUnicodeCheck !== false
316
+ }
317
+ };
318
+ },
319
+ getSource: (obj) => obj.getSource(),
320
+ fromMetadata: (meta) => ({
321
+ name: (meta?.program?.name ?? "").toUpperCase(),
322
+ type: "PROG/P",
323
+ description: meta?.header?.description,
324
+ language: meta?.header?.originalLanguage,
325
+ programType: meta?.program?.programType
326
+ }),
327
+ setSources: (prog, sources) => {
328
+ if (sources.main) prog._pendingSource = sources.main;
329
+ }
330
+ });
331
+
332
+ //#endregion
333
+ //#region src/lib/handlers/objects/devc.ts
334
+ /**
335
+ * DEVC (package) handler for gCTS / AFF format.
336
+ *
337
+ * Packages use a fixed filename (`package.devc.json`) — same convention as
338
+ * abapGit's `package.devc.xml`.
339
+ */
340
+ const packageHandler = createHandler(AdkPackage, {
341
+ metadataFileName: PACKAGE_FILENAME,
342
+ toMetadata(pkg) {
343
+ return {
344
+ header: {
345
+ formatVersion: "1.0",
346
+ description: pkg.description ?? "",
347
+ originalLanguage: pkg.dataSync?.language ?? pkg.dataSync?.masterLanguage
348
+ },
349
+ package: {
350
+ softwareComponent: pkg.dataSync?.transport?.softwareComponent?.name,
351
+ applicationComponent: pkg.dataSync?.applicationComponent?.name,
352
+ packageType: pkg.dataSync?.attributes?.packageType
353
+ }
354
+ };
355
+ },
356
+ fromMetadata: (meta) => ({
357
+ name: "",
358
+ description: meta?.header?.description
359
+ })
360
+ });
361
+
362
+ //#endregion
363
+ //#region src/lib/handlers/objects/doma.ts
364
+ /**
365
+ * DOMA (domain) handler for gCTS / AFF format.
366
+ */
367
+ const domainHandler = createHandler(AdkDomain, {
368
+ toMetadata(doma) {
369
+ const data = doma.dataSync;
370
+ return {
371
+ header: {
372
+ formatVersion: "1.0",
373
+ description: doma.description ?? "",
374
+ originalLanguage: data.language ?? data.masterLanguage
375
+ },
376
+ domain: {
377
+ dataType: data.dataType,
378
+ length: data.length,
379
+ decimals: data.decimals,
380
+ outputLength: data.outputLength,
381
+ caseSensitive: data.caseSensitive === true,
382
+ valueTable: data.valueTableRef?.name
383
+ }
384
+ };
385
+ },
386
+ fromMetadata: (meta) => ({
387
+ name: (meta?.domain?.name ?? "").toUpperCase(),
388
+ description: meta?.header?.description,
389
+ dataType: meta?.domain?.dataType,
390
+ length: meta?.domain?.length,
391
+ decimals: meta?.domain?.decimals
392
+ })
393
+ });
394
+
395
+ //#endregion
396
+ //#region src/lib/handlers/objects/dtel.ts
397
+ /**
398
+ * DTEL (data element) handler for gCTS / AFF format.
399
+ */
400
+ const dataElementHandler = createHandler(AdkDataElement, {
401
+ toMetadata(dtel) {
402
+ const data = dtel.dataSync;
403
+ return {
404
+ header: {
405
+ formatVersion: "1.0",
406
+ description: dtel.description ?? "",
407
+ originalLanguage: data.language ?? data.masterLanguage
408
+ },
409
+ dataElement: {
410
+ typeKind: data.typeKind,
411
+ dataType: data.dataType,
412
+ length: data.length,
413
+ decimals: data.decimals,
414
+ domain: data.domainRef?.name,
415
+ predefinedType: data.predefinedType
416
+ }
417
+ };
418
+ },
419
+ fromMetadata: (meta) => ({
420
+ name: (meta?.dataElement?.name ?? "").toUpperCase(),
421
+ description: meta?.header?.description,
422
+ dataType: meta?.dataElement?.dataType
423
+ })
424
+ });
425
+
426
+ //#endregion
427
+ //#region src/lib/handlers/objects/tabl.ts
428
+ /**
429
+ * TABL (table / structure) handler for gCTS / AFF format.
430
+ */
431
+ const tableHandler = createHandler(AdkTable, {
432
+ toMetadata(tabl) {
433
+ const data = tabl.dataSync;
434
+ return {
435
+ header: {
436
+ formatVersion: "1.0",
437
+ description: tabl.description ?? "",
438
+ originalLanguage: data.language ?? data.masterLanguage
439
+ },
440
+ table: {
441
+ tableCategory: data.tableCategory,
442
+ deliveryClass: data.deliveryClass,
443
+ dataMaintenance: data.dataMaintenance,
444
+ fields: data.fields
445
+ }
446
+ };
447
+ },
448
+ fromMetadata: (meta) => ({
449
+ name: (meta?.table?.name ?? "").toUpperCase(),
450
+ description: meta?.header?.description
451
+ })
452
+ });
453
+
454
+ //#endregion
455
+ //#region src/lib/handlers/objects/ttyp.ts
456
+ /**
457
+ * TTYP (table type) handler for gCTS / AFF format.
458
+ */
459
+ const tableTypeHandler = createHandler(AdkTableType, {
460
+ toMetadata(ttyp) {
461
+ const data = ttyp.dataSync;
462
+ return {
463
+ header: {
464
+ formatVersion: "1.0",
465
+ description: ttyp.description ?? "",
466
+ originalLanguage: data.language ?? data.masterLanguage
467
+ },
468
+ tableType: {
469
+ accessMode: data.accessMode,
470
+ rowType: data.rowTypeRef?.name,
471
+ primaryKey: data.primaryKey,
472
+ secondaryKeys: data.secondaryKeys
473
+ }
474
+ };
475
+ },
476
+ fromMetadata: (meta) => ({
477
+ name: (meta?.tableType?.name ?? "").toUpperCase(),
478
+ description: meta?.header?.description
479
+ })
480
+ });
481
+
482
+ //#endregion
483
+ //#region src/lib/handlers/objects/fugr.ts
484
+ /**
485
+ * FUGR (function group) handler for gCTS / AFF format.
486
+ *
487
+ * AFF's FUGR representation nests function modules under the group
488
+ * directory. This plugin emits the group metadata only — per-module files
489
+ * are produced by individual FUNC handlers once ADK exposes them.
490
+ */
491
+ const functionGroupHandler = createHandler(AdkFunctionGroup, {
492
+ toMetadata(fugr) {
493
+ const data = fugr.dataSync;
494
+ return {
495
+ header: {
496
+ formatVersion: "1.0",
497
+ description: fugr.description ?? "",
498
+ originalLanguage: data.language ?? data.masterLanguage
499
+ },
500
+ functionGroup: {
501
+ fixedPointArithmetic: data.fixPointArithmetic === true,
502
+ unicodeChecksActive: data.activeUnicodeCheck !== false
503
+ }
504
+ };
505
+ },
506
+ fromMetadata: (meta) => ({
507
+ name: (meta?.functionGroup?.name ?? "").toUpperCase(),
508
+ description: meta?.header?.description
509
+ })
510
+ });
511
+
512
+ //#endregion
513
+ //#region src/lib/format/gcts-format.ts
514
+ const gctsFormatPlugin = {
515
+ id: "gcts",
516
+ description: "gCTS / AFF (abap-file-formats) serialization format (JSON metadata + .abap/.acds sources)",
517
+ get supportedTypes() {
518
+ return getSupportedTypes();
519
+ },
520
+ getHandler(type) {
521
+ return getHandler(type);
522
+ },
523
+ parseFilename(filename) {
524
+ return parseGctsFilename(filename);
525
+ }
526
+ };
527
+
528
+ //#endregion
529
+ //#region src/lib/deserializer.ts
530
+ /** Source-file extensions emitted by gCTS handlers. */
531
+ const SOURCE_EXTENSIONS = new Set([
532
+ "abap",
533
+ "asddls",
534
+ "asdcls"
535
+ ]);
536
+ /**
537
+ * Map numeric abapLanguageVersion codes (`'5'` etc.) to the descriptive
538
+ * string the ADT REST API expects (`'cloudDevelopment'`). Mirrors the
539
+ * helper in `adt-plugin-abapgit` — kept local so this package does not
540
+ * depend on its sibling.
541
+ */
542
+ const ABAP_LANG_VER_TO_ADT = {
543
+ "2": "keyUser",
544
+ "5": "cloudDevelopment"
545
+ };
546
+ function abapLangVerToAdt(code) {
547
+ if (!code) return void 0;
548
+ return ABAP_LANG_VER_TO_ADT[code] ?? code;
549
+ }
550
+ /**
551
+ * Deserialise a gCTS/AFF file tree into `AdkObject` instances.
552
+ *
553
+ * @param fileTree Virtual FS abstraction (checkin supplies a real-fs impl).
554
+ * @param client `AdtClient` — required by `createAdk` to build ADK objects.
555
+ * @param options Export options. `rootPackage` is assigned as packageRef
556
+ * to every discovered object that lacks one, mirroring the
557
+ * abapGit behaviour when `.abapgit.xml` is absent.
558
+ */
559
+ async function* deserialize(fileTree, client, options) {
560
+ const adk = createAdk(client);
561
+ const jsonFiles = await fileTree.glob("**/*.json");
562
+ const supportedTypes = new Set(getSupportedTypes().map((t) => t.toLowerCase()));
563
+ const objectMap = /* @__PURE__ */ new Map();
564
+ for (const jsonPath of jsonFiles) {
565
+ const filename = jsonPath.split("/").pop();
566
+ if (filename === "package.devc.json") continue;
567
+ const parsed = parseGctsFilename(filename);
568
+ if (!parsed) continue;
569
+ if (parsed.extension !== "json") continue;
570
+ if (!supportedTypes.has(parsed.type.toLowerCase())) continue;
571
+ const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
572
+ if (!objectMap.has(key)) objectMap.set(key, {
573
+ name: parsed.name.toUpperCase(),
574
+ type: parsed.type.toUpperCase(),
575
+ sourceFiles: []
576
+ });
577
+ objectMap.get(key).metadataFile = jsonPath;
578
+ }
579
+ for (const ext of SOURCE_EXTENSIONS) {
580
+ const paths = await fileTree.glob(`**/*.${ext}`);
581
+ for (const path of paths) {
582
+ const parsed = parseGctsFilename(path.split("/").pop());
583
+ if (!parsed) continue;
584
+ const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;
585
+ const obj = objectMap.get(key);
586
+ if (!obj) continue;
587
+ obj.sourceFiles.push({
588
+ path,
589
+ suffix: parsed.suffix
590
+ });
591
+ }
592
+ }
593
+ for (const [, objFiles] of objectMap) {
594
+ if (!objFiles.metadataFile) continue;
595
+ const handler = getHandler(objFiles.type);
596
+ if (!handler) continue;
597
+ try {
598
+ const raw = await fileTree.read(objFiles.metadataFile);
599
+ const metadata = handler.schema.parse(raw);
600
+ const sources = {};
601
+ for (const { path, suffix } of objFiles.sourceFiles) {
602
+ const content = await fileTree.read(path);
603
+ const sourceKey = suffix ? handler.suffixToSourceKey?.[suffix] ?? suffix : "main";
604
+ sources[sourceKey] = content;
605
+ }
606
+ const payload = handler.fromAbapGit ? handler.fromAbapGit(metadata) : { name: objFiles.name };
607
+ const objectName = payload.name || objFiles.name;
608
+ const fullData = {
609
+ ...payload,
610
+ name: objectName
611
+ };
612
+ const adkType = typeof payload.type === "string" ? payload.type : objFiles.type;
613
+ const adkObject = adk.getWithData(fullData, adkType);
614
+ if (Object.keys(sources).length > 0) {
615
+ if (handler.setSources) handler.setSources(adkObject, sources);
616
+ else if (sources.main) adkObject._pendingSource = sources.main;
617
+ }
618
+ if (payload.description) adkObject._pendingDescription = payload.description;
619
+ adkObject._relDir = objFiles.metadataFile.split("/").slice(0, -1).join("/");
620
+ if (options?.rootPackage) {
621
+ const data = adkObject._data;
622
+ if (data && !data.packageRef) data.packageRef = { name: options.rootPackage };
623
+ }
624
+ if (options?.abapLanguageVersion) {
625
+ const data = adkObject._data;
626
+ if (data && !data.abapLanguageVersion) data.abapLanguageVersion = abapLangVerToAdt(options.abapLanguageVersion) ?? options.abapLanguageVersion;
627
+ }
628
+ yield adkObject;
629
+ } catch (error) {
630
+ console.error(`Failed to deserialize ${objFiles.type} ${objFiles.name}:`, error);
631
+ }
632
+ }
633
+ }
634
+
635
+ //#endregion
636
+ //#region src/lib/gcts-plugin.ts
637
+ /**
638
+ * gCTS AdtPlugin.
639
+ *
640
+ * The `FormatPlugin` in `format/gcts-format.ts` provides the declarative
641
+ * contract (used by registry consumers); this `AdtPlugin` provides the
642
+ * behaviour expected by `adt-cli`'s higher-level import/export services.
643
+ *
644
+ * SAP → disk ("import") serialises ADK objects to AFF JSON + source files.
645
+ * Disk → SAP ("export" in adt-cli terminology — Git → SAP direction) is
646
+ * delegated to `./deserializer.ts`, which yields AdkObjects for the
647
+ * `CheckinService` apply pipeline (E08). Together they close the
648
+ * round-trip that the E06 v0.1 follow-ups called out.
649
+ */
650
+ const gctsPlugin = createPlugin({
651
+ name: "gcts",
652
+ version: "0.1.0",
653
+ description: "gCTS / AFF format plugin — JSON metadata + .abap/.acds sources",
654
+ registry: {
655
+ isSupported,
656
+ getSupportedTypes
657
+ },
658
+ format: {
659
+ async import(object, targetPath, context) {
660
+ try {
661
+ const objPackage = object.type?.startsWith("DEVC") ? object.name : object.package || object.name || "ROOT";
662
+ const packageDir = (await context.resolvePackagePath(objPackage)).map((p) => p.toLowerCase()).join("/");
663
+ const handler = getHandler(object.type);
664
+ if (!handler) return {
665
+ success: false,
666
+ filesCreated: [],
667
+ errors: [`No gCTS handler registered for object type: ${object.type}`]
668
+ };
669
+ const files = await handler.serialize(object);
670
+ const baseDir = join(targetPath, "src", packageDir);
671
+ mkdirSync(baseDir, { recursive: true });
672
+ const written = [];
673
+ for (const f of files) {
674
+ const full = join(baseDir, f.path);
675
+ mkdirSync(dirname(full), { recursive: true });
676
+ writeFileSync(full, f.content, f.encoding ?? "utf8");
677
+ written.push(full);
678
+ }
679
+ return {
680
+ success: true,
681
+ filesCreated: written
682
+ };
683
+ } catch (error) {
684
+ return {
685
+ success: false,
686
+ filesCreated: [],
687
+ errors: [error instanceof Error ? error.message : String(error)]
688
+ };
689
+ }
690
+ },
691
+ export: (fileTree, client, options) => deserialize(fileTree, client, options)
692
+ }
693
+ });
694
+
695
+ //#endregion
696
+ //#region src/index.ts
697
+ /**
698
+ * @abapify/adt-plugin-gcts — gCTS / AFF format plugin entry point.
699
+ *
700
+ * Importing this module self-registers the plugin into the global
701
+ * `FormatPlugin` registry so that `--format gcts` becomes available
702
+ * throughout the `adt` CLI.
703
+ */
704
+ registerFormatPlugin(gctsFormatPlugin);
705
+
706
+ //#endregion
707
+ export { gctsPlugin as GctsPlugin, gctsPlugin as default, gctsPlugin, METADATA_EXTENSION, PACKAGE_FILENAME, adtUriToGctsPath, createHandler, gctsFilename, gctsFormatPlugin, getHandler, getSupportedTypes, isSupported, parseGctsFilename };
708
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/lib/format/filename.ts","../src/lib/handlers/base.ts","../src/lib/handlers/objects/clas.ts","../src/lib/handlers/objects/intf.ts","../src/lib/handlers/objects/prog.ts","../src/lib/handlers/objects/devc.ts","../src/lib/handlers/objects/doma.ts","../src/lib/handlers/objects/dtel.ts","../src/lib/handlers/objects/tabl.ts","../src/lib/handlers/objects/ttyp.ts","../src/lib/handlers/objects/fugr.ts","../src/lib/format/gcts-format.ts","../src/lib/deserializer.ts","../src/lib/gcts-plugin.ts","../src/index.ts"],"sourcesContent":["/**\n * gCTS / AFF filename conventions.\n *\n * gCTS and AFF both use the pattern `<name>.<type>.<ext>` (same as abapGit),\n * but with JSON for metadata instead of XML and with CDS-specific\n * extensions (`.acds`, `.asddls`, ...) for CDS sources.\n *\n * Packages use a fixed `package.devc.json` filename (mirrors abapGit's\n * `package.devc.xml`).\n *\n * This module is independent of any particular handler — it exists so that\n * consumers (diff, round-trip tests, deserializers) can map filenames to\n * (name, type) pairs without pulling in the object-type registry.\n */\n\nimport type { ParsedFormatFilename } from '@abapify/adt-plugin';\n\n/**\n * Extension used for the source-file part of each object type.\n *\n * Order of precedence: CDS types use AFF's `.asddls` / `.asdcls`; everything\n * else uses `.abap`. Metadata is always `.json`.\n */\nconst TYPE_TO_SOURCE_EXT: Record<string, string> = {\n CLAS: 'abap',\n INTF: 'abap',\n PROG: 'abap',\n FUGR: 'abap',\n DDLS: 'asddls',\n DCLS: 'asdcls',\n};\n\n/** Metadata extension for all AFF/gCTS objects. */\nexport const METADATA_EXTENSION = 'json';\n\n/** Fixed filename for package metadata (AFF / gCTS convention). */\nexport const PACKAGE_FILENAME = 'package.devc.json';\n\n/**\n * Build the AFF/gCTS on-disk filename for an object.\n *\n * @param name Object name (case preserved — AFF normalises to lowercase)\n * @param type ABAP object type code (CLAS, INTF, ...)\n * @param kind `\"metadata\"` (default) or `\"source\"`.\n * @param suffix Optional sub-include suffix (e.g. `locals_def` for CLAS).\n */\nexport function gctsFilename(\n name: string,\n type: string,\n kind: 'metadata' | 'source' = 'metadata',\n suffix?: string,\n): string {\n const base = name.toLowerCase();\n const typeLower = mainType(type).toLowerCase();\n if (kind === 'metadata') {\n return `${base}.${typeLower}.${METADATA_EXTENSION}`;\n }\n const ext = TYPE_TO_SOURCE_EXT[mainType(type).toUpperCase()] ?? 'abap';\n return suffix\n ? `${base}.${typeLower}.${suffix}.${ext}`\n : `${base}.${typeLower}.${ext}`;\n}\n\n/**\n * Parse an AFF/gCTS filename back into its components.\n *\n * Returns `undefined` if the filename does not look like a known AFF/gCTS\n * artefact — callers should skip unknown files (e.g. `README.md`).\n */\nexport function parseGctsFilename(\n filename: string,\n): ParsedFormatFilename | undefined {\n // Fixed package filename.\n if (filename === PACKAGE_FILENAME) {\n return {\n name: '',\n type: 'DEVC',\n extension: METADATA_EXTENSION,\n };\n }\n\n const parts = filename.split('.');\n if (parts.length < 3) {\n return undefined;\n }\n\n const extension = parts.at(-1)!;\n const maybeSuffix = parts.length >= 4 ? parts.at(-2) : undefined;\n const nameParts = maybeSuffix ? parts.slice(0, -3) : parts.slice(0, -2);\n\n if (nameParts.length === 0) {\n return undefined;\n }\n\n // For 3-part filenames (name.type.ext) the \"maybeSuffix\" branch would\n // misclassify a 4-part filename vs a 3-part filename. Use a recognised\n // source extension to decide: if ext is 'json' there can't be a suffix.\n if (extension === METADATA_EXTENSION) {\n return {\n name: nameParts.length === 0 ? '' : parts.slice(0, -2).join('.'),\n type: parts.at(-2)!.toUpperCase(),\n extension,\n };\n }\n\n // Source file — suffix is optional.\n const knownSourceExts = new Set(['abap', 'asddls', 'asdcls']);\n if (!knownSourceExts.has(extension)) {\n return undefined;\n }\n\n // Detect suffix: the part before the extension is a suffix only if the part\n // before THAT is a valid-looking lowercase type code. Use a narrow heuristic:\n // suffix present iff parts.length >= 4.\n if (parts.length >= 4) {\n return {\n name: parts.slice(0, -3).join('.'),\n type: parts.at(-3)!.toUpperCase(),\n suffix: parts.at(-2),\n extension,\n };\n }\n\n return {\n name: parts.slice(0, -2).join('.'),\n type: parts.at(-2)!.toUpperCase(),\n extension,\n };\n}\n\n/**\n * Translate an ADT object URI (e.g. `/sap/bc/adt/oo/classes/zcl_foo`) to\n * the AFF/gCTS on-disk path (e.g. `zcl_foo/zcl_foo.clas.json`).\n *\n * Matches the `adtUriToAbapGitPath` helper in the abapGit plugin.\n */\nexport function adtUriToGctsPath(uri: string): string | undefined {\n const ADT_PREFIX = '/sap/bc/adt/';\n if (!uri.startsWith(ADT_PREFIX)) return undefined;\n const tail = uri.slice(ADT_PREFIX.length);\n if (tail.length === 0) return undefined;\n\n // Common ADT URI → (type, name) table. Mirrors abapGit's mapping.\n const TABLE: Array<[RegExp, string]> = [\n [/^oo\\/classes\\/([^/]+)$/, 'CLAS'],\n [/^oo\\/interfaces\\/([^/]+)$/, 'INTF'],\n [/^programs\\/programs\\/([^/]+)$/, 'PROG'],\n [/^functions\\/groups\\/([^/]+)$/, 'FUGR'],\n [/^packages\\/([^/]+)$/, 'DEVC'],\n [/^ddic\\/domains\\/([^/]+)$/, 'DOMA'],\n [/^ddic\\/dataelements\\/([^/]+)$/, 'DTEL'],\n [/^ddic\\/structures\\/([^/]+)$/, 'TABL'],\n [/^ddic\\/tables\\/([^/]+)$/, 'TABL'],\n [/^ddic\\/tabletypes\\/([^/]+)$/, 'TTYP'],\n [/^ddic\\/ddl\\/sources\\/([^/]+)$/, 'DDLS'],\n [/^acm\\/dcls\\/sources\\/([^/]+)$/, 'DCLS'],\n ];\n\n for (const [pattern, type] of TABLE) {\n const m = pattern.exec(tail);\n if (m) {\n const name = m[1];\n if (type === 'DEVC') return `${name.toLowerCase()}/${PACKAGE_FILENAME}`;\n return `${name.toLowerCase()}/${gctsFilename(name, type)}`;\n }\n }\n\n return undefined;\n}\n\nfunction mainType(type: string): string {\n return type.split('/')[0];\n}\n","/**\n * gCTS / AFF handler factory.\n *\n * Mirrors the abapGit `createHandler` factory but produces **JSON** metadata\n * (AFF / gCTS convention) instead of abapGit's `.xml` files. Handlers are\n * kept intentionally small — business logic lives in `@abapify/adk` and the\n * only job of a gCTS handler is to project ADK data to the on-disk shape.\n *\n * Self-registration: `createHandler` stores the handler in the module-local\n * registry so `getHandler(type)` can resolve it. The `FormatPlugin` wrapper\n * (`format/gcts-format.ts`) exposes the registry through the public\n * `@abapify/adt-plugin` contract.\n */\n\nimport type { AdkObject, AdkKind } from '@abapify/adk';\nimport { getTypeForKind, getMainType } from '@abapify/adk';\nimport type { FormatHandler, SerializedFile } from '@abapify/adt-plugin';\nimport { gctsFilename } from '../format/filename';\nimport type { GctsMetadata } from '../format/types';\n\nexport type AbapObjectType = string;\n\nexport type AdkObjectClass<T extends AdkObject = AdkObject> = {\n new (...args: any[]): T;\n readonly kind: AdkKind;\n};\n\n/**\n * Lazy source entry.\n *\n * `content` may be a string, a promise, or a thunk returning either — the\n * factory awaits whichever form the handler returns.\n */\nexport interface GctsSourceEntry {\n suffix?: string;\n content: string | Promise<string> | (() => string | Promise<string>);\n}\n\n/**\n * Handler definition for a single ABAP object type.\n *\n * The shape intentionally mirrors the abapGit `HandlerDefinition` so that\n * anyone familiar with the sister plugin can move between them with minimal\n * friction. The `toMetadata` function is the only required hook: it maps an\n * ADK object to the JSON metadata shape for the target type.\n */\nexport interface GctsHandlerDefinition<\n T extends AdkObject,\n M extends GctsMetadata = GctsMetadata,\n> {\n /** Map ADK object → JSON metadata payload (including the required `header`). */\n toMetadata(object: T): M;\n\n /** Optional: single primary source file. */\n getSource?(object: T): string | Promise<string>;\n\n /** Optional: multiple source files (e.g. CLAS includes). */\n getSources?(object: T): GctsSourceEntry[];\n\n /** Optional: custom metadata filename (e.g. `package.devc.json` for DEVC). */\n metadataFileName?: string | ((object: T) => string);\n\n /**\n * Optional: inverse mapping used during deserialization.\n *\n * `fromMetadata` receives the parsed JSON payload and returns a partial\n * ADK-data projection. `setSources` mirrors abapGit's behaviour: it stages\n * source content on the ADK object for later deploy.\n */\n fromMetadata?(metadata: M): { name: string } & Record<string, unknown>;\n suffixToSourceKey?: Record<string, string>;\n setSources?(object: T, sources: Record<string, string>): void;\n}\n\n/** Runtime shape of a gCTS handler after `createHandler` processing. */\nexport interface GctsHandler<\n T extends AdkObject = AdkObject,\n> extends FormatHandler {\n readonly type: AbapObjectType;\n readonly fileExtension: string;\n readonly schema: {\n parse(raw: string): unknown;\n build(data: unknown): string;\n };\n serialize(object: T): Promise<SerializedFile[]>;\n fromAbapGit?(values: unknown): { name: string } & Record<string, unknown>;\n setSources?(object: T, sources: Record<string, string>): void;\n}\n\nconst handlerRegistry = new Map<AbapObjectType, GctsHandler>();\n\n/** Look up a handler (full-type first, then main-type fallback). */\nexport function getHandler(type: AbapObjectType): GctsHandler | undefined {\n return handlerRegistry.get(type) ?? handlerRegistry.get(getMainType(type));\n}\n\n/** `true` iff the given object type has a registered handler. */\nexport function isSupported(type: AbapObjectType): boolean {\n return handlerRegistry.has(type) || handlerRegistry.has(getMainType(type));\n}\n\n/** Snapshot of all registered object types. */\nexport function getSupportedTypes(): AbapObjectType[] {\n return [...handlerRegistry.keys()];\n}\n\n/** Internal — test helper. */\nexport function __resetRegistry(): void {\n handlerRegistry.clear();\n}\n\n/**\n * Build a JSON metadata file for the object. JSON is pretty-printed (2-space\n * indent) so the output is diff-friendly and matches AFF's own tooling.\n */\nfunction buildMetadataFile(meta: GctsMetadata): string {\n return JSON.stringify(meta, null, 2) + '\\n';\n}\n\n/**\n * Register a handler for an ADK class (preferred — `type` is derived from\n * the static `kind`) or an explicit type string (for types without an ADK\n * class, e.g. DOMA/DTEL).\n */\nexport function createHandler<\n T extends AdkObject,\n M extends GctsMetadata = GctsMetadata,\n>(\n adkClass: AdkObjectClass<T>,\n definition: GctsHandlerDefinition<T, M>,\n): GctsHandler<T>;\nexport function createHandler<\n T extends AdkObject,\n M extends GctsMetadata = GctsMetadata,\n>(\n type: AbapObjectType,\n definition: GctsHandlerDefinition<T, M>,\n): GctsHandler<T>;\nexport function createHandler<\n T extends AdkObject,\n M extends GctsMetadata = GctsMetadata,\n>(\n adkClassOrType: AdkObjectClass<T> | AbapObjectType,\n definition: GctsHandlerDefinition<T, M>,\n): GctsHandler<T> {\n let type: AbapObjectType;\n if (typeof adkClassOrType === 'string') {\n type = adkClassOrType;\n } else {\n const kind = adkClassOrType.kind;\n const derived = getTypeForKind(kind);\n if (!derived) {\n throw new Error(\n `Unknown ADK kind: ${kind}. Ensure the ADK class has a static 'kind' property.`,\n );\n }\n type = derived;\n }\n\n const fileExtension = getMainType(type).toLowerCase();\n\n async function resolveSource(entry: GctsSourceEntry): Promise<string> {\n const raw =\n typeof entry.content === 'function' ? entry.content() : entry.content;\n return await raw;\n }\n\n const handler: GctsHandler<T> = {\n type,\n fileExtension,\n // Minimal JSON \"schema\" — matches the FormatHandlerSchema contract.\n schema: {\n parse: (raw: string) => JSON.parse(raw) as unknown,\n build: (data: unknown) => JSON.stringify(data, null, 2) + '\\n',\n },\n suffixToSourceKey: definition.suffixToSourceKey,\n async serialize(object: T): Promise<SerializedFile[]> {\n const files: SerializedFile[] = [];\n const objectName = (object.name ?? '').toLowerCase();\n\n // Source files.\n if (definition.getSources) {\n for (const entry of definition.getSources(object)) {\n const content = await resolveSource(entry);\n if (!content) continue;\n files.push({\n path: gctsFilename(objectName, type, 'source', entry.suffix),\n content,\n });\n }\n } else if (definition.getSource) {\n const content = await definition.getSource(object);\n if (content) {\n files.push({\n path: gctsFilename(objectName, type, 'source'),\n content,\n });\n }\n }\n\n // Metadata file.\n const metadata = definition.toMetadata(object);\n const metadataFile =\n typeof definition.metadataFileName === 'function'\n ? definition.metadataFileName(object)\n : (definition.metadataFileName ??\n gctsFilename(objectName, type, 'metadata'));\n files.push({\n path: metadataFile,\n content: buildMetadataFile(metadata),\n });\n\n return files;\n },\n fromAbapGit: definition.fromMetadata\n ? (values: unknown) =>\n definition.fromMetadata!(values as M) as { name: string } & Record<\n string,\n unknown\n >\n : undefined,\n setSources: definition.setSources,\n };\n\n handlerRegistry.set(type, handler as GctsHandler);\n return handler;\n}\n\n/** Convenience re-export — matches abapGit's `package.devc.xml` pattern. */\nexport { PACKAGE_FILENAME } from '../format/filename';\n","/**\n * CLAS handler for gCTS / AFF format.\n *\n * Projects ADK class data to the AFF class-metadata shape:\n *\n * {\n * header: { formatVersion, description, originalLanguage, ... },\n * class: { category, visibility, final, abstract, ... }\n * }\n *\n * Sources are emitted per include (main, definitions, implementations, ...).\n * Abapgit suffix convention is reused for consistency — AFF does not\n * standardise include filenames, but using the same suffixes as abapGit\n * means downstream tooling (diff, round-trip) can treat both formats with\n * the same suffix map.\n */\n\nimport { AdkClass, type ClassIncludeType } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nconst SUFFIX: Record<ClassIncludeType, string | undefined> = {\n main: undefined,\n definitions: 'locals_def',\n implementations: 'locals_imp',\n localtypes: 'locals_types',\n macros: 'macros',\n testclasses: 'testclasses',\n};\n\nconst SUFFIX_TO_SOURCE_KEY = Object.fromEntries(\n Object.entries(SUFFIX)\n .filter(([, v]) => v !== undefined)\n .map(([k, v]) => [v, k]),\n) as Record<string, ClassIncludeType>;\n\nexport const classHandler = createHandler(AdkClass, {\n suffixToSourceKey: SUFFIX_TO_SOURCE_KEY,\n\n toMetadata(cls) {\n const data = cls.dataSync;\n return {\n header: {\n formatVersion: '1.0',\n description: cls.description ?? data.description ?? '',\n originalLanguage: data.language ?? data.masterLanguage,\n abapLanguageVersion: data.abapLanguageVersion,\n },\n class: {\n category: data.category,\n visibility: data.visibility ?? 'public',\n final: data.final === true,\n abstract: data.abstract === true,\n fixedPointArithmetic: data.fixPointArithmetic === true,\n unicodeChecksActive: data.activeUnicodeCheck !== false,\n sharedMemoryEnabled: data.sharedMemoryEnabled === true,\n superClass: data.superClassRef?.name,\n },\n };\n },\n\n getSources: (cls) => {\n const includes = cls.dataSync.include ?? [];\n return includes.map((inc) => ({\n suffix: SUFFIX[String(inc.includeType ?? 'main') as ClassIncludeType],\n content: () =>\n cls.getIncludeSource(\n String(inc.includeType ?? 'main') as ClassIncludeType,\n ),\n }));\n },\n\n fromMetadata: (meta: any) => ({\n name: (meta?.class?.name ?? '').toUpperCase(),\n type: 'CLAS/OC',\n description: meta?.header?.description,\n language: meta?.header?.originalLanguage,\n masterLanguage: meta?.header?.originalLanguage,\n category: meta?.class?.category,\n visibility: meta?.class?.visibility,\n final: meta?.class?.final === true,\n abstract: meta?.class?.abstract === true,\n abapLanguageVersion: meta?.header?.abapLanguageVersion,\n }),\n\n setSources: (cls, sources) => {\n (\n cls as unknown as { _pendingSources: Record<string, string> }\n )._pendingSources = sources;\n if (sources.main) {\n (cls as unknown as { _pendingSource: string })._pendingSource =\n sources.main;\n }\n },\n});\n","/**\n * INTF handler for gCTS / AFF format.\n */\nimport { AdkInterface } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const interfaceHandler = createHandler(AdkInterface, {\n toMetadata(intf) {\n const data = intf.dataSync;\n return {\n header: {\n formatVersion: '1.0',\n description: intf.description ?? data.description ?? '',\n originalLanguage: data.language ?? data.masterLanguage,\n abapLanguageVersion: data.abapLanguageVersion,\n },\n interface: {\n unicodeChecksActive: data.activeUnicodeCheck !== false,\n },\n };\n },\n\n getSource: (obj) => obj.getSource(),\n\n fromMetadata: (meta: any) => ({\n name: (meta?.interface?.name ?? '').toUpperCase(),\n type: 'INTF/OI',\n description: meta?.header?.description,\n language: meta?.header?.originalLanguage,\n masterLanguage: meta?.header?.originalLanguage,\n abapLanguageVersion: meta?.header?.abapLanguageVersion,\n }),\n\n setSources: (intf, sources) => {\n if (sources.main) {\n (intf as unknown as { _pendingSource: string })._pendingSource =\n sources.main;\n }\n },\n});\n","/**\n * PROG handler for gCTS / AFF format.\n */\nimport { AdkProgram } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const programHandler = createHandler(AdkProgram, {\n toMetadata(prog) {\n const data = prog.dataSync;\n return {\n header: {\n formatVersion: '1.0',\n description: prog.description ?? data.description ?? '',\n originalLanguage: data.language ?? data.masterLanguage,\n abapLanguageVersion: data.abapLanguageVersion,\n },\n program: {\n programType: data.programType ?? 'executableProgram',\n fixedPointArithmetic: data.fixPointArithmetic === true,\n unicodeChecksActive: data.activeUnicodeCheck !== false,\n },\n };\n },\n\n getSource: (obj) => obj.getSource(),\n\n fromMetadata: (meta: any) => ({\n name: (meta?.program?.name ?? '').toUpperCase(),\n type: 'PROG/P',\n description: meta?.header?.description,\n language: meta?.header?.originalLanguage,\n programType: meta?.program?.programType,\n }),\n\n setSources: (prog, sources) => {\n if (sources.main) {\n (prog as unknown as { _pendingSource: string })._pendingSource =\n sources.main;\n }\n },\n});\n","/**\n * DEVC (package) handler for gCTS / AFF format.\n *\n * Packages use a fixed filename (`package.devc.json`) — same convention as\n * abapGit's `package.devc.xml`.\n */\nimport { AdkPackage } from '@abapify/adk';\nimport { createHandler, PACKAGE_FILENAME } from '../base';\n\nexport const packageHandler = createHandler(AdkPackage, {\n metadataFileName: PACKAGE_FILENAME,\n\n toMetadata(pkg) {\n return {\n header: {\n formatVersion: '1.0',\n description: pkg.description ?? '',\n originalLanguage:\n pkg.dataSync?.language ?? pkg.dataSync?.masterLanguage,\n },\n package: {\n // DEVCLASS is carried by filename/directory, not by metadata.\n softwareComponent: pkg.dataSync?.transport?.softwareComponent?.name,\n applicationComponent: pkg.dataSync?.applicationComponent?.name,\n packageType: pkg.dataSync?.attributes?.packageType,\n },\n };\n },\n\n fromMetadata: (meta: any) => ({\n name: '',\n description: meta?.header?.description,\n }),\n});\n","/**\n * DOMA (domain) handler for gCTS / AFF format.\n */\nimport { AdkDomain } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const domainHandler = createHandler(AdkDomain, {\n toMetadata(doma) {\n const data = doma.dataSync as Record<string, unknown>;\n return {\n header: {\n formatVersion: '1.0',\n description: doma.description ?? '',\n originalLanguage:\n (data.language as string) ?? (data.masterLanguage as string),\n },\n domain: {\n dataType: data.dataType,\n length: data.length,\n decimals: data.decimals,\n outputLength: data.outputLength,\n caseSensitive: data.caseSensitive === true,\n valueTable: (data.valueTableRef as { name?: string } | undefined)?.name,\n },\n };\n },\n\n fromMetadata: (meta: any) => ({\n name: (meta?.domain?.name ?? '').toUpperCase(),\n description: meta?.header?.description,\n dataType: meta?.domain?.dataType,\n length: meta?.domain?.length,\n decimals: meta?.domain?.decimals,\n }),\n});\n","/**\n * DTEL (data element) handler for gCTS / AFF format.\n */\nimport { AdkDataElement } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const dataElementHandler = createHandler(AdkDataElement, {\n toMetadata(dtel) {\n const data = dtel.dataSync as Record<string, unknown>;\n return {\n header: {\n formatVersion: '1.0',\n description: dtel.description ?? '',\n originalLanguage:\n (data.language as string) ?? (data.masterLanguage as string),\n },\n dataElement: {\n typeKind: data.typeKind,\n dataType: data.dataType,\n length: data.length,\n decimals: data.decimals,\n domain: (data.domainRef as { name?: string } | undefined)?.name,\n predefinedType: data.predefinedType,\n },\n };\n },\n\n fromMetadata: (meta: any) => ({\n name: (meta?.dataElement?.name ?? '').toUpperCase(),\n description: meta?.header?.description,\n dataType: meta?.dataElement?.dataType,\n }),\n});\n","/**\n * TABL (table / structure) handler for gCTS / AFF format.\n */\nimport { AdkTable } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const tableHandler = createHandler(AdkTable, {\n toMetadata(tabl) {\n const data = tabl.dataSync as Record<string, unknown>;\n return {\n header: {\n formatVersion: '1.0',\n description: tabl.description ?? '',\n originalLanguage:\n (data.language as string) ?? (data.masterLanguage as string),\n },\n table: {\n tableCategory: data.tableCategory,\n deliveryClass: data.deliveryClass,\n dataMaintenance: data.dataMaintenance,\n fields: data.fields,\n },\n };\n },\n\n fromMetadata: (meta: any) => ({\n name: (meta?.table?.name ?? '').toUpperCase(),\n description: meta?.header?.description,\n }),\n});\n","/**\n * TTYP (table type) handler for gCTS / AFF format.\n */\nimport { AdkTableType } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const tableTypeHandler = createHandler(AdkTableType, {\n toMetadata(ttyp) {\n const data = ttyp.dataSync as Record<string, unknown>;\n return {\n header: {\n formatVersion: '1.0',\n description: ttyp.description ?? '',\n originalLanguage:\n (data.language as string) ?? (data.masterLanguage as string),\n },\n tableType: {\n accessMode: data.accessMode,\n rowType: (data.rowTypeRef as { name?: string } | undefined)?.name,\n primaryKey: data.primaryKey,\n secondaryKeys: data.secondaryKeys,\n },\n };\n },\n\n fromMetadata: (meta: any) => ({\n name: (meta?.tableType?.name ?? '').toUpperCase(),\n description: meta?.header?.description,\n }),\n});\n","/**\n * FUGR (function group) handler for gCTS / AFF format.\n *\n * AFF's FUGR representation nests function modules under the group\n * directory. This plugin emits the group metadata only — per-module files\n * are produced by individual FUNC handlers once ADK exposes them.\n */\nimport { AdkFunctionGroup } from '@abapify/adk';\nimport { createHandler } from '../base';\n\nexport const functionGroupHandler = createHandler(AdkFunctionGroup, {\n toMetadata(fugr) {\n const data = fugr.dataSync as Record<string, unknown>;\n return {\n header: {\n formatVersion: '1.0',\n description: fugr.description ?? '',\n originalLanguage:\n (data.language as string) ?? (data.masterLanguage as string),\n },\n functionGroup: {\n // Function-module enumeration is intentionally deferred — AFF treats\n // FMs as separate artefacts and ADK already models them per FM.\n fixedPointArithmetic: data.fixPointArithmetic === true,\n unicodeChecksActive: data.activeUnicodeCheck !== false,\n },\n };\n },\n\n fromMetadata: (meta: any) => ({\n name: (meta?.functionGroup?.name ?? '').toUpperCase(),\n description: meta?.header?.description,\n }),\n});\n","/**\n * gCTS / AFF FormatPlugin.\n *\n * Thin adapter that plugs the gCTS handler registry into the generic\n * `FormatPlugin` contract defined by `@abapify/adt-plugin`. External\n * consumers (adt-export, adt-diff, adt-cli) interact with this plugin\n * through the registry only — they look it up with\n * `getFormatPlugin('gcts')` and never import this package directly.\n *\n * Registration happens as a side-effect of importing\n * `@abapify/adt-plugin-gcts` (`src/index.ts`).\n */\n\nimport type { FormatPlugin, FormatHandler } from '@abapify/adt-plugin';\nimport { getHandler, getSupportedTypes } from '../handlers/base';\nimport '../handlers/objects';\nimport { parseGctsFilename } from './filename';\n\nexport const gctsFormatPlugin: FormatPlugin = {\n id: 'gcts',\n description:\n 'gCTS / AFF (abap-file-formats) serialization format (JSON metadata + .abap/.acds sources)',\n\n get supportedTypes(): ReadonlyArray<string> {\n return getSupportedTypes();\n },\n\n getHandler(type: string): FormatHandler | undefined {\n return getHandler(type) as unknown as FormatHandler | undefined;\n },\n\n parseFilename(filename: string) {\n return parseGctsFilename(filename);\n },\n};\n\nexport default gctsFormatPlugin;\n","/**\n * gCTS / AFF Deserializer — disk → ADK (format.export direction).\n *\n * Reads a gCTS-shaped file tree and yields `AdkObject` instances that the\n * `CheckinService` (E08) drives through the regular diff / plan / apply\n * pipeline. This is the counterpart to the serializer implemented in\n * `gcts-plugin.ts` (SAP → disk / format.import).\n *\n * Layout (matches the writer in `gcts-plugin.ts`):\n *\n * src/<pkg-lowercased>/<obj>.<type>.json metadata (AFF JSON)\n * src/<pkg-lowercased>/<obj>.<type>[.<sfx>].abap ABAP sources (and\n * .asddls / .asdcls for\n * CDS).\n * src/<pkg-lowercased>/package.devc.json package metadata (skipped\n * — packages must exist on\n * target, same convention\n * as abapGit).\n *\n * Unlike abapGit this plugin has no `.abapgit.xml` equivalent — AFF does not\n * encode folder-logic. We therefore rely on `options.rootPackage` (or\n * leave `packageRef` unset so downstream apply logic can decide) — no\n * guesswork per directory for now. Richer directory → package mapping is\n * tracked in the E06 follow-ups.\n */\n\nimport type { FileTree, ExportOptions } from '@abapify/adt-plugin';\nimport { createAdk, type AdkObject, type AdtClient } from '@abapify/adk';\nimport { getHandler, getSupportedTypes } from './handlers/base';\nimport { parseGctsFilename, PACKAGE_FILENAME } from './format/filename';\n\n/** Source-file extensions emitted by gCTS handlers. */\nconst SOURCE_EXTENSIONS = new Set(['abap', 'asddls', 'asdcls']);\n\n/**\n * Map numeric abapLanguageVersion codes (`'5'` etc.) to the descriptive\n * string the ADT REST API expects (`'cloudDevelopment'`). Mirrors the\n * helper in `adt-plugin-abapgit` — kept local so this package does not\n * depend on its sibling.\n */\nconst ABAP_LANG_VER_TO_ADT: Record<string, string> = {\n '2': 'keyUser',\n '5': 'cloudDevelopment',\n};\n\nfunction abapLangVerToAdt(code: string | undefined): string | undefined {\n if (!code) return undefined;\n return ABAP_LANG_VER_TO_ADT[code] ?? code;\n}\n\ninterface ObjectFiles {\n name: string;\n type: string;\n metadataFile?: string;\n sourceFiles: Array<{ path: string; suffix?: string }>;\n}\n\n/**\n * Deserialise a gCTS/AFF file tree into `AdkObject` instances.\n *\n * @param fileTree Virtual FS abstraction (checkin supplies a real-fs impl).\n * @param client `AdtClient` — required by `createAdk` to build ADK objects.\n * @param options Export options. `rootPackage` is assigned as packageRef\n * to every discovered object that lacks one, mirroring the\n * abapGit behaviour when `.abapgit.xml` is absent.\n */\nexport async function* deserialize(\n fileTree: FileTree,\n client: AdtClient,\n options?: ExportOptions,\n): AsyncGenerator<AdkObject> {\n const adk = createAdk(client);\n\n // Scan every JSON file — these are the anchors for each object.\n const jsonFiles = await fileTree.glob('**/*.json');\n\n const supportedTypes = new Set(\n getSupportedTypes().map((t) => t.toLowerCase()),\n );\n\n const objectMap = new Map<string, ObjectFiles>();\n\n for (const jsonPath of jsonFiles) {\n const filename = jsonPath.split('/').pop()!;\n\n // Packages are NOT deployed (same convention as abapGit's\n // package.devc.xml) — they must exist on target.\n if (filename === PACKAGE_FILENAME) continue;\n\n const parsed = parseGctsFilename(filename);\n if (!parsed) continue;\n if (parsed.extension !== 'json') continue;\n if (!supportedTypes.has(parsed.type.toLowerCase())) continue;\n\n const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;\n if (!objectMap.has(key)) {\n objectMap.set(key, {\n name: parsed.name.toUpperCase(),\n type: parsed.type.toUpperCase(),\n sourceFiles: [],\n });\n }\n objectMap.get(key)!.metadataFile = jsonPath;\n }\n\n // Collect every source file (.abap/.asddls/.asdcls) and group by name:type.\n for (const ext of SOURCE_EXTENSIONS) {\n const paths = await fileTree.glob(`**/*.${ext}`);\n for (const path of paths) {\n const filename = path.split('/').pop()!;\n const parsed = parseGctsFilename(filename);\n if (!parsed) continue;\n\n const key = `${parsed.name.toUpperCase()}:${parsed.type.toUpperCase()}`;\n const obj = objectMap.get(key);\n if (!obj) continue;\n\n obj.sourceFiles.push({ path, suffix: parsed.suffix });\n }\n }\n\n for (const [, objFiles] of objectMap) {\n if (!objFiles.metadataFile) continue;\n\n const handler = getHandler(objFiles.type);\n if (!handler) continue;\n\n try {\n const raw = await fileTree.read(objFiles.metadataFile);\n // Handler schema.parse is plain JSON.parse — the parsed object IS the\n // metadata passed to fromMetadata.\n const metadata = handler.schema.parse(raw);\n\n // Read sources, mapping suffix → source key via handler map.\n const sources: Record<string, string> = {};\n for (const { path, suffix } of objFiles.sourceFiles) {\n const content = await fileTree.read(path);\n const sourceKey = suffix\n ? (handler.suffixToSourceKey?.[suffix] ?? suffix)\n : 'main';\n sources[sourceKey] = content;\n }\n\n const payload: {\n name: string;\n description?: string;\n [key: string]: unknown;\n } = handler.fromAbapGit\n ? handler.fromAbapGit(metadata)\n : { name: objFiles.name };\n\n // AFF metadata frequently omits the object name (it's encoded in the\n // filename). Fall back to the filename-derived name.\n const objectName = payload.name || objFiles.name;\n const fullData = { ...payload, name: objectName };\n\n const adkType =\n typeof payload.type === 'string' ? payload.type : objFiles.type;\n const adkObject = adk.getWithData(fullData, adkType) as AdkObject;\n\n if (Object.keys(sources).length > 0) {\n if (handler.setSources) {\n handler.setSources(adkObject, sources);\n } else if (sources.main) {\n (adkObject as unknown as { _pendingSource: string })._pendingSource =\n sources.main;\n }\n }\n\n if (payload.description) {\n (\n adkObject as unknown as { _pendingDescription: string }\n )._pendingDescription = payload.description;\n }\n\n // Record relative directory (useful for future directory-based package\n // resolution). Plain metadata dir, no starting-folder normalisation —\n // gCTS does not define one.\n const sourceDir = objFiles\n .metadataFile!.split('/')\n .slice(0, -1)\n .join('/');\n (adkObject as unknown as { _relDir: string })._relDir = sourceDir;\n\n // Assign rootPackage to every object without a packageRef — no folder\n // logic available, so we cannot derive per-package assignments (see\n // E06 follow-ups). Matches abapGit's \"no .abapgit.xml\" fallback.\n if (options?.rootPackage) {\n const data = (\n adkObject as unknown as { _data?: Record<string, unknown> }\n )._data;\n if (data && !data.packageRef) {\n data.packageRef = { name: options.rootPackage };\n }\n }\n\n if (options?.abapLanguageVersion) {\n const data = (\n adkObject as unknown as { _data?: Record<string, unknown> }\n )._data;\n if (data && !data.abapLanguageVersion) {\n data.abapLanguageVersion =\n abapLangVerToAdt(options.abapLanguageVersion) ??\n options.abapLanguageVersion;\n }\n }\n\n yield adkObject;\n } catch (error) {\n // Mirrors abapGit: log and continue so one bad object does not abort\n // the whole checkin.\n console.error(\n `Failed to deserialize ${objFiles.type} ${objFiles.name}:`,\n error,\n );\n }\n }\n}\n","/**\n * gCTS AdtPlugin.\n *\n * The `FormatPlugin` in `format/gcts-format.ts` provides the declarative\n * contract (used by registry consumers); this `AdtPlugin` provides the\n * behaviour expected by `adt-cli`'s higher-level import/export services.\n *\n * SAP → disk (\"import\") serialises ADK objects to AFF JSON + source files.\n * Disk → SAP (\"export\" in adt-cli terminology — Git → SAP direction) is\n * delegated to `./deserializer.ts`, which yields AdkObjects for the\n * `CheckinService` apply pipeline (E08). Together they close the\n * round-trip that the E06 v0.1 follow-ups called out.\n */\n\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { createPlugin, type AdtPlugin } from '@abapify/adt-plugin';\nimport type { AdtClient } from '@abapify/adk';\nimport { getHandler, getSupportedTypes, isSupported } from './handlers/base';\nimport './handlers/objects';\nimport { deserialize } from './deserializer';\n\nexport const gctsPlugin: AdtPlugin = createPlugin({\n name: 'gcts',\n version: '0.1.0',\n description: 'gCTS / AFF format plugin — JSON metadata + .abap/.acds sources',\n\n registry: {\n isSupported,\n getSupportedTypes,\n },\n\n format: {\n async import(object, targetPath, context) {\n try {\n const isPackage = object.type?.startsWith('DEVC');\n const objPackage = isPackage\n ? object.name\n : (object as { package?: string }).package || object.name || 'ROOT';\n const packagePath = await context.resolvePackagePath(objPackage);\n\n // gCTS layout: flat per-package directory under src/<package-path>/.\n // Object files live directly inside their package dir (no extra\n // per-object subdirectory — matches AFF's default \"flat\" layout).\n const packageDir = packagePath.map((p) => p.toLowerCase()).join('/');\n\n const handler = getHandler(object.type);\n if (!handler) {\n return {\n success: false,\n filesCreated: [],\n errors: [\n `No gCTS handler registered for object type: ${object.type}`,\n ],\n };\n }\n\n const files = await handler.serialize(object as unknown as never);\n const baseDir = join(targetPath, 'src', packageDir);\n mkdirSync(baseDir, { recursive: true });\n\n const written: string[] = [];\n for (const f of files) {\n const full = join(baseDir, f.path);\n mkdirSync(dirname(full), { recursive: true });\n writeFileSync(full, f.content, f.encoding ?? 'utf8');\n written.push(full);\n }\n\n return { success: true, filesCreated: written };\n } catch (error) {\n return {\n success: false,\n filesCreated: [],\n errors: [error instanceof Error ? error.message : String(error)],\n };\n }\n },\n\n // Git → SAP: deserialise a gCTS/AFF file tree into AdkObjects. The\n // apply pipeline (diff/plan/lock/save) lives in CheckinService — this\n // plugin only knows how to decode its own on-disk layout.\n export: (fileTree, client, options?) =>\n deserialize(fileTree, client as AdtClient, options),\n },\n});\n\nexport default gctsPlugin;\nexport { gctsPlugin as GctsPlugin };\n","/**\n * @abapify/adt-plugin-gcts — gCTS / AFF format plugin entry point.\n *\n * Importing this module self-registers the plugin into the global\n * `FormatPlugin` registry so that `--format gcts` becomes available\n * throughout the `adt` CLI.\n */\n\nimport { registerFormatPlugin } from '@abapify/adt-plugin';\nimport { gctsFormatPlugin } from './lib/format/gcts-format';\n\n// Self-register on module load. Idempotent — safe against dual module-graph\n// evaluation (the same guard abapGit uses).\nregisterFormatPlugin(gctsFormatPlugin);\n\n// FormatPlugin — preferred public entry-point.\nexport { gctsFormatPlugin } from './lib/format/gcts-format';\n\n// AdtPlugin — needed for dynamic-import code paths in adt-cli.\nexport { gctsPlugin, GctsPlugin } from './lib/gcts-plugin';\nexport { gctsPlugin as default } from './lib/gcts-plugin';\n\n// Handler utilities\nexport {\n getHandler,\n getSupportedTypes,\n isSupported,\n createHandler,\n} from './lib/handlers/base';\nexport type {\n GctsHandler,\n GctsHandlerDefinition,\n GctsSourceEntry,\n} from './lib/handlers/base';\n\n// Filename utilities\nexport {\n gctsFilename,\n parseGctsFilename,\n adtUriToGctsPath,\n PACKAGE_FILENAME,\n METADATA_EXTENSION,\n} from './lib/format/filename';\n\n// Type re-exports\nexport type { GctsMetadata, GctsHeader, WithHeader } from './lib/format/types';\nexport type {\n AdtPlugin,\n FormatPlugin,\n FormatHandler,\n SerializedFile,\n} from '@abapify/adt-plugin';\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abapify/adt-plugin-gcts",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "license": "MIT",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -18,8 +18,8 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
- "@abapify/adk": "0.4.0",
22
- "@abapify/adt-plugin": "0.4.0"
21
+ "@abapify/adk": "0.4.1",
22
+ "@abapify/adt-plugin": "0.4.1"
23
23
  },
24
24
  "repository": {
25
25
  "type": "git",