@autometa/config 0.1.27 → 1.0.0-rc.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/dist/index.js CHANGED
@@ -1,172 +1,790 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
9
- };
10
- var __copyProps = (to, from, except, desc) => {
11
- if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
- }
16
- return to;
17
- };
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var __accessCheck = (obj, member, msg) => {
20
- if (!member.has(obj))
21
- throw TypeError("Cannot " + msg);
22
- };
23
- var __privateGet = (obj, member, getter) => {
24
- __accessCheck(obj, member, "read from private field");
25
- return getter ? getter.call(obj) : member.get(obj);
26
- };
27
- var __privateAdd = (obj, member, value) => {
28
- if (member.has(obj))
29
- throw TypeError("Cannot add the same private member more than once");
30
- member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
31
- };
32
- var __privateSet = (obj, member, value, setter) => {
33
- __accessCheck(obj, member, "write to private field");
34
- setter ? setter.call(obj, value) : member.set(obj, value);
35
- return value;
36
- };
37
-
38
- // src/index.ts
39
- var src_exports = {};
40
- __export(src_exports, {
41
- Config: () => Config,
42
- EnvironmentReader: () => EnvironmentReader,
43
- defineConfig: () => defineConfig
44
- });
45
- module.exports = __toCommonJS(src_exports);
1
+ import { AutomationError } from '@autometa/errors';
2
+ import { posix } from 'node:path';
3
+ import { z } from 'zod';
46
4
 
47
- // src/config-object.ts
48
- var import_errors = require("@autometa/errors");
5
+ // src/config.ts
49
6
 
50
- // src/environment-reader.ts
51
- var _envVar, _factory, _literal;
52
- var EnvironmentReader = class {
7
+ // src/environment-selector.ts
8
+ var sanitize = (value) => {
9
+ if (value == null) {
10
+ return void 0;
11
+ }
12
+ const trimmed = value.trim();
13
+ return trimmed.length === 0 ? void 0 : trimmed;
14
+ };
15
+ var EnvironmentSelector = class {
53
16
  constructor() {
54
- __privateAdd(this, _envVar, void 0);
55
- __privateAdd(this, _factory, void 0);
56
- __privateAdd(this, _literal, void 0);
57
- }
58
- /**
59
- * Returns the configuration object for the selected
60
- * environment by weighting.
61
- *
62
- * By priority the environment is selected by:
63
- * 1. Literal
64
- * 2. Environment Variable
65
- * 3. Factory
66
- */
67
- get value() {
68
- if (__privateGet(this, _literal)) {
69
- return __privateGet(this, _literal);
70
- }
71
- if (__privateGet(this, _envVar)) {
72
- const value = process.env[__privateGet(this, _envVar)];
73
- if (value) {
74
- return value;
75
- }
76
- }
77
- if (__privateGet(this, _factory)) {
78
- return __privateGet(this, _factory).call(this);
79
- }
17
+ this.detectors = [];
18
+ this.fallback = "default";
19
+ }
20
+ byLiteral(name) {
21
+ this.detectors.push(() => sanitize(name));
22
+ return this;
80
23
  }
81
- byEnvironmentVariable(envVar) {
82
- __privateSet(this, _envVar, envVar);
24
+ byEnvironmentVariable(variable) {
25
+ this.detectors.push(() => sanitize(process.env[variable]));
83
26
  return this;
84
27
  }
85
28
  byFactory(factory) {
86
- __privateSet(this, _factory, factory);
29
+ this.detectors.push(() => sanitize(factory()));
87
30
  return this;
88
31
  }
89
- byLiteral(literal) {
90
- __privateSet(this, _literal, literal);
32
+ defaultTo(name) {
33
+ const sanitized = sanitize(name);
34
+ if (!sanitized) {
35
+ throw new Error("Default environment name must be a non-empty string");
36
+ }
37
+ this.fallback = sanitized;
91
38
  return this;
92
39
  }
40
+ resolve() {
41
+ for (const detector of this.detectors) {
42
+ const detected = detector();
43
+ if (detected) {
44
+ return detected;
45
+ }
46
+ }
47
+ return this.fallback;
48
+ }
93
49
  };
94
- _envVar = new WeakMap();
95
- _factory = new WeakMap();
96
- _literal = new WeakMap();
50
+ var TimeUnitSchema = z.enum(["ms", "s", "m", "h"]);
51
+ var TimeoutSchema = z.union([
52
+ z.number().nonnegative(),
53
+ z.tuple([z.number().nonnegative(), TimeUnitSchema]),
54
+ z.object({
55
+ value: z.number().nonnegative(),
56
+ unit: TimeUnitSchema.optional()
57
+ })
58
+ ]).optional();
59
+ var RunnerSchema = z.union([z.literal("jest"), z.literal("vitest"), z.literal("playwright")]);
60
+ var TagFilterSchema = z.string().refine(
61
+ (value) => value.startsWith("@") || value.startsWith("not @"),
62
+ "tag filter must start with `@` or `not @`"
63
+ ).optional();
64
+ var TestSchema = z.object({
65
+ timeout: TimeoutSchema,
66
+ tagFilter: TagFilterSchema,
67
+ groupLogging: z.boolean().optional()
68
+ }).partial();
69
+ var ShimSchema = z.object({
70
+ errorCause: z.boolean().optional()
71
+ });
72
+ var PathSchema = z.array(z.string());
73
+ var RootSchema = z.object({
74
+ features: PathSchema,
75
+ steps: PathSchema,
76
+ support: PathSchema.optional()
77
+ }).catchall(PathSchema);
78
+ var EventsSchema = z.array(z.string());
79
+ var LoggingSchema = z.object({
80
+ http: z.boolean().optional()
81
+ }).optional();
82
+ var ReporterSchema = z.object({
83
+ hierarchical: z.object({
84
+ bufferOutput: z.boolean().optional()
85
+ }).optional()
86
+ }).optional();
87
+ var ModuleFormatSchema = z.enum(["cjs", "esm"]);
88
+ var PartialRootSchema = RootSchema.partial();
89
+ var ModuleDeclarationSchema = z.lazy(
90
+ () => z.union([
91
+ z.string(),
92
+ z.object({
93
+ name: z.string().min(1),
94
+ submodules: z.array(ModuleDeclarationSchema).optional()
95
+ })
96
+ ])
97
+ );
98
+ var ModulesConfigSchema = z.object({
99
+ stepScoping: z.enum(["global", "scoped"]).optional(),
100
+ relativeRoots: PartialRootSchema.optional(),
101
+ groups: z.record(
102
+ z.object({
103
+ root: z.string(),
104
+ modules: z.array(ModuleDeclarationSchema).nonempty()
105
+ })
106
+ ).optional(),
107
+ explicit: z.array(z.string()).optional()
108
+ });
109
+ var SourceMapSchema = z.union([
110
+ z.literal(true),
111
+ z.literal(false),
112
+ z.literal("inline"),
113
+ z.literal("external")
114
+ ]);
115
+ var BuildHookSchema = z.custom((value) => {
116
+ return typeof value === "function";
117
+ }, {
118
+ message: "build hooks must be functions"
119
+ });
120
+ var BuilderHooksSchema = z.object({
121
+ before: z.array(BuildHookSchema).optional(),
122
+ after: z.array(BuildHookSchema).optional()
123
+ });
124
+ var BuilderConfigSchema = z.object({
125
+ format: ModuleFormatSchema.optional(),
126
+ target: z.union([z.string(), z.array(z.string()).nonempty()]).optional(),
127
+ sourcemap: SourceMapSchema.optional(),
128
+ tsconfig: z.string().optional(),
129
+ external: z.array(z.string()).optional(),
130
+ outDir: z.string().optional(),
131
+ hooks: BuilderHooksSchema.optional()
132
+ });
133
+ var ExecutorConfigSchema = z.object({
134
+ runner: RunnerSchema,
135
+ test: TestSchema.optional(),
136
+ roots: RootSchema,
137
+ modules: ModulesConfigSchema.optional(),
138
+ shim: ShimSchema.optional(),
139
+ events: EventsSchema.optional(),
140
+ builder: BuilderConfigSchema.optional(),
141
+ logging: LoggingSchema.optional(),
142
+ reporting: ReporterSchema.optional()
143
+ });
144
+ var PartialExecutorConfigSchema = z.object({
145
+ runner: RunnerSchema.optional(),
146
+ test: TestSchema.optional(),
147
+ roots: PartialRootSchema.optional(),
148
+ modules: ModulesConfigSchema.optional(),
149
+ shim: ShimSchema.optional(),
150
+ events: EventsSchema.optional(),
151
+ builder: BuilderConfigSchema.optional(),
152
+ logging: LoggingSchema.optional(),
153
+ reporting: ReporterSchema.optional()
154
+ });
97
155
 
98
- // src/config-object.ts
156
+ // src/config.ts
99
157
  var Config = class {
100
- constructor(envMap) {
101
- this.envMap = envMap;
102
- this.environments = new EnvironmentReader();
103
- }
104
- get current() {
105
- const key = this.environments.value;
106
- if (!key) {
107
- if (!this.envMap.has("default")) {
108
- throw new import_errors.AutomationError(
109
- `No environment is defined. Define an environment with 'env.byLiteral("my-environment")' or 'env.byEnvironmentVariable("MY_ENVIRONMENT")' or 'env.byFactory(() => "my-environment")' or 'env.byLiteral("default")'`
158
+ constructor(definition) {
159
+ this.definition = definition;
160
+ }
161
+ resolve(options = {}) {
162
+ const environment = this.resolveEnvironment(options);
163
+ const override = this.definition.environments[environment] ?? {};
164
+ const merged = mergeExecutorConfig(this.definition.default, override);
165
+ const validated = ExecutorConfigSchema.parse(merged);
166
+ const expanded = expandModules(validated, options.modules, options.groups);
167
+ return {
168
+ environment,
169
+ config: deepFreeze(expanded)
170
+ };
171
+ }
172
+ current(options) {
173
+ return this.resolve(options).config;
174
+ }
175
+ get environment() {
176
+ return this.resolve().environment;
177
+ }
178
+ forEnvironment(environment) {
179
+ return this.resolve({ environment }).config;
180
+ }
181
+ resolveEnvironment(options) {
182
+ if (options.environment) {
183
+ return this.assertEnvironment(options.environment);
184
+ }
185
+ const detected = this.definition.selector.resolve();
186
+ return this.assertEnvironment(detected);
187
+ }
188
+ assertEnvironment(environment) {
189
+ if (environment === "default") {
190
+ return environment;
191
+ }
192
+ if (!this.definition.environments[environment]) {
193
+ const available = [
194
+ "default",
195
+ ...Object.keys(this.definition.environments).filter(
196
+ (name) => name !== "default"
197
+ )
198
+ ];
199
+ const options = available.length ? available.join(", ") : "(define environments to extend the default profile)";
200
+ throw new AutomationError(
201
+ `Environment "${environment}" is not defined. Available environments: ${options}`
202
+ );
203
+ }
204
+ return environment;
205
+ }
206
+ };
207
+ var defineConfig = (input) => {
208
+ const selector = new EnvironmentSelector();
209
+ selector.defaultTo("default");
210
+ if (input.environment) {
211
+ input.environment(selector);
212
+ }
213
+ const defaultConfig = deepFreeze(ExecutorConfigSchema.parse(input.default));
214
+ const environments = {};
215
+ for (const [name, rawOverride] of Object.entries(input.environments ?? {})) {
216
+ if (!name.trim()) {
217
+ throw new AutomationError("Environment name must be a non-empty string");
218
+ }
219
+ const override = rawOverride ? PartialExecutorConfigSchema.parse(rawOverride) : {};
220
+ environments[name] = deepFreeze(override);
221
+ }
222
+ return new Config({
223
+ default: defaultConfig,
224
+ environments,
225
+ selector
226
+ });
227
+ };
228
+ var mergeExecutorConfig = (base, override) => {
229
+ const result = cloneConfig(base);
230
+ if (override.runner) {
231
+ result.runner = override.runner;
232
+ }
233
+ if (override.test !== void 0) {
234
+ result.test = mergeTest(result.test, override.test);
235
+ }
236
+ if (override.roots !== void 0) {
237
+ result.roots = mergeRoots(result.roots, override.roots);
238
+ }
239
+ if (override.modules !== void 0) {
240
+ result.modules = cloneModules(override.modules);
241
+ }
242
+ if (override.shim !== void 0) {
243
+ result.shim = mergeShim(result.shim, override.shim);
244
+ }
245
+ if (override.events !== void 0) {
246
+ result.events = cloneArray(override.events);
247
+ }
248
+ if (override.builder !== void 0) {
249
+ result.builder = mergeBuilder(result.builder, override.builder);
250
+ }
251
+ if (override.logging !== void 0) {
252
+ result.logging = mergeLogging(result.logging, override.logging);
253
+ }
254
+ if (override.reporting !== void 0) {
255
+ result.reporting = mergeReporting(result.reporting, override.reporting);
256
+ }
257
+ return result;
258
+ };
259
+ var expandModules = (config, moduleFilters, groupFilters) => {
260
+ const modulesConfig = config.modules;
261
+ if (!modulesConfig) {
262
+ return config;
263
+ }
264
+ const relativeRoots = modulesConfig.relativeRoots;
265
+ const hasRelativeRoots = !!relativeRoots && Object.keys(relativeRoots).length > 0;
266
+ if (!hasRelativeRoots) {
267
+ const hasFilters = (moduleFilters?.some((m) => m.trim().length > 0) ?? false) || (groupFilters?.some((g) => g.trim().length > 0) ?? false);
268
+ if (hasFilters) {
269
+ throw new AutomationError(
270
+ 'Module filters were provided, but "modules.relativeRoots" is not configured. Configure at least one relative root (e.g. { steps: ["steps/**/*.ts"] }) or remove -m/-g.'
271
+ );
272
+ }
273
+ return config;
274
+ }
275
+ const moduleEntries = collectModuleEntries(modulesConfig);
276
+ if (moduleEntries.length === 0) {
277
+ throw new AutomationError(
278
+ 'When "modules" is provided, at least one module must be declared via "groups" or "explicit".'
279
+ );
280
+ }
281
+ const selectedModules = selectModules(moduleEntries, moduleFilters, groupFilters);
282
+ const expandedByKey = {};
283
+ for (const [key, entries] of Object.entries(relativeRoots)) {
284
+ if (!entries || entries.length === 0) {
285
+ continue;
286
+ }
287
+ const expanded = [];
288
+ for (const moduleDir of selectedModules) {
289
+ for (const entry of entries) {
290
+ const joined = joinModuleEntry(moduleDir, entry);
291
+ if (joined) {
292
+ expanded.push(joined);
293
+ }
294
+ }
295
+ }
296
+ if (expanded.length > 0) {
297
+ expandedByKey[key] = expanded;
298
+ }
299
+ }
300
+ if (Object.keys(expandedByKey).length === 0) {
301
+ return config;
302
+ }
303
+ const roots = cloneRoots(config.roots);
304
+ for (const [key, expanded] of Object.entries(expandedByKey)) {
305
+ const existing = roots[key] ?? [];
306
+ roots[key] = [...expanded, ...existing];
307
+ }
308
+ return {
309
+ ...config,
310
+ roots
311
+ };
312
+ };
313
+ var flattenModuleDeclarations = (declarations, prefix = "") => {
314
+ const flattened = [];
315
+ const walk = (items, currentPrefix) => {
316
+ for (const item of items) {
317
+ if (typeof item === "string") {
318
+ const name2 = normalizeSlashes(item.trim()).replace(/^\/+|\/+$/gu, "");
319
+ if (!name2) {
320
+ continue;
321
+ }
322
+ flattened.push(normalizeSlashes(posix.join(currentPrefix, name2)));
323
+ continue;
324
+ }
325
+ const name = normalizeSlashes(item.name.trim()).replace(/^\/+|\/+$/gu, "");
326
+ if (!name) {
327
+ continue;
328
+ }
329
+ const nextPrefix = normalizeSlashes(posix.join(currentPrefix, name));
330
+ flattened.push(nextPrefix);
331
+ if (item.submodules && item.submodules.length > 0) {
332
+ walk(item.submodules, nextPrefix);
333
+ }
334
+ }
335
+ };
336
+ const cleanedPrefix = normalizeSlashes(prefix.trim()).replace(/\/+$/u, "");
337
+ walk(declarations, cleanedPrefix);
338
+ return Array.from(new Set(flattened));
339
+ };
340
+ var collectModuleEntries = (modulesConfig) => {
341
+ const entries = [];
342
+ const seen = /* @__PURE__ */ new Set();
343
+ for (const [groupId, group] of Object.entries(modulesConfig.groups ?? {})) {
344
+ const normalizedGroupId = groupId.trim();
345
+ if (!normalizedGroupId) {
346
+ continue;
347
+ }
348
+ const root = normalizeSlashes(group.root.trim()).replace(/\/+$/u, "");
349
+ if (!root) {
350
+ continue;
351
+ }
352
+ const modulePaths = flattenModuleDeclarations(group.modules);
353
+ for (const modulePath of modulePaths) {
354
+ const cleaned = normalizeSlashes(modulePath.trim()).replace(/^\/+|\/+$/gu, "");
355
+ if (!cleaned) {
356
+ continue;
357
+ }
358
+ const dir = normalizeSlashes(posix.join(root, cleaned));
359
+ const id = `${normalizedGroupId}/${cleaned}`;
360
+ const key = `${id}::${dir}`;
361
+ if (seen.has(key)) {
362
+ continue;
363
+ }
364
+ seen.add(key);
365
+ entries.push({ id, dir });
366
+ }
367
+ }
368
+ for (const explicit of modulesConfig.explicit ?? []) {
369
+ const normalized = normalizeSlashes(explicit.trim());
370
+ if (!normalized) {
371
+ continue;
372
+ }
373
+ const id = normalized;
374
+ const key = `${id}::${normalized}`;
375
+ if (seen.has(key)) {
376
+ continue;
377
+ }
378
+ seen.add(key);
379
+ entries.push({ id, dir: normalized });
380
+ }
381
+ return entries;
382
+ };
383
+ var selectModules = (moduleEntries, moduleFilters, groupFilters) => {
384
+ const options = moduleEntries.map((m) => ({
385
+ id: normalizeSlashes(m.id),
386
+ dir: normalizeSlashes(m.dir),
387
+ group: normalizeSlashes(m.id.split("/")[0] ?? "")
388
+ }));
389
+ const groupFilterSet = new Set(
390
+ (groupFilters ?? []).map((g) => normalizeSlashes(g.trim())).filter(Boolean)
391
+ );
392
+ const inGroupScope = (candidate) => {
393
+ if (groupFilterSet.size === 0) {
394
+ return true;
395
+ }
396
+ return groupFilterSet.has(candidate.group);
397
+ };
398
+ const scopedOptions = options.filter(inGroupScope);
399
+ if (groupFilterSet.size > 0 && scopedOptions.length === 0) {
400
+ throw new AutomationError(
401
+ `No modules found for group filter(s): ${Array.from(groupFilterSet).join(", ")}. Available groups: ${Array.from(new Set(options.map((o) => o.group))).filter(Boolean).join(", ")}`
402
+ );
403
+ }
404
+ if (!moduleFilters || moduleFilters.length === 0) {
405
+ return scopedOptions.map((o) => o.dir);
406
+ }
407
+ const scopedGroups = new Set(scopedOptions.map((o) => o.group).filter(Boolean));
408
+ const selected = /* @__PURE__ */ new Set();
409
+ for (const rawFilter of moduleFilters) {
410
+ const filter = normalizeSlashes(rawFilter.trim());
411
+ if (!filter) {
412
+ continue;
413
+ }
414
+ const parsed = parseModuleSelector(filter, scopedGroups);
415
+ if (parsed) {
416
+ const wantedId = `${parsed.group}/${parsed.modulePath}`;
417
+ const exact = scopedOptions.filter((o) => o.id === wantedId);
418
+ if (exact.length === 0) {
419
+ throw new AutomationError(
420
+ `Module "${rawFilter}" not found. Available modules: ${scopedOptions.map((o) => o.id).join(", ")}`
110
421
  );
111
422
  }
112
- return this.envMap.get("default");
113
- }
114
- if (!this.envMap.has(key)) {
115
- throw new import_errors.AutomationError(
116
- `Environment ${key} is not defined. Options are:
117
- ${Object.keys(
118
- this.envMap
119
- ).join("\n")}`
423
+ const match2 = exact[0];
424
+ if (match2) {
425
+ selected.add(match2.dir);
426
+ }
427
+ continue;
428
+ }
429
+ const pathSelector = filter.includes(":") ? filter.split(":").join("/") : filter;
430
+ const suffixMatches = scopedOptions.filter((o) => o.id.endsWith(`/${pathSelector}`));
431
+ if (suffixMatches.length === 0) {
432
+ throw new AutomationError(
433
+ `Module "${rawFilter}" not found. Available modules: ${scopedOptions.map((o) => o.id).join(", ")}`
120
434
  );
121
435
  }
122
- return this.envMap.get(key) ?? (0, import_errors.raise)(`Environment ${key} is not defined`);
436
+ if (suffixMatches.length > 1) {
437
+ throw new AutomationError(
438
+ `Module filter "${rawFilter}" is ambiguous. Candidates: ${suffixMatches.map((m) => m.id).join(", ")}. Use "<group>/<module>" or "<group>:<module>" to disambiguate.`
439
+ );
440
+ }
441
+ const match = suffixMatches[0];
442
+ if (match) {
443
+ selected.add(match.dir);
444
+ }
445
+ }
446
+ return scopedOptions.map((o) => o.dir).filter((dir) => selected.has(dir));
447
+ };
448
+ var parseModuleSelector = (selector, knownGroups) => {
449
+ if (!selector) {
450
+ return void 0;
451
+ }
452
+ if (selector.includes(":")) {
453
+ const parts = selector.split(":").map((p) => p.trim()).filter(Boolean);
454
+ if (parts.length >= 2) {
455
+ const group = parts[0];
456
+ if (!group) {
457
+ return void 0;
458
+ }
459
+ if (knownGroups.has(group)) {
460
+ const modulePath = normalizeSlashes(parts.slice(1).join("/")).replace(/^\/+|\/+$/gu, "");
461
+ if (modulePath) {
462
+ return { group, modulePath };
463
+ }
464
+ }
465
+ }
123
466
  }
124
- get currentEnvironment() {
125
- return this.environments.value;
467
+ if (selector.includes("/")) {
468
+ const parts = selector.split("/").map((p) => p.trim()).filter(Boolean);
469
+ if (parts.length >= 2) {
470
+ const group = parts[0];
471
+ if (!group) {
472
+ return void 0;
473
+ }
474
+ if (knownGroups.has(group)) {
475
+ const modulePath = normalizeSlashes(parts.slice(1).join("/")).replace(/^\/+|\/+$/gu, "");
476
+ if (modulePath) {
477
+ return { group, modulePath };
478
+ }
479
+ }
480
+ }
126
481
  }
482
+ return void 0;
127
483
  };
128
-
129
- // src/define-config.ts
130
- var import_errors2 = require("@autometa/errors");
131
- function defineConfig(config, ...configs) {
132
- const envs = [];
133
- const envMap = config.envMap;
134
- for (const config2 of configs) {
135
- if (config2.environment) {
136
- if (envs.includes(config2.environment)) {
137
- throw new import_errors2.AutomationError(
138
- `Environment ${config2.environment} is defined more than once`
139
- );
484
+ var joinModuleEntry = (moduleDir, entry) => {
485
+ const moduleTrimmed = normalizeSlashes(moduleDir.trim()).replace(/\/+$/u, "");
486
+ if (!moduleTrimmed) {
487
+ return void 0;
488
+ }
489
+ const entryTrimmed = normalizeSlashes(entry.trim());
490
+ if (!entryTrimmed) {
491
+ return void 0;
492
+ }
493
+ const negated = entryTrimmed.startsWith("!");
494
+ const raw = negated ? entryTrimmed.slice(1).trim() : entryTrimmed;
495
+ if (!raw || raw === ".") {
496
+ return negated ? `!${moduleTrimmed}` : moduleTrimmed;
497
+ }
498
+ if (raw.startsWith("/") || /^[A-Za-z]:\//u.test(raw)) {
499
+ return negated ? `!${raw}` : raw;
500
+ }
501
+ const joined = normalizeSlashes(posix.join(moduleTrimmed, raw));
502
+ return negated ? `!${joined}` : joined;
503
+ };
504
+ var normalizeSlashes = (value) => value.replace(/\\/gu, "/");
505
+ var mergeTest = (base, override) => {
506
+ if (override === void 0) {
507
+ return base ? cloneTest(base) : void 0;
508
+ }
509
+ const result = base ? cloneTest(base) : {};
510
+ if (override.timeout !== void 0) {
511
+ result.timeout = cloneTimeout(override.timeout);
512
+ }
513
+ if (override.tagFilter !== void 0) {
514
+ result.tagFilter = override.tagFilter;
515
+ }
516
+ if (override.groupLogging !== void 0) {
517
+ result.groupLogging = override.groupLogging;
518
+ }
519
+ return Object.keys(result).length === 0 ? void 0 : result;
520
+ };
521
+ var mergeShim = (base, override) => {
522
+ if (override === void 0) {
523
+ return base ? cloneShim(base) : void 0;
524
+ }
525
+ const result = base ? cloneShim(base) : {};
526
+ if (override.errorCause !== void 0) {
527
+ result.errorCause = override.errorCause;
528
+ }
529
+ return Object.keys(result).length === 0 ? void 0 : result;
530
+ };
531
+ var mergeLogging = (base, override) => {
532
+ if (override === void 0) {
533
+ return base ? cloneLogging(base) : void 0;
534
+ }
535
+ const result = base ? cloneLogging(base) : {};
536
+ if (override.http !== void 0) {
537
+ result.http = override.http;
538
+ }
539
+ return Object.keys(result).length === 0 ? void 0 : result;
540
+ };
541
+ var mergeReporting = (base, override) => {
542
+ if (override === void 0) {
543
+ return base ? cloneReporting(base) : void 0;
544
+ }
545
+ const result = base ? cloneReporting(base) : {};
546
+ if (override.hierarchical !== void 0) {
547
+ const hierarchicalOverride = override.hierarchical;
548
+ if (hierarchicalOverride) {
549
+ const hierarchical = result.hierarchical ? { ...result.hierarchical } : {};
550
+ if (hierarchicalOverride.bufferOutput !== void 0) {
551
+ hierarchical.bufferOutput = hierarchicalOverride.bufferOutput;
552
+ }
553
+ if (Object.keys(hierarchical).length > 0) {
554
+ result.hierarchical = hierarchical;
555
+ } else {
556
+ delete result.hierarchical;
140
557
  }
141
- envMap.set(config2.environment, config2);
142
- envs.push(config2.environment);
143
- } else if (!config2.environment && envs.includes("default")) {
144
- throw new import_errors2.AutomationError(`Only one default environment can be defined`);
145
558
  } else {
146
- envMap.set("default", config2);
147
- envs.push("default");
148
- config2.environment = "default";
559
+ delete result.hierarchical;
149
560
  }
150
- if (config2.shim) {
151
- if ("error-cause" in config2.shim && config2.shim["error-cause"] === true) {
152
- require("error-cause/auto");
153
- }
561
+ }
562
+ return Object.keys(result).length === 0 ? void 0 : result;
563
+ };
564
+ var mergeRoots = (base, override) => {
565
+ const result = cloneRoots(base);
566
+ if (!override) {
567
+ return result;
568
+ }
569
+ for (const [key, value] of Object.entries(override)) {
570
+ if (value === void 0) {
571
+ continue;
154
572
  }
573
+ result[key] = cloneArray(value);
155
574
  }
156
- if (envs.length > 1 && !envs.includes("default")) {
157
- throw new import_errors2.AutomationError(
158
- `A default environment must be defined first. At one config must not have an environment defined or define a default environment explicitly with 'environement="default"`
575
+ if (!result.features) {
576
+ throw new AutomationError(
577
+ 'Environment overrides removed required root "features"'
159
578
  );
160
579
  }
161
- const setters = config.environments;
162
- return {
163
- env: setters
164
- };
165
- }
166
- // Annotate the CommonJS export names for ESM import in node:
167
- 0 && (module.exports = {
168
- Config,
169
- EnvironmentReader,
170
- defineConfig
580
+ if (!result.steps) {
581
+ throw new AutomationError(
582
+ 'Environment overrides removed required root "steps"'
583
+ );
584
+ }
585
+ return result;
586
+ };
587
+ var mergeBuilder = (base, override) => {
588
+ if (override === void 0) {
589
+ return base ? cloneBuilder(base) : void 0;
590
+ }
591
+ const result = base ? cloneBuilder(base) : {};
592
+ if (override.format !== void 0) {
593
+ result.format = override.format;
594
+ }
595
+ if (override.target !== void 0) {
596
+ result.target = Array.isArray(override.target) ? [...override.target] : override.target;
597
+ }
598
+ if (override.sourcemap !== void 0) {
599
+ result.sourcemap = override.sourcemap;
600
+ }
601
+ if (override.tsconfig !== void 0) {
602
+ result.tsconfig = override.tsconfig;
603
+ }
604
+ if (override.external !== void 0) {
605
+ result.external = cloneArray(override.external);
606
+ }
607
+ if (override.outDir !== void 0) {
608
+ result.outDir = override.outDir;
609
+ }
610
+ if (override.hooks !== void 0) {
611
+ const clonedHooks = cloneBuilderHooks(override.hooks);
612
+ if (clonedHooks) {
613
+ result.hooks = clonedHooks;
614
+ } else {
615
+ delete result.hooks;
616
+ }
617
+ }
618
+ return Object.keys(result).length === 0 ? void 0 : result;
619
+ };
620
+ var cloneConfig = (config) => ({
621
+ runner: config.runner,
622
+ roots: cloneRoots(config.roots),
623
+ modules: config.modules ? cloneModules(config.modules) : void 0,
624
+ test: config.test ? cloneTest(config.test) : void 0,
625
+ shim: config.shim ? cloneShim(config.shim) : void 0,
626
+ events: cloneOptionalArray(config.events),
627
+ builder: config.builder ? cloneBuilder(config.builder) : void 0,
628
+ logging: config.logging ? cloneLogging(config.logging) : void 0,
629
+ reporting: config.reporting ? cloneReporting(config.reporting) : void 0
171
630
  });
631
+ var cloneRoots = (roots) => {
632
+ const cloned = {};
633
+ for (const [key, value] of Object.entries(roots)) {
634
+ if (value) {
635
+ cloned[key] = cloneArray(value);
636
+ }
637
+ }
638
+ return cloned;
639
+ };
640
+ var cloneRootRecord = (roots) => {
641
+ const cloned = {};
642
+ for (const [key, value] of Object.entries(roots)) {
643
+ if (!value) {
644
+ continue;
645
+ }
646
+ cloned[key] = cloneArray(value);
647
+ }
648
+ return cloned;
649
+ };
650
+ var cloneGroups = (groups) => {
651
+ const cloneModuleDeclaration = (value) => {
652
+ if (typeof value === "string") {
653
+ return value;
654
+ }
655
+ return {
656
+ name: value.name,
657
+ submodules: value.submodules ? value.submodules.map((child) => cloneModuleDeclaration(child)) : void 0
658
+ };
659
+ };
660
+ const cloned = {};
661
+ for (const [key, group] of Object.entries(groups)) {
662
+ cloned[key] = {
663
+ root: group.root,
664
+ modules: group.modules.map((m) => cloneModuleDeclaration(m))
665
+ };
666
+ }
667
+ return cloned;
668
+ };
669
+ var cloneModules = (modules) => {
670
+ const clone = {};
671
+ if (modules.relativeRoots) {
672
+ clone.relativeRoots = cloneRootRecord(modules.relativeRoots);
673
+ }
674
+ if (modules.groups) {
675
+ clone.groups = cloneGroups(modules.groups);
676
+ }
677
+ if (modules.explicit) {
678
+ clone.explicit = cloneArray(modules.explicit);
679
+ }
680
+ return clone;
681
+ };
682
+ var cloneTest = (test) => {
683
+ const clone = {};
684
+ if (test.timeout !== void 0) {
685
+ clone.timeout = cloneTimeout(test.timeout);
686
+ }
687
+ if (test.tagFilter !== void 0) {
688
+ clone.tagFilter = test.tagFilter;
689
+ }
690
+ if (test.groupLogging !== void 0) {
691
+ clone.groupLogging = test.groupLogging;
692
+ }
693
+ return clone;
694
+ };
695
+ var cloneShim = (shim) => {
696
+ const clone = {};
697
+ if (shim.errorCause !== void 0) {
698
+ clone.errorCause = shim.errorCause;
699
+ }
700
+ return clone;
701
+ };
702
+ var cloneLogging = (logging) => {
703
+ const clone = {};
704
+ if (logging.http !== void 0) {
705
+ clone.http = logging.http;
706
+ }
707
+ return clone;
708
+ };
709
+ var cloneReporting = (reporting) => {
710
+ const clone = {};
711
+ if (reporting.hierarchical) {
712
+ clone.hierarchical = { ...reporting.hierarchical };
713
+ }
714
+ return clone;
715
+ };
716
+ var cloneBuilder = (config) => {
717
+ const clone = {};
718
+ if (config.format !== void 0) {
719
+ clone.format = config.format;
720
+ }
721
+ if (config.target !== void 0) {
722
+ clone.target = Array.isArray(config.target) ? [...config.target] : config.target;
723
+ }
724
+ if (config.sourcemap !== void 0) {
725
+ clone.sourcemap = config.sourcemap;
726
+ }
727
+ if (config.tsconfig !== void 0) {
728
+ clone.tsconfig = config.tsconfig;
729
+ }
730
+ if (config.external !== void 0) {
731
+ clone.external = cloneArray(config.external);
732
+ }
733
+ if (config.outDir !== void 0) {
734
+ clone.outDir = config.outDir;
735
+ }
736
+ if (config.hooks) {
737
+ const clonedHooks = cloneBuilderHooks(config.hooks);
738
+ if (clonedHooks) {
739
+ clone.hooks = clonedHooks;
740
+ }
741
+ }
742
+ return clone;
743
+ };
744
+ var cloneBuilderHooks = (hooks) => {
745
+ const clone = {};
746
+ if (hooks.before && hooks.before.length > 0) {
747
+ clone.before = [...hooks.before];
748
+ }
749
+ if (hooks.after && hooks.after.length > 0) {
750
+ clone.after = [...hooks.after];
751
+ }
752
+ return Object.keys(clone).length === 0 ? void 0 : clone;
753
+ };
754
+ var cloneTimeout = (timeout) => {
755
+ if (timeout === void 0) {
756
+ return void 0;
757
+ }
758
+ if (typeof timeout === "number") {
759
+ return timeout;
760
+ }
761
+ if (Array.isArray(timeout)) {
762
+ const [value, unit] = timeout;
763
+ return [value, unit];
764
+ }
765
+ return { ...timeout };
766
+ };
767
+ var cloneArray = (value) => [...value];
768
+ var cloneOptionalArray = (value) => {
769
+ if (value === void 0) {
770
+ return void 0;
771
+ }
772
+ return [...value];
773
+ };
774
+ var deepFreeze = (value) => {
775
+ if (value === null || typeof value !== "object") {
776
+ return value;
777
+ }
778
+ const propertyNames = Object.getOwnPropertyNames(value);
779
+ for (const name of propertyNames) {
780
+ const property = value[name];
781
+ if (property && typeof property === "object") {
782
+ deepFreeze(property);
783
+ }
784
+ }
785
+ return Object.freeze(value);
786
+ };
787
+
788
+ export { BuilderConfigSchema, Config, EnvironmentSelector, EventsSchema, ExecutorConfigSchema, ModuleFormatSchema, PartialExecutorConfigSchema, PartialRootSchema, PathSchema, ReporterSchema, RootSchema, RunnerSchema, ShimSchema, TagFilterSchema, TestSchema, TimeUnitSchema, TimeoutSchema, defineConfig };
789
+ //# sourceMappingURL=out.js.map
172
790
  //# sourceMappingURL=index.js.map