@untangle-code/file-graph 0.0.0-stage → 0.1.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.
- package/LICENSE +661 -0
- package/NOTICE +90 -0
- package/README.md +284 -2
- package/THIRD_PARTY_LICENSES.md +29 -0
- package/dist/assignment.d.ts +15 -0
- package/dist/assignment.d.ts.map +1 -0
- package/dist/assignment.js +75 -0
- package/dist/assignment.js.map +1 -0
- package/dist/boundaries/endpoints.d.ts +11 -0
- package/dist/boundaries/endpoints.d.ts.map +1 -0
- package/dist/boundaries/endpoints.js +195 -0
- package/dist/boundaries/endpoints.js.map +1 -0
- package/dist/boundaries/index.d.ts +9 -0
- package/dist/boundaries/index.d.ts.map +1 -0
- package/dist/boundaries/index.js +93 -0
- package/dist/boundaries/index.js.map +1 -0
- package/dist/boundaries/requests.d.ts +12 -0
- package/dist/boundaries/requests.d.ts.map +1 -0
- package/dist/boundaries/requests.js +311 -0
- package/dist/boundaries/requests.js.map +1 -0
- package/dist/edges.d.ts +49 -0
- package/dist/edges.d.ts.map +1 -0
- package/dist/edges.js +223 -0
- package/dist/edges.js.map +1 -0
- package/dist/file-index.d.ts +37 -0
- package/dist/file-index.d.ts.map +1 -0
- package/dist/file-index.js +103 -0
- package/dist/file-index.js.map +1 -0
- package/dist/graph.d.ts +160 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +448 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.d.ts +67 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +272 -0
- package/dist/metrics.js.map +1 -0
- package/dist/package-catalog.d.ts +43 -0
- package/dist/package-catalog.d.ts.map +1 -0
- package/dist/package-catalog.js +136 -0
- package/dist/package-catalog.js.map +1 -0
- package/dist/paths.d.ts +56 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +129 -0
- package/dist/paths.js.map +1 -0
- package/dist/persistence.d.ts +83 -0
- package/dist/persistence.d.ts.map +1 -0
- package/dist/persistence.js +538 -0
- package/dist/persistence.js.map +1 -0
- package/dist/resolve/candidates.d.ts +52 -0
- package/dist/resolve/candidates.d.ts.map +1 -0
- package/dist/resolve/candidates.js +202 -0
- package/dist/resolve/candidates.js.map +1 -0
- package/dist/resolve/package-exports.d.ts +31 -0
- package/dist/resolve/package-exports.d.ts.map +1 -0
- package/dist/resolve/package-exports.js +229 -0
- package/dist/resolve/package-exports.js.map +1 -0
- package/dist/resolve/pipeline.d.ts +11 -0
- package/dist/resolve/pipeline.d.ts.map +1 -0
- package/dist/resolve/pipeline.js +109 -0
- package/dist/resolve/pipeline.js.map +1 -0
- package/dist/resolve/resolvers.d.ts +25 -0
- package/dist/resolve/resolvers.d.ts.map +1 -0
- package/dist/resolve/resolvers.js +367 -0
- package/dist/resolve/resolvers.js.map +1 -0
- package/dist/restore.d.ts +75 -0
- package/dist/restore.d.ts.map +1 -0
- package/dist/restore.js +136 -0
- package/dist/restore.js.map +1 -0
- package/dist/topology/compose.d.ts +27 -0
- package/dist/topology/compose.d.ts.map +1 -0
- package/dist/topology/compose.js +208 -0
- package/dist/topology/compose.js.map +1 -0
- package/dist/topology/jsonc.d.ts +38 -0
- package/dist/topology/jsonc.d.ts.map +1 -0
- package/dist/topology/jsonc.js +137 -0
- package/dist/topology/jsonc.js.map +1 -0
- package/dist/topology/load.d.ts +61 -0
- package/dist/topology/load.d.ts.map +1 -0
- package/dist/topology/load.js +436 -0
- package/dist/topology/load.js.map +1 -0
- package/dist/topology/manifest.d.ts +48 -0
- package/dist/topology/manifest.d.ts.map +1 -0
- package/dist/topology/manifest.js +109 -0
- package/dist/topology/manifest.js.map +1 -0
- package/dist/topology/project-config.d.ts +39 -0
- package/dist/topology/project-config.d.ts.map +1 -0
- package/dist/topology/project-config.js +150 -0
- package/dist/topology/project-config.js.map +1 -0
- package/dist/topology/workspace-definition.d.ts +26 -0
- package/dist/topology/workspace-definition.d.ts.map +1 -0
- package/dist/topology/workspace-definition.js +104 -0
- package/dist/topology/workspace-definition.js.map +1 -0
- package/dist/traverse.d.ts +49 -0
- package/dist/traverse.d.ts.map +1 -0
- package/dist/traverse.js +167 -0
- package/dist/traverse.js.map +1 -0
- package/dist/types.d.ts +332 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +63 -3
- package/src/assignment.ts +83 -0
- package/src/boundaries/endpoints.ts +273 -0
- package/src/boundaries/index.ts +118 -0
- package/src/boundaries/requests.ts +411 -0
- package/src/edges.ts +334 -0
- package/src/file-index.ts +127 -0
- package/src/graph.ts +591 -0
- package/src/index.ts +58 -0
- package/src/metrics.ts +350 -0
- package/src/package-catalog.ts +145 -0
- package/src/paths.ts +138 -0
- package/src/persistence.ts +746 -0
- package/src/resolve/candidates.ts +230 -0
- package/src/resolve/package-exports.ts +268 -0
- package/src/resolve/pipeline.ts +140 -0
- package/src/resolve/resolvers.ts +468 -0
- package/src/restore.ts +201 -0
- package/src/topology/compose.ts +268 -0
- package/src/topology/jsonc.ts +147 -0
- package/src/topology/load.ts +644 -0
- package/src/topology/manifest.ts +132 -0
- package/src/topology/project-config.ts +183 -0
- package/src/topology/workspace-definition.ts +115 -0
- package/src/traverse.ts +232 -0
- package/src/types.ts +372 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Container-Kompositionsdatei → Dienstknoten und Dienstkanten.
|
|
3
|
+
*
|
|
4
|
+
* WARUM DAS HIERHER GEHOERT (Nutzerwunsch A3): Ein Monorepo ist nicht nur ein
|
|
5
|
+
* Importgraph. Wer wissen will, was bricht, wenn er etwas aendert, muss auch
|
|
6
|
+
* die Betriebsebene sehen: `frontend`, `backend`, `worker` sind Knoten einer
|
|
7
|
+
* groeberen Ebene, und ihre Startreihenfolge (`depends_on`) und ihre
|
|
8
|
+
* Erreichbarkeit (gemeinsame Netzwerke) sind Kanten, die kein Import je
|
|
9
|
+
* abbildet.
|
|
10
|
+
*
|
|
11
|
+
* ZWEI KANTENARTEN, BEWUSST GETRENNT:
|
|
12
|
+
* - `depends_on` ist GERICHTET und beantwortet „wer braucht wen zuerst";
|
|
13
|
+
* - `shared-network` ist UNGERICHTET (als zwei gegenlaeufige Kanten gefuehrt)
|
|
14
|
+
* und beantwortet „wer kann wen ueberhaupt erreichen". Zwei Dienste ohne
|
|
15
|
+
* `depends_on`, aber im selben Netzwerk, koennen einander trotzdem
|
|
16
|
+
* aufrufen — das waere sonst ein unsichtbarer Zusammenhang.
|
|
17
|
+
*
|
|
18
|
+
* IMPLIZITES `default`-NETZWERK: Compose legt fuer jede Datei ein Netzwerk
|
|
19
|
+
* `default` an, dem jeder Dienst ohne eigene `networks`-Angabe beitritt. Wer
|
|
20
|
+
* das weglaesst, meldet fuer die haeufigste aller Kompositionsdateien — eine
|
|
21
|
+
* ohne jede `networks`-Angabe — null Erreichbarkeitskanten, obwohl in
|
|
22
|
+
* Wirklichkeit jeder jeden erreicht.
|
|
23
|
+
*/
|
|
24
|
+
import { compareCodepoints, compareByKeys } from "@untangle-code/domain";
|
|
25
|
+
import { parse as parseYaml } from "yaml";
|
|
26
|
+
import { dirnameOf, joinRelative, normalizePath } from "../paths.js";
|
|
27
|
+
/** Name des impliziten Netzwerks, dem Dienste ohne eigene Angabe beitreten. */
|
|
28
|
+
export const IMPLICIT_DEFAULT_NETWORK = "default";
|
|
29
|
+
/** Dateinamen, die als Kompositionsdatei gelten (Compose-Spezifikation). */
|
|
30
|
+
export const COMPOSE_FILE_NAMES = [
|
|
31
|
+
"compose.yaml",
|
|
32
|
+
"compose.yml",
|
|
33
|
+
"docker-compose.yaml",
|
|
34
|
+
"docker-compose.yml",
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* Liest eine Kompositionsdatei.
|
|
38
|
+
*
|
|
39
|
+
* `composeFilePath` ist repo-relativ; relative Build-Kontexte werden gegen
|
|
40
|
+
* SEIN Verzeichnis aufgeloest, nicht gegen die Repositorywurzel — genau so
|
|
41
|
+
* verhaelt sich Compose auch.
|
|
42
|
+
*/
|
|
43
|
+
export function parseComposeFile(repoId, composeFilePath, text) {
|
|
44
|
+
let document;
|
|
45
|
+
try {
|
|
46
|
+
document = parseYaml(text);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
50
|
+
}
|
|
51
|
+
if (!isObject(document)) {
|
|
52
|
+
return { ok: false, error: "compose document root is not a mapping" };
|
|
53
|
+
}
|
|
54
|
+
const servicesValue = document["services"];
|
|
55
|
+
if (!isObject(servicesValue)) {
|
|
56
|
+
return { ok: false, error: 'compose document has no "services" mapping' };
|
|
57
|
+
}
|
|
58
|
+
const composeFile = normalizePath(composeFilePath);
|
|
59
|
+
const composeDir = dirnameOf(composeFile);
|
|
60
|
+
const warnings = [];
|
|
61
|
+
const services = [];
|
|
62
|
+
for (const [name, rawService] of Object.entries(servicesValue)) {
|
|
63
|
+
if (!isObject(rawService)) {
|
|
64
|
+
warnings.push(`service "${name}" in ${composeFile} is not a mapping`);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const service = {
|
|
68
|
+
name,
|
|
69
|
+
repoId,
|
|
70
|
+
composeFile,
|
|
71
|
+
dependsOn: readDependsOn(rawService, name, composeFile, warnings).names,
|
|
72
|
+
networks: readNetworks(rawService, name, composeFile, warnings),
|
|
73
|
+
};
|
|
74
|
+
const image = rawService["image"];
|
|
75
|
+
if (typeof image === "string") {
|
|
76
|
+
service.image = image;
|
|
77
|
+
}
|
|
78
|
+
const buildContext = readBuildContext(rawService, composeDir, name, composeFile, warnings);
|
|
79
|
+
if (buildContext !== undefined) {
|
|
80
|
+
service.buildContext = buildContext;
|
|
81
|
+
}
|
|
82
|
+
services.push(service);
|
|
83
|
+
}
|
|
84
|
+
services.sort((left, right) => compareCodepoints(left.name, right.name));
|
|
85
|
+
const knownNames = new Set(services.map((service) => service.name));
|
|
86
|
+
const edges = [];
|
|
87
|
+
for (const [name, rawService] of Object.entries(servicesValue)) {
|
|
88
|
+
if (!isObject(rawService))
|
|
89
|
+
continue;
|
|
90
|
+
const dependsOn = readDependsOn(rawService, name, composeFile, warnings);
|
|
91
|
+
for (const target of dependsOn.names) {
|
|
92
|
+
if (!knownNames.has(target)) {
|
|
93
|
+
// E4: eine `depends_on`-Angabe auf einen unbekannten Dienst wird
|
|
94
|
+
// gemeldet, nicht verschluckt — sie ist fast immer ein Tippfehler.
|
|
95
|
+
warnings.push(`service "${name}" in ${composeFile} depends_on unknown service "${target}"`);
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
const edge = {
|
|
99
|
+
fromService: name,
|
|
100
|
+
toService: target,
|
|
101
|
+
kind: "depends_on",
|
|
102
|
+
};
|
|
103
|
+
const condition = dependsOn.conditions[target];
|
|
104
|
+
if (condition !== undefined) {
|
|
105
|
+
edge.condition = condition;
|
|
106
|
+
}
|
|
107
|
+
edges.push(edge);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Erreichbarkeit: je Netzwerk jedes geordnete Paar verschiedener Dienste.
|
|
111
|
+
const membersByNetwork = new Map();
|
|
112
|
+
for (const service of services) {
|
|
113
|
+
for (const network of service.networks) {
|
|
114
|
+
const members = membersByNetwork.get(network) ?? [];
|
|
115
|
+
members.push(service.name);
|
|
116
|
+
membersByNetwork.set(network, members);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
for (const [network, rawMembers] of [...membersByNetwork.entries()].sort((left, right) => compareCodepoints(left[0], right[0]))) {
|
|
120
|
+
const members = [...rawMembers].sort(compareCodepoints);
|
|
121
|
+
for (const from of members) {
|
|
122
|
+
for (const to of members) {
|
|
123
|
+
if (from === to)
|
|
124
|
+
continue;
|
|
125
|
+
edges.push({ fromService: from, toService: to, kind: "shared-network", network });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
edges.sort((left, right) => compareByKeys(["kind", "fromService", "toService", "network"], sortable(left), sortable(right)));
|
|
130
|
+
return { ok: true, result: { services, edges, warnings } };
|
|
131
|
+
}
|
|
132
|
+
/** Vergleichsform: `compareByKeys` verlangt Strings, `network` ist optional. */
|
|
133
|
+
function sortable(edge) {
|
|
134
|
+
return {
|
|
135
|
+
kind: edge.kind,
|
|
136
|
+
fromService: edge.fromService,
|
|
137
|
+
toService: edge.toService,
|
|
138
|
+
network: edge.network ?? "",
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function readDependsOn(service, serviceName, composeFile, warnings) {
|
|
142
|
+
const value = service["depends_on"];
|
|
143
|
+
const conditions = {};
|
|
144
|
+
if (value === undefined) {
|
|
145
|
+
return { names: [], conditions };
|
|
146
|
+
}
|
|
147
|
+
// Kurzform: eine Liste von Dienstnamen.
|
|
148
|
+
if (Array.isArray(value)) {
|
|
149
|
+
const names = value.filter((entry) => typeof entry === "string");
|
|
150
|
+
if (names.length !== value.length) {
|
|
151
|
+
warnings.push(`depends_on of "${serviceName}" in ${composeFile} contains non-string entries`);
|
|
152
|
+
}
|
|
153
|
+
return { names: names.sort(compareCodepoints), conditions };
|
|
154
|
+
}
|
|
155
|
+
// Langform: Name → { condition: ... }.
|
|
156
|
+
if (isObject(value)) {
|
|
157
|
+
const names = [];
|
|
158
|
+
for (const [target, options] of Object.entries(value)) {
|
|
159
|
+
names.push(target);
|
|
160
|
+
if (isObject(options) && typeof options["condition"] === "string") {
|
|
161
|
+
conditions[target] = options["condition"];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return { names: names.sort(compareCodepoints), conditions };
|
|
165
|
+
}
|
|
166
|
+
warnings.push(`depends_on of "${serviceName}" in ${composeFile} is neither a list nor a mapping`);
|
|
167
|
+
return { names: [], conditions };
|
|
168
|
+
}
|
|
169
|
+
function readNetworks(service, serviceName, composeFile, warnings) {
|
|
170
|
+
const value = service["networks"];
|
|
171
|
+
if (value === undefined) {
|
|
172
|
+
return [IMPLICIT_DEFAULT_NETWORK];
|
|
173
|
+
}
|
|
174
|
+
if (Array.isArray(value)) {
|
|
175
|
+
const names = value.filter((entry) => typeof entry === "string");
|
|
176
|
+
if (names.length !== value.length) {
|
|
177
|
+
warnings.push(`networks of "${serviceName}" in ${composeFile} contains non-string entries`);
|
|
178
|
+
}
|
|
179
|
+
return names.length === 0 ? [IMPLICIT_DEFAULT_NETWORK] : names.sort(compareCodepoints);
|
|
180
|
+
}
|
|
181
|
+
if (isObject(value)) {
|
|
182
|
+
const names = Object.keys(value).sort(compareCodepoints);
|
|
183
|
+
return names.length === 0 ? [IMPLICIT_DEFAULT_NETWORK] : names;
|
|
184
|
+
}
|
|
185
|
+
warnings.push(`networks of "${serviceName}" in ${composeFile} is neither a list nor a mapping`);
|
|
186
|
+
return [IMPLICIT_DEFAULT_NETWORK];
|
|
187
|
+
}
|
|
188
|
+
function readBuildContext(service, composeDir, serviceName, composeFile, warnings) {
|
|
189
|
+
const build = service["build"];
|
|
190
|
+
const rawContext = typeof build === "string"
|
|
191
|
+
? build
|
|
192
|
+
: isObject(build) && typeof build["context"] === "string"
|
|
193
|
+
? build["context"]
|
|
194
|
+
: undefined;
|
|
195
|
+
if (rawContext === undefined) {
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
const resolved = joinRelative(composeDir, rawContext);
|
|
199
|
+
if (resolved === null) {
|
|
200
|
+
warnings.push(`build context of "${serviceName}" in ${composeFile} escapes the repository root: ${rawContext}`);
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
return resolved;
|
|
204
|
+
}
|
|
205
|
+
function isObject(value) {
|
|
206
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
207
|
+
}
|
|
208
|
+
//# sourceMappingURL=compose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/topology/compose.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toleranter JSON-Leser fuer Projektkonfigurationen.
|
|
3
|
+
*
|
|
4
|
+
* Warum nicht direkt `JSON.parse`: Projektkonfigurationen im
|
|
5
|
+
* TypeScript-Umfeld duerfen Kommentare und abschliessende Kommata enthalten
|
|
6
|
+
* (die `tsconfig.base.json` dieses Repositories tut es). `JSON.parse` wirft
|
|
7
|
+
* darauf, und ein geworfener Fehler wuerde bedeuten, dass saemtliche
|
|
8
|
+
* Pfad-Aliase eines Pakets stillschweigend fehlen — genau das, was E4
|
|
9
|
+
* verbietet. Deshalb ein Vorlauf, der Kommentare und abschliessende Kommata
|
|
10
|
+
* entfernt, und danach `JSON.parse`.
|
|
11
|
+
*
|
|
12
|
+
* Der Vorlauf ist zeichenweise und stringbewusst: ein `"http://x"` in einem
|
|
13
|
+
* Wert darf nicht als Zeilenkommentar gelesen werden.
|
|
14
|
+
*/
|
|
15
|
+
/** Entfernt Kommentare und abschliessende Kommata; laesst alles andere unveraendert. */
|
|
16
|
+
export declare function stripJsonComments(text: string): string;
|
|
17
|
+
/** Ergebnis eines toleranten JSON-Lesevorgangs. */
|
|
18
|
+
export type JsoncParseResult = {
|
|
19
|
+
ok: true;
|
|
20
|
+
value: unknown;
|
|
21
|
+
} | {
|
|
22
|
+
ok: false;
|
|
23
|
+
error: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Liest ein JSON-Dokument mit Kommentaren. Wirft NICHT: bei einem Fehlschlag
|
|
27
|
+
* kommt `{ ok: false, error }` zurueck, damit der Aufrufer einen
|
|
28
|
+
* Ledger-Eintrag mit Grund schreiben kann, statt still ein leeres Objekt zu
|
|
29
|
+
* verwenden (E4).
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseJsonc(text: string): JsoncParseResult;
|
|
32
|
+
/** Typwaechter fuer „ein JSON-Objekt, keine Liste, kein null". */
|
|
33
|
+
export declare function isJsonObject(value: unknown): value is Record<string, unknown>;
|
|
34
|
+
/** Liest ein Stringfeld eines JSON-Objekts; `undefined`, wenn es keinen String gibt. */
|
|
35
|
+
export declare function stringField(object: Record<string, unknown>, key: string): string | undefined;
|
|
36
|
+
/** Liest ein `Record<string, string>`-Feld; nicht-String-Werte werden ausgelassen. */
|
|
37
|
+
export declare function stringRecordField(object: Record<string, unknown>, key: string): Record<string, string>;
|
|
38
|
+
//# sourceMappingURL=jsonc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonc.d.ts","sourceRoot":"","sources":["../../src/topology/jsonc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,wFAAwF;AACxF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CA+CtD;AAuCD,mDAAmD;AACnD,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CAMzD;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE7E;AAED,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5F;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,MAAM,GACV,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAYxB"}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Toleranter JSON-Leser fuer Projektkonfigurationen.
|
|
3
|
+
*
|
|
4
|
+
* Warum nicht direkt `JSON.parse`: Projektkonfigurationen im
|
|
5
|
+
* TypeScript-Umfeld duerfen Kommentare und abschliessende Kommata enthalten
|
|
6
|
+
* (die `tsconfig.base.json` dieses Repositories tut es). `JSON.parse` wirft
|
|
7
|
+
* darauf, und ein geworfener Fehler wuerde bedeuten, dass saemtliche
|
|
8
|
+
* Pfad-Aliase eines Pakets stillschweigend fehlen — genau das, was E4
|
|
9
|
+
* verbietet. Deshalb ein Vorlauf, der Kommentare und abschliessende Kommata
|
|
10
|
+
* entfernt, und danach `JSON.parse`.
|
|
11
|
+
*
|
|
12
|
+
* Der Vorlauf ist zeichenweise und stringbewusst: ein `"http://x"` in einem
|
|
13
|
+
* Wert darf nicht als Zeilenkommentar gelesen werden.
|
|
14
|
+
*/
|
|
15
|
+
/** Entfernt Kommentare und abschliessende Kommata; laesst alles andere unveraendert. */
|
|
16
|
+
export function stripJsonComments(text) {
|
|
17
|
+
let result = "";
|
|
18
|
+
let index = 0;
|
|
19
|
+
let inString = false;
|
|
20
|
+
while (index < text.length) {
|
|
21
|
+
const char = text[index];
|
|
22
|
+
if (inString) {
|
|
23
|
+
result += char;
|
|
24
|
+
if (char === "\\" && index + 1 < text.length) {
|
|
25
|
+
result += text[index + 1];
|
|
26
|
+
index += 2;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (char === '"') {
|
|
30
|
+
inString = false;
|
|
31
|
+
}
|
|
32
|
+
index += 1;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (char === '"') {
|
|
36
|
+
inString = true;
|
|
37
|
+
result += char;
|
|
38
|
+
index += 1;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (char === "/" && text[index + 1] === "/") {
|
|
42
|
+
while (index < text.length && text[index] !== "\n") {
|
|
43
|
+
index += 1;
|
|
44
|
+
}
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (char === "/" && text[index + 1] === "*") {
|
|
48
|
+
index += 2;
|
|
49
|
+
while (index < text.length && !(text[index] === "*" && text[index + 1] === "/")) {
|
|
50
|
+
// Zeilenumbrueche erhalten, damit Zeilennummern in Fehlermeldungen stimmen.
|
|
51
|
+
if (text[index] === "\n") {
|
|
52
|
+
result += "\n";
|
|
53
|
+
}
|
|
54
|
+
index += 1;
|
|
55
|
+
}
|
|
56
|
+
index += 2;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
result += char;
|
|
60
|
+
index += 1;
|
|
61
|
+
}
|
|
62
|
+
return removeTrailingCommas(result);
|
|
63
|
+
}
|
|
64
|
+
function removeTrailingCommas(text) {
|
|
65
|
+
let result = "";
|
|
66
|
+
let inString = false;
|
|
67
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
68
|
+
const char = text[index];
|
|
69
|
+
if (inString) {
|
|
70
|
+
result += char;
|
|
71
|
+
if (char === "\\" && index + 1 < text.length) {
|
|
72
|
+
result += text[index + 1];
|
|
73
|
+
index += 1;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (char === '"') {
|
|
77
|
+
inString = false;
|
|
78
|
+
}
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (char === '"') {
|
|
82
|
+
inString = true;
|
|
83
|
+
result += char;
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (char === ",") {
|
|
87
|
+
let lookahead = index + 1;
|
|
88
|
+
while (lookahead < text.length && /\s/.test(text[lookahead])) {
|
|
89
|
+
lookahead += 1;
|
|
90
|
+
}
|
|
91
|
+
const next = text[lookahead];
|
|
92
|
+
if (next === "}" || next === "]") {
|
|
93
|
+
continue; // abschliessendes Komma verwerfen
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
result += char;
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Liest ein JSON-Dokument mit Kommentaren. Wirft NICHT: bei einem Fehlschlag
|
|
102
|
+
* kommt `{ ok: false, error }` zurueck, damit der Aufrufer einen
|
|
103
|
+
* Ledger-Eintrag mit Grund schreiben kann, statt still ein leeres Objekt zu
|
|
104
|
+
* verwenden (E4).
|
|
105
|
+
*/
|
|
106
|
+
export function parseJsonc(text) {
|
|
107
|
+
try {
|
|
108
|
+
return { ok: true, value: JSON.parse(stripJsonComments(text)) };
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Typwaechter fuer „ein JSON-Objekt, keine Liste, kein null". */
|
|
115
|
+
export function isJsonObject(value) {
|
|
116
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
117
|
+
}
|
|
118
|
+
/** Liest ein Stringfeld eines JSON-Objekts; `undefined`, wenn es keinen String gibt. */
|
|
119
|
+
export function stringField(object, key) {
|
|
120
|
+
const value = object[key];
|
|
121
|
+
return typeof value === "string" ? value : undefined;
|
|
122
|
+
}
|
|
123
|
+
/** Liest ein `Record<string, string>`-Feld; nicht-String-Werte werden ausgelassen. */
|
|
124
|
+
export function stringRecordField(object, key) {
|
|
125
|
+
const value = object[key];
|
|
126
|
+
if (!isJsonObject(value)) {
|
|
127
|
+
return {};
|
|
128
|
+
}
|
|
129
|
+
const result = {};
|
|
130
|
+
for (const [entryKey, entryValue] of Object.entries(value)) {
|
|
131
|
+
if (typeof entryValue === "string") {
|
|
132
|
+
result[entryKey] = entryValue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=jsonc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonc.js","sourceRoot":"","sources":["../../src/topology/jsonc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aufbau der Monorepo-Topologie aus echten Dateien (architecture.md §16.1
|
|
3
|
+
* Schritt 1 und §16.3, Nutzerwunsch A3).
|
|
4
|
+
*
|
|
5
|
+
* Dies ist die EINZIGE Stelle des Pakets, die ueberhaupt liest — und auch
|
|
6
|
+
* hier nur ueber `FileSystemPort`, nie ueber `node:fs`. Alles danach
|
|
7
|
+
* (Aufloesung, Graphbau, Traversierung, Fortschreibung) ist rein und
|
|
8
|
+
* arbeitet auf dem Ergebnis.
|
|
9
|
+
*
|
|
10
|
+
* Gelesen werden genau vier Arten von Dateien:
|
|
11
|
+
* - `pnpm-workspace.yaml` — die Liste der Teilprojekte;
|
|
12
|
+
* - `package.json` — Paketname, `exports`, Abhaengigkeiten, `workspaces`;
|
|
13
|
+
* - `tsconfig*.json` — Pfad-Aliase und die Abbildung Quelle ↔ Build-Ausgabe;
|
|
14
|
+
* - Container-Kompositionsdateien — die Dienstebene.
|
|
15
|
+
*
|
|
16
|
+
* Jede Datei, die zwar gefunden, aber nicht gelesen werden konnte, landet mit
|
|
17
|
+
* Grund im Skip-Ledger (E4). Ein unlesbares Manifest darf nie dazu fuehren,
|
|
18
|
+
* dass ein ganzes Teilprojekt lautlos aus der Topologie verschwindet.
|
|
19
|
+
*/
|
|
20
|
+
import type { FileSystemPort } from "@untangle-code/domain";
|
|
21
|
+
import type { AliasRuleV1, RepositoryInputV1, WorkspaceTopologyV1 } from "../types.js";
|
|
22
|
+
import type { ProjectConfigV1 } from "./project-config.js";
|
|
23
|
+
/** Verzeichnisnamen, die der Topologielauf nie betritt. */
|
|
24
|
+
export declare const DEFAULT_IGNORED_DIRECTORIES: readonly [".git", ".hg", ".svn", ".turbo", "__pycache__", "build", "coverage", "dist", "node_modules", "out", "target", "vendor"];
|
|
25
|
+
export interface LoadTopologyOptionsV1 {
|
|
26
|
+
workspaceId: string;
|
|
27
|
+
/** Generation, unter der das Skip-Ledger gefuehrt wird. */
|
|
28
|
+
generationId: string;
|
|
29
|
+
repositories: readonly RepositoryInputV1[];
|
|
30
|
+
/** Ueberschreibt `DEFAULT_IGNORED_DIRECTORIES`, wenn gesetzt. */
|
|
31
|
+
ignoredDirectories?: readonly string[];
|
|
32
|
+
/** Obergrenze der Verzeichnistiefe je Repository. */
|
|
33
|
+
maxDepth?: number;
|
|
34
|
+
/** Obergrenze besuchter Verzeichnisse je Repository (Budget, kein Ratschlag). */
|
|
35
|
+
maxDirectories?: number;
|
|
36
|
+
}
|
|
37
|
+
/** Eine gelesene Projektkonfiguration samt ihrem Repository. */
|
|
38
|
+
export interface ProjectConfigEntryV1 {
|
|
39
|
+
repoId: string;
|
|
40
|
+
config: ProjectConfigV1;
|
|
41
|
+
}
|
|
42
|
+
/** Ergebnis inklusive der gelesenen Projektkonfigurationen. */
|
|
43
|
+
export interface LoadedTopologyV1 {
|
|
44
|
+
topology: WorkspaceTopologyV1;
|
|
45
|
+
/** `configKey(repoId, pfad)` → ausgewertete Konfiguration. */
|
|
46
|
+
projectConfigs: Map<string, ProjectConfigEntryV1>;
|
|
47
|
+
}
|
|
48
|
+
/** Baut die Topologie eines Workspace aus den Dateien seiner Repositories. */
|
|
49
|
+
export declare function loadWorkspaceTopology(fs: FileSystemPort, options: LoadTopologyOptionsV1): Promise<LoadedTopologyV1>;
|
|
50
|
+
/** Schluessel eines Konfigurationsfundes: Repository plus repo-relativer Pfad. */
|
|
51
|
+
export declare function configKey(repoId: string, path: string): string;
|
|
52
|
+
/**
|
|
53
|
+
* Aliasregeln aller gelesenen Projektkonfigurationen, in stabiler Reihenfolge.
|
|
54
|
+
*
|
|
55
|
+
* Die Reihenfolge ist „spezifischstes Muster zuerst": ein Muster ohne `*`
|
|
56
|
+
* schlaegt eines mit `*`, und laengere Praefixe schlagen kuerzere. Genau so
|
|
57
|
+
* loest TypeScript `paths` auf; ohne diese Ordnung wuerde `@app/*` ein
|
|
58
|
+
* konkretes `@app/core` verdecken.
|
|
59
|
+
*/
|
|
60
|
+
export declare function aliasRulesFromConfigs(configs: ReadonlyMap<string, ProjectConfigEntryV1>): AliasRuleV1[];
|
|
61
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../../src/topology/load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,cAAc,EAAiC,MAAM,uBAAuB,CAAC;AAS3F,OAAO,KAAK,EACV,WAAW,EAGX,iBAAiB,EAGjB,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAKrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,mIAa9B,CAAC;AAEX,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,SAAS,iBAAiB,EAAE,CAAC;IAC3C,iEAAiE;IACjE,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,qDAAqD;IACrD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iFAAiF;IACjF,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,gEAAgE;AAChE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,eAAe,CAAC;CACzB;AAED,+DAA+D;AAC/D,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,8DAA8D;IAC9D,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;CACnD;AASD,8EAA8E;AAC9E,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,cAAc,EAClB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,gBAAgB,CAAC,CA8d3B;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE9D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,GACjD,WAAW,EAAE,CAqBf"}
|