@likec4/leanix-bridge 1.53.0 → 1.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +9 -2
- package/dist/index.mjs +53 -12
- package/package.json +6 -6
- package/src/contracts.ts +18 -3
- package/src/governance-checks.ts +1 -0
- package/src/index.ts +1 -0
- package/src/leanix-graphql-operations.ts +7 -2
- package/src/mapping.ts +57 -4
- package/src/to-bridge-manifest.ts +1 -0
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Uses readFileSync (not require) so when bundled into likec4 CLI the bundler
|
|
6
6
|
* does not emit require('../package.json') which fails in the tarball layout.
|
|
7
7
|
*/
|
|
8
|
-
/**
|
|
8
|
+
/** Bridge version; must match package version (from package.json when available). */
|
|
9
9
|
declare const BRIDGE_VERSION: string;
|
|
10
10
|
/** Semantic anchor: LikeC4 FQN (e.g. cloud.backend.api) */
|
|
11
11
|
type CanonicalId = string;
|
|
@@ -86,6 +86,11 @@ interface LeanixMappingConfig {
|
|
|
86
86
|
declare const FALLBACK_FACT_SHEET_TYPE = "Application";
|
|
87
87
|
/** Fallback when relation kind is unknown (G25: named constant). */
|
|
88
88
|
declare const FALLBACK_RELATION_TYPE = "depends on";
|
|
89
|
+
/**
|
|
90
|
+
* Parses and validates a partial LeanIX mapping from untrusted input (e.g. YAML/JSON).
|
|
91
|
+
* Returns `null`/`undefined` unchanged. Throws with a clear message on invalid shape or unknown keys.
|
|
92
|
+
*/
|
|
93
|
+
declare function parseLeanixMappingInput(input: unknown): LeanixMappingConfig | null | undefined;
|
|
89
94
|
/** Default mapping: actor → Provider; override factSheetTypes/relationTypes as needed */
|
|
90
95
|
declare const DEFAULT_LEANIX_MAPPING: Required<LeanixMappingConfig>;
|
|
91
96
|
/**
|
|
@@ -142,6 +147,7 @@ interface BridgeModelInput {
|
|
|
142
147
|
}
|
|
143
148
|
//#endregion
|
|
144
149
|
//#region src/to-bridge-manifest.d.ts
|
|
150
|
+
/** Optional overrides when building a bridge manifest (versions, timestamp, mapping profile). */
|
|
145
151
|
interface ToBridgeManifestOptions {
|
|
146
152
|
manifestVersion?: string;
|
|
147
153
|
generatedAt?: string;
|
|
@@ -524,6 +530,7 @@ interface GovernanceCheckResult {
|
|
|
524
530
|
passed: boolean;
|
|
525
531
|
message?: string;
|
|
526
532
|
}
|
|
533
|
+
/** Aggregated governance outcome (passed, timestamp, per-check results). */
|
|
527
534
|
interface GovernanceReport {
|
|
528
535
|
passed: boolean;
|
|
529
536
|
generatedAt: string;
|
|
@@ -556,4 +563,4 @@ declare function isBridgeManifest(obj: unknown): obj is BridgeManifest;
|
|
|
556
563
|
*/
|
|
557
564
|
declare function isLeanixInventorySnapshot(obj: unknown): obj is LeanixInventorySnapshot;
|
|
558
565
|
//#endregion
|
|
559
|
-
export { type AdrGenerationOptions, type AmbiguousMatch, BRIDGE_MANIFEST_VERSION, BRIDGE_VERSION, type BridgeElementLike, type BridgeManifest, type BridgeModelInput, type RelationId as BridgeRelationId, type BridgeRelationLike, type BridgeReport, type BridgeVersion, type ViewId as BridgeViewId, type BridgeViewLike, type CanonicalId, DEFAULT_LEANIX_MAPPING, type DrawioLeanixMapping, type DriftAdrGenerationOptions, type DriftReport, type DriftStatus, type ExternalId, FALLBACK_FACT_SHEET_TYPE, FALLBACK_RELATION_TYPE, type FetchLeanixInventorySnapshotOptions, type GeneratedAt, type GovernanceCheckOptions, type GovernanceCheckResult, type GovernanceReport, type GraphQLResponse, type ImpactReport, LEANIX_PROVIDER, LeanixApiClient, type LeanixApiClientConfig, LeanixApiError, type LeanixFactSheetDryRun, type LeanixFactSheetSnapshotItem, type LeanixInventoryDryRun, type LeanixInventorySnapshot, type LeanixMappingConfig, type LeanixRelationDryRun, type LeanixRelationSnapshotItem, type ManifestEntity, type ManifestRelation, type ManifestVersion, type ManifestView, type MappingProfile, type MatchedPair, type PlanSyncToLeanixOptions, type Provider, type ProviderExternalIds, type ReconcileOptions, type ReconciliationResult, type SyncPlan, type SyncPlanFactSheetEntry, type SyncPlanRelationEntry, type SyncPlanSummary, type SyncToLeanixOptions, type SyncToLeanixResult, type ToBridgeManifestOptions, type ToLeanixInventoryDryRunOptions, type UnmatchedInLeanix, type UnmatchedInLikec4, buildBridgeReport, buildDriftReport, fetchLeanixInventorySnapshot, generateAdrFromDriftReport, generateAdrFromReconciliation, getFactSheetType, getRelationType, impactReportFromSyncPlan, isBridgeManifest, isLeanixInventorySnapshot, manifestToDrawioLeanixMapping, mergeWithDefault, planSyncToLeanix, reconcileInventoryWithManifest, runGovernanceChecks, syncToLeanix, toBridgeManifest, toLeanixInventoryDryRun };
|
|
566
|
+
export { type AdrGenerationOptions, type AmbiguousMatch, BRIDGE_MANIFEST_VERSION, BRIDGE_VERSION, type BridgeElementLike, type BridgeManifest, type BridgeModelInput, type RelationId as BridgeRelationId, type BridgeRelationLike, type BridgeReport, type BridgeVersion, type ViewId as BridgeViewId, type BridgeViewLike, type CanonicalId, DEFAULT_LEANIX_MAPPING, type DrawioLeanixMapping, type DriftAdrGenerationOptions, type DriftReport, type DriftStatus, type ExternalId, FALLBACK_FACT_SHEET_TYPE, FALLBACK_RELATION_TYPE, type FetchLeanixInventorySnapshotOptions, type GeneratedAt, type GovernanceCheckOptions, type GovernanceCheckResult, type GovernanceReport, type GraphQLResponse, type ImpactReport, LEANIX_PROVIDER, LeanixApiClient, type LeanixApiClientConfig, LeanixApiError, type LeanixFactSheetDryRun, type LeanixFactSheetSnapshotItem, type LeanixInventoryDryRun, type LeanixInventorySnapshot, type LeanixMappingConfig, type LeanixRelationDryRun, type LeanixRelationSnapshotItem, type ManifestEntity, type ManifestRelation, type ManifestVersion, type ManifestView, type MappingProfile, type MatchedPair, type PlanSyncToLeanixOptions, type Provider, type ProviderExternalIds, type ReconcileOptions, type ReconciliationResult, type SyncPlan, type SyncPlanFactSheetEntry, type SyncPlanRelationEntry, type SyncPlanSummary, type SyncToLeanixOptions, type SyncToLeanixResult, type ToBridgeManifestOptions, type ToLeanixInventoryDryRunOptions, type UnmatchedInLeanix, type UnmatchedInLikec4, buildBridgeReport, buildDriftReport, fetchLeanixInventorySnapshot, generateAdrFromDriftReport, generateAdrFromReconciliation, getFactSheetType, getRelationType, impactReportFromSyncPlan, isBridgeManifest, isLeanixInventorySnapshot, manifestToDrawioLeanixMapping, mergeWithDefault, parseLeanixMappingInput, planSyncToLeanix, reconcileInventoryWithManifest, runGovernanceChecks, syncToLeanix, toBridgeManifest, toLeanixInventoryDryRun };
|
package/dist/index.mjs
CHANGED
|
@@ -8,14 +8,24 @@ import { fileURLToPath } from "node:url";
|
|
|
8
8
|
* does not emit require('../package.json') which fails in the tarball layout.
|
|
9
9
|
*/
|
|
10
10
|
const _dir = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
/** Last-resort fallback when no package.json is readable (e.g. CI test layout). */
|
|
12
|
+
const DEFAULT_BRIDGE_VERSION = "0.1.0";
|
|
13
|
+
/**
|
|
14
|
+
* Resolves bridge version from package.json so BRIDGE_VERSION stays in sync with the published package.
|
|
15
|
+
* 1) @likec4/leanix-bridge package (when not bundled). 2) likec4 CLI package (when bridge is bundled into CLI; versions are kept in sync). 3) Default only when neither is readable.
|
|
16
|
+
*/
|
|
11
17
|
function readVersion() {
|
|
12
18
|
try {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
const pkg = JSON.parse(readFileSync(join(_dir, "..", "package.json"), "utf8"));
|
|
20
|
+
if (pkg.version) return pkg.version;
|
|
21
|
+
} catch {}
|
|
22
|
+
try {
|
|
23
|
+
const pkg = JSON.parse(readFileSync(join(_dir, "..", "..", "package.json"), "utf8"));
|
|
24
|
+
if (pkg.version) return pkg.version;
|
|
25
|
+
} catch {}
|
|
26
|
+
return DEFAULT_BRIDGE_VERSION;
|
|
17
27
|
}
|
|
18
|
-
/**
|
|
28
|
+
/** Bridge version; must match package version (from package.json when available). */
|
|
19
29
|
const BRIDGE_VERSION = readVersion();
|
|
20
30
|
/** Manifest schema version (semantic; must match parser). */
|
|
21
31
|
const BRIDGE_MANIFEST_VERSION = "1.0";
|
|
@@ -25,6 +35,31 @@ const LEANIX_PROVIDER = "leanix";
|
|
|
25
35
|
const FALLBACK_FACT_SHEET_TYPE = "Application";
|
|
26
36
|
/** Fallback when relation kind is unknown (G25: named constant). */
|
|
27
37
|
const FALLBACK_RELATION_TYPE = "depends on";
|
|
38
|
+
const MAPPING_TOP_KEYS = new Set([
|
|
39
|
+
"factSheetTypes",
|
|
40
|
+
"relationTypes",
|
|
41
|
+
"metadataToFields"
|
|
42
|
+
]);
|
|
43
|
+
/** True when `value` is a non-array object whose values are all strings. */
|
|
44
|
+
function isPlainObjectRecordOfStrings(value) {
|
|
45
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
46
|
+
for (const v of Object.values(value)) if (typeof v !== "string") return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parses and validates a partial LeanIX mapping from untrusted input (e.g. YAML/JSON).
|
|
51
|
+
* Returns `null`/`undefined` unchanged. Throws with a clear message on invalid shape or unknown keys.
|
|
52
|
+
*/
|
|
53
|
+
function parseLeanixMappingInput(input) {
|
|
54
|
+
if (input === null || input === void 0) return input;
|
|
55
|
+
if (typeof input !== "object" || Array.isArray(input)) throw new Error("LeanIX mapping must be a plain object (not an array or primitive)");
|
|
56
|
+
const obj = input;
|
|
57
|
+
for (const key of Object.keys(obj)) if (!MAPPING_TOP_KEYS.has(key)) throw new Error(`LeanIX mapping has unknown key "${key}". Allowed: factSheetTypes, relationTypes, metadataToFields`);
|
|
58
|
+
if (obj["factSheetTypes"] !== void 0 && !isPlainObjectRecordOfStrings(obj["factSheetTypes"])) throw new Error("LeanIX mapping \"factSheetTypes\" must be an object with string keys and string values");
|
|
59
|
+
if (obj["relationTypes"] !== void 0 && !isPlainObjectRecordOfStrings(obj["relationTypes"])) throw new Error("LeanIX mapping \"relationTypes\" must be an object with string keys and string values");
|
|
60
|
+
if (obj["metadataToFields"] !== void 0 && !isPlainObjectRecordOfStrings(obj["metadataToFields"])) throw new Error("LeanIX mapping \"metadataToFields\" must be an object with string keys and string values");
|
|
61
|
+
return input;
|
|
62
|
+
}
|
|
28
63
|
/** Default mapping: actor → Provider; override factSheetTypes/relationTypes as needed */
|
|
29
64
|
const DEFAULT_LEANIX_MAPPING = {
|
|
30
65
|
factSheetTypes: {
|
|
@@ -44,24 +79,25 @@ const DEFAULT_LEANIX_MAPPING = {
|
|
|
44
79
|
* Merges partial mapping config with DEFAULT_LEANIX_MAPPING; returns a full Required<LeanixMappingConfig>.
|
|
45
80
|
*/
|
|
46
81
|
function mergeWithDefault(partial) {
|
|
82
|
+
const normalized = parseLeanixMappingInput(partial);
|
|
47
83
|
const base = {
|
|
48
84
|
factSheetTypes: { ...DEFAULT_LEANIX_MAPPING.factSheetTypes },
|
|
49
85
|
relationTypes: { ...DEFAULT_LEANIX_MAPPING.relationTypes },
|
|
50
86
|
metadataToFields: { ...DEFAULT_LEANIX_MAPPING.metadataToFields }
|
|
51
87
|
};
|
|
52
|
-
if (!
|
|
88
|
+
if (!normalized) return base;
|
|
53
89
|
return {
|
|
54
90
|
factSheetTypes: {
|
|
55
91
|
...base.factSheetTypes,
|
|
56
|
-
...
|
|
92
|
+
...normalized.factSheetTypes
|
|
57
93
|
},
|
|
58
94
|
relationTypes: {
|
|
59
95
|
...base.relationTypes,
|
|
60
|
-
...
|
|
96
|
+
...normalized.relationTypes
|
|
61
97
|
},
|
|
62
98
|
metadataToFields: {
|
|
63
99
|
...base.metadataToFields,
|
|
64
|
-
...
|
|
100
|
+
...normalized.metadataToFields
|
|
65
101
|
}
|
|
66
102
|
};
|
|
67
103
|
}
|
|
@@ -318,8 +354,13 @@ async function findFactSheetByNameAndType(client, name, type) {
|
|
|
318
354
|
return (edges[0]?.node)?.id ?? null;
|
|
319
355
|
}
|
|
320
356
|
/**
|
|
321
|
-
* Search fact sheets by custom attribute (e.g. likec4Id) for idempotent lookup.
|
|
322
|
-
*
|
|
357
|
+
* Search LeanIX fact sheets by custom attribute (e.g. likec4Id) for idempotent lookup after bridge sync.
|
|
358
|
+
*
|
|
359
|
+
* @param client - Authenticated LeanIX GraphQL client.
|
|
360
|
+
* @param attributeKey - Custom attribute facet key (e.g. workspace-specific likec4 id field).
|
|
361
|
+
* @param likec4Id - Canonical LikeC4 element id stored in LeanIX.
|
|
362
|
+
* @returns Fact sheet id when exactly one match exists; `null` when none found.
|
|
363
|
+
* @throws Error when multiple matches, network failure, or GraphQL error.
|
|
323
364
|
*/
|
|
324
365
|
async function findFactSheetByLikec4IdAttribute(client, attributeKey, likec4Id) {
|
|
325
366
|
const query = `
|
|
@@ -1107,4 +1148,4 @@ function isLeanixInventorySnapshot(obj) {
|
|
|
1107
1148
|
for (const rel of obj["relations"]) if (!isLeanixRelationSnapshotItem(rel)) return false;
|
|
1108
1149
|
return true;
|
|
1109
1150
|
}
|
|
1110
|
-
export { BRIDGE_MANIFEST_VERSION, BRIDGE_VERSION, DEFAULT_LEANIX_MAPPING, FALLBACK_FACT_SHEET_TYPE, FALLBACK_RELATION_TYPE, LEANIX_PROVIDER, LeanixApiClient, LeanixApiError, buildBridgeReport, buildDriftReport, fetchLeanixInventorySnapshot, generateAdrFromDriftReport, generateAdrFromReconciliation, getFactSheetType, getRelationType, impactReportFromSyncPlan, isBridgeManifest, isLeanixInventorySnapshot, manifestToDrawioLeanixMapping, mergeWithDefault, planSyncToLeanix, reconcileInventoryWithManifest, runGovernanceChecks, syncToLeanix, toBridgeManifest, toLeanixInventoryDryRun };
|
|
1151
|
+
export { BRIDGE_MANIFEST_VERSION, BRIDGE_VERSION, DEFAULT_LEANIX_MAPPING, FALLBACK_FACT_SHEET_TYPE, FALLBACK_RELATION_TYPE, LEANIX_PROVIDER, LeanixApiClient, LeanixApiError, buildBridgeReport, buildDriftReport, fetchLeanixInventorySnapshot, generateAdrFromDriftReport, generateAdrFromReconciliation, getFactSheetType, getRelationType, impactReportFromSyncPlan, isBridgeManifest, isLeanixInventorySnapshot, manifestToDrawioLeanixMapping, mergeWithDefault, parseLeanixMappingInput, planSyncToLeanix, reconcileInventoryWithManifest, runGovernanceChecks, syncToLeanix, toBridgeManifest, toLeanixInventoryDryRun };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/leanix-bridge",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.55.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -37,16 +37,16 @@
|
|
|
37
37
|
"access": "public"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"remeda": "^2.33.
|
|
41
|
-
"@likec4/core": "1.
|
|
40
|
+
"remeda": "^2.33.7",
|
|
41
|
+
"@likec4/core": "1.55.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "~22.19.15",
|
|
45
45
|
"typescript": "5.9.3",
|
|
46
46
|
"obuild": "0.4.31",
|
|
47
|
-
"vitest": "4.1.
|
|
48
|
-
"@likec4/
|
|
49
|
-
"@likec4/
|
|
47
|
+
"vitest": "4.1.3",
|
|
48
|
+
"@likec4/tsconfig": "1.55.0",
|
|
49
|
+
"@likec4/devops": "1.42.0"
|
|
50
50
|
},
|
|
51
51
|
"scripts": {
|
|
52
52
|
"typecheck": "tsc -b --verbose",
|
package/src/contracts.ts
CHANGED
|
@@ -10,16 +10,31 @@ import { dirname, join } from 'node:path'
|
|
|
10
10
|
import { fileURLToPath } from 'node:url'
|
|
11
11
|
|
|
12
12
|
const _dir = dirname(fileURLToPath(import.meta.url))
|
|
13
|
+
|
|
14
|
+
/** Last-resort fallback when no package.json is readable (e.g. CI test layout). */
|
|
15
|
+
const DEFAULT_BRIDGE_VERSION = '0.1.0'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolves bridge version from package.json so BRIDGE_VERSION stays in sync with the published package.
|
|
19
|
+
* 1) @likec4/leanix-bridge package (when not bundled). 2) likec4 CLI package (when bridge is bundled into CLI; versions are kept in sync). 3) Default only when neither is readable.
|
|
20
|
+
*/
|
|
13
21
|
function readVersion(): string {
|
|
14
22
|
try {
|
|
15
23
|
const pkg = JSON.parse(readFileSync(join(_dir, '..', 'package.json'), 'utf8')) as { version?: string }
|
|
16
|
-
|
|
24
|
+
if (pkg.version) return pkg.version
|
|
17
25
|
} catch {
|
|
26
|
+
// Bundled CLI: import.meta.url is under packages/likec4/dist/cli, so ../package.json is missing; use ../../ (CLI package).
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
18
29
|
const pkg = JSON.parse(readFileSync(join(_dir, '..', '..', 'package.json'), 'utf8')) as { version?: string }
|
|
19
|
-
|
|
30
|
+
if (pkg.version) return pkg.version
|
|
31
|
+
} catch {
|
|
32
|
+
// Neither readable (e.g. test env).
|
|
20
33
|
}
|
|
34
|
+
return DEFAULT_BRIDGE_VERSION
|
|
21
35
|
}
|
|
22
|
-
|
|
36
|
+
|
|
37
|
+
/** Bridge version; must match package version (from package.json when available). */
|
|
23
38
|
export const BRIDGE_VERSION: string = readVersion()
|
|
24
39
|
|
|
25
40
|
/** Semantic anchor: LikeC4 FQN (e.g. cloud.backend.api) */
|
package/src/governance-checks.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -38,8 +38,13 @@ export async function findFactSheetByNameAndType(
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Search fact sheets by custom attribute (e.g. likec4Id) for idempotent lookup.
|
|
42
|
-
*
|
|
41
|
+
* Search LeanIX fact sheets by custom attribute (e.g. likec4Id) for idempotent lookup after bridge sync.
|
|
42
|
+
*
|
|
43
|
+
* @param client - Authenticated LeanIX GraphQL client.
|
|
44
|
+
* @param attributeKey - Custom attribute facet key (e.g. workspace-specific likec4 id field).
|
|
45
|
+
* @param likec4Id - Canonical LikeC4 element id stored in LeanIX.
|
|
46
|
+
* @returns Fact sheet id when exactly one match exists; `null` when none found.
|
|
47
|
+
* @throws Error when multiple matches, network failure, or GraphQL error.
|
|
43
48
|
*/
|
|
44
49
|
export async function findFactSheetByLikec4IdAttribute(
|
|
45
50
|
client: LeanixApiClient,
|
package/src/mapping.ts
CHANGED
|
@@ -19,6 +19,58 @@ export const FALLBACK_FACT_SHEET_TYPE = 'Application'
|
|
|
19
19
|
/** Fallback when relation kind is unknown (G25: named constant). */
|
|
20
20
|
export const FALLBACK_RELATION_TYPE = 'depends on'
|
|
21
21
|
|
|
22
|
+
const MAPPING_TOP_KEYS = new Set(['factSheetTypes', 'relationTypes', 'metadataToFields'])
|
|
23
|
+
|
|
24
|
+
/** True when `value` is a non-array object whose values are all strings. */
|
|
25
|
+
function isPlainObjectRecordOfStrings(value: unknown): value is Record<string, string> {
|
|
26
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
27
|
+
return false
|
|
28
|
+
}
|
|
29
|
+
for (const v of Object.values(value as Record<string, unknown>)) {
|
|
30
|
+
if (typeof v !== 'string') {
|
|
31
|
+
return false
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return true
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Parses and validates a partial LeanIX mapping from untrusted input (e.g. YAML/JSON).
|
|
39
|
+
* Returns `null`/`undefined` unchanged. Throws with a clear message on invalid shape or unknown keys.
|
|
40
|
+
*/
|
|
41
|
+
export function parseLeanixMappingInput(input: unknown): LeanixMappingConfig | null | undefined {
|
|
42
|
+
if (input === null || input === undefined) {
|
|
43
|
+
return input
|
|
44
|
+
}
|
|
45
|
+
if (typeof input !== 'object' || Array.isArray(input)) {
|
|
46
|
+
throw new Error('LeanIX mapping must be a plain object (not an array or primitive)')
|
|
47
|
+
}
|
|
48
|
+
const obj = input as Record<string, unknown>
|
|
49
|
+
for (const key of Object.keys(obj)) {
|
|
50
|
+
if (!MAPPING_TOP_KEYS.has(key)) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`LeanIX mapping has unknown key "${key}". Allowed: factSheetTypes, relationTypes, metadataToFields`,
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (obj['factSheetTypes'] !== undefined && !isPlainObjectRecordOfStrings(obj['factSheetTypes'])) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
'LeanIX mapping "factSheetTypes" must be an object with string keys and string values',
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
if (obj['relationTypes'] !== undefined && !isPlainObjectRecordOfStrings(obj['relationTypes'])) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
'LeanIX mapping "relationTypes" must be an object with string keys and string values',
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
if (obj['metadataToFields'] !== undefined && !isPlainObjectRecordOfStrings(obj['metadataToFields'])) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
'LeanIX mapping "metadataToFields" must be an object with string keys and string values',
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
return input as LeanixMappingConfig
|
|
72
|
+
}
|
|
73
|
+
|
|
22
74
|
/** Default mapping: actor → Provider; override factSheetTypes/relationTypes as needed */
|
|
23
75
|
export const DEFAULT_LEANIX_MAPPING: Required<LeanixMappingConfig> = {
|
|
24
76
|
factSheetTypes: {
|
|
@@ -41,18 +93,19 @@ export const DEFAULT_LEANIX_MAPPING: Required<LeanixMappingConfig> = {
|
|
|
41
93
|
* Merges partial mapping config with DEFAULT_LEANIX_MAPPING; returns a full Required<LeanixMappingConfig>.
|
|
42
94
|
*/
|
|
43
95
|
export function mergeWithDefault(partial?: LeanixMappingConfig | null): Required<LeanixMappingConfig> {
|
|
96
|
+
const normalized = parseLeanixMappingInput(partial)
|
|
44
97
|
const base = {
|
|
45
98
|
factSheetTypes: { ...DEFAULT_LEANIX_MAPPING.factSheetTypes },
|
|
46
99
|
relationTypes: { ...DEFAULT_LEANIX_MAPPING.relationTypes },
|
|
47
100
|
metadataToFields: { ...DEFAULT_LEANIX_MAPPING.metadataToFields },
|
|
48
101
|
}
|
|
49
|
-
if (!
|
|
102
|
+
if (!normalized) {
|
|
50
103
|
return base
|
|
51
104
|
}
|
|
52
105
|
return {
|
|
53
|
-
factSheetTypes: { ...base.factSheetTypes, ...
|
|
54
|
-
relationTypes: { ...base.relationTypes, ...
|
|
55
|
-
metadataToFields: { ...base.metadataToFields, ...
|
|
106
|
+
factSheetTypes: { ...base.factSheetTypes, ...normalized.factSheetTypes },
|
|
107
|
+
relationTypes: { ...base.relationTypes, ...normalized.relationTypes },
|
|
108
|
+
metadataToFields: { ...base.metadataToFields, ...normalized.metadataToFields },
|
|
56
109
|
}
|
|
57
110
|
}
|
|
58
111
|
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from './contracts'
|
|
13
13
|
import type { BridgeModelInput } from './model-input'
|
|
14
14
|
|
|
15
|
+
/** Optional overrides when building a bridge manifest (versions, timestamp, mapping profile). */
|
|
15
16
|
export interface ToBridgeManifestOptions {
|
|
16
17
|
manifestVersion?: string
|
|
17
18
|
generatedAt?: string
|