@untangle-code/config 0.0.0-stage → 0.1.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/LICENSE +661 -0
- package/NOTICE +90 -0
- package/README.md +262 -2
- package/THIRD_PARTY_LICENSES.md +29 -0
- package/dist/chunker-budget.d.ts +58 -0
- package/dist/chunker-budget.d.ts.map +1 -0
- package/dist/chunker-budget.js +11 -0
- package/dist/chunker-budget.js.map +1 -0
- package/dist/defaults.d.ts +50 -0
- package/dist/defaults.d.ts.map +1 -0
- package/dist/defaults.js +179 -0
- package/dist/defaults.js.map +1 -0
- package/dist/discovery.d.ts +40 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +76 -0
- package/dist/discovery.js.map +1 -0
- package/dist/env.d.ts +37 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +100 -0
- package/dist/env.js.map +1 -0
- package/dist/hash.d.ts +37 -0
- package/dist/hash.d.ts.map +1 -0
- package/dist/hash.js +52 -0
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +61 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +264 -0
- package/dist/load.js.map +1 -0
- package/dist/merge.d.ts +32 -0
- package/dist/merge.d.ts.map +1 -0
- package/dist/merge.js +65 -0
- package/dist/merge.js.map +1 -0
- package/dist/migrations.d.ts +26 -0
- package/dist/migrations.d.ts.map +1 -0
- package/dist/migrations.js +40 -0
- package/dist/migrations.js.map +1 -0
- package/dist/parse.d.ts +7 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +14 -0
- package/dist/parse.js.map +1 -0
- package/dist/paths.d.ts +14 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +37 -0
- package/dist/paths.js.map +1 -0
- package/dist/schema.d.ts +5 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +19 -0
- package/dist/schema.js.map +1 -0
- package/dist/secrets.d.ts +33 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +69 -0
- package/dist/secrets.js.map +1 -0
- package/dist/types.d.ts +323 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +20 -0
- package/dist/types.js.map +1 -0
- package/dist/user-config.d.ts +13 -0
- package/dist/user-config.d.ts.map +1 -0
- package/dist/user-config.js +34 -0
- package/dist/user-config.js.map +1 -0
- package/dist/validate.d.ts +36 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +337 -0
- package/dist/validate.js.map +1 -0
- package/package.json +65 -3
- package/schemas/config-v1.json +375 -0
- package/src/chunker-budget.ts +63 -0
- package/src/defaults.ts +207 -0
- package/src/discovery.ts +95 -0
- package/src/env.ts +141 -0
- package/src/hash.ts +71 -0
- package/src/index.ts +51 -0
- package/src/load.ts +346 -0
- package/src/merge.ts +69 -0
- package/src/migrations.ts +64 -0
- package/src/parse.ts +18 -0
- package/src/paths.ts +42 -0
- package/src/schema.ts +23 -0
- package/src/secrets.ts +78 -0
- package/src/types.ts +366 -0
- package/src/user-config.ts +48 -0
- package/src/validate.ts +430 -0
package/dist/load.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { RawConfigLayer, EffectiveUntangleConfigV1 } from "./types.js";
|
|
2
|
+
import type { ConfigIssue } from "./validate.js";
|
|
3
|
+
export interface LoadConfigOptions {
|
|
4
|
+
/** Directory to start upward config-file discovery from. Defaults to `process.cwd()`. */
|
|
5
|
+
cwd?: string;
|
|
6
|
+
/** Highest-priority layer (spec.md §4.1 layer 1): explicit API/CLI arguments. */
|
|
7
|
+
explicit?: RawConfigLayer;
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
platform?: NodeJS.Platform;
|
|
10
|
+
}
|
|
11
|
+
export interface ConfigSources {
|
|
12
|
+
userConfigPath: string | undefined;
|
|
13
|
+
projectConfigPath: string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* `untangle.toml` (layer 4b) — the file `untangle init` writes. Reported
|
|
16
|
+
* separately so a diagnostic command can name the file the user actually
|
|
17
|
+
* has instead of the one it expected (WP-222).
|
|
18
|
+
*/
|
|
19
|
+
tomlConfigPath: string | undefined;
|
|
20
|
+
localConfigPath: string | undefined;
|
|
21
|
+
explicitProvided: boolean;
|
|
22
|
+
/** `UNTANGLE_*` variables from `ENV_MAPPING` that were actually set. */
|
|
23
|
+
envVarsApplied: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Fallback directory shown for diagnostics only: `.untangle.json`'s
|
|
26
|
+
* directory, else `untangle.toml`'s, else `.untangle.local.json`'s, else
|
|
27
|
+
* `cwd`. It is NOT
|
|
28
|
+
* necessarily what `repositories`/`contextArtifacts` paths were resolved
|
|
29
|
+
* against — each of those resolves against the directory of whichever
|
|
30
|
+
* layer actually defined it (spec.md §4.3; see `loadConfig`'s
|
|
31
|
+
* `originBaseDirFor`), which may be the OS user config directory or `cwd`
|
|
32
|
+
* (env/explicit layers) instead.
|
|
33
|
+
*/
|
|
34
|
+
configBaseDir: string;
|
|
35
|
+
/** Logical project root for `.untangle/config.json`; legacy layouts keep their existing base. */
|
|
36
|
+
projectRoot?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface LoadConfigResult {
|
|
39
|
+
effectiveConfig: EffectiveUntangleConfigV1;
|
|
40
|
+
warnings: ConfigIssue[];
|
|
41
|
+
errors: ConfigIssue[];
|
|
42
|
+
sources: ConfigSources;
|
|
43
|
+
/** Canonical effective-config hash; Qdrant excludes additive storage fields for legacy identity. */
|
|
44
|
+
configHash: string;
|
|
45
|
+
/** `buildWorkspaceId({ explicitId: effectiveConfig.workspaceId, configHash })` (spec.md §5.1). */
|
|
46
|
+
workspaceId: string;
|
|
47
|
+
/** `buildEmbeddingProfileId` over the derived profile (spec.md §5.7). */
|
|
48
|
+
embeddingProfileId: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Loads and resolves the effective Untangle configuration through all six
|
|
52
|
+
* layers of spec.md §4.1: explicit args > env (`UNTANGLE_*`) >
|
|
53
|
+
* `.untangle.local.json` > `.untangle.json` > OS user config > product
|
|
54
|
+
* defaults. Never throws for validation problems — see {@link ConfigIssue}
|
|
55
|
+
* and `validate.ts`'s `assertConfigValid` for the "MUST abort" behavior
|
|
56
|
+
* spec.md §4.8 requires from a caller.
|
|
57
|
+
*/
|
|
58
|
+
export declare function loadConfig(options?: LoadConfigOptions): LoadConfigResult;
|
|
59
|
+
/** Re-exported for callers that only need to check whether a discovered path exists (rare; mostly test convenience). */
|
|
60
|
+
export declare function configFileExists(path: string | undefined): boolean;
|
|
61
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,MAAM,WAAW,iBAAiB;IAChC,yFAAyF;IACzF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,aAAa;IAC5B,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,iBAAiB,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC;;;;OAIG;IACH,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,wEAAwE;IACxE,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB;;;;;;;;;OASG;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,eAAe,EAAE,yBAAyB,CAAC;IAC3C,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,aAAa,CAAC;IACvB,oGAAoG;IACpG,UAAU,EAAE,MAAM,CAAC;IACnB,kGAAkG;IAClG,WAAW,EAAE,MAAM,CAAC;IACpB,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AA2FD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA0K5E;AAED,wHAAwH;AACxH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAElE"}
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level configuration loading: discovery + six-level layering (spec.md
|
|
3
|
+
* §4.1) + path resolution (spec.md §4.3) + validation (spec.md §4.8) +
|
|
4
|
+
* canonical hashing and embedding profile derivation (architecture.md §6.3).
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
7
|
+
import { dirname } from "node:path";
|
|
8
|
+
import { buildWorkspaceId } from "@untangle-code/domain";
|
|
9
|
+
import { parse as parseToml } from "smol-toml";
|
|
10
|
+
import { PRODUCT_DEFAULT_CONFIG } from "./defaults.js";
|
|
11
|
+
import { discoverConfigFiles } from "./discovery.js";
|
|
12
|
+
import { buildEnvConfigLayer } from "./env.js";
|
|
13
|
+
import { computeConfigHash, deriveEmbeddingProfileId } from "./hash.js";
|
|
14
|
+
import { mergeConfigLayers } from "./merge.js";
|
|
15
|
+
import { migrateConfig } from "./migrations.js";
|
|
16
|
+
import { resolveConfigPath } from "./paths.js";
|
|
17
|
+
import { resolveUserConfigPath } from "./user-config.js";
|
|
18
|
+
import { validateEffectiveConfig } from "./validate.js";
|
|
19
|
+
function readJsonConfigFile(path) {
|
|
20
|
+
let text;
|
|
21
|
+
try {
|
|
22
|
+
text = readFileSync(path, "utf8");
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
return {
|
|
26
|
+
layer: {},
|
|
27
|
+
error: {
|
|
28
|
+
code: "CONFIG_INVALID",
|
|
29
|
+
message: `failed to read config file "${path}": ${String(error)}`,
|
|
30
|
+
path,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
let parsed;
|
|
35
|
+
try {
|
|
36
|
+
parsed = JSON.parse(text);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
return {
|
|
40
|
+
layer: {},
|
|
41
|
+
error: {
|
|
42
|
+
code: "CONFIG_INVALID",
|
|
43
|
+
message: `"${path}" is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
44
|
+
path,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
49
|
+
return {
|
|
50
|
+
layer: {},
|
|
51
|
+
error: { code: "CONFIG_INVALID", message: `"${path}" must contain a JSON object`, path },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
const migrated = migrateConfig(parsed);
|
|
55
|
+
return { layer: migrated.config, error: undefined };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Reads `untangle.toml` into the same raw layer shape a JSON config produces.
|
|
59
|
+
*
|
|
60
|
+
* The TOML file `untangle init` writes carries the SAME keys as
|
|
61
|
+
* `.untangle.json` — `schemaVersion`, `repositories`, `qdrant`, `embeddings`
|
|
62
|
+
* and so on — so it needs no separate schema, only a separate parser. It
|
|
63
|
+
* runs through `migrateConfig` and the ordinary validation like every other
|
|
64
|
+
* layer; a typo in it is reported the same way, in the same list, against
|
|
65
|
+
* the same paths.
|
|
66
|
+
*/
|
|
67
|
+
function readTomlConfigFile(path) {
|
|
68
|
+
let text;
|
|
69
|
+
try {
|
|
70
|
+
text = readFileSync(path, "utf8");
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
return {
|
|
74
|
+
layer: {},
|
|
75
|
+
error: {
|
|
76
|
+
code: "CONFIG_INVALID",
|
|
77
|
+
message: `failed to read config file "${path}": ${String(error)}`,
|
|
78
|
+
path,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
let parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = parseToml(text);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
return {
|
|
88
|
+
layer: {},
|
|
89
|
+
error: {
|
|
90
|
+
code: "CONFIG_INVALID",
|
|
91
|
+
message: `"${path}" is not valid TOML: ${error instanceof Error ? error.message : String(error)}`,
|
|
92
|
+
path,
|
|
93
|
+
},
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
97
|
+
return {
|
|
98
|
+
layer: {},
|
|
99
|
+
error: { code: "CONFIG_INVALID", message: `"${path}" must contain a TOML table`, path },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const migrated = migrateConfig(parsed);
|
|
103
|
+
return { layer: migrated.config, error: undefined };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Loads and resolves the effective Untangle configuration through all six
|
|
107
|
+
* layers of spec.md §4.1: explicit args > env (`UNTANGLE_*`) >
|
|
108
|
+
* `.untangle.local.json` > `.untangle.json` > OS user config > product
|
|
109
|
+
* defaults. Never throws for validation problems — see {@link ConfigIssue}
|
|
110
|
+
* and `validate.ts`'s `assertConfigValid` for the "MUST abort" behavior
|
|
111
|
+
* spec.md §4.8 requires from a caller.
|
|
112
|
+
*/
|
|
113
|
+
export function loadConfig(options = {}) {
|
|
114
|
+
const cwd = options.cwd ?? process.cwd();
|
|
115
|
+
const env = options.env ?? process.env;
|
|
116
|
+
const platform = options.platform ?? process.platform;
|
|
117
|
+
const { projectConfigPath, tomlConfigPath, localConfigPath, projectRoot } = discoverConfigFiles(cwd);
|
|
118
|
+
const userConfigPath = resolveUserConfigPath(env, platform);
|
|
119
|
+
const errors = [];
|
|
120
|
+
const userLayerOutcome = userConfigPath
|
|
121
|
+
? readJsonConfigFile(userConfigPath)
|
|
122
|
+
: { layer: {}, error: undefined };
|
|
123
|
+
const projectLayerOutcome = projectConfigPath
|
|
124
|
+
? readJsonConfigFile(projectConfigPath)
|
|
125
|
+
: { layer: {}, error: undefined };
|
|
126
|
+
const tomlLayerOutcome = tomlConfigPath
|
|
127
|
+
? readTomlConfigFile(tomlConfigPath)
|
|
128
|
+
: { layer: {}, error: undefined };
|
|
129
|
+
const localLayerOutcome = localConfigPath
|
|
130
|
+
? readJsonConfigFile(localConfigPath)
|
|
131
|
+
: { layer: {}, error: undefined };
|
|
132
|
+
for (const outcome of [
|
|
133
|
+
userLayerOutcome,
|
|
134
|
+
tomlLayerOutcome,
|
|
135
|
+
projectLayerOutcome,
|
|
136
|
+
localLayerOutcome,
|
|
137
|
+
]) {
|
|
138
|
+
if (outcome.error) {
|
|
139
|
+
errors.push(outcome.error);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const envLayerResult = buildEnvConfigLayer(env);
|
|
143
|
+
for (const parseError of envLayerResult.parseErrors) {
|
|
144
|
+
errors.push({
|
|
145
|
+
code: "CONFIG_INVALID",
|
|
146
|
+
message: `environment variable ${parseError.env}: ${parseError.message}`,
|
|
147
|
+
path: parseError.env,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const explicitLayer = options.explicit ?? {};
|
|
151
|
+
// Each layer's OWN directory (spec.md §4.3: a path resolves relative to
|
|
152
|
+
// the config file that declared it). Layers with no backing file (product
|
|
153
|
+
// defaults, the env layer, explicit args) have no directory of their own,
|
|
154
|
+
// so they fall back to `cwd` — the directory the caller is running from.
|
|
155
|
+
const namedLayers = [
|
|
156
|
+
{ layer: PRODUCT_DEFAULT_CONFIG, baseDir: cwd },
|
|
157
|
+
{ layer: userLayerOutcome.layer, baseDir: userConfigPath ? dirname(userConfigPath) : cwd },
|
|
158
|
+
// Layer 4b, directly beneath `.untangle.json`: `untangle.toml`. Where
|
|
159
|
+
// both exist the JSON file wins — and `warnings` says so out loud, so a
|
|
160
|
+
// user never wonders why an edit had no effect (WP-222).
|
|
161
|
+
{ layer: tomlLayerOutcome.layer, baseDir: tomlConfigPath ? dirname(tomlConfigPath) : cwd },
|
|
162
|
+
{
|
|
163
|
+
layer: projectLayerOutcome.layer,
|
|
164
|
+
baseDir: projectConfigPath ? dirname(projectConfigPath) : cwd,
|
|
165
|
+
},
|
|
166
|
+
{ layer: localLayerOutcome.layer, baseDir: localConfigPath ? dirname(localConfigPath) : cwd },
|
|
167
|
+
{ layer: envLayerResult.layer, baseDir: cwd },
|
|
168
|
+
{ layer: explicitLayer, baseDir: cwd },
|
|
169
|
+
];
|
|
170
|
+
// Preserve existing Qdrant projects without letting the product-default
|
|
171
|
+
// qdrant section choose a backend for new projects. This compatibility
|
|
172
|
+
// default sits below every user layer: an explicit storage.backend at any
|
|
173
|
+
// priority overrides it, while storage.path alone never migrates an index.
|
|
174
|
+
const configuredLayers = namedLayers.slice(1).map((named) => named.layer);
|
|
175
|
+
const legacyStorageDefault = configuredLayers.some((layer) => layer.qdrant !== undefined)
|
|
176
|
+
? { storage: { backend: "qdrant" } }
|
|
177
|
+
: {};
|
|
178
|
+
const merged = mergeConfigLayers([
|
|
179
|
+
PRODUCT_DEFAULT_CONFIG,
|
|
180
|
+
legacyStorageDefault,
|
|
181
|
+
...configuredLayers,
|
|
182
|
+
]);
|
|
183
|
+
const configBaseDir = projectConfigPath
|
|
184
|
+
? dirname(projectConfigPath)
|
|
185
|
+
: tomlConfigPath
|
|
186
|
+
? dirname(tomlConfigPath)
|
|
187
|
+
: localConfigPath
|
|
188
|
+
? dirname(localConfigPath)
|
|
189
|
+
: cwd;
|
|
190
|
+
/**
|
|
191
|
+
* `mergeConfigLayers` REPLACES arrays wholesale rather than concatenating
|
|
192
|
+
* them (merge.ts) — so the final `repositories`/`contextArtifacts` array
|
|
193
|
+
* in `merged` originates entirely from ONE layer: the highest-priority
|
|
194
|
+
* layer that defined it. Its entries' `path` fields MUST resolve against
|
|
195
|
+
* THAT layer's own directory (spec.md §4.3), not a single global
|
|
196
|
+
* `configBaseDir` computed after the merge — otherwise a repository
|
|
197
|
+
* defined in the OS user config (or via an env/explicit layer) silently
|
|
198
|
+
* loses its origin and resolves against the wrong directory. Walking
|
|
199
|
+
* `namedLayers` highest-priority-first and taking the first one that set
|
|
200
|
+
* `key` recovers exactly the layer the merge itself used.
|
|
201
|
+
*/
|
|
202
|
+
function originBaseDirFor(key) {
|
|
203
|
+
for (let i = namedLayers.length - 1; i >= 0; i -= 1) {
|
|
204
|
+
const candidate = namedLayers[i];
|
|
205
|
+
if (candidate && Array.isArray(candidate.layer[key])) {
|
|
206
|
+
return candidate.baseDir;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return cwd;
|
|
210
|
+
}
|
|
211
|
+
if (Array.isArray(merged["repositories"])) {
|
|
212
|
+
const baseDir = originBaseDirFor("repositories");
|
|
213
|
+
merged["repositories"] = merged["repositories"].map((repo) => ({
|
|
214
|
+
...repo,
|
|
215
|
+
path: resolveConfigPath(repo.path, baseDir),
|
|
216
|
+
}));
|
|
217
|
+
}
|
|
218
|
+
if (Array.isArray(merged["contextArtifacts"])) {
|
|
219
|
+
const baseDir = originBaseDirFor("contextArtifacts");
|
|
220
|
+
merged["contextArtifacts"] = merged["contextArtifacts"].map((artifact) => ({
|
|
221
|
+
...artifact,
|
|
222
|
+
path: resolveConfigPath(artifact.path, baseDir),
|
|
223
|
+
}));
|
|
224
|
+
}
|
|
225
|
+
const { errors: validationErrors, warnings } = validateEffectiveConfig(merged);
|
|
226
|
+
errors.push(...validationErrors);
|
|
227
|
+
if (projectConfigPath !== undefined && tomlConfigPath !== undefined) {
|
|
228
|
+
warnings.push({
|
|
229
|
+
code: "CONFIG_DUPLICATE_PROJECT_FILE",
|
|
230
|
+
message: `both "${projectConfigPath}" and "${tomlConfigPath}" exist; ` +
|
|
231
|
+
`"${projectConfigPath}" wins for every key it sets`,
|
|
232
|
+
path: "(project config)",
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
const effectiveConfig = merged;
|
|
236
|
+
const configHash = computeConfigHash(effectiveConfig);
|
|
237
|
+
const workspaceId = buildWorkspaceId(effectiveConfig.workspaceId === undefined
|
|
238
|
+
? { configHash }
|
|
239
|
+
: { explicitId: effectiveConfig.workspaceId, configHash });
|
|
240
|
+
const embeddingProfileId = deriveEmbeddingProfileId(effectiveConfig);
|
|
241
|
+
return {
|
|
242
|
+
effectiveConfig,
|
|
243
|
+
warnings,
|
|
244
|
+
errors,
|
|
245
|
+
sources: {
|
|
246
|
+
userConfigPath,
|
|
247
|
+
projectConfigPath,
|
|
248
|
+
tomlConfigPath,
|
|
249
|
+
localConfigPath,
|
|
250
|
+
explicitProvided: options.explicit !== undefined,
|
|
251
|
+
envVarsApplied: Object.keys(env).filter((key) => key.startsWith("UNTANGLE_") && env[key] !== undefined),
|
|
252
|
+
configBaseDir,
|
|
253
|
+
...(projectRoot === undefined ? {} : { projectRoot }),
|
|
254
|
+
},
|
|
255
|
+
configHash,
|
|
256
|
+
workspaceId,
|
|
257
|
+
embeddingProfileId,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/** Re-exported for callers that only need to check whether a discovered path exists (rare; mostly test convenience). */
|
|
261
|
+
export function configFileExists(path) {
|
|
262
|
+
return path !== undefined && existsSync(path);
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=load.js.map
|
package/dist/load.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"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"}
|
package/dist/merge.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge for the layering pipeline (spec.md §4.1).
|
|
3
|
+
*
|
|
4
|
+
* Array semantics: arrays REPLACE, they never concatenate. A layer with
|
|
5
|
+
* `index.extraExtensions: [".proto"]` fully replaces a lower layer's array —
|
|
6
|
+
* two layers are never spliced together, because there is no reasonable way
|
|
7
|
+
* to know whether a higher layer meant to add to or reset a list (e.g.
|
|
8
|
+
* `exclude` globs), and silent concatenation would make higher-priority
|
|
9
|
+
* layers unable to shrink a list at all.
|
|
10
|
+
*
|
|
11
|
+
* Relevance-policy bindings are another deliberate replacement boundary:
|
|
12
|
+
* entries below `search.relevancePolicies.<profileId>` are calibrated,
|
|
13
|
+
* corpus-bound units. Merging a new workspace/collection with thresholds
|
|
14
|
+
* inherited from a lower layer would silently apply one corpus's policy to
|
|
15
|
+
* another corpus.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Merges `override` onto `base`. Plain objects merge key by key (recursively);
|
|
19
|
+
* arrays, primitives, `null` and any non-plain object (e.g. would-be class
|
|
20
|
+
* instances) from `override` replace the corresponding value in `base`
|
|
21
|
+
* wholesale. `undefined` values in `override` are treated as "not set" and do
|
|
22
|
+
* not overwrite a present `base` value — this lets a layer omit a field
|
|
23
|
+
* without needing to know the value from lower layers.
|
|
24
|
+
*/
|
|
25
|
+
export declare function deepMergeConfig<T>(base: T, override: unknown): T;
|
|
26
|
+
/**
|
|
27
|
+
* Merges layers left to right — later layers win — mirroring spec.md §4.1's
|
|
28
|
+
* priority order when called with `[productDefaults, userConfig, projectConfig,
|
|
29
|
+
* localConfig, envLayer, explicitArgs]` (lowest priority first).
|
|
30
|
+
*/
|
|
31
|
+
export declare function mergeConfigLayers<T>(layers: readonly unknown[]): T;
|
|
32
|
+
//# sourceMappingURL=merge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAMH;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,GAAG,CAAC,CAEhE;AA8BD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,SAAS,OAAO,EAAE,GAAG,CAAC,CAElE"}
|
package/dist/merge.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge for the layering pipeline (spec.md §4.1).
|
|
3
|
+
*
|
|
4
|
+
* Array semantics: arrays REPLACE, they never concatenate. A layer with
|
|
5
|
+
* `index.extraExtensions: [".proto"]` fully replaces a lower layer's array —
|
|
6
|
+
* two layers are never spliced together, because there is no reasonable way
|
|
7
|
+
* to know whether a higher layer meant to add to or reset a list (e.g.
|
|
8
|
+
* `exclude` globs), and silent concatenation would make higher-priority
|
|
9
|
+
* layers unable to shrink a list at all.
|
|
10
|
+
*
|
|
11
|
+
* Relevance-policy bindings are another deliberate replacement boundary:
|
|
12
|
+
* entries below `search.relevancePolicies.<profileId>` are calibrated,
|
|
13
|
+
* corpus-bound units. Merging a new workspace/collection with thresholds
|
|
14
|
+
* inherited from a lower layer would silently apply one corpus's policy to
|
|
15
|
+
* another corpus.
|
|
16
|
+
*/
|
|
17
|
+
function isPlainObject(value) {
|
|
18
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Merges `override` onto `base`. Plain objects merge key by key (recursively);
|
|
22
|
+
* arrays, primitives, `null` and any non-plain object (e.g. would-be class
|
|
23
|
+
* instances) from `override` replace the corresponding value in `base`
|
|
24
|
+
* wholesale. `undefined` values in `override` are treated as "not set" and do
|
|
25
|
+
* not overwrite a present `base` value — this lets a layer omit a field
|
|
26
|
+
* without needing to know the value from lower layers.
|
|
27
|
+
*/
|
|
28
|
+
export function deepMergeConfig(base, override) {
|
|
29
|
+
return deepMergeConfigAtPath(base, override, []);
|
|
30
|
+
}
|
|
31
|
+
function isAtomicReplacementPath(path) {
|
|
32
|
+
return path.length === 3 && path[0] === "search" && path[1] === "relevancePolicies";
|
|
33
|
+
}
|
|
34
|
+
function deepMergeConfigAtPath(base, override, path) {
|
|
35
|
+
if (override === undefined) {
|
|
36
|
+
return base;
|
|
37
|
+
}
|
|
38
|
+
if (isAtomicReplacementPath(path)) {
|
|
39
|
+
return override;
|
|
40
|
+
}
|
|
41
|
+
if (!isPlainObject(base) || !isPlainObject(override)) {
|
|
42
|
+
return override;
|
|
43
|
+
}
|
|
44
|
+
const result = { ...base };
|
|
45
|
+
for (const [key, value] of Object.entries(override)) {
|
|
46
|
+
if (value === undefined) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const baseValue = base[key];
|
|
50
|
+
result[key] =
|
|
51
|
+
isPlainObject(baseValue) && isPlainObject(value)
|
|
52
|
+
? deepMergeConfigAtPath(baseValue, value, [...path, key])
|
|
53
|
+
: value;
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Merges layers left to right — later layers win — mirroring spec.md §4.1's
|
|
59
|
+
* priority order when called with `[productDefaults, userConfig, projectConfig,
|
|
60
|
+
* localConfig, envLayer, explicitArgs]` (lowest priority first).
|
|
61
|
+
*/
|
|
62
|
+
export function mergeConfigLayers(layers) {
|
|
63
|
+
return layers.reduce((acc, layer) => deepMergeConfig(acc, layer), {});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAI,IAAO,EAAE,QAAiB;IAC3D,OAAO,qBAAqB,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,SAAS,uBAAuB,CAAC,IAAuB;IACtD,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,mBAAmB,CAAC;AACtF,CAAC;AAED,SAAS,qBAAqB,CAAI,IAAO,EAAE,QAAiB,EAAE,IAAuB;IACnF,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,OAAO,QAAa,CAAC;IACvB,CAAC;IACD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,OAAO,QAAa,CAAC;IACvB,CAAC;IACD,MAAM,MAAM,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;IACpD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,SAAS;QACX,CAAC;QACD,MAAM,SAAS,GAAI,IAAgC,CAAC,GAAG,CAAC,CAAC;QACzD,MAAM,CAAC,GAAG,CAAC;YACT,aAAa,CAAC,SAAS,CAAC,IAAI,aAAa,CAAC,KAAK,CAAC;gBAC9C,CAAC,CAAC,qBAAqB,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,CAAC;gBACzD,CAAC,CAAC,KAAK,CAAC;IACd,CAAC;IACD,OAAO,MAAW,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAI,MAA0B;IAC7D,OAAO,MAAM,CAAC,MAAM,CAAU,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAM,CAAC;AACtF,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface MigrationStep {
|
|
2
|
+
fromVersion: number;
|
|
3
|
+
toVersion: number;
|
|
4
|
+
/** Pure transform: old raw config shape in, new raw config shape out. */
|
|
5
|
+
migrate: (raw: Record<string, unknown>) => Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
/** Registers a migration step keyed by its `fromVersion`. Overwrites a step already registered for that version. */
|
|
8
|
+
export declare function registerMigration(step: MigrationStep): void;
|
|
9
|
+
/** Removes every registered migration step (test isolation). */
|
|
10
|
+
export declare function clearMigrations(): void;
|
|
11
|
+
export interface MigrationResult {
|
|
12
|
+
config: Record<string, unknown>;
|
|
13
|
+
finalVersion: number;
|
|
14
|
+
/** Versions the config was migrated through, e.g. `[1, 2]` for a single `1 -> 2` hop. */
|
|
15
|
+
appliedFrom: number[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Applies registered migration steps in sequence starting from
|
|
19
|
+
* `raw.schemaVersion` (defaulting to `1` when absent) until
|
|
20
|
+
* `targetVersion` (default: {@link CURRENT_SCHEMA_VERSION}) is reached.
|
|
21
|
+
*
|
|
22
|
+
* A config already at `targetVersion` is returned unchanged — the identity
|
|
23
|
+
* migration — without requiring any step to be registered for it.
|
|
24
|
+
*/
|
|
25
|
+
export declare function migrateConfig(raw: Record<string, unknown>, targetVersion?: number): MigrationResult;
|
|
26
|
+
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,yEAAyE;IACzE,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpE;AAID,oHAAoH;AACpH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAE3D;AAED,gEAAgE;AAChE,wBAAgB,eAAe,IAAI,IAAI,CAEtC;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,yFAAyF;IACzF,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,aAAa,GAAE,MAA+B,GAC7C,eAAe,CAkBjB"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration scaffold for future `schemaVersion` jumps (architecture.md §6.3:
|
|
3
|
+
* "Migration älterer Configversionen"). spec.md is at `schemaVersion: 1`
|
|
4
|
+
* today; this registry lets a future WP register a `1 -> 2` step (etc.)
|
|
5
|
+
* without `loadConfig` needing to change.
|
|
6
|
+
*/
|
|
7
|
+
import { CURRENT_SCHEMA_VERSION } from "./defaults.js";
|
|
8
|
+
const registry = new Map();
|
|
9
|
+
/** Registers a migration step keyed by its `fromVersion`. Overwrites a step already registered for that version. */
|
|
10
|
+
export function registerMigration(step) {
|
|
11
|
+
registry.set(step.fromVersion, step);
|
|
12
|
+
}
|
|
13
|
+
/** Removes every registered migration step (test isolation). */
|
|
14
|
+
export function clearMigrations() {
|
|
15
|
+
registry.clear();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Applies registered migration steps in sequence starting from
|
|
19
|
+
* `raw.schemaVersion` (defaulting to `1` when absent) until
|
|
20
|
+
* `targetVersion` (default: {@link CURRENT_SCHEMA_VERSION}) is reached.
|
|
21
|
+
*
|
|
22
|
+
* A config already at `targetVersion` is returned unchanged — the identity
|
|
23
|
+
* migration — without requiring any step to be registered for it.
|
|
24
|
+
*/
|
|
25
|
+
export function migrateConfig(raw, targetVersion = CURRENT_SCHEMA_VERSION) {
|
|
26
|
+
let current = raw;
|
|
27
|
+
let version = typeof raw["schemaVersion"] === "number" ? raw["schemaVersion"] : 1;
|
|
28
|
+
const appliedFrom = [version];
|
|
29
|
+
while (version < targetVersion) {
|
|
30
|
+
const step = registry.get(version);
|
|
31
|
+
if (step === undefined) {
|
|
32
|
+
throw new Error(`no migration registered from schemaVersion ${version} towards ${targetVersion}`);
|
|
33
|
+
}
|
|
34
|
+
current = { ...step.migrate(current), schemaVersion: step.toVersion };
|
|
35
|
+
version = step.toVersion;
|
|
36
|
+
appliedFrom.push(version);
|
|
37
|
+
}
|
|
38
|
+
return { config: current, finalVersion: version, appliedFrom };
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=migrations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrations.js","sourceRoot":"","sources":["../src/migrations.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AASvD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAyB,CAAC;AAElD,oHAAoH;AACpH,MAAM,UAAU,iBAAiB,CAAC,IAAmB;IACnD,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;AACvC,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,eAAe;IAC7B,QAAQ,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC;AASD;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,GAA4B,EAC5B,gBAAwB,sBAAsB;IAE9C,IAAI,OAAO,GAA4B,GAAG,CAAC;IAC3C,IAAI,OAAO,GAAG,OAAO,GAAG,CAAC,eAAe,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClF,MAAM,WAAW,GAAa,CAAC,OAAO,CAAC,CAAC;IAExC,OAAO,OAAO,GAAG,aAAa,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,8CAA8C,OAAO,YAAY,aAAa,EAAE,CACjF,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QACtE,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QACzB,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AACjE,CAAC"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { RawConfigLayer } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parses a config document without filesystem access, defaults or environment
|
|
4
|
+
* overrides. Syntax and non-object input errors propagate to the caller.
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseConfigText(text: string, format: "json" | "toml"): RawConfigLayer;
|
|
7
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,cAAc,CAQrF"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { parse as parseToml } from "smol-toml";
|
|
2
|
+
import { migrateConfig } from "./migrations.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parses a config document without filesystem access, defaults or environment
|
|
5
|
+
* overrides. Syntax and non-object input errors propagate to the caller.
|
|
6
|
+
*/
|
|
7
|
+
export function parseConfigText(text, format) {
|
|
8
|
+
const parsed = format === "json" ? JSON.parse(text) : parseToml(text);
|
|
9
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
10
|
+
throw new TypeError(`Configuration must contain a ${format === "json" ? "JSON object" : "TOML table"}.`);
|
|
11
|
+
}
|
|
12
|
+
return migrateConfig(parsed).config;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAE/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY,EAAE,MAAuB;IACnE,MAAM,MAAM,GAAY,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAC/E,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,SAAS,CACjB,gCAAgC,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,GAAG,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAAC,MAAiC,CAAC,CAAC,MAAwB,CAAC;AACnF,CAAC"}
|
package/dist/paths.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves `candidatePath` against `configFileDir` (the directory containing
|
|
3
|
+
* the config file that declared it). An already-absolute `candidatePath` is
|
|
4
|
+
* returned canonicalized as-is (spec.md §4.3 allows absolute paths).
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveConfigPath(candidatePath: string, configFileDir: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Resolves every `RepositoryConfig.path` in `repositories` relative to
|
|
9
|
+
* `configFileDir`, returning new objects (inputs are not mutated).
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveRepositoryPaths<T extends {
|
|
12
|
+
path: string;
|
|
13
|
+
}>(repositories: readonly T[], configFileDir: string): T[];
|
|
14
|
+
//# sourceMappingURL=paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,MAAM,CAKtF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAC/D,YAAY,EAAE,SAAS,CAAC,EAAE,EAC1B,aAAa,EAAE,MAAM,GACpB,CAAC,EAAE,CAKL"}
|
package/dist/paths.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path resolution relative to the configuration file (spec.md §4.3:
|
|
3
|
+
* "Pfade MÜSSEN relativ zur Konfigurationsdatei oder absolut auflösbar
|
|
4
|
+
* sein."). Results are canonical: absolute, `/`-separated, no trailing slash,
|
|
5
|
+
* no `.`/`..` segments.
|
|
6
|
+
*/
|
|
7
|
+
import { isAbsolute, resolve, sep } from "node:path";
|
|
8
|
+
/** Canonicalizes a resolved absolute filesystem path to forward slashes, no trailing slash. */
|
|
9
|
+
function toCanonicalAbsolute(absolutePath) {
|
|
10
|
+
const normalized = absolutePath.split(sep).join("/");
|
|
11
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
12
|
+
return normalized.slice(0, -1);
|
|
13
|
+
}
|
|
14
|
+
return normalized;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Resolves `candidatePath` against `configFileDir` (the directory containing
|
|
18
|
+
* the config file that declared it). An already-absolute `candidatePath` is
|
|
19
|
+
* returned canonicalized as-is (spec.md §4.3 allows absolute paths).
|
|
20
|
+
*/
|
|
21
|
+
export function resolveConfigPath(candidatePath, configFileDir) {
|
|
22
|
+
const absolute = isAbsolute(candidatePath)
|
|
23
|
+
? candidatePath
|
|
24
|
+
: resolve(configFileDir, candidatePath);
|
|
25
|
+
return toCanonicalAbsolute(absolute);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolves every `RepositoryConfig.path` in `repositories` relative to
|
|
29
|
+
* `configFileDir`, returning new objects (inputs are not mutated).
|
|
30
|
+
*/
|
|
31
|
+
export function resolveRepositoryPaths(repositories, configFileDir) {
|
|
32
|
+
return repositories.map((repo) => ({
|
|
33
|
+
...repo,
|
|
34
|
+
path: resolveConfigPath(repo.path, configFileDir),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../src/paths.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAErD,+FAA+F;AAC/F,SAAS,mBAAmB,CAAC,YAAoB;IAC/C,MAAM,UAAU,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACtD,OAAO,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,aAAqB,EAAE,aAAqB;IAC5E,MAAM,QAAQ,GAAG,UAAU,CAAC,aAAa,CAAC;QACxC,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IAC1C,OAAO,mBAAmB,CAAC,QAAQ,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,YAA0B,EAC1B,aAAqB;IAErB,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjC,GAAG,IAAI;QACP,IAAI,EAAE,iBAAiB,CAAC,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC;KAClD,CAAC,CAAC,CAAC;AACN,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Absolute filesystem path to the hand-authored JSON Schema (Draft 2020-12) for `UntangleConfigV1`. */
|
|
2
|
+
export declare const CONFIG_SCHEMA_PATH: string;
|
|
3
|
+
/** The parsed JSON Schema object itself, read once at module load. */
|
|
4
|
+
export declare const CONFIG_SCHEMA: Record<string, unknown>;
|
|
5
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAgBA,wGAAwG;AACxG,eAAO,MAAM,kBAAkB,EAAE,MAAiC,CAAC;AAEnE,sEAAsE;AACtE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAEtB,CAAC"}
|