@powerlines/engine 0.45.2 → 0.46.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.
Files changed (52) hide show
  1. package/dist/_internal/worker.cjs +844 -788
  2. package/dist/_internal/worker.mjs +847 -791
  3. package/dist/_internal/worker.mjs.map +1 -1
  4. package/dist/api.cjs +292 -323
  5. package/dist/api.d.cts +44 -11
  6. package/dist/api.d.cts.map +1 -1
  7. package/dist/api.d.mts +44 -11
  8. package/dist/api.d.mts.map +1 -1
  9. package/dist/api.mjs +292 -323
  10. package/dist/api.mjs.map +1 -1
  11. package/dist/{base-context-Byizvf4F.cjs → base-context-BCG0xN2e.cjs} +70 -64
  12. package/dist/{base-context-BSAC5sO9.mjs → base-context-Cmo6TTh7.mjs} +73 -67
  13. package/dist/base-context-Cmo6TTh7.mjs.map +1 -0
  14. package/dist/context/index.cjs +3 -3
  15. package/dist/context/index.d.cts +44 -617
  16. package/dist/context/index.d.cts.map +1 -1
  17. package/dist/context/index.d.mts +44 -617
  18. package/dist/context/index.d.mts.map +1 -1
  19. package/dist/context/index.mjs +3 -3
  20. package/dist/engine-context-BjFMVQEE.mjs +86 -0
  21. package/dist/engine-context-BjFMVQEE.mjs.map +1 -0
  22. package/dist/engine-context-DOsGtgD9.cjs +91 -0
  23. package/dist/execution-context-BdZt7wWa.d.mts +631 -0
  24. package/dist/execution-context-BdZt7wWa.d.mts.map +1 -0
  25. package/dist/execution-context-CU6iNchD.d.cts +631 -0
  26. package/dist/execution-context-CU6iNchD.d.cts.map +1 -0
  27. package/dist/{execution-context-BRzNYU9u.mjs → execution-context-Cp32TarF.mjs} +421 -363
  28. package/dist/execution-context-Cp32TarF.mjs.map +1 -0
  29. package/dist/{execution-context-BlWK2rTX.cjs → execution-context-DgqxcDDx.cjs} +419 -361
  30. package/dist/index.cjs +15 -16
  31. package/dist/index.d.cts +3 -3
  32. package/dist/index.d.cts.map +1 -1
  33. package/dist/index.d.mts +3 -3
  34. package/dist/index.d.mts.map +1 -1
  35. package/dist/index.mjs +15 -16
  36. package/dist/index.mjs.map +1 -1
  37. package/dist/{tsconfig-QMSxSwBD.cjs → tsconfig-BUDqmOaT.cjs} +13 -13
  38. package/dist/{tsconfig-CI6bla4E.mjs → tsconfig-MeFEs21S.mjs} +14 -14
  39. package/dist/tsconfig-MeFEs21S.mjs.map +1 -0
  40. package/dist/typescript/index.cjs +1 -1
  41. package/dist/typescript/index.d.cts +6 -6
  42. package/dist/typescript/index.d.cts.map +1 -1
  43. package/dist/typescript/index.d.mts +6 -6
  44. package/dist/typescript/index.d.mts.map +1 -1
  45. package/dist/typescript/index.mjs +1 -1
  46. package/package.json +17 -17
  47. package/dist/base-context-BSAC5sO9.mjs.map +0 -1
  48. package/dist/engine-context-CI_0NWIk.cjs +0 -73
  49. package/dist/engine-context-_RMFwG4J.mjs +0 -68
  50. package/dist/engine-context-_RMFwG4J.mjs.map +0 -1
  51. package/dist/execution-context-BRzNYU9u.mjs.map +0 -1
  52. package/dist/tsconfig-CI6bla4E.mjs.map +0 -1
@@ -1,26 +1,26 @@
1
- import { t as PowerlinesBaseContext } from "./base-context-BSAC5sO9.mjs";
1
+ import { t as PowerlinesBaseContext } from "./base-context-Cmo6TTh7.mjs";
2
2
  import { a as FileSystem } from "./fs-D1nIP45P.mjs";
3
3
  import { n as FileSystemStorageAdapter, t as VirtualStorageAdapter } from "./virtual-CYGZHTDd.mjs";
4
- import { i as getTsconfigFilePath } from "./tsconfig-CI6bla4E.mjs";
4
+ import { i as getTsconfigFilePath } from "./tsconfig-MeFEs21S.mjs";
5
5
  import { CACHE_HASH_LENGTH, DEFAULT_DEVELOPMENT_LOG_LEVEL, DEFAULT_ENVIRONMENT, DEFAULT_PRODUCTION_LOG_LEVEL, DEFAULT_TEST_LOG_LEVEL, GLOBAL_ENVIRONMENT, PLUGIN_NON_HOOK_FIELDS, ROOT_HASH_LENGTH } from "@powerlines/core/constants";
6
6
  import { toArray } from "@stryke/convert/to-array";
7
- import { getResolutionCombinations, resolve, resolvePackage, resolveSync } from "@stryke/fs/resolve";
7
+ import { getResolutionCombinations, resolve, resolveSync } from "@stryke/fs/resolve";
8
8
  import { joinPaths } from "@stryke/path/join";
9
9
  import { isSet } from "@stryke/type-checks/is-set";
10
10
  import { isSetObject } from "@stryke/type-checks/is-set-object";
11
11
  import { isString } from "@stryke/type-checks/is-string";
12
+ import { messageParent } from "jest-worker";
12
13
  import { isSetString } from "@stryke/type-checks/is-set-string";
13
14
  import { uuid } from "@stryke/unique-id/uuid";
14
15
  import { addPluginHook, createLogger, dedupeHooklist, isDuplicate, isPlugin, isPluginConfig, isPluginHook, isPluginHookField, mergeConfig, replacePathTokens, resolveLogLevel, withCustomLogger, withLogFn } from "@powerlines/core/plugin-utils";
15
16
  import { colorText } from "@powerlines/core/plugin-utils/logging";
16
17
  import { getEnvPaths } from "@stryke/env/get-env-paths";
17
18
  import { appendPath } from "@stryke/path/append";
18
- import { isEqual } from "@stryke/path/is-equal";
19
19
  import { replaceExtension, replacePath } from "@stryke/path/replace";
20
+ import { kebabCase } from "@stryke/string-format/kebab-case";
20
21
  import chalk from "chalk";
21
22
  import defu, { defu as defu$1 } from "defu";
22
23
  import { joinPaths as joinPaths$1 } from "@stryke/path/join-paths";
23
- import { titleCase } from "@stryke/string-format/title-case";
24
24
  import { format } from "@powerlines/core/lib/utilities/format";
25
25
  import { formatLogMessage } from "@storm-software/config-tools/logger/console";
26
26
  import { existsSync } from "@stryke/fs/exists";
@@ -28,17 +28,18 @@ import { getUnique, getUniqueBy } from "@stryke/helpers/get-unique";
28
28
  import { omit } from "@stryke/helpers/omit";
29
29
  import { findFileDotExtensionSafe, findFileExtensionSafe, findFileName, findFilePath, hasFileExtension } from "@stryke/path/file-path-fns";
30
30
  import { isParentPath } from "@stryke/path/is-parent-path";
31
+ import { titleCase } from "@stryke/string-format/title-case";
31
32
  import { isFunction } from "@stryke/type-checks/is-function";
32
33
  import { isObject } from "@stryke/type-checks/is-object";
34
+ import { isPromise } from "@stryke/type-checks/is-promise";
33
35
  import { readJsonFile } from "@stryke/fs/json";
34
36
  import { deepClone } from "@stryke/helpers/deep-clone";
35
37
  import { getUniqueInputs, isTypeDefinition, resolveInputsSync } from "@powerlines/core/lib/entry";
36
- import { toBool } from "@stryke/convert/to-bool";
37
38
  import { relativeToWorkspaceRoot } from "@stryke/fs/get-workspace-root";
38
39
  import { murmurhash } from "@stryke/hash";
39
40
  import { hashDirectory } from "@stryke/hash/node";
40
41
  import { fetchRequest } from "@stryke/http/fetch";
41
- import { kebabCase } from "@stryke/string-format/kebab-case";
42
+ import { isEqual } from "@stryke/path/is-equal";
42
43
  import { match, tsconfigPathsToRegExp } from "bundle-require";
43
44
  import { resolveCompatibilityDates } from "compatx";
44
45
  import { create } from "flat-cache";
@@ -59,9 +60,9 @@ import { fileURLToPath } from "node:url";
59
60
  import { getField } from "@stryke/helpers/get-field";
60
61
 
61
62
  //#region src/_internal/helpers/environment.ts
62
- function createEnvironment(name, config = {}) {
63
+ function createEnvironment(name, config) {
63
64
  return defu(config.environments?.[name] ?? {}, {
64
- environmentId: uuid(),
65
+ id: uuid(),
65
66
  name,
66
67
  title: config.title ?? titleCase(config.name),
67
68
  ssr: false,
@@ -87,7 +88,7 @@ function createEnvironment(name, config = {}) {
87
88
  } : void 0
88
89
  });
89
90
  }
90
- function createDefaultEnvironment(config = {}) {
91
+ function createDefaultEnvironment(config) {
91
92
  return createEnvironment(DEFAULT_ENVIRONMENT, config);
92
93
  }
93
94
 
@@ -144,16 +145,16 @@ async function writeMetaFile(context) {
144
145
 
145
146
  //#endregion
146
147
  //#region src/_internal/ipc/send.ts
147
- function sendWriteLogMessage(context, meta, message) {
148
+ function formatWriteLogMessage(context, meta, message) {
148
149
  const combinedMeta = {
149
150
  ...context.logger.options,
150
151
  ...isSetObject(meta) ? meta : { type: meta }
151
152
  };
152
- process.send?.({
153
+ return {
153
154
  id: uuid(),
154
155
  type: "write-log",
155
- executionId: combinedMeta.executionId || context.config.executionId,
156
- executionIndex: combinedMeta.executionIndex ?? context.config.executionIndex,
156
+ executionId: combinedMeta.executionId || context.options.executionId,
157
+ executionIndex: combinedMeta.executionIndex ?? context.options.executionIndex,
157
158
  environment: combinedMeta.environment,
158
159
  timestamp: Date.now(),
159
160
  payload: {
@@ -163,8 +164,8 @@ function sendWriteLogMessage(context, meta, message) {
163
164
  logId: combinedMeta.logId || uuid(),
164
165
  timestamp: combinedMeta.timestamp ?? Date.now(),
165
166
  name: combinedMeta.name || context.config.name,
166
- executionId: combinedMeta.executionId || context.config.executionId,
167
- executionIndex: combinedMeta.executionIndex ?? context.config.executionIndex,
167
+ executionId: combinedMeta.executionId || context.options.executionId,
168
+ executionIndex: combinedMeta.executionIndex ?? context.options.executionIndex,
168
169
  command: combinedMeta.command || context.config.command,
169
170
  hook: combinedMeta.hook,
170
171
  environment: combinedMeta.environment,
@@ -173,7 +174,21 @@ function sendWriteLogMessage(context, meta, message) {
173
174
  },
174
175
  message
175
176
  }
176
- });
177
+ };
178
+ }
179
+ function childProcessSend(message) {
180
+ process.send?.(message);
181
+ }
182
+ function workerThreadSend(message) {
183
+ messageParent(message);
184
+ }
185
+ function send(message) {
186
+ if (process.env.POWERLINES_EXECUTION_THREAD_TYPE === "child-process") childProcessSend(message);
187
+ else if (process.env.POWERLINES_EXECUTION_THREAD_TYPE === "worker-thread") workerThreadSend(message);
188
+ else console.warn("No IPC mechanism available to send message:", message);
189
+ }
190
+ function sendWriteLogMessage(context, meta, message) {
191
+ send(formatWriteLogMessage(context, meta, message));
177
192
  }
178
193
 
179
194
  //#endregion
@@ -1269,27 +1284,13 @@ setGlobalDispatcher(new Agent({ keepAliveTimeout: 1e4 }).compose(interceptors.re
1269
1284
  timeoutFactor: 2,
1270
1285
  retryAfter: true
1271
1286
  })));
1272
- const SKIP_CLONING_PROPS = [
1273
- "dependencies",
1274
- "devDependencies",
1275
- "persistedMeta",
1276
- "packageJson",
1277
- "projectJson",
1278
- "tsconfig",
1279
- "resolver",
1280
- "fs",
1281
- "$$internal"
1287
+ const UNRESOLVED_CONFIG_NAMES = [
1288
+ "initialConfig",
1289
+ "userConfig",
1290
+ "inlineConfig",
1291
+ "pluginConfig"
1282
1292
  ];
1283
1293
  var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1284
- /**
1285
- * Internal references storage
1286
- *
1287
- * @danger
1288
- * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
1289
- *
1290
- * @internal
1291
- */
1292
- #internal = {};
1293
1294
  #checksum = null;
1294
1295
  #buildId = uuid();
1295
1296
  #releaseId = uuid();
@@ -1297,24 +1298,22 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1297
1298
  #tsconfig;
1298
1299
  #parserCache;
1299
1300
  #requestCache;
1301
+ #configProxy;
1300
1302
  /**
1301
- * Create a new Storm context from the workspace root and user config.
1303
+ * Create a new context from the workspace root and user config.
1302
1304
  *
1303
1305
  * @param options - The options for resolving the context.
1304
1306
  * @returns A promise that resolves to the new context.
1305
1307
  */
1306
- static async init(options, initialConfig) {
1307
- const context = new PowerlinesContext(options);
1308
- await context.init(options, initialConfig);
1309
- const powerlinesPath = await resolvePackage("powerlines");
1310
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
1311
- context.powerlinesPath = powerlinesPath;
1308
+ static async fromInitialConfig(options, initialConfig) {
1309
+ const context = new PowerlinesContext(options, initialConfig);
1310
+ await context.init();
1312
1311
  return context;
1313
1312
  }
1314
1313
  /**
1315
- * The options provided to the Powerlines process
1314
+ * The options provided to the Powerlines process, resolved with default values and merged with any configuration provided by plugins or other sources. This is typically the final configuration used during the build process, but may also include additional options that are relevant to the context and its interactions with the Powerlines engine.
1316
1315
  */
1317
- options;
1316
+ options = {};
1318
1317
  /**
1319
1318
  * An object containing the dependencies that should be installed for the project
1320
1319
  */
@@ -1328,39 +1327,33 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1328
1327
  */
1329
1328
  persistedMeta = void 0;
1330
1329
  /**
1331
- * The parsed `package.json` file for the project
1330
+ * The resolved tsconfig file paths for the project
1332
1331
  */
1333
- packageJson;
1332
+ resolvePatterns = [];
1334
1333
  /**
1335
- * The parsed `project.json` file for the project
1334
+ * The input options used to initialize the context, which may be used when cloning the context to ensure the same configuration is applied to the new context
1336
1335
  */
1337
- projectJson = void 0;
1336
+ initialOptions = {};
1338
1337
  /**
1339
- * The resolved tsconfig file paths for the project
1338
+ * The resolved configuration for this context
1340
1339
  */
1341
- resolvePatterns = [];
1340
+ resolvedConfig = {};
1342
1341
  /**
1343
- * Internal context fields and methods
1344
- *
1345
- * @danger
1346
- * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
1347
- *
1348
- * @internal
1342
+ * The configuration options that were overridden by plugins during the build process, which may include additional properties or modifications made during the configuration loading process.
1349
1343
  */
1350
- get $$internal() {
1351
- return this.#internal;
1352
- }
1344
+ overriddenConfig = {};
1353
1345
  /**
1354
- * Internal context fields and methods
1355
- *
1356
- * @danger
1357
- * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
1358
- *
1359
- * @internal
1346
+ * The configuration options provided inline during execution, such as CLI flags or other parameters that may be relevant to the command being executed. These options can be used to override or supplement the configuration options defined in a configuration file on disk, and are typically provided as part of the execution context when running a Powerlines command.
1360
1347
  */
1361
- set $$internal(value) {
1362
- this.#internal = value;
1363
- }
1348
+ inlineConfig = {};
1349
+ /**
1350
+ * The configuration options read from a configuration file on disk, which may be used to resolve the final configuration for the context. This typically includes the user configuration options defined in the `powerlines.config.ts` file, as well as any inline configuration options provided during execution.
1351
+ */
1352
+ userConfig = {};
1353
+ /**
1354
+ * The configuration options provided by plugins added by the user (and other plugins)
1355
+ */
1356
+ pluginConfig = {};
1364
1357
  /**
1365
1358
  * The resolved entry type definitions for the project
1366
1359
  */
@@ -1415,13 +1408,14 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1415
1408
  * The resolved configuration options
1416
1409
  */
1417
1410
  get config() {
1418
- return this.resolvedConfig;
1411
+ if (!this.#configProxy) this.#configProxy = this.createConfigProxy();
1412
+ return this.#configProxy;
1419
1413
  }
1420
1414
  /**
1421
1415
  * Get the path to the artifacts directory for the project
1422
1416
  */
1423
1417
  get artifactsPath() {
1424
- return joinPaths(this.config.cwd, this.config.root, this.config.output.artifactsPath);
1418
+ return joinPaths(this.config.cwd, this.config.root, this.config.output?.artifactsPath || `.${this.config.framework || "powerlines"}`);
1425
1419
  }
1426
1420
  /**
1427
1421
  * Get the path to the builtin modules used by the project
@@ -1478,7 +1472,7 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1478
1472
  * Additional arguments provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed.
1479
1473
  */
1480
1474
  get additionalArgs() {
1481
- return Object.entries(this.config.inlineConfig?.additionalArgs ?? {}).reduce((ret, [key, value]) => {
1475
+ return Object.entries(this.config.inlineConfig.additionalArgs ?? {}).reduce((ret, [key, value]) => {
1482
1476
  const formattedKey = key.replace(/^--?/, "");
1483
1477
  if (ret[formattedKey]) if (Array.isArray(ret[formattedKey])) if (Array.isArray(value)) ret[formattedKey] = [...toArray(ret[formattedKey]), ...value];
1484
1478
  else ret[formattedKey] = [...toArray(ret[formattedKey]), value];
@@ -1507,29 +1501,6 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1507
1501
  }, {}) : this.config.resolve.alias : {});
1508
1502
  }
1509
1503
  /**
1510
- * Create a new logger instance
1511
- *
1512
- * @param options - The configuration options to use for the logger instance, which can be used to customize the appearance and behavior of the log messages generated by the logger. This is typically the name of the plugin or module that is creating the logger instance.
1513
- * @param logFn - The custom logging function to use for logging messages, which can be used to override the default logging behavior of the original logger.
1514
- * @returns A logger client instance that can be used to generate log messages with consistent formatting and metadata.
1515
- */
1516
- createLogger(options, logFn) {
1517
- let logger;
1518
- if (toBool(process.env.POWERLINES_WORKER_THREAD_EXECUTION)) logger = createLogger(this.config.name, {
1519
- ...this.options,
1520
- ...this.config,
1521
- ...options
1522
- }, (meta, message) => sendWriteLogMessage(this, meta, message));
1523
- else logger = createLogger(this.config.name, {
1524
- ...this.options,
1525
- ...this.config,
1526
- ...options
1527
- });
1528
- if (this.config.customLogger) logger = withCustomLogger(logger, this.config.customLogger);
1529
- if (logFn) logger = withLogFn(logger, logFn);
1530
- return logger;
1531
- }
1532
- /**
1533
1504
  * The log level for the context, which determines the minimum level of log messages that will be emitted by the logger. This is resolved based on the configuration options provided by the user, and can be set to different levels for development, production, and test environments. The log level can also be overridden by plugins or other parts of the build process to provide more granular control over logging output.
1534
1505
  */
1535
1506
  get logLevel() {
@@ -1591,25 +1562,38 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1591
1562
  }).filter(Boolean);
1592
1563
  }
1593
1564
  /**
1594
- * Creates a new StormContext instance.
1565
+ * Creates a new Context instance.
1595
1566
  *
1596
1567
  * @param options - The options to use for creating the context, including the resolved configuration and workspace settings.
1568
+ * @param initialConfig - The initial configuration provided by the user, which can be used to resolve the final configuration for the context. This typically includes the user configuration options defined in the `powerlines.config.ts` file, as well as any inline configuration options provided during execution.
1597
1569
  */
1598
- constructor(options) {
1599
- super();
1600
- this.options = options;
1570
+ constructor(options, initialConfig) {
1571
+ super(options, initialConfig);
1572
+ this.initialOptions = options;
1573
+ this.initialConfig = initialConfig;
1601
1574
  }
1602
1575
  /**
1603
- * Creates a clone of the current context with the same configuration and workspace settings. This can be useful for running multiple builds in parallel or for creating isolated contexts for different parts of the build process.
1604
- *
1605
- * @remarks
1606
- * The cloned context will have the same configuration and workspace settings as the original context, but will have a different build ID, release ID, and timestamp. The virtual file system and caches will also be separate between the original and cloned contexts.
1576
+ * Create a new logger instance
1607
1577
  *
1608
- * @returns A promise that resolves to the cloned context.
1578
+ * @param options - The configuration options to use for the logger instance, which can be used to customize the appearance and behavior of the log messages generated by the logger. This is typically the name of the plugin or module that is creating the logger instance.
1579
+ * @param logFn - The custom logging function to use for logging messages, which can be used to override the default logging behavior of the original logger.
1580
+ * @returns A logger client instance that can be used to generate log messages with consistent formatting and metadata.
1609
1581
  */
1610
- async clone() {
1611
- const clone = await PowerlinesContext.init(this.options, this.initialConfig);
1612
- return this.copyTo(clone);
1582
+ createLogger(options, logFn) {
1583
+ let logger;
1584
+ if (isSetString(process.env.POWERLINES_EXECUTION_THREAD_TYPE)) logger = createLogger(this.config.name, {
1585
+ ...this.options,
1586
+ ...this.config,
1587
+ ...options
1588
+ }, (meta, message) => sendWriteLogMessage(this, meta, message));
1589
+ else logger = createLogger(this.config.name, {
1590
+ ...this.options,
1591
+ ...this.config,
1592
+ ...options
1593
+ });
1594
+ if (this.config.customLogger) logger = withCustomLogger(logger, this.config.customLogger);
1595
+ if (logFn) logger = withLogFn(logger, logFn);
1596
+ return logger;
1613
1597
  }
1614
1598
  /**
1615
1599
  * A function to perform HTTP fetch requests
@@ -1939,206 +1923,233 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
1939
1923
  /**
1940
1924
  * Generates a checksum representing the current context state
1941
1925
  *
1942
- * @param root - The root directory of the project to generate the checksum for
1926
+ * @param path - The root directory of the project to generate the checksum for
1943
1927
  * @returns A promise that resolves to a string representing the checksum
1944
1928
  */
1945
- async generateChecksum(root = this.config.root) {
1946
- this.#checksum = await hashDirectory(root, { ignore: [
1947
- "node_modules",
1948
- ".git",
1949
- ".nx",
1950
- ".cache",
1951
- "tmp",
1952
- "dist"
1953
- ] });
1954
- return this.#checksum;
1929
+ async generateChecksum(path) {
1930
+ return hashDirectory(path || appendPath(this.options.root, this.options.cwd));
1955
1931
  }
1956
1932
  /**
1957
- * Initialize the context with the provided configuration options
1933
+ * A setter function to populate the inline config values provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed. This function can be used to update the context with the inline configuration values, which may be used during the configuration resolution process to ensure that the final configuration reflects both the user configuration and any inline configuration provided during execution.
1934
+ *
1935
+ * @param config - The inline configuration values to set.
1936
+ * @returns A promise that resolves when the inline configuration values have been set.
1937
+ */
1938
+ async setInlineConfig(config) {
1939
+ this.logger.debug({
1940
+ meta: { category: "config" },
1941
+ message: `Updating inline configuration object: \n${this.logConfig(config)}`
1942
+ });
1943
+ this.inlineConfig = config;
1944
+ await this.resolveConfig();
1945
+ }
1946
+ /**
1947
+ * A setter function to populate the plugin config values provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed. This function can be used to update the context with the plugin configuration values, which may be used during the configuration resolution process to ensure that the final configuration reflects both the user configuration and any plugin configuration provided during execution.
1948
+ *
1949
+ * @param config - The plugin configuration values to set.
1950
+ * @returns A promise that resolves when the plugin configuration values have been set.
1951
+ */
1952
+ async setPluginConfig(config) {
1953
+ this.logger.debug({
1954
+ meta: { category: "config" },
1955
+ message: `Updating plugin configuration object: \n${this.logConfig(config)}`
1956
+ });
1957
+ this.pluginConfig = config;
1958
+ await this.resolveConfig();
1959
+ }
1960
+ /**
1961
+ * A function to merge the various configuration objects (initial, user, inline, and plugin) into a single resolved configuration object that can be used throughout the Powerlines process. This function takes into account the different sources of configuration and their respective priorities, ensuring that the final configuration reflects the intended settings for the project. The merged configuration is then returned as a new object that can be accessed through the `config` property of the context.
1962
+ *
1963
+ * @returns The merged configuration object that combines the initial, user, inline, and plugin configurations.
1958
1964
  */
1959
- async setup() {
1960
- this.resolvedConfig = mergeConfig({
1961
- root: this.options.root,
1962
- cwd: this.options.cwd,
1963
- inlineConfig: this.config.inlineConfig ?? {},
1964
- userConfig: this.config.userConfig ?? {},
1965
- initialConfig: this.config.initialConfig ?? {},
1966
- pluginConfig: this.config.pluginConfig ?? {}
1967
- }, getConfigProps(this.config.inlineConfig), getConfigProps(this.config.userConfig), getConfigProps(this.config.initialConfig), getConfigProps(this.config.pluginConfig), this.options, {
1968
- name: this.projectJson?.name || this.packageJson?.name,
1965
+ mergeConfig() {
1966
+ return mergeConfig({
1967
+ mode: this.initialOptions.mode,
1968
+ framework: this.initialOptions.framework,
1969
+ initialOptions: this.initialOptions,
1970
+ options: this.options,
1971
+ inlineConfig: this.inlineConfig,
1972
+ userConfig: this.userConfig,
1973
+ initialConfig: this.initialConfig,
1974
+ pluginConfig: this.pluginConfig
1975
+ }, getConfigProps(this.overriddenConfig), omit(this.options, ["mode", "framework"]), getConfigProps(this.inlineConfig), getConfigProps(this.userConfig), getConfigProps(this.initialConfig), getConfigProps(this.pluginConfig), {
1969
1976
  version: this.packageJson?.version,
1970
1977
  description: this.packageJson?.description
1971
1978
  }, {
1972
1979
  environments: {},
1973
1980
  resolve: {}
1974
1981
  });
1975
- this.config.plugins = (this.config.initialConfig.plugins ?? []).concat(this.config.userConfig.plugins ?? [], this.config.inlineConfig.plugins ?? []);
1976
- await this.innerSetup();
1977
1982
  }
1978
1983
  /**
1979
- * The resolved configuration for this context
1980
- */
1981
- resolvedConfig = {};
1982
- /**
1983
- * Creates a clone of the current context with the same configuration and workspace settings. This can be useful for running multiple builds in parallel or for creating isolated contexts for different parts of the build process.
1984
- *
1985
- * @remarks
1986
- * The cloned context will have the same configuration and workspace settings as the original context, but will have a different build ID, release ID, and timestamp. The virtual file system and caches will also be separate between the original and cloned contexts.
1984
+ * A setter function to populate the user config values provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed. This function can be used to update the context with the user configuration values, which may be used during the configuration resolution process to ensure that the final configuration reflects both the user configuration and any inline configuration provided during execution.
1987
1985
  *
1988
- * @returns The cloned context.
1986
+ * @param config - The user configuration values to set.
1987
+ * @returns A promise that resolves when the user configuration values have been set.
1989
1988
  */
1990
- copyTo(context) {
1991
- for (const [key, value] of Object.entries(this)) if (!SKIP_CLONING_PROPS.includes(key)) if (isObject(value) || Array.isArray(value)) context[key] = deepClone(value);
1992
- else context[key] = value;
1993
- context.initialConfig = deepClone(this.initialConfig);
1994
- context.initialOptions = deepClone(this.initialOptions);
1995
- context.options = deepClone(this.options);
1996
- context.dependencies = deepClone(this.dependencies);
1997
- context.devDependencies = deepClone(this.devDependencies);
1998
- context.persistedMeta = this.persistedMeta ? deepClone(this.persistedMeta) : void 0;
1999
- context.packageJson = deepClone(this.packageJson);
2000
- context.projectJson = this.projectJson ? deepClone(this.projectJson) : void 0;
2001
- context.tsconfig ??= deepClone(this.tsconfig);
2002
- context.resolver ??= this.resolver;
2003
- context.fs ??= this.#fs;
2004
- context.$$internal = this.$$internal;
2005
- return context;
1989
+ async setUserConfig(config) {
1990
+ this.logger.debug({
1991
+ meta: { category: "config" },
1992
+ message: `Updating user configuration object: \n${this.logConfig(config)}`
1993
+ });
1994
+ this.userConfig = config;
1995
+ await this.resolveConfig();
2006
1996
  }
2007
1997
  /**
2008
1998
  * Initialize the context with the provided configuration options
2009
- *
2010
- * @remarks
2011
- * This method will set up the resolver and load the user configuration file based on the provided options. It is called during the construction of the context and can also be called when cloning the context to ensure that the new context has the same configuration and resolver setup.
2012
- *
2013
- * @param options - The configuration options to initialize the context with
2014
- */
2015
- async init(options, initialConfig) {
2016
- await super.init(options, initialConfig ?? {});
2017
- this.options.executionId = options.executionId ?? this.options.executionId;
2018
- this.options.executionIndex = options.executionIndex ?? this.options.executionIndex ?? 0;
2019
- const projectJsonPath = joinPaths(this.options.cwd, this.options.root, "project.json");
2020
- if (existsSync(projectJsonPath)) this.projectJson = await readJsonFile(projectJsonPath);
2021
- const packageJsonPath = joinPaths(this.options.cwd, this.options.root, "package.json");
2022
- if (existsSync(packageJsonPath)) {
2023
- this.packageJson = await readJsonFile(packageJsonPath);
2024
- this.options.organization ??= isSetObject(this.packageJson?.author) ? kebabCase(this.packageJson?.author?.name) : kebabCase(this.packageJson?.author);
2025
- }
2026
- this.#checksum = await this.generateChecksum(joinPaths(this.options.cwd, this.options.root));
2027
- const userConfig = this.configFile.config ? Array.isArray(this.configFile.config) && this.configFile.config.length > this.options.executionIndex ? this.configFile.config[this.options.executionIndex] : this.configFile.config : {};
2028
- this.resolvedConfig = {
2029
- cwd: this.options.cwd,
2030
- root: this.options.root,
2031
- ...this.initialOptions,
2032
- ...initialConfig,
2033
- ...userConfig,
2034
- inlineConfig: {},
2035
- pluginConfig: {},
2036
- initialConfig,
2037
- userConfig
2038
- };
1999
+ */
2000
+ async init() {
2001
+ await super.init();
2002
+ this.options.executionId = this.initialOptions.executionId || uuid();
2003
+ this.options.executionIndex = this.initialOptions.executionIndex ?? 0;
2004
+ this.#checksum = await this.generateChecksum();
2005
+ const result = this.configFile.config && toArray(this.configFile.config).length > this.options.executionIndex ? toArray(this.configFile.config)[this.options.executionIndex] : this.configFile.config;
2006
+ if (!result) this.logger.warn(`No configuration found in ${this.options.configFile} for execution index ${this.options.executionIndex}.`);
2007
+ else await this.setUserConfig(isFunction(result) ? await Promise.resolve(result(this.options)) : result);
2039
2008
  }
2040
2009
  /**
2041
2010
  * Initialize the context with the provided configuration options
2042
2011
  */
2043
- async innerSetup() {
2044
- const logger = this.extendLogger({ category: "config" });
2045
- this.config.output = defu(this.config.output ?? {}, {
2012
+ async resolveConfig() {
2013
+ const mergedConfig = this.mergeConfig();
2014
+ this.logger.trace({
2015
+ meta: { category: "config" },
2016
+ message: `Pre-setup Powerlines configuration object: \n --- Pre-Resolved Config --- \n${this.logConfig(mergedConfig)} \n --- Initial Config --- \n${this.logConfig(this.initialConfig)} \n --- User Config --- \n${this.logConfig(this.userConfig)} \n --- Inline Config --- \n${this.logConfig(this.inlineConfig)} \n --- Plugin Config --- \n${this.logConfig(this.pluginConfig)}`
2017
+ });
2018
+ mergedConfig.output = defu(mergedConfig.output ?? {}, {
2046
2019
  copy: { assets: [
2047
2020
  { glob: "LICENSE" },
2048
2021
  {
2049
- input: this.config.root,
2022
+ input: mergedConfig.root,
2050
2023
  glob: "*.md"
2051
2024
  },
2052
2025
  {
2053
- input: this.config.root,
2026
+ input: mergedConfig.root,
2054
2027
  glob: "package.json"
2055
2028
  }
2056
2029
  ] },
2057
2030
  dts: true
2058
2031
  });
2059
- logger.trace(`Pre-setup Powerlines configuration object: \n${formatLogMessage({
2060
- ...omit(this.config, [
2061
- "inlineConfig",
2062
- "userConfig",
2063
- "initialConfig",
2064
- "pluginConfig",
2065
- "plugins"
2066
- ]),
2067
- inlineConfig: isSetObject(this.config.inlineConfig) ? omit(this.config.inlineConfig, ["plugins"]) : void 0,
2068
- userConfig: isSetObject(this.config.userConfig) ? omit(this.config.userConfig, ["plugins"]) : void 0,
2069
- initialConfig: isSetObject(this.config.initialConfig) ? omit(this.config.initialConfig, ["plugins"]) : void 0,
2070
- pluginConfig: isSetObject(this.config.pluginConfig) ? omit(this.config.pluginConfig, ["plugins"]) : void 0
2071
- })}`);
2072
- if (!this.initialOptions.mode && !this.config.userConfig?.mode && !this.config.inlineConfig?.mode && !this.config.initialConfig?.mode && !this.config.pluginConfig?.mode) {
2073
- this.options.mode = "production";
2074
- this.config.mode = "production";
2075
- }
2076
- if (!this.initialOptions.framework && !this.config.userConfig?.framework && !this.config.inlineConfig?.framework && !this.config.initialConfig?.framework && !this.config.pluginConfig?.framework) {
2077
- this.options.framework = "powerlines";
2078
- this.config.framework = "powerlines";
2079
- }
2080
- if (!this.config.userConfig?.projectType && !this.config.inlineConfig?.projectType && !this.config.initialConfig?.projectType && !this.config.pluginConfig?.projectType) this.config.projectType = "application";
2081
- if (!this.config.userConfig?.platform && !this.config.inlineConfig?.platform && !this.config.initialConfig?.platform && !this.config.pluginConfig?.platform) this.config.platform = "neutral";
2082
- this.config.compatibilityDate = resolveCompatibilityDates(this.config.inlineConfig.compatibilityDate ?? this.config.userConfig.compatibilityDate ?? this.config.initialConfig.compatibilityDate ?? this.config.pluginConfig.compatibilityDate, "latest");
2083
- this.config.input = getUniqueInputs(this.config.input);
2084
- if (this.config.name?.startsWith("@") && this.config.name.split("/").filter(Boolean).length > 1) this.config.name = this.config.name.split("/").filter(Boolean)[1];
2085
- this.config.title ??= titleCase(this.config.name);
2086
- if (this.config.resolve.external) this.config.resolve.external = getUnique(this.config.resolve.external);
2087
- if (this.config.resolve.noExternal) this.config.resolve.noExternal = getUnique(this.config.resolve.noExternal);
2088
- this.config.plugins = (this.config.plugins ?? []).flatMap((plugin) => toArray(plugin)).filter(Boolean).reduce((ret, plugin) => {
2032
+ if (!mergedConfig.mode) mergedConfig.mode = "production";
2033
+ if (!mergedConfig.framework) mergedConfig.framework = "powerlines";
2034
+ if (!mergedConfig.projectType) mergedConfig.projectType = "application";
2035
+ if (!mergedConfig.platform) mergedConfig.platform = "neutral";
2036
+ mergedConfig.compatibilityDate = resolveCompatibilityDates(mergedConfig.compatibilityDate, "latest");
2037
+ this.resolvedConfig = mergedConfig;
2038
+ this.#configProxy = this.createConfigProxy();
2039
+ mergedConfig.input = getUniqueInputs(mergedConfig.input);
2040
+ if (mergedConfig.name?.startsWith("@") && mergedConfig.name.split("/").filter(Boolean).length > 1) mergedConfig.name = mergedConfig.name.split("/").filter(Boolean)[1];
2041
+ mergedConfig.title ??= titleCase(mergedConfig.name);
2042
+ if (mergedConfig.resolve.external) mergedConfig.resolve.external = getUnique(mergedConfig.resolve.external);
2043
+ if (mergedConfig.resolve.noExternal) mergedConfig.resolve.noExternal = getUnique(mergedConfig.resolve.noExternal);
2044
+ mergedConfig.plugins = (mergedConfig.plugins ?? []).flatMap((plugin) => toArray(plugin)).filter(Boolean).reduce((ret, plugin) => {
2089
2045
  if (isPlugin(plugin) && isDuplicate(plugin, ret.filter((p) => isPlugin(p)))) return ret;
2090
2046
  ret.push(plugin);
2091
2047
  return ret;
2092
2048
  }, []);
2093
- if (!this.config.userConfig?.logLevel && !this.config.initialConfig?.logLevel && !this.config.pluginConfig?.logLevel && !this.config.inlineConfig?.logLevel) if (this.config.mode === "development") this.config.logLevel = DEFAULT_DEVELOPMENT_LOG_LEVEL;
2094
- else if (this.config.mode === "test") this.config.logLevel = DEFAULT_TEST_LOG_LEVEL;
2095
- else this.config.logLevel = DEFAULT_PRODUCTION_LOG_LEVEL;
2096
- if (!this.config.userConfig?.tsconfig && !this.config.initialConfig?.tsconfig && !this.config.pluginConfig?.tsconfig && !this.config.inlineConfig?.tsconfig) this.config.tsconfig = getTsconfigFilePath(this.config.cwd, this.config.root);
2097
- else if (this.config.tsconfig) this.config.tsconfig = replacePath(replacePathTokens(this, this.config.tsconfig), this.config.cwd);
2098
- this.config.output.format = getUnique(toArray(this.config.output?.format ?? (this.config.projectType === "library" ? ["cjs", "esm"] : ["esm"])));
2099
- if (this.config.output.path) this.config.output.path = appendPath(replacePathTokens(this, this.config.output.path), this.config.cwd);
2100
- else this.config.output.path = appendPath(joinPaths(this.config.root, "dist"), this.config.cwd);
2101
- if (this.config.output.copy !== false) {
2102
- this.config.output.copy ??= {};
2103
- if (!this.config.root.replace(/^\.\/?/, "")) this.config.output.copy.path = this.config.output.copy.path ? appendPath(replacePathTokens(this, this.config.output.copy.path), this.config.cwd) : this.config.output.path;
2104
- else this.config.output.copy.path = appendPath(replacePathTokens(this, this.config.output.copy.path || joinPaths("dist", this.config.root)), this.config.cwd);
2105
- }
2106
- if (this.config.output.types !== false) this.config.output.types = appendPath(replacePathTokens(this, this.config.userConfig?.output?.types || this.config.inlineConfig?.output?.types || this.config.initialConfig?.output?.types || this.config.pluginConfig?.output?.types || joinPaths(this.config.root, `${this.config.framework ?? "powerlines"}.d.ts`)), this.config.cwd);
2107
- if (this.config.output.copy && this.config.output.copy.path && this.config.output.copy.assets && Array.isArray(this.config.output.copy.assets)) this.config.output.copy.assets = getUniqueBy(this.config.output.copy.assets.map((asset) => {
2049
+ if (!mergedConfig.logLevel) if (mergedConfig.mode === "development") mergedConfig.logLevel = DEFAULT_DEVELOPMENT_LOG_LEVEL;
2050
+ else if (mergedConfig.mode === "test") mergedConfig.logLevel = DEFAULT_TEST_LOG_LEVEL;
2051
+ else mergedConfig.logLevel = DEFAULT_PRODUCTION_LOG_LEVEL;
2052
+ if (mergedConfig.tsconfig) mergedConfig.tsconfig = replacePath(replacePathTokens(this, mergedConfig.tsconfig), mergedConfig.cwd);
2053
+ else mergedConfig.tsconfig = getTsconfigFilePath(mergedConfig.cwd, mergedConfig.root);
2054
+ mergedConfig.output.format = getUnique(toArray(mergedConfig.output?.format ?? (mergedConfig.projectType === "library" ? ["cjs", "esm"] : ["esm"])));
2055
+ if (mergedConfig.output.path) mergedConfig.output.path = appendPath(replacePathTokens(this, mergedConfig.output.path), mergedConfig.cwd);
2056
+ else mergedConfig.output.path = appendPath(joinPaths(mergedConfig.root, "dist"), mergedConfig.cwd);
2057
+ mergedConfig.output.copy ??= {};
2058
+ if (mergedConfig.output.copy !== false) if (!mergedConfig.root.replace(/^\.\/?/, "")) mergedConfig.output.copy.path = mergedConfig.output.copy.path ? appendPath(replacePathTokens(this, mergedConfig.output.copy.path), mergedConfig.cwd) : mergedConfig.output.path;
2059
+ else mergedConfig.output.copy.path = appendPath(replacePathTokens(this, mergedConfig.output.copy.path || joinPaths("dist", mergedConfig.root)), mergedConfig.cwd);
2060
+ if (mergedConfig.output.types !== false) mergedConfig.output.types = appendPath(replacePathTokens(this, mergedConfig.output.types || joinPaths(mergedConfig.root, `${mergedConfig.framework ?? "powerlines"}.d.ts`)), mergedConfig.cwd);
2061
+ if (mergedConfig.output.copy && mergedConfig.output.copy.path && mergedConfig.output.copy.assets && Array.isArray(mergedConfig.output.copy.assets)) mergedConfig.output.copy.assets = getUniqueBy(mergedConfig.output.copy.assets.map((asset) => {
2108
2062
  return {
2109
2063
  glob: isSetObject(asset) ? asset.glob : asset,
2110
- input: isString(asset) || !asset.input || asset.input === "." || asset.input === "/" || asset.input === "./" ? this.options.cwd : isParentPath(asset.input, this.config.cwd) || isEqual(asset.input, this.config.cwd) ? asset.input : appendPath(asset.input, this.config.cwd),
2111
- output: isSetObject(asset) && asset.output ? isParentPath(asset.output, this.config.cwd) ? asset.output : appendPath(joinPaths(this.config.output.copy.path, replacePath(replacePath(asset.output, replacePath(this.config.output.copy.path, this.config.cwd)), this.config.output.copy.path)), this.config.cwd) : appendPath(this.config.output.copy.path, this.config.cwd),
2064
+ input: isString(asset) || !asset.input || asset.input === "." || asset.input === "/" || asset.input === "./" ? mergedConfig.cwd : isParentPath(asset.input, mergedConfig.cwd) || isEqual(asset.input, mergedConfig.cwd) ? asset.input : appendPath(asset.input, mergedConfig.cwd),
2065
+ output: isSetObject(asset) && asset.output ? isParentPath(asset.output, mergedConfig.cwd) ? asset.output : appendPath(joinPaths(mergedConfig.output.copy.path, replacePath(replacePath(asset.output, replacePath(mergedConfig.output.copy.path, mergedConfig.cwd)), mergedConfig.output.copy.path)), mergedConfig.cwd) : appendPath(mergedConfig.output.copy.path, mergedConfig.cwd),
2112
2066
  ignore: isSetObject(asset) && asset.ignore ? toArray(asset.ignore) : void 0
2113
2067
  };
2114
2068
  }), (a) => `${a.input}-${a.glob}-${a.output}`);
2115
- if (!this.config.userConfig?.output?.sourceMap && !this.config.initialConfig?.output?.sourceMap && !this.config.inlineConfig?.output?.sourceMap && !this.config.pluginConfig?.output?.sourceMap) if (this.config.mode === "development") this.config.output.sourceMap = true;
2116
- else this.config.output.sourceMap = false;
2117
- if (!this.config.userConfig?.output?.minify && !this.config.initialConfig?.output?.minify && !this.config.inlineConfig?.output?.minify && !this.config.pluginConfig?.output?.minify) if (this.config.mode === "production") this.config.output.minify = true;
2118
- else this.config.output.minify = false;
2119
- if (!this.config.userConfig?.output?.artifactsPath && !this.config.initialConfig?.output?.artifactsPath && !this.config.inlineConfig?.output?.artifactsPath && !this.config.pluginConfig?.output?.artifactsPath) this.config.output.artifactsPath = `.${this.config.framework || "powerlines"}`;
2120
- if (this.config.output.copy && this.config.output.copy.assets) this.config.output.copy.assets = this.config.output.copy.assets.map((asset) => ({
2069
+ if (!mergedConfig.output?.sourceMap) if (mergedConfig.mode === "development") mergedConfig.output.sourceMap = true;
2070
+ else mergedConfig.output.sourceMap = false;
2071
+ if (!mergedConfig.output.minify) if (mergedConfig.mode === "production") mergedConfig.output.minify = true;
2072
+ else mergedConfig.output.minify = false;
2073
+ if (!mergedConfig.output.artifactsPath) mergedConfig.output.artifactsPath = `.${mergedConfig.framework || "powerlines"}`;
2074
+ if (mergedConfig.output.copy && mergedConfig.output.copy.assets) mergedConfig.output.copy.assets = mergedConfig.output.copy.assets.map((asset) => ({
2121
2075
  ...asset,
2122
2076
  glob: replacePathTokens(this, asset.glob),
2123
2077
  ignore: asset.ignore ? asset.ignore.map((ignore) => replacePathTokens(this, ignore)) : void 0,
2124
2078
  input: replacePathTokens(this, asset.input),
2125
2079
  output: replacePathTokens(this, asset.output)
2126
2080
  }));
2127
- if (isSetString(this.config.output?.storage) && this.config.output.storage === "virtual" || isSetObject(this.config.output?.storage) && Object.values(this.config.output.storage).every((adapter) => adapter.preset === "virtual")) this.config.output.overwrite = true;
2081
+ if (isSetString(mergedConfig.output?.storage) && mergedConfig.output.storage === "virtual" || isSetObject(mergedConfig.output?.storage) && Object.values(mergedConfig.output.storage).every((adapter) => adapter.preset === "virtual")) mergedConfig.output.overwrite = true;
2082
+ this.resolvedConfig = mergedConfig;
2083
+ this.#configProxy = this.createConfigProxy();
2084
+ this.logger.debug({
2085
+ meta: { category: "config" },
2086
+ message: `Resolved Powerlines configuration object: \n --- Resolved Config --- \n${this.logConfig(this.resolvedConfig)} \n --- Initial Config --- \n${this.logConfig(this.initialConfig)} \n --- User Config --- \n${this.logConfig(this.userConfig)} \n --- Inline Config --- \n${this.logConfig(this.inlineConfig)} \n --- Plugin Config --- \n${this.logConfig(this.pluginConfig)}`
2087
+ });
2128
2088
  this.#fs ??= await VirtualFileSystem.create(this);
2129
- if (isSetObject(this.config.inlineConfig) && isSetObject(this.config.userConfig) && isSetObject(this.config.initialConfig) && isSetObject(this.config.pluginConfig)) logger.debug(`Resolved Powerlines configuration object: \n${formatLogMessage({
2130
- ...omit(this.config, [
2131
- "inlineConfig",
2132
- "userConfig",
2133
- "initialConfig",
2134
- "pluginConfig",
2135
- "plugins"
2136
- ]),
2137
- inlineConfig: isSetObject(this.config.inlineConfig) ? omit(this.config.inlineConfig, ["plugins"]) : void 0,
2138
- userConfig: isSetObject(this.config.userConfig) ? omit(this.config.userConfig, ["plugins"]) : void 0,
2139
- initialConfig: isSetObject(this.config.initialConfig) ? omit(this.config.initialConfig, ["plugins"]) : void 0,
2140
- pluginConfig: isSetObject(this.config.pluginConfig) ? omit(this.config.pluginConfig, ["plugins"]) : void 0
2141
- })}`);
2089
+ }
2090
+ logConfig(config) {
2091
+ return formatLogMessage({
2092
+ ...omit(config, ["plugins"]),
2093
+ plugins: config.plugins ? config.plugins.flatMap((plugin) => toArray(plugin)).map((plugin) => String(isSetString(plugin) ? plugin : isPromise(plugin) ? "<promise>" : isFunction(plugin) ? plugin.name || "<anonymous function>" : Array.isArray(plugin) ? plugin[0] || "<anonymous function plugin>" : "<unknown plugin>")) : void 0
2094
+ });
2095
+ }
2096
+ createConfigProxy() {
2097
+ return new Proxy(this.resolvedConfig, {
2098
+ /**
2099
+ * A trap for the `delete` operator.
2100
+ * @param target - The original object which is being proxied.
2101
+ * @param key - The name or `Symbol` of the property to delete.
2102
+ * @returns A `boolean` indicating whether or not the property was deleted.
2103
+ */
2104
+ deleteProperty: (target, key) => {
2105
+ if (UNRESOLVED_CONFIG_NAMES.includes(key.toString())) throw new Error(`Cannot delete property ${key.toString()} from config - it is only intended to be used as a reference.`);
2106
+ Reflect.deleteProperty(this.overriddenConfig, key);
2107
+ return Reflect.deleteProperty(target, key);
2108
+ },
2109
+ /**
2110
+ * A trap for getting a property value.
2111
+ * @param target - The original object which is being proxied.
2112
+ * @param key - The name or `Symbol` of the property to get.
2113
+ * @param receiver - The proxy or an object that inherits from the proxy.
2114
+ */
2115
+ get: (target, key, receiver) => {
2116
+ if (UNRESOLVED_CONFIG_NAMES.includes(key.toString())) {
2117
+ if (key === "initialConfig") return this.initialConfig;
2118
+ if (key === "userConfig") return this.userConfig;
2119
+ if (key === "inlineConfig") return this.inlineConfig;
2120
+ if (key === "pluginConfig") return this.pluginConfig;
2121
+ }
2122
+ return Reflect.get(target, key, receiver);
2123
+ },
2124
+ /**
2125
+ * A trap for the `in` operator.
2126
+ * @param target - The original object which is being proxied.
2127
+ * @param key - The name or `Symbol` of the property to check for existence.
2128
+ */
2129
+ has: (target, key) => {
2130
+ return Reflect.has(target, key) || UNRESOLVED_CONFIG_NAMES.includes(key.toString());
2131
+ },
2132
+ /**
2133
+ * A trap for `Reflect.ownKeys()`.
2134
+ * @param target - The original object which is being proxied.
2135
+ */
2136
+ ownKeys: (target) => {
2137
+ return getUnique([...Reflect.ownKeys(target), ...UNRESOLVED_CONFIG_NAMES]);
2138
+ },
2139
+ /**
2140
+ * A trap for setting a property value.
2141
+ * @param target - The original object which is being proxied.
2142
+ * @param key - The name or `Symbol` of the property to set.
2143
+ * @param newValue - The new value to assign to the property.
2144
+ * @param receiver - The object to which the assignment was originally directed.
2145
+ * @returns A `boolean` indicating whether or not the property was set.
2146
+ */
2147
+ set: (target, key, newValue, receiver) => {
2148
+ if (UNRESOLVED_CONFIG_NAMES.includes(key.toString())) throw new Error(`Cannot change property ${key.toString()} from config - it is only intended to be used as a reference.`);
2149
+ Reflect.set(this.overriddenConfig, key, newValue, receiver);
2150
+ return Reflect.set(target, key, newValue, receiver);
2151
+ }
2152
+ });
2142
2153
  }
2143
2154
  };
2144
2155
 
@@ -2283,7 +2294,7 @@ function createPluginContext(pluginId, plugin, environment) {
2283
2294
  return {
2284
2295
  meta: {
2285
2296
  ...isSetObject(message) ? message.meta : {},
2286
- environment: environment.environment?.name,
2297
+ environment: environment.config.environment.name,
2287
2298
  plugin: plugin.name
2288
2299
  },
2289
2300
  message: isString(message) ? message : message.message
@@ -2306,6 +2317,8 @@ function createPluginContext(pluginId, plugin, environment) {
2306
2317
  callHook: callHookFn,
2307
2318
  meta
2308
2319
  };
2320
+ if (prop === "api") return environment.$$internal.api;
2321
+ if (prop === "environment") return environment;
2309
2322
  if (prop === "id") return pluginId;
2310
2323
  if (prop === "logger") return logger;
2311
2324
  if (prop === "log") return (type, message) => {
@@ -2358,6 +2371,15 @@ function createPluginContext(pluginId, plugin, environment) {
2358
2371
  //#endregion
2359
2372
  //#region src/context/environment-context.ts
2360
2373
  var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends PowerlinesContext {
2374
+ /**
2375
+ * Internal references storage
2376
+ *
2377
+ * @danger
2378
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2379
+ *
2380
+ * @internal
2381
+ */
2382
+ #internal = {};
2361
2383
  /**
2362
2384
  * The hooks registered by plugins in this environment
2363
2385
  */
@@ -2367,29 +2389,50 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
2367
2389
  *
2368
2390
  * @param options - The resolved execution options.
2369
2391
  * @param config - The user configuration options.
2370
- * @returns A promise that resolves to the new context.
2392
+ * @param overriddenConfig - The configuration options that should override all other configuration sources, such as CLI flags or environment variables. This is used to ensure that certain configuration values take precedence over any other settings defined in the user configuration or environment configuration, allowing for dynamic overrides based on the execution context.
2393
+ * @param environment - The resolved environment configuration, which may include additional properties or modifications made during the configuration loading process. This is used to provide context about the environment in which the command is being executed, allowing for environment-specific behavior and configuration resolution.
2394
+ * @returns A promise that resolves to an instance of the PowerlinesEnvironmentContext class, initialized with the provided configuration and environment data.
2371
2395
  */
2372
- static async fromConfig(options, config, environment) {
2373
- const context = new PowerlinesEnvironmentContext(options, config, environment);
2374
- await context.setup();
2375
- const powerlinesPath = await resolvePackage("powerlines");
2376
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
2377
- context.powerlinesPath = powerlinesPath;
2396
+ static async createEnvironment(options, config, overriddenConfig, environment) {
2397
+ const context = new PowerlinesEnvironmentContext(options, config, overriddenConfig);
2398
+ await context.setEnvironmentConfig(environment);
2378
2399
  return context;
2379
2400
  }
2380
2401
  /**
2381
- * The resolved environment configuration
2402
+ * The configuration options provided by plugins added by the user (and other plugins)
2382
2403
  */
2383
- environment;
2404
+ environmentConfig = {};
2384
2405
  /**
2385
2406
  * The list of plugins applied to this environment
2386
2407
  */
2387
2408
  plugins = [];
2388
2409
  /**
2410
+ * Internal context fields and methods
2411
+ *
2412
+ * @danger
2413
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2414
+ *
2415
+ * @internal
2416
+ */
2417
+ get $$internal() {
2418
+ return this.#internal;
2419
+ }
2420
+ /**
2421
+ * Internal context fields and methods
2422
+ *
2423
+ * @danger
2424
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2425
+ *
2426
+ * @internal
2427
+ */
2428
+ set $$internal(value) {
2429
+ this.#internal = value;
2430
+ }
2431
+ /**
2389
2432
  * The unique identifier of the environment associated with this context, which can be used for logging and other purposes to distinguish between different environments in the same process.
2390
2433
  */
2391
2434
  get id() {
2392
- return this.environment.environmentId;
2435
+ return this.config.environment.id;
2393
2436
  }
2394
2437
  /**
2395
2438
  * The hooks registered by plugins in this environment
@@ -2398,6 +2441,20 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
2398
2441
  return this.#hooks;
2399
2442
  }
2400
2443
  /**
2444
+ * A setter function to populate the environment config values provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed. This function can be used to update the context with the environment configuration values, which may be used during the configuration resolution process to ensure that the final configuration reflects both the user configuration and any environment configuration provided during execution.
2445
+ *
2446
+ * @param config - The environment configuration values to set.
2447
+ * @returns A promise that resolves when the environment configuration values have been set.
2448
+ */
2449
+ async setEnvironmentConfig(config) {
2450
+ this.logger.debug({
2451
+ meta: { category: "config" },
2452
+ message: `Updating environment configuration object: \n${this.logConfig(config)}`
2453
+ });
2454
+ this.environmentConfig = config;
2455
+ await this.resolveConfig();
2456
+ }
2457
+ /**
2401
2458
  * Create a new logger instance
2402
2459
  *
2403
2460
  * @param options - The configuration options to use for the logger instance, which can be used to customize the appearance and behavior of the log messages generated by the logger. This is typically the name of the plugin or module that is creating the logger instance.
@@ -2407,7 +2464,7 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
2407
2464
  createLogger(options, logFn) {
2408
2465
  return super.createLogger({
2409
2466
  ...options,
2410
- environment: this.environment?.name
2467
+ environment: this.config.environment?.name
2411
2468
  }, logFn);
2412
2469
  }
2413
2470
  /**
@@ -2419,39 +2476,13 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
2419
2476
  extendLogger(options) {
2420
2477
  return super.extendLogger({
2421
2478
  ...options,
2422
- environment: this.environment?.name
2479
+ environment: this.config.environment?.name
2423
2480
  });
2424
2481
  }
2425
- /**
2426
- * Creates a clone of the current context with the same configuration and workspace settings. This can be useful for running multiple builds in parallel or for creating isolated contexts for different parts of the build process.
2427
- *
2428
- * @remarks
2429
- * The cloned context will have the same configuration and workspace settings as the original context, but will have a different build ID, release ID, and timestamp. The virtual file system and caches will also be separate between the original and cloned contexts.
2430
- *
2431
- * @returns A promise that resolves to the cloned context.
2432
- */
2433
- async clone() {
2434
- const context = await PowerlinesEnvironmentContext.fromConfig(deepClone(this.options), deepClone(this.config), deepClone(this.environment));
2435
- return this.copyTo(context);
2436
- }
2437
- /**
2438
- * Initialize the context with the provided configuration options
2439
- */
2440
- async setup() {
2441
- this.resolvedConfig = mergeConfig({
2442
- name: this.config.name,
2443
- title: this.config.title
2444
- }, getConfigProps({
2445
- ...this.environment,
2446
- root: this.options.root,
2447
- cwd: this.options.cwd
2448
- }), this.config);
2449
- await this.innerSetup();
2450
- }
2451
2482
  async addPlugin(plugin) {
2452
2483
  let resolvedPlugin = plugin;
2453
2484
  if (isFunction(plugin.applyToEnvironment)) {
2454
- const result = await Promise.resolve(plugin.applyToEnvironment(this.environment));
2485
+ const result = await Promise.resolve(plugin.applyToEnvironment(this.config.environment));
2455
2486
  if (!result || isObject(result) && Object.keys(result).length === 0) return;
2456
2487
  if (isPluginConfig(result)) return this.$$internal.addPlugin(result);
2457
2488
  resolvedPlugin = isPlugin(result) ? result : plugin;
@@ -2502,29 +2533,51 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
2502
2533
  }
2503
2534
  return result;
2504
2535
  }
2505
- constructor(options, config, environment) {
2506
- super(options);
2507
- this.resolvedConfig = config;
2508
- this.environment = environment;
2536
+ constructor(options, config, overriddenConfig) {
2537
+ super(options, config.initialConfig);
2538
+ this.userConfig = config.userConfig ?? {};
2539
+ this.inlineConfig = config.inlineConfig ?? {};
2540
+ this.pluginConfig = config.pluginConfig ?? {};
2541
+ this.overriddenConfig = overriddenConfig;
2509
2542
  }
2510
2543
  /**
2511
- * Creates a clone of the current context with the same configuration and workspace settings. This can be useful for running multiple builds in parallel or for creating isolated contexts for different parts of the build process.
2512
- *
2513
- * @remarks
2514
- * The cloned context will have the same configuration and workspace settings as the original context, but will have a different build ID, release ID, and timestamp. The virtual file system and caches will also be separate between the original and cloned contexts.
2544
+ * A function to merge the various configuration objects (initial, user, inline, and plugin) into a single resolved configuration object that can be used throughout the Powerlines process. This function takes into account the different sources of configuration and their respective priorities, ensuring that the final configuration reflects the intended settings for the project. The merged configuration is then returned as a new object that can be accessed through the `config` property of the context.
2515
2545
  *
2516
- * @returns The cloned context.
2546
+ * @returns The merged configuration object that combines the initial, user, inline, and plugin configurations.
2517
2547
  */
2518
- copyTo(context) {
2519
- context.plugins = this.plugins;
2520
- return super.copyTo(context);
2548
+ mergeConfig() {
2549
+ return mergeConfig({
2550
+ ...omit(this.environmentConfig ?? {}, [
2551
+ "ssr",
2552
+ "preview",
2553
+ "consumer",
2554
+ "runtime"
2555
+ ]),
2556
+ environment: { name: this.environmentConfig?.name || DEFAULT_ENVIRONMENT },
2557
+ environmentConfig: this.environmentConfig ?? {}
2558
+ }, super.mergeConfig());
2521
2559
  }
2522
2560
  };
2523
2561
 
2524
2562
  //#endregion
2525
2563
  //#region src/context/execution-context.ts
2526
2564
  var PowerlinesExecutionContext = class PowerlinesExecutionContext extends PowerlinesContext {
2565
+ /**
2566
+ * Internal references storage
2567
+ *
2568
+ * @danger
2569
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2570
+ *
2571
+ * @internal
2572
+ */
2573
+ #internal = {};
2574
+ /**
2575
+ * A record of all environments by name
2576
+ */
2527
2577
  #environments = {};
2578
+ /**
2579
+ * The plugins added to this execution context, which may be used to track the plugins that have been added to the context and ensure that they are properly registered and executed during the build process. This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2580
+ */
2528
2581
  #plugins = [];
2529
2582
  /**
2530
2583
  * Create a new Storm context from the workspace root and user config.
@@ -2532,12 +2585,9 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2532
2585
  * @param options - The options for resolving the context.
2533
2586
  * @returns A promise that resolves to the new context.
2534
2587
  */
2535
- static async init(options, initialConfig) {
2536
- const context = new PowerlinesExecutionContext(options);
2537
- await context.init(options, initialConfig);
2538
- const powerlinesPath = await resolvePackage("powerlines");
2539
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
2540
- context.powerlinesPath = powerlinesPath;
2588
+ static async fromInitialConfig(options, initialConfig) {
2589
+ const context = new PowerlinesExecutionContext(options, initialConfig);
2590
+ await context.init();
2541
2591
  return context;
2542
2592
  }
2543
2593
  /**
@@ -2546,19 +2596,10 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2546
2596
  * @param options - The options for resolving the context.
2547
2597
  * @returns A promise that resolves to the new context.
2548
2598
  */
2549
- static async inline(options, initialConfig, inlineConfig) {
2550
- const context = new PowerlinesExecutionContext(options);
2551
- await context.init(options, initialConfig);
2552
- context.config.inlineConfig = inlineConfig;
2553
- if (context.config.inlineConfig.command === "new") {
2554
- const workspacePackageJsonPath = joinPaths(context.config.cwd, "package.json");
2555
- if (!existsSync(workspacePackageJsonPath)) throw new Error(`The workspace package.json file could not be found at ${workspacePackageJsonPath}`);
2556
- context.packageJson = await readJsonFile(workspacePackageJsonPath);
2557
- }
2558
- await context.setup();
2559
- const powerlinesPath = await resolvePackage("powerlines");
2560
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
2561
- context.powerlinesPath = powerlinesPath;
2599
+ static async fromInlineConfig(options, initialConfig, inlineConfig) {
2600
+ const context = new PowerlinesExecutionContext(options, initialConfig);
2601
+ await context.init();
2602
+ await context.setInlineConfig(inlineConfig);
2562
2603
  return context;
2563
2604
  }
2564
2605
  /**
@@ -2570,7 +2611,7 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2570
2611
  * @internal
2571
2612
  */
2572
2613
  get $$internal() {
2573
- return super.$$internal;
2614
+ return this.#internal;
2574
2615
  }
2575
2616
  /**
2576
2617
  * Internal context fields and methods
@@ -2581,8 +2622,8 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2581
2622
  * @internal
2582
2623
  */
2583
2624
  set $$internal(value) {
2584
- super.$$internal = value;
2585
- for (const environment of Object.values(this.environments)) environment.$$internal = super.$$internal;
2625
+ this.#internal = value;
2626
+ for (const environment of Object.values(this.environments)) environment.$$internal = value;
2586
2627
  }
2587
2628
  /**
2588
2629
  * The unique identifier of the execution context, which can be used for logging and other purposes to distinguish between different executions in the same process.
@@ -2603,9 +2644,26 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2603
2644
  * Creates a new instance.
2604
2645
  *
2605
2646
  * @param options - The options to use for creating the context, including the resolved configuration and workspace settings.
2647
+ * @param initialConfig - The initial configuration options to use for the context, which can be used to provide default values for configuration options that may be overridden by user configuration or inline configuration. This is typically the configuration options provided by the user in a configuration file on disk, and can include any relevant settings such as environment definitions, plugin configurations, and other parameters that may be relevant to the execution of a Powerlines command.
2606
2648
  */
2607
- constructor(options) {
2608
- super(options);
2649
+ constructor(options, initialConfig = {}) {
2650
+ super(options, initialConfig);
2651
+ this.initialOptions = options;
2652
+ this.initialConfig = initialConfig;
2653
+ }
2654
+ /**
2655
+ * A setter function to populate the inline config values provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed. This function can be used to update the context with the inline configuration values, which may be used during the configuration resolution process to ensure that the final configuration reflects both the user configuration and any inline configuration provided during execution.
2656
+ *
2657
+ * @param config - The inline configuration values to set.
2658
+ * @returns A promise that resolves when the inline configuration values have been set.
2659
+ */
2660
+ async setInlineConfig(config) {
2661
+ await super.setInlineConfig(config);
2662
+ if (this.inlineConfig.command === "new") {
2663
+ const workspacePackageJsonPath = joinPaths(this.config.cwd, "package.json");
2664
+ if (!existsSync(workspacePackageJsonPath)) throw new Error(`The workspace package.json file could not be found at ${workspacePackageJsonPath}`);
2665
+ this.packageJson = await readJsonFile(workspacePackageJsonPath);
2666
+ }
2609
2667
  }
2610
2668
  /**
2611
2669
  * Create a new logger instance
@@ -2635,31 +2693,20 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2635
2693
  });
2636
2694
  }
2637
2695
  /**
2638
- * Creates a clone of the current context with the same configuration and workspace settings. This can be useful for running multiple builds in parallel or for creating isolated contexts for different parts of the build process.
2639
- *
2640
- * @remarks
2641
- * The cloned context will have the same configuration and workspace settings as the original context, but will have a different build ID, release ID, and timestamp. The virtual file system and caches will also be separate between the original and cloned contexts.
2642
- *
2643
- * @returns A promise that resolves to the cloned context.
2644
- */
2645
- async clone() {
2646
- const clone = await PowerlinesExecutionContext.init(this.options, this.initialConfig);
2647
- clone.config.userConfig = deepClone(this.config.userConfig);
2648
- clone.config.initialConfig = deepClone(this.config.initialConfig);
2649
- clone.config.inlineConfig = deepClone(this.config.inlineConfig);
2650
- clone.config.pluginConfig = deepClone(this.config.pluginConfig);
2651
- await clone.setup();
2652
- clone.$$internal = this.$$internal;
2653
- return this.copyTo(clone);
2654
- }
2655
- /**
2656
2696
  * A function to copy the context and update the fields for a specific environment
2657
2697
  *
2658
2698
  * @param environment - The environment configuration to use.
2659
2699
  * @returns A new context instance with the updated environment.
2660
2700
  */
2661
- async in(environment) {
2662
- const context = this.copyTo(await PowerlinesEnvironmentContext.fromConfig(deepClone(this.options), deepClone(this.config), deepClone(environment)));
2701
+ async createEnvironment(environment) {
2702
+ const context = await PowerlinesEnvironmentContext.createEnvironment(deepClone(this.options), deepClone(this.config), deepClone(this.overriddenConfig), deepClone(environment));
2703
+ context.dependencies = deepClone(this.dependencies);
2704
+ context.devDependencies = deepClone(this.devDependencies);
2705
+ context.persistedMeta = deepClone(this.persistedMeta);
2706
+ context.resolvePatterns = deepClone(this.resolvePatterns);
2707
+ context.powerlinesPath ??= this.powerlinesPath;
2708
+ context.resolver ??= this.resolver;
2709
+ context.$$internal = this.$$internal;
2663
2710
  context.plugins = [];
2664
2711
  for (const plugin of this.plugins) await context.addPlugin(plugin);
2665
2712
  return context;
@@ -2667,10 +2714,10 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2667
2714
  /**
2668
2715
  * Update the context using a new inline configuration options
2669
2716
  */
2670
- async setup() {
2671
- await super.setup();
2717
+ async resolveConfig() {
2718
+ await super.resolveConfig();
2672
2719
  await Promise.all(toArray(this.config.environments && Object.keys(this.config.environments).length > 0 ? Object.keys(this.config.environments).map((name) => createEnvironment(name, this.config)) : createDefaultEnvironment(this.config)).map(async (env) => {
2673
- this.#environments[env.name] = await this.in(env);
2720
+ this.#environments[env.name] = await this.createEnvironment(env);
2674
2721
  }));
2675
2722
  }
2676
2723
  /**
@@ -2695,12 +2742,20 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2695
2742
  if (name) environment = this.environments[name];
2696
2743
  if (Object.keys(this.environments).length === 1) {
2697
2744
  environment = this.environments[Object.keys(this.environments)[0]];
2698
- this.debug(`Applying the only configured environment: ${chalk.bold.cyanBright(environment?.environment.name)}`);
2745
+ this.trace({
2746
+ meta: { category: "plugins" },
2747
+ message: `Applying the only configured environment: ${chalk.bold.cyanBright(environment?.config.environment?.name)}`
2748
+ });
2699
2749
  }
2700
2750
  if (!environment) {
2701
2751
  if (name) throw new Error(`Environment "${name}" not found.`);
2702
- environment = await this.in(createDefaultEnvironment(this.config));
2703
- this.warn(`No environment specified, and no default environment found. Using a temporary default environment: ${chalk.bold.cyanBright(environment?.environment.name)}`);
2752
+ environment = await PowerlinesEnvironmentContext.createEnvironment(deepClone(this.options), deepClone(this.config), deepClone(this.overriddenConfig), deepClone(createDefaultEnvironment(this.config)));
2753
+ environment.plugins = [];
2754
+ for (const plugin of this.plugins) await environment.addPlugin(plugin);
2755
+ this.warn({
2756
+ meta: { category: "plugins" },
2757
+ message: `No environment specified, and no default environment found. Using a temporary default environment: ${chalk.bold.cyanBright(environment.config.environment?.name)}`
2758
+ });
2704
2759
  }
2705
2760
  return environment;
2706
2761
  }
@@ -2728,8 +2783,11 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2728
2783
  async toEnvironment() {
2729
2784
  let environment;
2730
2785
  if (Object.keys(this.environments).length > 1) {
2731
- environment = await this.in(createEnvironment(GLOBAL_ENVIRONMENT, this.config));
2732
- this.debug(`Combined all ${Object.keys(this.environments).length} environments into a single global context.`);
2786
+ environment = await this.createEnvironment(createEnvironment(GLOBAL_ENVIRONMENT, this.config));
2787
+ this.debug({
2788
+ meta: { category: "plugins" },
2789
+ message: `Combined all ${Object.keys(this.environments).length} environments into a single global context.`
2790
+ });
2733
2791
  } else environment = await this.getEnvironment();
2734
2792
  return environment;
2735
2793
  }
@@ -2737,4 +2795,4 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
2737
2795
 
2738
2796
  //#endregion
2739
2797
  export { mergeConfigs as a, callHook as i, PowerlinesEnvironmentContext as n, PowerlinesContext as o, createPluginContext as r, writeMetaFile as s, PowerlinesExecutionContext as t };
2740
- //# sourceMappingURL=execution-context-BRzNYU9u.mjs.map
2798
+ //# sourceMappingURL=execution-context-Cp32TarF.mjs.map