@powerlines/engine 0.45.3 → 0.46.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.
Files changed (52) hide show
  1. package/dist/_internal/worker.cjs +886 -803
  2. package/dist/_internal/worker.mjs +889 -806
  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-D7G_24-i.cjs} +82 -76
  12. package/dist/{base-context-BSAC5sO9.mjs → base-context-DU0NRHDt.mjs} +85 -79
  13. package/dist/base-context-DU0NRHDt.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-BuJQY312.cjs +91 -0
  21. package/dist/engine-context-BvDfqfY7.mjs +86 -0
  22. package/dist/engine-context-BvDfqfY7.mjs.map +1 -0
  23. package/dist/execution-context-BpRfsnkE.d.mts +644 -0
  24. package/dist/execution-context-BpRfsnkE.d.mts.map +1 -0
  25. package/dist/{execution-context-BYGFYty0.cjs → execution-context-BrX9i_L8.cjs} +449 -364
  26. package/dist/{execution-context-Bkxp1fML.mjs → execution-context-CgDuoi8o.mjs} +451 -366
  27. package/dist/execution-context-CgDuoi8o.mjs.map +1 -0
  28. package/dist/execution-context-CodQucFX.d.cts +644 -0
  29. package/dist/execution-context-CodQucFX.d.cts.map +1 -0
  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-Bkxp1fML.mjs.map +0 -1
  52. package/dist/tsconfig-CI6bla4E.mjs.map +0 -1
@@ -69,21 +69,21 @@ let _stryke_helpers_deep_clone = require("@stryke/helpers/deep-clone");
69
69
  let _stryke_path_join = require("@stryke/path/join");
70
70
  let _stryke_unique_id_uuid = require("@stryke/unique-id/uuid");
71
71
  let _powerlines_core_lib_entry = require("@powerlines/core/lib/entry");
72
- let _stryke_convert_to_bool = require("@stryke/convert/to-bool");
73
72
  let _stryke_env_get_env_paths = require("@stryke/env/get-env-paths");
74
73
  let _stryke_fs_get_workspace_root = require("@stryke/fs/get-workspace-root");
75
74
  let _stryke_hash = require("@stryke/hash");
76
75
  let _stryke_hash_node = require("@stryke/hash/node");
77
76
  let _stryke_http_fetch = require("@stryke/http/fetch");
78
77
  let _stryke_path_is_equal = require("@stryke/path/is-equal");
79
- let _stryke_string_format_kebab_case = require("@stryke/string-format/kebab-case");
80
78
  let bundle_require = require("bundle-require");
81
79
  let compatx = require("compatx");
82
80
  let flat_cache = require("flat-cache");
83
81
  let oxc_parser = require("oxc-parser");
84
82
  let undici = require("undici");
85
83
  require("@stryke/fs/remove-file");
84
+ let _stryke_string_format_kebab_case = require("@stryke/string-format/kebab-case");
86
85
  let _powerlines_core = require("@powerlines/core");
86
+ let jest_worker = require("jest-worker");
87
87
  let _stryke_capnp = require("@stryke/capnp");
88
88
  _stryke_capnp = __toESM(_stryke_capnp, 1);
89
89
  let _stryke_fs_buffer = require("@stryke/fs/buffer");
@@ -117,9 +117,9 @@ let _donedeal0_superdiff = require("@donedeal0/superdiff");
117
117
  let _stryke_json_storm_json = require("@stryke/json/storm-json");
118
118
 
119
119
  //#region src/_internal/helpers/environment.ts
120
- function createEnvironment(name, config = {}) {
120
+ function createEnvironment(name, config) {
121
121
  return (0, defu.default)(config.environments?.[name] ?? {}, {
122
- environmentId: (0, _stryke_unique_id_uuid.uuid)(),
122
+ id: (0, _stryke_unique_id_uuid.uuid)(),
123
123
  name,
124
124
  title: config.title ?? (0, _stryke_string_format_title_case.titleCase)(config.name),
125
125
  ssr: false,
@@ -145,7 +145,7 @@ function createEnvironment(name, config = {}) {
145
145
  } : void 0
146
146
  });
147
147
  }
148
- function createDefaultEnvironment(config = {}) {
148
+ function createDefaultEnvironment(config) {
149
149
  return createEnvironment(_powerlines_core_constants.DEFAULT_ENVIRONMENT, config);
150
150
  }
151
151
 
@@ -202,16 +202,16 @@ async function writeMetaFile(context) {
202
202
 
203
203
  //#endregion
204
204
  //#region src/_internal/ipc/send.ts
205
- function sendWriteLogMessage(context, meta, message) {
205
+ function formatWriteLogMessage(context, meta, message) {
206
206
  const combinedMeta = {
207
207
  ...context.logger.options,
208
208
  ...(0, _stryke_type_checks_is_set_object.isSetObject)(meta) ? meta : { type: meta }
209
209
  };
210
- process.send?.({
210
+ return {
211
211
  id: (0, _stryke_unique_id_uuid.uuid)(),
212
212
  type: "write-log",
213
- executionId: combinedMeta.executionId || context.config.executionId,
214
- executionIndex: combinedMeta.executionIndex ?? context.config.executionIndex,
213
+ executionId: combinedMeta.executionId || context.options.executionId,
214
+ executionIndex: combinedMeta.executionIndex ?? context.options.executionIndex,
215
215
  environment: combinedMeta.environment,
216
216
  timestamp: Date.now(),
217
217
  payload: {
@@ -221,8 +221,8 @@ function sendWriteLogMessage(context, meta, message) {
221
221
  logId: combinedMeta.logId || (0, _stryke_unique_id_uuid.uuid)(),
222
222
  timestamp: combinedMeta.timestamp ?? Date.now(),
223
223
  name: combinedMeta.name || context.config.name,
224
- executionId: combinedMeta.executionId || context.config.executionId,
225
- executionIndex: combinedMeta.executionIndex ?? context.config.executionIndex,
224
+ executionId: combinedMeta.executionId || context.options.executionId,
225
+ executionIndex: combinedMeta.executionIndex ?? context.options.executionIndex,
226
226
  command: combinedMeta.command || context.config.command,
227
227
  hook: combinedMeta.hook,
228
228
  environment: combinedMeta.environment,
@@ -231,7 +231,21 @@ function sendWriteLogMessage(context, meta, message) {
231
231
  },
232
232
  message
233
233
  }
234
- });
234
+ };
235
+ }
236
+ function childProcessSend(message) {
237
+ process.send?.(message);
238
+ }
239
+ function workerThreadSend(message) {
240
+ (0, jest_worker.messageParent)(message);
241
+ }
242
+ function send(message) {
243
+ if (process.env.POWERLINES_EXECUTION_THREAD_TYPE === "child-process") childProcessSend(message);
244
+ else if (process.env.POWERLINES_EXECUTION_THREAD_TYPE === "worker-thread") workerThreadSend(message);
245
+ else console.warn("No IPC mechanism available to send message:", message);
246
+ }
247
+ function sendWriteLogMessage(context, meta, message) {
248
+ send(formatWriteLogMessage(context, meta, message));
235
249
  }
236
250
 
237
251
  //#endregion
@@ -2029,40 +2043,40 @@ var VirtualFileSystem = class VirtualFileSystem {
2029
2043
  /**
2030
2044
  * Get the path to the tsconfig.json file.
2031
2045
  *
2032
- * @param workspaceRoot - The root directory of the workspace.
2033
- * @param projectRoot - The root directory of the project.
2046
+ * @param cwd - The root directory of the workspace.
2047
+ * @param root - The root directory of the project.
2034
2048
  * @param tsconfig - The path to the tsconfig.json file.
2035
2049
  * @returns The absolute path to the tsconfig.json file.
2036
2050
  * @throws If the tsconfig.json file does not exist.
2037
2051
  */
2038
- function getTsconfigFilePath(workspaceRoot, projectRoot, tsconfig) {
2052
+ function getTsconfigFilePath(cwd, root, tsconfig) {
2039
2053
  let tsconfigFilePath;
2040
- if (tsconfig) tsconfigFilePath = tryTsconfigFilePath(workspaceRoot, projectRoot, tsconfig);
2054
+ if (tsconfig) tsconfigFilePath = tryTsconfigFilePath(cwd, root, tsconfig);
2041
2055
  else {
2042
- tsconfigFilePath = tryTsconfigFilePath(workspaceRoot, projectRoot, "tsconfig.app.json");
2056
+ tsconfigFilePath = tryTsconfigFilePath(cwd, root, "tsconfig.app.json");
2043
2057
  if (!tsconfigFilePath) {
2044
- tsconfigFilePath = tryTsconfigFilePath(workspaceRoot, projectRoot, "tsconfig.lib.json");
2045
- if (!tsconfigFilePath) tsconfigFilePath = tryTsconfigFilePath(workspaceRoot, projectRoot, "tsconfig.json");
2058
+ tsconfigFilePath = tryTsconfigFilePath(cwd, root, "tsconfig.lib.json");
2059
+ if (!tsconfigFilePath) tsconfigFilePath = tryTsconfigFilePath(cwd, root, "tsconfig.json");
2046
2060
  }
2047
2061
  }
2048
- if (!tsconfigFilePath) throw new Error(`Cannot find the \`tsconfig.json\` configuration file for the project at ${projectRoot}.`);
2062
+ if (!tsconfigFilePath) throw new Error(`Cannot find the \`tsconfig.json\` configuration file for the project at ${root}.`);
2049
2063
  return tsconfigFilePath;
2050
2064
  }
2051
2065
  /**
2052
2066
  * Get the path to the tsconfig.json file.
2053
2067
  *
2054
- * @param workspaceRoot - The root directory of the workspace.
2055
- * @param projectRoot - The root directory of the project.
2068
+ * @param cwd - The root directory of the workspace.
2069
+ * @param root - The root directory of the project.
2056
2070
  * @param tsconfig - The path to the tsconfig.json file.
2057
2071
  * @returns The absolute path to the tsconfig.json file.
2058
2072
  * @throws If the tsconfig.json file does not exist.
2059
2073
  */
2060
- function tryTsconfigFilePath(workspaceRoot, projectRoot, tsconfig) {
2074
+ function tryTsconfigFilePath(cwd, root, tsconfig) {
2061
2075
  let tsconfigFilePath = tsconfig;
2062
2076
  if (!(0, _stryke_fs_exists.existsSync)(tsconfigFilePath)) {
2063
- tsconfigFilePath = (0, _stryke_path_append.appendPath)(tsconfig, projectRoot);
2077
+ tsconfigFilePath = (0, _stryke_path_append.appendPath)(tsconfig, root);
2064
2078
  if (!(0, _stryke_fs_exists.existsSync)(tsconfigFilePath)) {
2065
- tsconfigFilePath = (0, _stryke_path_append.appendPath)(tsconfig, (0, _stryke_path_append.appendPath)(projectRoot, workspaceRoot));
2079
+ tsconfigFilePath = (0, _stryke_path_append.appendPath)(tsconfig, (0, _stryke_path_append.appendPath)(root, cwd));
2066
2080
  if (!(0, _stryke_fs_exists.existsSync)(tsconfigFilePath)) return;
2067
2081
  }
2068
2082
  }
@@ -2189,7 +2203,7 @@ function createResolver(options) {
2189
2203
 
2190
2204
  //#endregion
2191
2205
  //#region src/context/base-context.ts
2192
- var PowerlinesBaseContext = class PowerlinesBaseContext {
2206
+ var PowerlinesBaseContext = class {
2193
2207
  #timestamp = Date.now();
2194
2208
  /**
2195
2209
  * The path to the Powerlines package
@@ -2200,17 +2214,17 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2200
2214
  */
2201
2215
  resolver;
2202
2216
  /**
2203
- * The options provided to the Powerlines process
2217
+ * 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.
2204
2218
  */
2205
2219
  options;
2206
2220
  /**
2207
- * 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
2221
+ * The parsed `package.json` file for the project
2208
2222
  */
2209
- initialOptions = {};
2223
+ packageJson;
2210
2224
  /**
2211
- * The initial configuration provided when initializing the context, which may be used during the setup process to ensure that the configuration is properly merged and applied to the context. This is typically the user configuration provided in the Powerlines configuration file, but may also include additional configuration options provided by plugins or other sources.
2225
+ * The parsed `project.json` file for the project
2212
2226
  */
2213
- initialConfig = {};
2227
+ projectJson = void 0;
2214
2228
  /**
2215
2229
  * The parsed configuration file for the project
2216
2230
  */
@@ -2241,19 +2255,6 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2241
2255
  });
2242
2256
  }
2243
2257
  /**
2244
- * 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.
2245
- *
2246
- * @remarks
2247
- * 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.
2248
- *
2249
- * @returns A promise that resolves to the cloned context.
2250
- */
2251
- async clone() {
2252
- const clone = new PowerlinesBaseContext();
2253
- await clone.init(this.options, this.initialConfig);
2254
- return clone;
2255
- }
2256
- /**
2257
2258
  * A logging function for fatal messages
2258
2259
  *
2259
2260
  * @param message - The message to log.
@@ -2333,7 +2334,7 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2333
2334
  * @returns A logger client instance that can be used to generate log messages with consistent formatting and metadata.
2334
2335
  */
2335
2336
  createLogger(options, logFn) {
2336
- return (0, _powerlines_core_plugin_utils_logging.createLogger)(this.options.name || this.options.root, {
2337
+ return (0, _powerlines_core_plugin_utils_logging.createLogger)(this.options.name || this.options.root || "powerlines", {
2337
2338
  ...this.configFile.config,
2338
2339
  ...this.options,
2339
2340
  ...options
@@ -2349,6 +2350,24 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2349
2350
  return (0, _powerlines_core_plugin_utils_logging.extendLogger)(this.logger, options);
2350
2351
  }
2351
2352
  /**
2353
+ * 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
2354
+ */
2355
+ initialOptions = {};
2356
+ /**
2357
+ * The initial configuration provided when initializing the context, which may be used during the setup process to ensure that the configuration is properly merged and applied to the context. This is typically the user configuration provided in the Powerlines configuration file, but may also include additional configuration options provided by plugins or other sources.
2358
+ */
2359
+ initialConfig = {};
2360
+ /**
2361
+ * Initialize the context with the provided configuration options and set up the resolver and user configuration file. This method 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 as the original context.
2362
+ *
2363
+ * @param options - The configuration options to initialize the context with, which can include properties such as the project root, mode, log level, and other settings that affect the behavior of the context and its plugins.
2364
+ * @param initialConfig - The initial configuration to initialize the context with, which is typically the user configuration provided in the Powerlines configuration file. This can also include additional configuration options provided by plugins or other sources that should be merged with the user configuration during initialization
2365
+ */
2366
+ constructor(options, initialConfig = {}) {
2367
+ this.initialOptions = options;
2368
+ this.initialConfig = initialConfig;
2369
+ }
2370
+ /**
2352
2371
  * Retrieve the workspace configuration for the current project, if it exists. This function will look for a configuration file in the project root and return its contents as a JavaScript object. If no configuration file is found, it will return undefined.
2353
2372
  *
2354
2373
  * @returns A promise that resolves to the workspace configuration object, or undefined if no configuration file is found.
@@ -2360,64 +2379,41 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2360
2379
  } : void 0);
2361
2380
  }
2362
2381
  /**
2363
- * Determine the default mode for the current execution based on the environment and workspace configuration. This function will check the `NODE_ENV` environment variable to determine if the current environment is development, production, or test. If `NODE_ENV` is not set, it will look for a `mode` property in the workspace configuration file. If no mode is specified in the workspace configuration, it will default to "production".
2364
- *
2365
- * @returns A promise that resolves to the default mode for the current execution, which can be "development", "production", or "test".
2366
- */
2367
- async getDefaultMode() {
2368
- const workspaceConfig = await this.getWorkspaceConfig();
2369
- return _stryke_env_environment_checks.isProduction ? "production" : _stryke_env_environment_checks.isDevelopment ? "development" : _stryke_env_environment_checks.isTest ? "test" : workspaceConfig?.mode || "production";
2370
- }
2371
- /**
2372
- * Determine the default log level for the current execution based on the environment and workspace configuration. This function will check the `logLevel` property in the workspace configuration file and resolve it to a `LogLevelResolvedConfig` value. If no log level is specified in the workspace configuration, it will default to "info" for development mode and "warn" for production mode.
2373
- *
2374
- * @returns A promise that resolves to the default log level for the current execution, which can be "fatal", "error", "warn", "info", "debug", or "trace".
2375
- */
2376
- async getDefaultLogLevel() {
2377
- const workspaceConfig = await this.getWorkspaceConfig();
2378
- return (0, _powerlines_core_plugin_utils.resolveLogLevel)(workspaceConfig?.logLevel ? workspaceConfig.logLevel === "success" || workspaceConfig.logLevel === "performance" ? "info" : workspaceConfig.logLevel === "all" ? "debug" : workspaceConfig.logLevel === "fatal" ? "error" : workspaceConfig.logLevel : void 0, this.options?.mode || this.initialOptions?.mode || workspaceConfig?.mode || await this.getDefaultMode());
2379
- }
2380
- /**
2381
2382
  * Initialize the context with the provided configuration options
2382
2383
  *
2383
2384
  * @remarks
2384
2385
  * 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.
2385
- *
2386
- * @param options - The configuration options to initialize the context with
2387
- * @param initialConfig - The initial configuration to initialize the context with
2388
2386
  */
2389
- async init(options, initialConfig) {
2390
- this.initialOptions = { ...options };
2391
- this.initialConfig = { ...initialConfig };
2387
+ async init() {
2392
2388
  if (!this.powerlinesPath) {
2393
2389
  const powerlinesPath = await (0, _stryke_fs_resolve.resolvePackage)("powerlines");
2394
2390
  if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
2395
2391
  this.powerlinesPath = powerlinesPath;
2396
2392
  }
2397
- const cwd = options.cwd || this.options?.cwd || process.cwd();
2398
- const root = (0, _stryke_path_replace.replacePath)((options.root || this.options?.root) && (options.root || this.options.root).replace(/^\.\/?/, "") && !(0, _stryke_path_is_equal.isEqual)(options.root || this.options.root, cwd) ? options.root || this.options.root : ".", cwd);
2399
- this.options = (0, defu.default)({
2400
- name: options.name || this.initialConfig.name,
2401
- root,
2402
- cwd,
2403
- mode: options.mode || this.initialConfig.mode,
2404
- logLevel: options.logLevel || this.initialConfig.logLevel,
2405
- framework: options.framework || this.initialConfig.framework,
2406
- organization: options.organization || this.initialConfig.organization,
2407
- configFile: options.configFile || this.initialConfig.configFile
2408
- }, this.options ?? {}, {
2393
+ this.options = (0, defu.default)(this.initialOptions, this.initialConfig, {
2394
+ cwd: process.cwd(),
2409
2395
  mode: await this.getDefaultMode(),
2410
- logLevel: await this.getDefaultLogLevel()
2396
+ logLevel: await this.getDefaultLogLevel(),
2397
+ framework: "powerlines"
2411
2398
  });
2399
+ if (!this.options.root) if (this.options.configFile) {
2400
+ const configFile = (0, _stryke_path_append.appendPath)(this.options.configFile, this.options.cwd);
2401
+ if (!(0, node_fs.existsSync)(configFile)) throw new Error(`The user-provided configuration file at "${this.options.configFile}" does not exist. Please ensure this path is correct and try again.`);
2402
+ if (!(0, _stryke_fs.isFile)(configFile)) throw new Error(`The user-provided configuration file at "${this.options.configFile}" is not a file. Please ensure this path is correct and try again.`);
2403
+ this.options.root = (0, _stryke_path.relativePath)(this.options.cwd, (0, _stryke_path.findFilePath)(configFile));
2404
+ } else this.options.root = ".";
2405
+ else this.options.root = (0, _stryke_path_replace.replacePath)(this.options.root, this.options.cwd);
2412
2406
  this.resolver = createResolver({
2413
- workspaceRoot: cwd,
2414
- root,
2407
+ workspaceRoot: this.options.cwd,
2408
+ root: this.options.root,
2415
2409
  cacheDir: this.envPaths.cache,
2416
2410
  mode: this.options.mode
2417
2411
  });
2412
+ await this.resolvePackageConfigs();
2418
2413
  this.configFile = await (0, _powerlines_core_lib_config.loadUserConfigFile)(this.options, this.resolver);
2419
- if (!this.options.name) {
2420
- if (this.configFile.config) {
2414
+ if (this.configFile.config) {
2415
+ if ((0, _stryke_type_checks_is_set_string.isSetString)(this.configFile.configFile)) this.options.configFile ??= (0, _stryke_path_replace.replacePath)(this.configFile.configFile, this.options.cwd);
2416
+ if (!this.options.name) {
2421
2417
  if ((0, _stryke_type_checks_is_set_object.isSetObject)(this.configFile.config) && (0, _stryke_type_checks_is_set_string.isSetString)(this.configFile.config.name)) this.options.name = this.configFile.config.name;
2422
2418
  else if (Array.isArray(this.configFile.config)) {
2423
2419
  for (const config of this.configFile.config) if ((0, _stryke_type_checks_is_set_object.isSetObject)(config) && (0, _stryke_type_checks_is_set_string.isSetString)(config.name)) {
@@ -2426,22 +2422,46 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2426
2422
  }
2427
2423
  }
2428
2424
  }
2429
- if (!this.options.name) {
2430
- const packageJsonPath = (0, _stryke_path.joinPaths)((0, _stryke_path_append.appendPath)(this.options.root, this.options.cwd), "package.json");
2431
- if ((0, node_fs.existsSync)(packageJsonPath)) {
2432
- const packageJson = await (0, _stryke_fs.readJsonFile)(packageJsonPath);
2433
- this.options.name = packageJson.name;
2434
- }
2435
- if (!this.options.name) {
2436
- const projectJsonPath = (0, _stryke_path.joinPaths)((0, _stryke_path_append.appendPath)(this.options.root, this.options.cwd), "project.json");
2437
- if ((0, node_fs.existsSync)(projectJsonPath)) {
2438
- const projectJson = await (0, _stryke_fs.readJsonFile)(projectJsonPath);
2439
- this.options.name = projectJson.name;
2440
- }
2441
- }
2442
- }
2425
+ if (!this.options.name) this.options.name = this.projectJson?.name || this.packageJson?.name;
2426
+ }
2427
+ }
2428
+ /**
2429
+ * Resolve the package configurations for the project by loading the `package.json` and `project.json` files, if they exist. This function will look for these files in the project root and parse their contents as JavaScript objects. The parsed contents will be stored in the context for later use by plugins and other parts of the build process.
2430
+ *
2431
+ * @remarks
2432
+ * The `package.json` file is typically used to store metadata about the project, such as its name, version, dependencies, and other information. The `project.json` file is an optional file that can be used to store additional configuration or metadata specific to the project, and is not required for all projects.
2433
+ *
2434
+ * @param cwd - The current working directory to look for the package configurations. Defaults to the `cwd` specified in the context configuration.
2435
+ * @param root - The root directory of the project to look for the package configurations. Defaults to the `root` specified in the context configuration.
2436
+ * @returns A promise that resolves when the package configurations have been loaded and stored in the context.
2437
+ */
2438
+ async resolvePackageConfigs(cwd = this.options.cwd, root = this.options.root) {
2439
+ const projectJsonPath = (0, _stryke_path.joinPaths)((0, _stryke_path_append.appendPath)(root, cwd), "project.json");
2440
+ if ((0, node_fs.existsSync)(projectJsonPath)) this.projectJson = await (0, _stryke_fs.readJsonFile)(projectJsonPath);
2441
+ const packageJsonPath = (0, _stryke_path.joinPaths)((0, _stryke_path_append.appendPath)(root, cwd), "package.json");
2442
+ if ((0, node_fs.existsSync)(packageJsonPath)) {
2443
+ this.packageJson = await (0, _stryke_fs.readJsonFile)(packageJsonPath);
2444
+ this.options.organization ??= (0, _stryke_type_checks_is_set_object.isSetObject)(this.packageJson?.author) ? (0, _stryke_string_format_kebab_case.kebabCase)(this.packageJson?.author?.name) : (0, _stryke_string_format_kebab_case.kebabCase)(this.packageJson?.author);
2443
2445
  }
2444
2446
  }
2447
+ /**
2448
+ * Determine the default mode for the current execution based on the environment and workspace configuration. This function will check the `NODE_ENV` environment variable to determine if the current environment is development, production, or test. If `NODE_ENV` is not set, it will look for a `mode` property in the workspace configuration file. If no mode is specified in the workspace configuration, it will default to "production".
2449
+ *
2450
+ * @returns A promise that resolves to the default mode for the current execution, which can be "development", "production", or "test".
2451
+ */
2452
+ async getDefaultMode() {
2453
+ const workspaceConfig = await this.getWorkspaceConfig();
2454
+ return _stryke_env_environment_checks.isProduction ? "production" : _stryke_env_environment_checks.isDevelopment ? "development" : _stryke_env_environment_checks.isTest ? "test" : workspaceConfig?.mode || "production";
2455
+ }
2456
+ /**
2457
+ * Determine the default log level for the current execution based on the environment and workspace configuration. This function will check the `logLevel` property in the workspace configuration file and resolve it to a `LogLevelResolvedConfig` value. If no log level is specified in the workspace configuration, it will default to "info" for development mode and "warn" for production mode.
2458
+ *
2459
+ * @returns A promise that resolves to the default log level for the current execution, which can be "fatal", "error", "warn", "info", "debug", or "trace".
2460
+ */
2461
+ async getDefaultLogLevel() {
2462
+ const workspaceConfig = await this.getWorkspaceConfig();
2463
+ return (0, _powerlines_core_plugin_utils.resolveLogLevel)(workspaceConfig?.logLevel ? workspaceConfig.logLevel === "success" || workspaceConfig.logLevel === "performance" ? "info" : workspaceConfig.logLevel === "all" ? "debug" : workspaceConfig.logLevel === "fatal" ? "error" : workspaceConfig.logLevel : void 0, this.options?.mode || this.initialOptions?.mode || workspaceConfig?.mode || await this.getDefaultMode());
2464
+ }
2445
2465
  };
2446
2466
 
2447
2467
  //#endregion
@@ -2453,27 +2473,13 @@ var PowerlinesBaseContext = class PowerlinesBaseContext {
2453
2473
  timeoutFactor: 2,
2454
2474
  retryAfter: true
2455
2475
  })));
2456
- const SKIP_CLONING_PROPS = [
2457
- "dependencies",
2458
- "devDependencies",
2459
- "persistedMeta",
2460
- "packageJson",
2461
- "projectJson",
2462
- "tsconfig",
2463
- "resolver",
2464
- "fs",
2465
- "$$internal"
2476
+ const UNRESOLVED_CONFIG_NAMES = [
2477
+ "initialConfig",
2478
+ "userConfig",
2479
+ "inlineConfig",
2480
+ "pluginConfig"
2466
2481
  ];
2467
2482
  var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2468
- /**
2469
- * Internal references storage
2470
- *
2471
- * @danger
2472
- * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2473
- *
2474
- * @internal
2475
- */
2476
- #internal = {};
2477
2483
  #checksum = null;
2478
2484
  #buildId = (0, _stryke_unique_id_uuid.uuid)();
2479
2485
  #releaseId = (0, _stryke_unique_id_uuid.uuid)();
@@ -2481,24 +2487,22 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2481
2487
  #tsconfig;
2482
2488
  #parserCache;
2483
2489
  #requestCache;
2490
+ #configProxy;
2484
2491
  /**
2485
- * Create a new Storm context from the workspace root and user config.
2492
+ * Create a new context from the workspace root and user config.
2486
2493
  *
2487
2494
  * @param options - The options for resolving the context.
2488
2495
  * @returns A promise that resolves to the new context.
2489
2496
  */
2490
- static async init(options, initialConfig) {
2491
- const context = new PowerlinesContext(options);
2492
- await context.init(options, initialConfig);
2493
- const powerlinesPath = await (0, _stryke_fs_resolve.resolvePackage)("powerlines");
2494
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
2495
- context.powerlinesPath = powerlinesPath;
2497
+ static async fromInitialConfig(options, initialConfig) {
2498
+ const context = new PowerlinesContext(options, initialConfig);
2499
+ await context.init();
2496
2500
  return context;
2497
2501
  }
2498
2502
  /**
2499
- * The options provided to the Powerlines process
2503
+ * 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.
2500
2504
  */
2501
- options;
2505
+ options = {};
2502
2506
  /**
2503
2507
  * An object containing the dependencies that should be installed for the project
2504
2508
  */
@@ -2512,39 +2516,33 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2512
2516
  */
2513
2517
  persistedMeta = void 0;
2514
2518
  /**
2515
- * The parsed `package.json` file for the project
2519
+ * The resolved tsconfig file paths for the project
2516
2520
  */
2517
- packageJson;
2521
+ resolvePatterns = [];
2518
2522
  /**
2519
- * The parsed `project.json` file for the project
2523
+ * 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
2520
2524
  */
2521
- projectJson = void 0;
2525
+ initialOptions = {};
2522
2526
  /**
2523
- * The resolved tsconfig file paths for the project
2527
+ * The resolved configuration for this context
2524
2528
  */
2525
- resolvePatterns = [];
2529
+ resolvedConfig = {};
2526
2530
  /**
2527
- * Internal context fields and methods
2528
- *
2529
- * @danger
2530
- * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2531
- *
2532
- * @internal
2531
+ * 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.
2533
2532
  */
2534
- get $$internal() {
2535
- return this.#internal;
2536
- }
2533
+ overriddenConfig = {};
2537
2534
  /**
2538
- * Internal context fields and methods
2539
- *
2540
- * @danger
2541
- * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
2542
- *
2543
- * @internal
2535
+ * 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.
2544
2536
  */
2545
- set $$internal(value) {
2546
- this.#internal = value;
2547
- }
2537
+ inlineConfig = {};
2538
+ /**
2539
+ * 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.
2540
+ */
2541
+ userConfig = {};
2542
+ /**
2543
+ * The configuration options provided by plugins added by the user (and other plugins)
2544
+ */
2545
+ pluginConfig = {};
2548
2546
  /**
2549
2547
  * The resolved entry type definitions for the project
2550
2548
  */
@@ -2599,13 +2597,14 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2599
2597
  * The resolved configuration options
2600
2598
  */
2601
2599
  get config() {
2602
- return this.resolvedConfig;
2600
+ if (!this.#configProxy) this.#configProxy = this.createConfigProxy();
2601
+ return this.#configProxy;
2603
2602
  }
2604
2603
  /**
2605
2604
  * Get the path to the artifacts directory for the project
2606
2605
  */
2607
2606
  get artifactsPath() {
2608
- return (0, _stryke_path_join.joinPaths)(this.config.cwd, this.config.root, this.config.output.artifactsPath);
2607
+ return (0, _stryke_path_join.joinPaths)(this.config.cwd, this.config.root, this.config.output?.artifactsPath || `.${this.config.framework || "powerlines"}`);
2609
2608
  }
2610
2609
  /**
2611
2610
  * Get the path to the builtin modules used by the project
@@ -2662,7 +2661,7 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2662
2661
  * Additional arguments provided during execution of the command, such as CLI flags or other parameters that may be relevant to the command being executed.
2663
2662
  */
2664
2663
  get additionalArgs() {
2665
- return Object.entries(this.config.inlineConfig?.additionalArgs ?? {}).reduce((ret, [key, value]) => {
2664
+ return Object.entries(this.config.inlineConfig.additionalArgs ?? {}).reduce((ret, [key, value]) => {
2666
2665
  const formattedKey = key.replace(/^--?/, "");
2667
2666
  if (ret[formattedKey]) if (Array.isArray(ret[formattedKey])) if (Array.isArray(value)) ret[formattedKey] = [...(0, _stryke_convert_to_array.toArray)(ret[formattedKey]), ...value];
2668
2667
  else ret[formattedKey] = [...(0, _stryke_convert_to_array.toArray)(ret[formattedKey]), value];
@@ -2691,29 +2690,6 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2691
2690
  }, {}) : this.config.resolve.alias : {});
2692
2691
  }
2693
2692
  /**
2694
- * Create a new logger instance
2695
- *
2696
- * @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.
2697
- * @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.
2698
- * @returns A logger client instance that can be used to generate log messages with consistent formatting and metadata.
2699
- */
2700
- createLogger(options, logFn) {
2701
- let logger;
2702
- if ((0, _stryke_convert_to_bool.toBool)(process.env.POWERLINES_WORKER_THREAD_EXECUTION)) logger = (0, _powerlines_core_plugin_utils.createLogger)(this.config.name, {
2703
- ...this.options,
2704
- ...this.config,
2705
- ...options
2706
- }, (meta, message) => sendWriteLogMessage(this, meta, message));
2707
- else logger = (0, _powerlines_core_plugin_utils.createLogger)(this.config.name, {
2708
- ...this.options,
2709
- ...this.config,
2710
- ...options
2711
- });
2712
- if (this.config.customLogger) logger = (0, _powerlines_core_plugin_utils.withCustomLogger)(logger, this.config.customLogger);
2713
- if (logFn) logger = (0, _powerlines_core_plugin_utils.withLogFn)(logger, logFn);
2714
- return logger;
2715
- }
2716
- /**
2717
2693
  * 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.
2718
2694
  */
2719
2695
  get logLevel() {
@@ -2775,25 +2751,38 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
2775
2751
  }).filter(Boolean);
2776
2752
  }
2777
2753
  /**
2778
- * Creates a new StormContext instance.
2754
+ * Creates a new Context instance.
2779
2755
  *
2780
2756
  * @param options - The options to use for creating the context, including the resolved configuration and workspace settings.
2757
+ * @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.
2781
2758
  */
2782
- constructor(options) {
2783
- super();
2784
- this.options = options;
2759
+ constructor(options, initialConfig) {
2760
+ super(options, initialConfig);
2761
+ this.initialOptions = options;
2762
+ this.initialConfig = initialConfig;
2785
2763
  }
2786
2764
  /**
2787
- * 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.
2788
- *
2789
- * @remarks
2790
- * 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.
2765
+ * Create a new logger instance
2791
2766
  *
2792
- * @returns A promise that resolves to the cloned context.
2767
+ * @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.
2768
+ * @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.
2769
+ * @returns A logger client instance that can be used to generate log messages with consistent formatting and metadata.
2793
2770
  */
2794
- async clone() {
2795
- const clone = await PowerlinesContext.init(this.options, this.initialConfig);
2796
- return this.copyTo(clone);
2771
+ createLogger(options, logFn) {
2772
+ let logger;
2773
+ if ((0, _stryke_type_checks_is_set_string.isSetString)(process.env.POWERLINES_EXECUTION_THREAD_TYPE)) logger = (0, _powerlines_core_plugin_utils.createLogger)(this.config.name, {
2774
+ ...this.options,
2775
+ ...this.config,
2776
+ ...options
2777
+ }, (meta, message) => sendWriteLogMessage(this, meta, message));
2778
+ else logger = (0, _powerlines_core_plugin_utils.createLogger)(this.config.name, {
2779
+ ...this.options,
2780
+ ...this.config,
2781
+ ...options
2782
+ });
2783
+ if (this.config.customLogger) logger = (0, _powerlines_core_plugin_utils.withCustomLogger)(logger, this.config.customLogger);
2784
+ if (logFn) logger = (0, _powerlines_core_plugin_utils.withLogFn)(logger, logFn);
2785
+ return logger;
2797
2786
  }
2798
2787
  /**
2799
2788
  * A function to perform HTTP fetch requests
@@ -3123,206 +3112,247 @@ var PowerlinesContext = class PowerlinesContext extends PowerlinesBaseContext {
3123
3112
  /**
3124
3113
  * Generates a checksum representing the current context state
3125
3114
  *
3126
- * @param root - The root directory of the project to generate the checksum for
3115
+ * @param path - The root directory of the project to generate the checksum for
3127
3116
  * @returns A promise that resolves to a string representing the checksum
3128
3117
  */
3129
- async generateChecksum(root = this.config.root) {
3130
- this.#checksum = await (0, _stryke_hash_node.hashDirectory)(root, { ignore: [
3131
- "node_modules",
3132
- ".git",
3133
- ".nx",
3134
- ".cache",
3135
- "tmp",
3136
- "dist"
3137
- ] });
3138
- return this.#checksum;
3118
+ async generateChecksum(path) {
3119
+ return (0, _stryke_hash_node.hashDirectory)(path || (0, _stryke_path_append.appendPath)(this.options.root, this.options.cwd));
3139
3120
  }
3140
3121
  /**
3141
- * Initialize the context with the provided configuration options
3122
+ * 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.
3123
+ *
3124
+ * @param config - The inline configuration values to set.
3125
+ * @returns A promise that resolves when the inline configuration values have been set.
3142
3126
  */
3143
- async setup() {
3144
- this.resolvedConfig = (0, _powerlines_core_plugin_utils.mergeConfig)({
3145
- root: this.options.root,
3146
- cwd: this.options.cwd,
3147
- inlineConfig: this.config.inlineConfig ?? {},
3148
- userConfig: this.config.userConfig ?? {},
3149
- initialConfig: this.config.initialConfig ?? {},
3150
- pluginConfig: this.config.pluginConfig ?? {}
3151
- }, getConfigProps(this.config.inlineConfig), getConfigProps(this.config.userConfig), getConfigProps(this.config.initialConfig), getConfigProps(this.config.pluginConfig), this.options, {
3152
- name: this.projectJson?.name || this.packageJson?.name,
3127
+ async setInlineConfig(config) {
3128
+ this.logger.debug({
3129
+ meta: { category: "config" },
3130
+ message: `Updating inline configuration object: \n${this.logConfig(config)}`
3131
+ });
3132
+ this.inlineConfig = config;
3133
+ await this.resolveConfig();
3134
+ }
3135
+ /**
3136
+ * 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.
3137
+ *
3138
+ * @param config - The plugin configuration values to set.
3139
+ * @returns A promise that resolves when the plugin configuration values have been set.
3140
+ */
3141
+ async setPluginConfig(config) {
3142
+ this.logger.debug({
3143
+ meta: { category: "config" },
3144
+ message: `Updating plugin configuration object: \n${this.logConfig(config)}`
3145
+ });
3146
+ this.pluginConfig = config;
3147
+ await this.resolveConfig();
3148
+ }
3149
+ /**
3150
+ * 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.
3151
+ *
3152
+ * @returns The merged configuration object that combines the initial, user, inline, and plugin configurations.
3153
+ */
3154
+ mergeConfig() {
3155
+ return (0, _powerlines_core_plugin_utils.mergeConfig)({
3156
+ mode: this.initialOptions.mode,
3157
+ framework: this.initialOptions.framework,
3158
+ initialOptions: this.initialOptions,
3159
+ options: this.options,
3160
+ inlineConfig: this.inlineConfig,
3161
+ userConfig: this.userConfig,
3162
+ initialConfig: this.initialConfig,
3163
+ pluginConfig: this.pluginConfig
3164
+ }, getConfigProps(this.overriddenConfig), (0, _stryke_helpers_omit.omit)(this.options, ["mode", "framework"]), getConfigProps(this.inlineConfig), getConfigProps(this.userConfig), getConfigProps(this.initialConfig), getConfigProps(this.pluginConfig), {
3153
3165
  version: this.packageJson?.version,
3154
3166
  description: this.packageJson?.description
3155
3167
  }, {
3156
3168
  environments: {},
3157
3169
  resolve: {}
3158
3170
  });
3159
- await this.innerSetup();
3160
3171
  }
3161
3172
  /**
3162
- * The resolved configuration for this context
3163
- */
3164
- resolvedConfig = {};
3165
- /**
3166
- * 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.
3167
- *
3168
- * @remarks
3169
- * 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.
3173
+ * 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.
3170
3174
  *
3171
- * @returns The cloned context.
3175
+ * @param config - The user configuration values to set.
3176
+ * @returns A promise that resolves when the user configuration values have been set.
3172
3177
  */
3173
- copyTo(context) {
3174
- for (const [key, value] of Object.entries(this)) if (!SKIP_CLONING_PROPS.includes(key)) if ((0, _stryke_type_checks_is_object.isObject)(value) || Array.isArray(value)) context[key] = (0, _stryke_helpers_deep_clone.deepClone)(value);
3175
- else context[key] = value;
3176
- context.initialConfig = (0, _stryke_helpers_deep_clone.deepClone)(this.initialConfig);
3177
- context.initialOptions = (0, _stryke_helpers_deep_clone.deepClone)(this.initialOptions);
3178
- context.options = (0, _stryke_helpers_deep_clone.deepClone)(this.options);
3179
- context.dependencies = (0, _stryke_helpers_deep_clone.deepClone)(this.dependencies);
3180
- context.devDependencies = (0, _stryke_helpers_deep_clone.deepClone)(this.devDependencies);
3181
- context.persistedMeta = this.persistedMeta ? (0, _stryke_helpers_deep_clone.deepClone)(this.persistedMeta) : void 0;
3182
- context.packageJson = (0, _stryke_helpers_deep_clone.deepClone)(this.packageJson);
3183
- context.projectJson = this.projectJson ? (0, _stryke_helpers_deep_clone.deepClone)(this.projectJson) : void 0;
3184
- context.tsconfig ??= (0, _stryke_helpers_deep_clone.deepClone)(this.tsconfig);
3185
- context.resolver ??= this.resolver;
3186
- context.fs ??= this.#fs;
3187
- context.$$internal = this.$$internal;
3188
- return context;
3178
+ async setUserConfig(config) {
3179
+ this.logger.debug({
3180
+ meta: { category: "config" },
3181
+ message: `Updating user configuration object: \n${this.logConfig(config)}`
3182
+ });
3183
+ this.userConfig = config;
3184
+ await this.resolveConfig();
3189
3185
  }
3190
3186
  /**
3191
3187
  * Initialize the context with the provided configuration options
3188
+ */
3189
+ async init() {
3190
+ await super.init();
3191
+ this.options.executionId = this.initialOptions.executionId || (0, _stryke_unique_id_uuid.uuid)();
3192
+ this.options.executionIndex = this.initialOptions.executionIndex ?? 0;
3193
+ this.#checksum = await this.generateChecksum();
3194
+ const result = this.configFile.config && (0, _stryke_convert_to_array.toArray)(this.configFile.config).length > this.options.executionIndex ? (0, _stryke_convert_to_array.toArray)(this.configFile.config)[this.options.executionIndex] : this.configFile.config;
3195
+ if (!result) this.logger.warn(`No configuration found in ${this.options.configFile} for execution index ${this.options.executionIndex}.`);
3196
+ else await this.setUserConfig((0, _stryke_type_checks_is_function.isFunction)(result) ? await Promise.resolve(result(this.options)) : result);
3197
+ }
3198
+ /**
3199
+ * Resolve the package configurations for the project by loading the `package.json` and `project.json` files, if they exist. This function will look for these files in the project root and parse their contents as JavaScript objects. The parsed contents will be stored in the context for later use by plugins and other parts of the build process.
3192
3200
  *
3193
- * @remarks
3194
- * 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.
3201
+ * @remarks
3202
+ * The `package.json` file is typically used to store metadata about the project, such as its name, version, dependencies, and other information. The `project.json` file is an optional file that can be used to store additional configuration or metadata specific to the project, and is not required for all projects.
3195
3203
  *
3196
- * @param options - The configuration options to initialize the context with
3197
- */
3198
- async init(options, initialConfig) {
3199
- await super.init(options, initialConfig ?? {});
3200
- this.options.executionId = options.executionId ?? this.options.executionId;
3201
- this.options.executionIndex = options.executionIndex ?? this.options.executionIndex ?? 0;
3202
- const projectJsonPath = (0, _stryke_path_join.joinPaths)(this.options.cwd, this.options.root, "project.json");
3203
- if ((0, _stryke_fs_exists.existsSync)(projectJsonPath)) this.projectJson = await (0, _stryke_fs_json.readJsonFile)(projectJsonPath);
3204
- const packageJsonPath = (0, _stryke_path_join.joinPaths)(this.options.cwd, this.options.root, "package.json");
3205
- if ((0, _stryke_fs_exists.existsSync)(packageJsonPath)) {
3206
- this.packageJson = await (0, _stryke_fs_json.readJsonFile)(packageJsonPath);
3207
- this.options.organization ??= (0, _stryke_type_checks_is_set_object.isSetObject)(this.packageJson?.author) ? (0, _stryke_string_format_kebab_case.kebabCase)(this.packageJson?.author?.name) : (0, _stryke_string_format_kebab_case.kebabCase)(this.packageJson?.author);
3208
- }
3209
- this.#checksum = await this.generateChecksum((0, _stryke_path_join.joinPaths)(this.options.cwd, this.options.root));
3210
- 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 : {};
3211
- this.resolvedConfig = {
3212
- cwd: this.options.cwd,
3213
- root: this.options.root,
3214
- ...this.initialOptions,
3215
- ...initialConfig,
3216
- ...userConfig,
3217
- inlineConfig: {},
3218
- pluginConfig: {},
3219
- initialConfig,
3220
- userConfig
3221
- };
3204
+ * @param cwd - The current working directory to look for the package configurations. Defaults to the `cwd` specified in the context configuration.
3205
+ * @param root - The root directory of the project to look for the package configurations. Defaults to the `root` specified in the context configuration.
3206
+ * @returns A promise that resolves when the package configurations have been loaded and stored in the context.
3207
+ */
3208
+ async resolvePackageConfigs(cwd = this.config.cwd, root = this.config.root) {
3209
+ return super.resolvePackageConfigs(cwd, root);
3222
3210
  }
3223
3211
  /**
3224
3212
  * Initialize the context with the provided configuration options
3225
3213
  */
3226
- async innerSetup() {
3227
- const logger = this.extendLogger({ category: "config" });
3228
- this.config.plugins = (this.config.initialConfig.plugins ?? []).concat(this.config.userConfig.plugins ?? [], this.config.inlineConfig.plugins ?? []);
3229
- this.config.output = (0, defu.default)(this.config.output ?? {}, {
3214
+ async resolveConfig() {
3215
+ const mergedConfig = this.mergeConfig();
3216
+ this.logger.trace({
3217
+ meta: { category: "config" },
3218
+ 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)}`
3219
+ });
3220
+ mergedConfig.output = (0, defu.default)(mergedConfig.output ?? {}, {
3230
3221
  copy: { assets: [
3231
3222
  { glob: "LICENSE" },
3232
3223
  {
3233
- input: this.config.root,
3224
+ input: mergedConfig.root,
3234
3225
  glob: "*.md"
3235
3226
  },
3236
3227
  {
3237
- input: this.config.root,
3228
+ input: mergedConfig.root,
3238
3229
  glob: "package.json"
3239
3230
  }
3240
3231
  ] },
3241
3232
  dts: true
3242
3233
  });
3243
- logger.trace(`Pre-setup Powerlines configuration object: \n${(0, _storm_software_config_tools_logger_console.formatLogMessage)({
3244
- ...(0, _stryke_helpers_omit.omit)(this.config, [
3245
- "inlineConfig",
3246
- "userConfig",
3247
- "initialConfig",
3248
- "pluginConfig",
3249
- "plugins"
3250
- ]),
3251
- inlineConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.inlineConfig) ? (0, _stryke_helpers_omit.omit)(this.config.inlineConfig, ["plugins"]) : void 0,
3252
- userConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.userConfig) ? (0, _stryke_helpers_omit.omit)(this.config.userConfig, ["plugins"]) : void 0,
3253
- initialConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.initialConfig) ? (0, _stryke_helpers_omit.omit)(this.config.initialConfig, ["plugins"]) : void 0,
3254
- pluginConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.pluginConfig) ? (0, _stryke_helpers_omit.omit)(this.config.pluginConfig, ["plugins"]) : void 0
3255
- })}`);
3256
- if (!this.initialOptions.mode && !this.config.userConfig?.mode && !this.config.inlineConfig?.mode && !this.config.initialConfig?.mode && !this.config.pluginConfig?.mode) {
3257
- this.options.mode = "production";
3258
- this.config.mode = "production";
3259
- }
3260
- if (!this.initialOptions.framework && !this.config.userConfig?.framework && !this.config.inlineConfig?.framework && !this.config.initialConfig?.framework && !this.config.pluginConfig?.framework) {
3261
- this.options.framework = "powerlines";
3262
- this.config.framework = "powerlines";
3263
- }
3264
- if (!this.config.userConfig?.projectType && !this.config.inlineConfig?.projectType && !this.config.initialConfig?.projectType && !this.config.pluginConfig?.projectType) this.config.projectType = "application";
3265
- if (!this.config.userConfig?.platform && !this.config.inlineConfig?.platform && !this.config.initialConfig?.platform && !this.config.pluginConfig?.platform) this.config.platform = "neutral";
3266
- this.config.compatibilityDate = (0, compatx.resolveCompatibilityDates)(this.config.inlineConfig.compatibilityDate ?? this.config.userConfig.compatibilityDate ?? this.config.initialConfig.compatibilityDate ?? this.config.pluginConfig.compatibilityDate, "latest");
3267
- this.config.input = (0, _powerlines_core_lib_entry.getUniqueInputs)(this.config.input);
3268
- if (this.config.name?.startsWith("@") && this.config.name.split("/").filter(Boolean).length > 1) this.config.name = this.config.name.split("/").filter(Boolean)[1];
3269
- this.config.title ??= (0, _stryke_string_format_title_case.titleCase)(this.config.name);
3270
- if (this.config.resolve.external) this.config.resolve.external = (0, _stryke_helpers_get_unique.getUnique)(this.config.resolve.external);
3271
- if (this.config.resolve.noExternal) this.config.resolve.noExternal = (0, _stryke_helpers_get_unique.getUnique)(this.config.resolve.noExternal);
3272
- this.config.plugins = (this.config.plugins ?? []).flatMap((plugin) => (0, _stryke_convert_to_array.toArray)(plugin)).filter(Boolean).reduce((ret, plugin) => {
3234
+ if (!mergedConfig.mode) mergedConfig.mode = "production";
3235
+ if (!mergedConfig.framework) mergedConfig.framework = "powerlines";
3236
+ if (!mergedConfig.projectType) mergedConfig.projectType = "application";
3237
+ if (!mergedConfig.platform) mergedConfig.platform = "neutral";
3238
+ mergedConfig.compatibilityDate = (0, compatx.resolveCompatibilityDates)(mergedConfig.compatibilityDate, "latest");
3239
+ this.resolvedConfig = mergedConfig;
3240
+ this.#configProxy = this.createConfigProxy();
3241
+ if (!this.packageJson) await this.resolvePackageConfigs();
3242
+ mergedConfig.input = (0, _powerlines_core_lib_entry.getUniqueInputs)(mergedConfig.input);
3243
+ if (mergedConfig.name?.startsWith("@") && mergedConfig.name.split("/").filter(Boolean).length > 1) mergedConfig.name = mergedConfig.name.split("/").filter(Boolean)[1];
3244
+ mergedConfig.title ??= (0, _stryke_string_format_title_case.titleCase)(mergedConfig.name);
3245
+ if (mergedConfig.resolve.external) mergedConfig.resolve.external = (0, _stryke_helpers_get_unique.getUnique)(mergedConfig.resolve.external);
3246
+ if (mergedConfig.resolve.noExternal) mergedConfig.resolve.noExternal = (0, _stryke_helpers_get_unique.getUnique)(mergedConfig.resolve.noExternal);
3247
+ mergedConfig.plugins = (mergedConfig.plugins ?? []).flatMap((plugin) => (0, _stryke_convert_to_array.toArray)(plugin)).filter(Boolean).reduce((ret, plugin) => {
3273
3248
  if ((0, _powerlines_core_plugin_utils.isPlugin)(plugin) && (0, _powerlines_core_plugin_utils.isDuplicate)(plugin, ret.filter((p) => (0, _powerlines_core_plugin_utils.isPlugin)(p)))) return ret;
3274
3249
  ret.push(plugin);
3275
3250
  return ret;
3276
3251
  }, []);
3277
- 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 = _powerlines_core_constants.DEFAULT_DEVELOPMENT_LOG_LEVEL;
3278
- else if (this.config.mode === "test") this.config.logLevel = _powerlines_core_constants.DEFAULT_TEST_LOG_LEVEL;
3279
- else this.config.logLevel = _powerlines_core_constants.DEFAULT_PRODUCTION_LOG_LEVEL;
3280
- 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);
3281
- else if (this.config.tsconfig) this.config.tsconfig = (0, _stryke_path_replace.replacePath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, this.config.tsconfig), this.config.cwd);
3282
- this.config.output.format = (0, _stryke_helpers_get_unique.getUnique)((0, _stryke_convert_to_array.toArray)(this.config.output?.format ?? (this.config.projectType === "library" ? ["cjs", "esm"] : ["esm"])));
3283
- if (this.config.output.path) this.config.output.path = (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, this.config.output.path), this.config.cwd);
3284
- else this.config.output.path = (0, _stryke_path_append.appendPath)((0, _stryke_path_join.joinPaths)(this.config.root, "dist"), this.config.cwd);
3285
- if (this.config.output.copy !== false) {
3286
- this.config.output.copy ??= {};
3287
- if (!this.config.root.replace(/^\.\/?/, "")) this.config.output.copy.path = this.config.output.copy.path ? (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, this.config.output.copy.path), this.config.cwd) : this.config.output.path;
3288
- else this.config.output.copy.path = (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, this.config.output.copy.path || (0, _stryke_path_join.joinPaths)("dist", this.config.root)), this.config.cwd);
3289
- }
3290
- if (this.config.output.types !== false) this.config.output.types = (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, this.config.userConfig?.output?.types || this.config.inlineConfig?.output?.types || this.config.initialConfig?.output?.types || this.config.pluginConfig?.output?.types || (0, _stryke_path_join.joinPaths)(this.config.root, `${this.config.framework ?? "powerlines"}.d.ts`)), this.config.cwd);
3291
- 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 = (0, _stryke_helpers_get_unique.getUniqueBy)(this.config.output.copy.assets.map((asset) => {
3252
+ if (!mergedConfig.logLevel) if (mergedConfig.mode === "development") mergedConfig.logLevel = _powerlines_core_constants.DEFAULT_DEVELOPMENT_LOG_LEVEL;
3253
+ else if (mergedConfig.mode === "test") mergedConfig.logLevel = _powerlines_core_constants.DEFAULT_TEST_LOG_LEVEL;
3254
+ else mergedConfig.logLevel = _powerlines_core_constants.DEFAULT_PRODUCTION_LOG_LEVEL;
3255
+ if (mergedConfig.tsconfig) mergedConfig.tsconfig = (0, _stryke_path_replace.replacePath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, mergedConfig.tsconfig), mergedConfig.cwd);
3256
+ else mergedConfig.tsconfig = getTsconfigFilePath(mergedConfig.cwd, mergedConfig.root);
3257
+ mergedConfig.output.format = (0, _stryke_helpers_get_unique.getUnique)((0, _stryke_convert_to_array.toArray)(mergedConfig.output?.format ?? (mergedConfig.projectType === "library" ? ["cjs", "esm"] : ["esm"])));
3258
+ if (mergedConfig.output.path) mergedConfig.output.path = (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, mergedConfig.output.path), mergedConfig.cwd);
3259
+ else mergedConfig.output.path = (0, _stryke_path_append.appendPath)((0, _stryke_path_join.joinPaths)(mergedConfig.root, "dist"), mergedConfig.cwd);
3260
+ mergedConfig.output.copy ??= {};
3261
+ if (mergedConfig.output.copy !== false) if (!mergedConfig.root.replace(/^\.\/?/, "")) mergedConfig.output.copy.path = mergedConfig.output.copy.path ? (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, mergedConfig.output.copy.path), mergedConfig.cwd) : mergedConfig.output.path;
3262
+ else mergedConfig.output.copy.path = (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, mergedConfig.output.copy.path || (0, _stryke_path_join.joinPaths)("dist", mergedConfig.root)), mergedConfig.cwd);
3263
+ if (mergedConfig.output.types !== false) mergedConfig.output.types = (0, _stryke_path_append.appendPath)((0, _powerlines_core_plugin_utils.replacePathTokens)(this, mergedConfig.output.types || (0, _stryke_path_join.joinPaths)(mergedConfig.root, `${mergedConfig.framework ?? "powerlines"}.d.ts`)), mergedConfig.cwd);
3264
+ if (mergedConfig.output.copy && mergedConfig.output.copy.path && mergedConfig.output.copy.assets && Array.isArray(mergedConfig.output.copy.assets)) mergedConfig.output.copy.assets = (0, _stryke_helpers_get_unique.getUniqueBy)(mergedConfig.output.copy.assets.map((asset) => {
3292
3265
  return {
3293
3266
  glob: (0, _stryke_type_checks_is_set_object.isSetObject)(asset) ? asset.glob : asset,
3294
- input: (0, _stryke_type_checks_is_string.isString)(asset) || !asset.input || asset.input === "." || asset.input === "/" || asset.input === "./" ? this.options.cwd : (0, _stryke_path_is_parent_path.isParentPath)(asset.input, this.config.cwd) || (0, _stryke_path_is_equal.isEqual)(asset.input, this.config.cwd) ? asset.input : (0, _stryke_path_append.appendPath)(asset.input, this.config.cwd),
3295
- output: (0, _stryke_type_checks_is_set_object.isSetObject)(asset) && asset.output ? (0, _stryke_path_is_parent_path.isParentPath)(asset.output, this.config.cwd) ? asset.output : (0, _stryke_path_append.appendPath)((0, _stryke_path_join.joinPaths)(this.config.output.copy.path, (0, _stryke_path_replace.replacePath)((0, _stryke_path_replace.replacePath)(asset.output, (0, _stryke_path_replace.replacePath)(this.config.output.copy.path, this.config.cwd)), this.config.output.copy.path)), this.config.cwd) : (0, _stryke_path_append.appendPath)(this.config.output.copy.path, this.config.cwd),
3267
+ input: (0, _stryke_type_checks_is_string.isString)(asset) || !asset.input || asset.input === "." || asset.input === "/" || asset.input === "./" ? mergedConfig.cwd : (0, _stryke_path_is_parent_path.isParentPath)(asset.input, mergedConfig.cwd) || (0, _stryke_path_is_equal.isEqual)(asset.input, mergedConfig.cwd) ? asset.input : (0, _stryke_path_append.appendPath)(asset.input, mergedConfig.cwd),
3268
+ output: (0, _stryke_type_checks_is_set_object.isSetObject)(asset) && asset.output ? (0, _stryke_path_is_parent_path.isParentPath)(asset.output, mergedConfig.cwd) ? asset.output : (0, _stryke_path_append.appendPath)((0, _stryke_path_join.joinPaths)(mergedConfig.output.copy.path, (0, _stryke_path_replace.replacePath)((0, _stryke_path_replace.replacePath)(asset.output, (0, _stryke_path_replace.replacePath)(mergedConfig.output.copy.path, mergedConfig.cwd)), mergedConfig.output.copy.path)), mergedConfig.cwd) : (0, _stryke_path_append.appendPath)(mergedConfig.output.copy.path, mergedConfig.cwd),
3296
3269
  ignore: (0, _stryke_type_checks_is_set_object.isSetObject)(asset) && asset.ignore ? (0, _stryke_convert_to_array.toArray)(asset.ignore) : void 0
3297
3270
  };
3298
3271
  }), (a) => `${a.input}-${a.glob}-${a.output}`);
3299
- 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;
3300
- else this.config.output.sourceMap = false;
3301
- 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;
3302
- else this.config.output.minify = false;
3303
- 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"}`;
3304
- if (this.config.output.copy && this.config.output.copy.assets) this.config.output.copy.assets = this.config.output.copy.assets.map((asset) => ({
3272
+ if (!mergedConfig.output?.sourceMap) if (mergedConfig.mode === "development") mergedConfig.output.sourceMap = true;
3273
+ else mergedConfig.output.sourceMap = false;
3274
+ if (!mergedConfig.output.minify) if (mergedConfig.mode === "production") mergedConfig.output.minify = true;
3275
+ else mergedConfig.output.minify = false;
3276
+ if (!mergedConfig.output.artifactsPath) mergedConfig.output.artifactsPath = `.${mergedConfig.framework || "powerlines"}`;
3277
+ if (mergedConfig.output.copy && mergedConfig.output.copy.assets) mergedConfig.output.copy.assets = mergedConfig.output.copy.assets.map((asset) => ({
3305
3278
  ...asset,
3306
3279
  glob: (0, _powerlines_core_plugin_utils.replacePathTokens)(this, asset.glob),
3307
3280
  ignore: asset.ignore ? asset.ignore.map((ignore) => (0, _powerlines_core_plugin_utils.replacePathTokens)(this, ignore)) : void 0,
3308
3281
  input: (0, _powerlines_core_plugin_utils.replacePathTokens)(this, asset.input),
3309
3282
  output: (0, _powerlines_core_plugin_utils.replacePathTokens)(this, asset.output)
3310
3283
  }));
3311
- if ((0, _stryke_type_checks_is_set_string.isSetString)(this.config.output?.storage) && this.config.output.storage === "virtual" || (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.output?.storage) && Object.values(this.config.output.storage).every((adapter) => adapter.preset === "virtual")) this.config.output.overwrite = true;
3284
+ if ((0, _stryke_type_checks_is_set_string.isSetString)(mergedConfig.output?.storage) && mergedConfig.output.storage === "virtual" || (0, _stryke_type_checks_is_set_object.isSetObject)(mergedConfig.output?.storage) && Object.values(mergedConfig.output.storage).every((adapter) => adapter.preset === "virtual")) mergedConfig.output.overwrite = true;
3285
+ this.resolvedConfig = mergedConfig;
3286
+ this.#configProxy = this.createConfigProxy();
3287
+ this.logger.debug({
3288
+ meta: { category: "config" },
3289
+ 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)}`
3290
+ });
3312
3291
  this.#fs ??= await VirtualFileSystem.create(this);
3313
- if ((0, _stryke_type_checks_is_set_object.isSetObject)(this.config.inlineConfig) && (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.userConfig) && (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.initialConfig) && (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.pluginConfig)) logger.debug(`Resolved Powerlines configuration object: \n${(0, _storm_software_config_tools_logger_console.formatLogMessage)({
3314
- ...(0, _stryke_helpers_omit.omit)(this.config, [
3315
- "inlineConfig",
3316
- "userConfig",
3317
- "initialConfig",
3318
- "pluginConfig",
3319
- "plugins"
3320
- ]),
3321
- inlineConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.inlineConfig) ? (0, _stryke_helpers_omit.omit)(this.config.inlineConfig, ["plugins"]) : void 0,
3322
- userConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.userConfig) ? (0, _stryke_helpers_omit.omit)(this.config.userConfig, ["plugins"]) : void 0,
3323
- initialConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.initialConfig) ? (0, _stryke_helpers_omit.omit)(this.config.initialConfig, ["plugins"]) : void 0,
3324
- pluginConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(this.config.pluginConfig) ? (0, _stryke_helpers_omit.omit)(this.config.pluginConfig, ["plugins"]) : void 0
3325
- })}`);
3292
+ }
3293
+ logConfig(config) {
3294
+ return (0, _storm_software_config_tools_logger_console.formatLogMessage)({
3295
+ ...(0, _stryke_helpers_omit.omit)(config, ["plugins"]),
3296
+ plugins: config.plugins ? config.plugins.flatMap((plugin) => (0, _stryke_convert_to_array.toArray)(plugin)).map((plugin) => String((0, _stryke_type_checks_is_set_string.isSetString)(plugin) ? plugin : (0, _stryke_type_checks_is_promise.isPromise)(plugin) ? "<promise>" : (0, _stryke_type_checks_is_function.isFunction)(plugin) ? plugin.name || "<anonymous function>" : Array.isArray(plugin) ? plugin[0] || "<anonymous function plugin>" : "<unknown plugin>")) : void 0
3297
+ });
3298
+ }
3299
+ createConfigProxy() {
3300
+ return new Proxy(this.resolvedConfig, {
3301
+ /**
3302
+ * A trap for the `delete` operator.
3303
+ * @param target - The original object which is being proxied.
3304
+ * @param key - The name or `Symbol` of the property to delete.
3305
+ * @returns A `boolean` indicating whether or not the property was deleted.
3306
+ */
3307
+ deleteProperty: (target, key) => {
3308
+ 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.`);
3309
+ Reflect.deleteProperty(this.overriddenConfig, key);
3310
+ return Reflect.deleteProperty(target, key);
3311
+ },
3312
+ /**
3313
+ * A trap for getting a property value.
3314
+ * @param target - The original object which is being proxied.
3315
+ * @param key - The name or `Symbol` of the property to get.
3316
+ * @param receiver - The proxy or an object that inherits from the proxy.
3317
+ */
3318
+ get: (target, key, receiver) => {
3319
+ if (UNRESOLVED_CONFIG_NAMES.includes(key.toString())) {
3320
+ if (key === "initialConfig") return this.initialConfig;
3321
+ if (key === "userConfig") return this.userConfig;
3322
+ if (key === "inlineConfig") return this.inlineConfig;
3323
+ if (key === "pluginConfig") return this.pluginConfig;
3324
+ }
3325
+ return Reflect.get(target, key, receiver);
3326
+ },
3327
+ /**
3328
+ * A trap for the `in` operator.
3329
+ * @param target - The original object which is being proxied.
3330
+ * @param key - The name or `Symbol` of the property to check for existence.
3331
+ */
3332
+ has: (target, key) => {
3333
+ return Reflect.has(target, key) || UNRESOLVED_CONFIG_NAMES.includes(key.toString());
3334
+ },
3335
+ /**
3336
+ * A trap for `Reflect.ownKeys()`.
3337
+ * @param target - The original object which is being proxied.
3338
+ */
3339
+ ownKeys: (target) => {
3340
+ return (0, _stryke_helpers_get_unique.getUnique)([...Reflect.ownKeys(target), ...UNRESOLVED_CONFIG_NAMES]);
3341
+ },
3342
+ /**
3343
+ * A trap for setting a property value.
3344
+ * @param target - The original object which is being proxied.
3345
+ * @param key - The name or `Symbol` of the property to set.
3346
+ * @param newValue - The new value to assign to the property.
3347
+ * @param receiver - The object to which the assignment was originally directed.
3348
+ * @returns A `boolean` indicating whether or not the property was set.
3349
+ */
3350
+ set: (target, key, newValue, receiver) => {
3351
+ 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.`);
3352
+ Reflect.set(this.overriddenConfig, key, newValue, receiver);
3353
+ return Reflect.set(target, key, newValue, receiver);
3354
+ }
3355
+ });
3326
3356
  }
3327
3357
  };
3328
3358
 
@@ -3467,7 +3497,7 @@ function createPluginContext(pluginId, plugin, environment) {
3467
3497
  return {
3468
3498
  meta: {
3469
3499
  ...(0, _stryke_type_checks_is_set_object.isSetObject)(message) ? message.meta : {},
3470
- environment: environment.environment?.name,
3500
+ environment: environment.config.environment.name,
3471
3501
  plugin: plugin.name
3472
3502
  },
3473
3503
  message: (0, _stryke_type_checks_is_string.isString)(message) ? message : message.message
@@ -3490,6 +3520,8 @@ function createPluginContext(pluginId, plugin, environment) {
3490
3520
  callHook: callHookFn,
3491
3521
  meta
3492
3522
  };
3523
+ if (prop === "api") return environment.$$internal.api;
3524
+ if (prop === "environment") return environment;
3493
3525
  if (prop === "id") return pluginId;
3494
3526
  if (prop === "logger") return logger;
3495
3527
  if (prop === "log") return (type, message) => {
@@ -3542,6 +3574,15 @@ function createPluginContext(pluginId, plugin, environment) {
3542
3574
  //#endregion
3543
3575
  //#region src/context/environment-context.ts
3544
3576
  var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends PowerlinesContext {
3577
+ /**
3578
+ * Internal references storage
3579
+ *
3580
+ * @danger
3581
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
3582
+ *
3583
+ * @internal
3584
+ */
3585
+ #internal = {};
3545
3586
  /**
3546
3587
  * The hooks registered by plugins in this environment
3547
3588
  */
@@ -3551,29 +3592,50 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
3551
3592
  *
3552
3593
  * @param options - The resolved execution options.
3553
3594
  * @param config - The user configuration options.
3554
- * @returns A promise that resolves to the new context.
3595
+ * @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.
3596
+ * @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.
3597
+ * @returns A promise that resolves to an instance of the PowerlinesEnvironmentContext class, initialized with the provided configuration and environment data.
3555
3598
  */
3556
- static async fromConfig(options, config, environment) {
3557
- const context = new PowerlinesEnvironmentContext(options, config, environment);
3558
- await context.setup();
3559
- const powerlinesPath = await (0, _stryke_fs_resolve.resolvePackage)("powerlines");
3560
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
3561
- context.powerlinesPath = powerlinesPath;
3599
+ static async createEnvironment(options, config, overriddenConfig, environment) {
3600
+ const context = new PowerlinesEnvironmentContext(options, config, overriddenConfig);
3601
+ await context.setEnvironmentConfig(environment);
3562
3602
  return context;
3563
3603
  }
3564
3604
  /**
3565
- * The resolved environment configuration
3605
+ * The configuration options provided by plugins added by the user (and other plugins)
3566
3606
  */
3567
- environment;
3607
+ environmentConfig = {};
3568
3608
  /**
3569
3609
  * The list of plugins applied to this environment
3570
3610
  */
3571
3611
  plugins = [];
3572
3612
  /**
3573
- * 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.
3613
+ * Internal context fields and methods
3614
+ *
3615
+ * @danger
3616
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
3617
+ *
3618
+ * @internal
3574
3619
  */
3575
- get id() {
3576
- return this.environment.environmentId;
3620
+ get $$internal() {
3621
+ return this.#internal;
3622
+ }
3623
+ /**
3624
+ * Internal context fields and methods
3625
+ *
3626
+ * @danger
3627
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
3628
+ *
3629
+ * @internal
3630
+ */
3631
+ set $$internal(value) {
3632
+ this.#internal = value;
3633
+ }
3634
+ /**
3635
+ * 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.
3636
+ */
3637
+ get id() {
3638
+ return this.config.environment.id;
3577
3639
  }
3578
3640
  /**
3579
3641
  * The hooks registered by plugins in this environment
@@ -3582,6 +3644,20 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
3582
3644
  return this.#hooks;
3583
3645
  }
3584
3646
  /**
3647
+ * 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.
3648
+ *
3649
+ * @param config - The environment configuration values to set.
3650
+ * @returns A promise that resolves when the environment configuration values have been set.
3651
+ */
3652
+ async setEnvironmentConfig(config) {
3653
+ this.logger.debug({
3654
+ meta: { category: "config" },
3655
+ message: `Updating environment configuration object: \n${this.logConfig(config)}`
3656
+ });
3657
+ this.environmentConfig = config;
3658
+ await this.resolveConfig();
3659
+ }
3660
+ /**
3585
3661
  * Create a new logger instance
3586
3662
  *
3587
3663
  * @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.
@@ -3591,7 +3667,7 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
3591
3667
  createLogger(options, logFn) {
3592
3668
  return super.createLogger({
3593
3669
  ...options,
3594
- environment: this.environment?.name
3670
+ environment: this.config.environment?.name
3595
3671
  }, logFn);
3596
3672
  }
3597
3673
  /**
@@ -3603,47 +3679,21 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
3603
3679
  extendLogger(options) {
3604
3680
  return super.extendLogger({
3605
3681
  ...options,
3606
- environment: this.environment?.name
3682
+ environment: this.config.environment?.name
3607
3683
  });
3608
3684
  }
3609
- /**
3610
- * 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.
3611
- *
3612
- * @remarks
3613
- * 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.
3614
- *
3615
- * @returns A promise that resolves to the cloned context.
3616
- */
3617
- async clone() {
3618
- const context = await PowerlinesEnvironmentContext.fromConfig((0, _stryke_helpers_deep_clone.deepClone)(this.options), (0, _stryke_helpers_deep_clone.deepClone)(this.config), (0, _stryke_helpers_deep_clone.deepClone)(this.environment));
3619
- return this.copyTo(context);
3620
- }
3621
- /**
3622
- * Initialize the context with the provided configuration options
3623
- */
3624
- async setup() {
3625
- this.resolvedConfig = (0, _powerlines_core_plugin_utils.mergeConfig)({
3626
- name: this.config.name,
3627
- title: this.config.title
3628
- }, getConfigProps({
3629
- ...this.environment,
3630
- root: this.options.root,
3631
- cwd: this.options.cwd
3632
- }), this.config);
3633
- await this.innerSetup();
3634
- }
3635
3685
  async addPlugin(plugin) {
3636
3686
  let resolvedPlugin = plugin;
3637
3687
  if ((0, _stryke_type_checks_is_function.isFunction)(plugin.applyToEnvironment)) {
3638
- const result = await Promise.resolve(plugin.applyToEnvironment(this.environment));
3688
+ const result = await Promise.resolve(plugin.applyToEnvironment(this.config.environment));
3639
3689
  if (!result || (0, _stryke_type_checks_is_object.isObject)(result) && Object.keys(result).length === 0) return;
3640
3690
  if ((0, _powerlines_core_plugin_utils.isPluginConfig)(result)) return this.$$internal.addPlugin(result);
3641
3691
  resolvedPlugin = (0, _powerlines_core_plugin_utils.isPlugin)(result) ? result : plugin;
3642
3692
  }
3643
- const pluginId = (0, _stryke_unique_id_uuid.uuid)();
3644
- const context = createPluginContext(pluginId, resolvedPlugin, this);
3693
+ const id = (0, _stryke_unique_id_uuid.uuid)();
3694
+ const context = createPluginContext(id, resolvedPlugin, this);
3645
3695
  this.plugins.push({
3646
- pluginId,
3696
+ id,
3647
3697
  plugin: resolvedPlugin,
3648
3698
  context
3649
3699
  });
@@ -3686,29 +3736,51 @@ var PowerlinesEnvironmentContext = class PowerlinesEnvironmentContext extends Po
3686
3736
  }
3687
3737
  return result;
3688
3738
  }
3689
- constructor(options, config, environment) {
3690
- super(options);
3691
- this.resolvedConfig = config;
3692
- this.environment = environment;
3739
+ constructor(options, config, overriddenConfig) {
3740
+ super(options, config.initialConfig);
3741
+ this.userConfig = config.userConfig ?? {};
3742
+ this.inlineConfig = config.inlineConfig ?? {};
3743
+ this.pluginConfig = config.pluginConfig ?? {};
3744
+ this.overriddenConfig = overriddenConfig;
3693
3745
  }
3694
3746
  /**
3695
- * 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.
3747
+ * 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.
3696
3748
  *
3697
- * @remarks
3698
- * 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.
3699
- *
3700
- * @returns The cloned context.
3749
+ * @returns The merged configuration object that combines the initial, user, inline, and plugin configurations.
3701
3750
  */
3702
- copyTo(context) {
3703
- context.plugins = this.plugins;
3704
- return super.copyTo(context);
3751
+ mergeConfig() {
3752
+ return (0, _powerlines_core_plugin_utils.mergeConfig)({
3753
+ ...(0, _stryke_helpers_omit.omit)(this.environmentConfig ?? {}, [
3754
+ "ssr",
3755
+ "preview",
3756
+ "consumer",
3757
+ "runtime"
3758
+ ]),
3759
+ environment: { name: this.environmentConfig?.name || _powerlines_core_constants.DEFAULT_ENVIRONMENT },
3760
+ environmentConfig: this.environmentConfig ?? {}
3761
+ }, super.mergeConfig());
3705
3762
  }
3706
3763
  };
3707
3764
 
3708
3765
  //#endregion
3709
3766
  //#region src/context/execution-context.ts
3710
3767
  var PowerlinesExecutionContext = class PowerlinesExecutionContext extends PowerlinesContext {
3768
+ /**
3769
+ * Internal references storage
3770
+ *
3771
+ * @danger
3772
+ * This field is for internal use only and should not be accessed or modified directly. It is unstable and can be changed at anytime.
3773
+ *
3774
+ * @internal
3775
+ */
3776
+ #internal = {};
3777
+ /**
3778
+ * A record of all environments by name
3779
+ */
3711
3780
  #environments = {};
3781
+ /**
3782
+ * 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.
3783
+ */
3712
3784
  #plugins = [];
3713
3785
  /**
3714
3786
  * Create a new Storm context from the workspace root and user config.
@@ -3716,13 +3788,9 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3716
3788
  * @param options - The options for resolving the context.
3717
3789
  * @returns A promise that resolves to the new context.
3718
3790
  */
3719
- static async init(options, initialConfig) {
3720
- const context = new PowerlinesExecutionContext(options);
3721
- await context.init(options, initialConfig);
3722
- const powerlinesPath = await (0, _stryke_fs_resolve.resolvePackage)("powerlines");
3723
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
3724
- context.powerlinesPath = powerlinesPath;
3725
- await context.setup();
3791
+ static async fromInitialConfig(options, initialConfig) {
3792
+ const context = new PowerlinesExecutionContext(options, initialConfig);
3793
+ await context.init();
3726
3794
  return context;
3727
3795
  }
3728
3796
  /**
@@ -3731,19 +3799,10 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3731
3799
  * @param options - The options for resolving the context.
3732
3800
  * @returns A promise that resolves to the new context.
3733
3801
  */
3734
- static async inline(options, initialConfig, inlineConfig) {
3735
- const context = new PowerlinesExecutionContext(options);
3736
- await context.init(options, initialConfig);
3737
- context.config.inlineConfig = inlineConfig;
3738
- if (context.config.inlineConfig.command === "new") {
3739
- const workspacePackageJsonPath = (0, _stryke_path_join.joinPaths)(context.config.cwd, "package.json");
3740
- if (!(0, _stryke_fs_exists.existsSync)(workspacePackageJsonPath)) throw new Error(`The workspace package.json file could not be found at ${workspacePackageJsonPath}`);
3741
- context.packageJson = await (0, _stryke_fs_json.readJsonFile)(workspacePackageJsonPath);
3742
- }
3743
- await context.setup();
3744
- const powerlinesPath = await (0, _stryke_fs_resolve.resolvePackage)("powerlines");
3745
- if (!powerlinesPath) throw new Error("Could not resolve `powerlines` package location.");
3746
- context.powerlinesPath = powerlinesPath;
3802
+ static async fromInlineConfig(options, initialConfig, inlineConfig) {
3803
+ const context = new PowerlinesExecutionContext(options, initialConfig);
3804
+ await context.init();
3805
+ await context.setInlineConfig(inlineConfig);
3747
3806
  return context;
3748
3807
  }
3749
3808
  /**
@@ -3755,7 +3814,7 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3755
3814
  * @internal
3756
3815
  */
3757
3816
  get $$internal() {
3758
- return super.$$internal;
3817
+ return this.#internal;
3759
3818
  }
3760
3819
  /**
3761
3820
  * Internal context fields and methods
@@ -3766,8 +3825,8 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3766
3825
  * @internal
3767
3826
  */
3768
3827
  set $$internal(value) {
3769
- super.$$internal = value;
3770
- for (const environment of Object.values(this.environments)) environment.$$internal = super.$$internal;
3828
+ this.#internal = value;
3829
+ for (const environment of Object.values(this.environments)) environment.$$internal = value;
3771
3830
  }
3772
3831
  /**
3773
3832
  * 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.
@@ -3788,9 +3847,26 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3788
3847
  * Creates a new instance.
3789
3848
  *
3790
3849
  * @param options - The options to use for creating the context, including the resolved configuration and workspace settings.
3850
+ * @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.
3851
+ */
3852
+ constructor(options, initialConfig = {}) {
3853
+ super(options, initialConfig);
3854
+ this.initialOptions = options;
3855
+ this.initialConfig = initialConfig;
3856
+ }
3857
+ /**
3858
+ * 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.
3859
+ *
3860
+ * @param config - The inline configuration values to set.
3861
+ * @returns A promise that resolves when the inline configuration values have been set.
3791
3862
  */
3792
- constructor(options) {
3793
- super(options);
3863
+ async setInlineConfig(config) {
3864
+ await super.setInlineConfig(config);
3865
+ if (this.inlineConfig.command === "new") {
3866
+ const workspacePackageJsonPath = (0, _stryke_path_join.joinPaths)(this.config.cwd, "package.json");
3867
+ if (!(0, _stryke_fs_exists.existsSync)(workspacePackageJsonPath)) throw new Error(`The workspace package.json file could not be found at ${workspacePackageJsonPath}`);
3868
+ this.packageJson = await (0, _stryke_fs_json.readJsonFile)(workspacePackageJsonPath);
3869
+ }
3794
3870
  }
3795
3871
  /**
3796
3872
  * Create a new logger instance
@@ -3820,42 +3896,45 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3820
3896
  });
3821
3897
  }
3822
3898
  /**
3823
- * 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.
3824
- *
3825
- * @remarks
3826
- * 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.
3827
- *
3828
- * @returns A promise that resolves to the cloned context.
3829
- */
3830
- async clone() {
3831
- const clone = await PowerlinesExecutionContext.init(this.options, this.initialConfig);
3832
- clone.config.userConfig = (0, _stryke_helpers_deep_clone.deepClone)(this.config.userConfig);
3833
- clone.config.initialConfig = (0, _stryke_helpers_deep_clone.deepClone)(this.config.initialConfig);
3834
- clone.config.inlineConfig = (0, _stryke_helpers_deep_clone.deepClone)(this.config.inlineConfig);
3835
- clone.config.pluginConfig = (0, _stryke_helpers_deep_clone.deepClone)(this.config.pluginConfig);
3836
- await clone.setup();
3837
- clone.$$internal = this.$$internal;
3838
- return this.copyTo(clone);
3839
- }
3840
- /**
3841
3899
  * A function to copy the context and update the fields for a specific environment
3842
3900
  *
3843
3901
  * @param environment - The environment configuration to use.
3844
3902
  * @returns A new context instance with the updated environment.
3845
3903
  */
3846
- async in(environment) {
3847
- const context = this.copyTo(await PowerlinesEnvironmentContext.fromConfig((0, _stryke_helpers_deep_clone.deepClone)(this.options), (0, _stryke_helpers_deep_clone.deepClone)(this.config), (0, _stryke_helpers_deep_clone.deepClone)(environment)));
3904
+ async createEnvironment(environment) {
3905
+ const context = await PowerlinesEnvironmentContext.createEnvironment((0, _stryke_helpers_deep_clone.deepClone)(this.options), (0, _stryke_helpers_deep_clone.deepClone)(this.config), (0, _stryke_helpers_deep_clone.deepClone)(this.overriddenConfig), (0, _stryke_helpers_deep_clone.deepClone)(environment));
3906
+ context.$$internal = this.$$internal;
3907
+ context.dependencies = (0, _stryke_helpers_deep_clone.deepClone)(this.dependencies);
3908
+ context.devDependencies = (0, _stryke_helpers_deep_clone.deepClone)(this.devDependencies);
3909
+ context.persistedMeta = (0, _stryke_helpers_deep_clone.deepClone)(this.persistedMeta);
3910
+ context.resolvePatterns = (0, _stryke_helpers_deep_clone.deepClone)(this.resolvePatterns);
3911
+ context.powerlinesPath ??= this.powerlinesPath;
3912
+ context.resolver ??= this.resolver;
3848
3913
  context.plugins = [];
3849
3914
  for (const plugin of this.plugins) await context.addPlugin(plugin);
3915
+ for (const [key, value] of Object.entries(this)) if (![
3916
+ "fs",
3917
+ "$$internal",
3918
+ "dependencies",
3919
+ "devDependencies",
3920
+ "persistedMeta",
3921
+ "packageJson",
3922
+ "projectJson",
3923
+ "tsconfig",
3924
+ "resolver",
3925
+ "plugins",
3926
+ "environments"
3927
+ ].includes(key)) if ((0, _stryke_type_checks_is_object.isObject)(value) || Array.isArray(value)) context[key] = (0, _stryke_helpers_deep_clone.deepClone)(value);
3928
+ else context[key] = value;
3850
3929
  return context;
3851
3930
  }
3852
3931
  /**
3853
3932
  * Update the context using a new inline configuration options
3854
3933
  */
3855
- async setup() {
3856
- await super.setup();
3934
+ async resolveConfig() {
3935
+ await super.resolveConfig();
3857
3936
  await Promise.all((0, _stryke_convert_to_array.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) => {
3858
- this.#environments[env.name] = await this.in(env);
3937
+ this.#environments[env.name] = await this.createEnvironment(env);
3859
3938
  }));
3860
3939
  }
3861
3940
  /**
@@ -3880,12 +3959,20 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3880
3959
  if (name) environment = this.environments[name];
3881
3960
  if (Object.keys(this.environments).length === 1) {
3882
3961
  environment = this.environments[Object.keys(this.environments)[0]];
3883
- this.debug(`Applying the only configured environment: ${chalk.default.bold.cyanBright(environment?.environment.name)}`);
3962
+ this.trace({
3963
+ meta: { category: "plugins" },
3964
+ message: `Applying the only configured environment: ${chalk.default.bold.cyanBright(environment?.config.environment?.name)}`
3965
+ });
3884
3966
  }
3885
3967
  if (!environment) {
3886
3968
  if (name) throw new Error(`Environment "${name}" not found.`);
3887
- environment = await this.in(createDefaultEnvironment(this.config));
3888
- this.warn(`No environment specified, and no default environment found. Using a temporary default environment: ${chalk.default.bold.cyanBright(environment?.environment.name)}`);
3969
+ environment = await PowerlinesEnvironmentContext.createEnvironment((0, _stryke_helpers_deep_clone.deepClone)(this.options), (0, _stryke_helpers_deep_clone.deepClone)(this.config), (0, _stryke_helpers_deep_clone.deepClone)(this.overriddenConfig), (0, _stryke_helpers_deep_clone.deepClone)(createDefaultEnvironment(this.config)));
3970
+ environment.plugins = [];
3971
+ for (const plugin of this.plugins) await environment.addPlugin(plugin);
3972
+ this.warn({
3973
+ meta: { category: "plugins" },
3974
+ message: `No environment specified, and no default environment found. Using a temporary default environment: ${chalk.default.bold.cyanBright(environment.config.environment?.name)}`
3975
+ });
3889
3976
  }
3890
3977
  return environment;
3891
3978
  }
@@ -3913,8 +4000,11 @@ var PowerlinesExecutionContext = class PowerlinesExecutionContext extends Powerl
3913
4000
  async toEnvironment() {
3914
4001
  let environment;
3915
4002
  if (Object.keys(this.environments).length > 1) {
3916
- environment = await this.in(createEnvironment(_powerlines_core_constants.GLOBAL_ENVIRONMENT, this.config));
3917
- this.debug(`Combined all ${Object.keys(this.environments).length} environments into a single global context.`);
4003
+ environment = await this.createEnvironment(createEnvironment(_powerlines_core_constants.GLOBAL_ENVIRONMENT, this.config));
4004
+ this.debug({
4005
+ meta: { category: "plugins" },
4006
+ message: `Combined all ${Object.keys(this.environments).length} environments into a single global context.`
4007
+ });
3918
4008
  } else environment = await this.getEnvironment();
3919
4009
  return environment;
3920
4010
  }
@@ -4334,11 +4424,11 @@ async function installDependencies(context) {
4334
4424
  //#endregion
4335
4425
  //#region src/_internal/helpers/resolve-tsconfig.ts
4336
4426
  function getTsconfigDtsPath(context) {
4337
- return (0, _stryke_path_join_paths.joinPaths)((0, _stryke_path_file_path_fns.relativePath)((0, _stryke_path_join_paths.joinPaths)(context.options.cwd, context.options.root), (0, _stryke_path_file_path_fns.findFilePath)(context.typesPath)), (0, _stryke_path_file_path_fns.findFileName)(context.typesPath));
4427
+ return (0, _stryke_path_join_paths.joinPaths)((0, _stryke_path_file_path_fns.relativePath)((0, _stryke_path_join_paths.joinPaths)(context.config.cwd, context.config.root), (0, _stryke_path_file_path_fns.findFilePath)(context.typesPath)), (0, _stryke_path_file_path_fns.findFileName)(context.typesPath));
4338
4428
  }
4339
4429
  async function resolveTsconfigChanges(context) {
4340
- const tsconfig = getParsedTypeScriptConfig(context.options.cwd, context.options.root, context.config.tsconfig, context.config.tsconfigRaw);
4341
- const tsconfigJson = await (0, _stryke_fs_json.readJsonFile)(getTsconfigFilePath(context.options.cwd, context.options.root, context.config.tsconfig));
4430
+ const tsconfig = getParsedTypeScriptConfig(context.config.cwd, context.config.root, context.config.tsconfig, context.config.tsconfigRaw);
4431
+ const tsconfigJson = await (0, _stryke_fs_json.readJsonFile)(getTsconfigFilePath(context.config.cwd, context.config.root, context.config.tsconfig));
4342
4432
  tsconfigJson.compilerOptions ??= {};
4343
4433
  if (context.config.output.dts !== false) {
4344
4434
  const dtsRelativePath = getTsconfigDtsPath(context);
@@ -4428,353 +4518,86 @@ var PowerlinesExecution = class PowerlinesExecution {
4428
4518
  * The Powerlines context
4429
4519
  */
4430
4520
  #context;
4431
- async #handleBuild(context) {
4432
- await this.callHook("build", {
4433
- environment: context,
4434
- order: "pre"
4435
- });
4436
- context.debug("Formatting the generated entry files before the build process starts.");
4437
- await (0, _powerlines_core_lib_utilities_format.formatFolder)(context, context.entryPath);
4438
- await this.callHook("build", {
4439
- environment: context,
4440
- order: "normal"
4441
- });
4442
- if (context.config.output.copy) {
4443
- context.debug("Copying project's files from build output directory.");
4444
- const destinationPath = (0, _stryke_path_is_parent_path.isParentPath)((0, _stryke_path_append.appendPath)(context.config.output.path, context.config.cwd), (0, _stryke_path_append.appendPath)(context.config.root, context.config.cwd)) ? (0, _stryke_path_join_paths.joinPaths)(context.config.output.copy.path, (0, _stryke_path_file_path_fns.relativePath)((0, _stryke_path_append.appendPath)(context.config.root, context.config.cwd), (0, _stryke_path_append.appendPath)(context.config.output.path, context.config.cwd))) : (0, _stryke_path_join_paths.joinPaths)(context.config.output.copy.path, "dist");
4445
- const sourcePath = context.config.output.path;
4446
- if ((0, _stryke_fs_exists.existsSync)(sourcePath) && sourcePath !== destinationPath) {
4447
- context.debug(`Copying files from project's build output directory (${context.config.output.path}) to the project's copy/publish directory (${destinationPath}).`);
4448
- await (0, _stryke_fs_copy_file.copyFiles)(sourcePath, destinationPath);
4449
- } else context.warn(`The source path for the copy operation ${!(0, _stryke_fs_exists.existsSync)(sourcePath) ? "does not exist" : "is the same as the destination path"}. Source: ${sourcePath}, Destination: ${destinationPath}. Skipping copying of build output files.`);
4450
- if (context.config.output.copy.assets && Array.isArray(context.config.output.copy.assets)) await Promise.all(context.config.output.copy.assets.map(async (asset) => {
4451
- context.trace(`Copying asset(s): ${chalk.default.redBright(context.config.cwd === asset.input ? asset.glob : (0, _stryke_path_append.appendPath)(asset.glob, (0, _stryke_path_replace.replacePath)(asset.input, context.config.cwd)))} -> ${chalk.default.greenBright((0, _stryke_path_append.appendPath)(asset.glob, (0, _stryke_path_replace.replacePath)(asset.output, context.config.cwd)))} ${Array.isArray(asset.ignore) && asset.ignore.length > 0 ? ` (ignoring: ${asset.ignore.map((i) => chalk.default.yellowBright(i)).join(", ")})` : ""}`);
4452
- await context.fs.copy(asset, asset.output);
4453
- }));
4454
- } else context.debug("No copy configuration found for the project output. Skipping the copying of build output files.");
4455
- await this.callHook("build", {
4456
- environment: context,
4457
- order: "post"
4458
- });
4459
- }
4460
4521
  /**
4461
- * Get the configured environments
4522
+ * Initialize a Powerlines API instance
4462
4523
  *
4463
- * @returns The configured environments
4524
+ * @param options - The options to initialize the API with
4525
+ * @returns A new instance of the Powerlines API
4464
4526
  */
4465
- async #getEnvironments() {
4466
- if (!this.context.config.environments || Object.keys(this.context.config.environments).length <= 1) {
4467
- this.context.debug("No environments are configured for this Powerlines project. Using the default environment.");
4468
- return [await this.context.getEnvironment()];
4469
- }
4470
- this.context.debug(`Found ${Object.keys(this.context.config.environments).length} configured environment(s) for this Powerlines project.`);
4471
- return (await Promise.all(Object.entries(this.context.config.environments).map(async ([name, config]) => {
4472
- if (!await this.context.getEnvironmentSafe(name)) {
4473
- const resolvedEnvironment = await this.callHook("configEnvironment", { environment: name }, name, config);
4474
- if (resolvedEnvironment) this.context.environments[name] = await this.context.in(resolvedEnvironment);
4475
- }
4476
- return this.context.environments[name];
4477
- }))).filter((context) => (0, _stryke_type_checks_is_set.isSet)(context));
4527
+ static async from(options, initialConfig) {
4528
+ const api = new PowerlinesExecution(await PowerlinesExecutionContext.fromInitialConfig(options, initialConfig ?? {}));
4529
+ await api.init();
4530
+ return api;
4478
4531
  }
4479
4532
  /**
4480
- * Execute a handler function for each environment
4481
- *
4482
- * @param handle - The handler function to execute for each environment
4533
+ * The Powerlines context
4483
4534
  */
4484
- async #executeEnvironments(handle) {
4485
- await Promise.all((await this.#getEnvironments()).map(async (context) => {
4486
- return Promise.resolve(handle(context));
4487
- }));
4535
+ get context() {
4536
+ return this.#context;
4488
4537
  }
4489
4538
  /**
4490
- * Initialize a Powerlines plugin
4539
+ * Generate the Powerlines typescript declaration file
4491
4540
  *
4492
- * @param config - The configuration for the plugin
4493
- * @returns The initialized plugin instance, or null if the plugin was a duplicate
4494
- * @throws Will throw an error if the plugin cannot be found or is invalid
4541
+ * @remarks
4542
+ * This method will only generate the typescript declaration file for the Powerlines project. It is generally recommended to run the full `prepare` command, which will run this method as part of its process.
4543
+ *
4544
+ * @param inlineConfig - The inline configuration for the types command
4495
4545
  */
4496
- async #initPlugin(config) {
4497
- let awaited = config;
4498
- if ((0, _stryke_type_checks_is_promise.isPromiseLike)(config)) awaited = await Promise.resolve(config);
4499
- if (!(0, _powerlines_core_plugin_utils.isPluginConfig)(awaited)) {
4500
- const invalid = (0, _powerlines_core_plugin_utils.findInvalidPluginConfig)(awaited);
4501
- throw new Error(`Invalid ${invalid && invalid.length > 1 ? "plugins" : "plugin"} specified in the configuration - ${invalid && invalid.length > 0 ? JSON.stringify(awaited) : invalid?.join("\n\n")} \n\nPlease ensure the value is one of the following: \n - an instance of \`Plugin\` \n - a plugin name \n - an object with the \`plugin\` and \`options\` properties \n - a tuple array with the plugin and options \n - a factory function that returns a plugin or array of plugins \n - an array of plugins or plugin configurations`);
4502
- }
4503
- let plugins;
4504
- if ((0, _powerlines_core_plugin_utils.isPlugin)(awaited)) plugins = [awaited];
4505
- else if ((0, _stryke_type_checks_is_function.isFunction)(awaited)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(awaited()));
4506
- else if ((0, _stryke_type_checks_is_string.isString)(awaited)) {
4507
- const resolved = await this.#resolvePlugin(awaited);
4508
- if ((0, _stryke_type_checks_is_function.isFunction)(resolved)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(resolved()));
4509
- else plugins = (0, _stryke_convert_to_array.toArray)(resolved);
4510
- } else if (Array.isArray(awaited) && awaited.every(_powerlines_core_plugin_utils.isPlugin)) plugins = awaited;
4511
- else if (Array.isArray(awaited) && awaited.every(_powerlines_core_plugin_utils.isPluginConfig)) {
4512
- plugins = [];
4513
- for (const pluginConfig of awaited) {
4514
- const initialized = await this.#initPlugin(pluginConfig);
4515
- if (initialized) plugins.push(...initialized);
4516
- }
4517
- } else if ((0, _powerlines_core_plugin_utils.isPluginConfigTuple)(awaited) || (0, _powerlines_core_plugin_utils.isPluginConfigObject)(awaited)) {
4518
- let pluginConfig;
4519
- let pluginOptions;
4520
- if ((0, _powerlines_core_plugin_utils.isPluginConfigTuple)(awaited)) {
4521
- pluginConfig = awaited[0];
4522
- pluginOptions = awaited?.length === 2 ? awaited[1] : void 0;
4523
- } else {
4524
- pluginConfig = awaited.plugin;
4525
- pluginOptions = awaited.options;
4526
- }
4527
- if ((0, _stryke_type_checks_is_set_string.isSetString)(pluginConfig)) {
4528
- const resolved = await this.#resolvePlugin(pluginConfig);
4529
- if ((0, _stryke_type_checks_is_function.isFunction)(resolved)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(pluginOptions ? resolved(pluginOptions) : resolved()));
4530
- else plugins = (0, _stryke_convert_to_array.toArray)(resolved);
4531
- } else if ((0, _stryke_type_checks_is_function.isFunction)(pluginConfig)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(pluginConfig(pluginOptions)));
4532
- else if (Array.isArray(pluginConfig) && pluginConfig.every(_powerlines_core_plugin_utils.isPlugin)) plugins = pluginConfig;
4533
- else if ((0, _powerlines_core_plugin_utils.isPlugin)(pluginConfig)) plugins = (0, _stryke_convert_to_array.toArray)(pluginConfig);
4534
- }
4535
- if (!plugins) throw new Error(`The plugin configuration ${JSON.stringify(awaited)} is invalid. This configuration must point to a valid Powerlines plugin module.`);
4536
- if (plugins.length > 0 && !plugins.every(_powerlines_core_plugin_utils.isPlugin)) throw new Error(`The plugin option ${JSON.stringify(plugins)} does not export a valid module. This configuration must point to a valid Powerlines plugin module.`);
4537
- const result = [];
4538
- for (const plugin of plugins) if ((0, _powerlines_core_plugin_utils.isDuplicate)(plugin, this.context.plugins)) this.context.trace(`Duplicate ${chalk.default.bold.cyanBright(plugin.name)} plugin dependency detected - Skipping initialization.`);
4539
- else {
4540
- result.push(plugin);
4541
- this.context.trace(`Initializing the ${chalk.default.bold.cyanBright(plugin.name)} plugin...`);
4542
- }
4543
- return result;
4544
- }
4545
- async #resolvePlugin(pluginPath) {
4546
- if (pluginPath.startsWith("@") && pluginPath.split("/").filter(Boolean).length > 2) {
4547
- const splits = pluginPath.split("/").filter(Boolean);
4548
- pluginPath = `${splits[0]}/${splits[1]}`;
4549
- }
4550
- const isInstalled = (0, _stryke_fs_package_fns.isPackageExists)(pluginPath, { paths: [this.context.config.cwd, this.context.config.root] });
4551
- if (!isInstalled && this.context.config.autoInstall) {
4552
- this.#context.warn(`The plugin package "${pluginPath}" is not installed. It will be installed automatically.`);
4553
- const result = await (0, _stryke_fs_install.install)(pluginPath, { cwd: this.context.config.root });
4554
- if ((0, _stryke_type_checks_is_number.isNumber)(result.exitCode) && result.exitCode > 0) {
4555
- this.#context.error(result.stderr);
4556
- throw new Error(`An error occurred while installing the build plugin package "${pluginPath}" `);
4557
- }
4558
- }
4559
- try {
4560
- const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve((0, _stryke_path_join_paths.joinPaths)(pluginPath, "plugin")));
4561
- const result = module.plugin ?? module.default;
4562
- if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
4563
- return result;
4564
- } catch (error) {
4565
- try {
4566
- const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve(pluginPath));
4567
- const result = module.plugin ?? module.default;
4568
- if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
4569
- return result;
4570
- } catch {
4571
- if (!isInstalled) throw new Error(`The plugin package "${pluginPath}" is not installed. Please install the package using the command: "npm install ${pluginPath} --save-dev"`);
4572
- else throw new Error(`An error occurred while importing the build plugin package "${pluginPath}":
4573
- ${(0, _stryke_type_checks_is_error.isError)(error) ? error.message : String(error)}
4574
-
4575
- Note: Please ensure the plugin package's default export is a class that extends \`Plugin\` with a constructor that excepts a single arguments of type \`PluginOptions\`.`);
4546
+ async types(inlineConfig = { command: "types" }) {
4547
+ this.context.debug(" Aggregating configuration options for the Powerlines project");
4548
+ inlineConfig.command ??= "types";
4549
+ await this.context.setInlineConfig(inlineConfig);
4550
+ await this.executeEnvironments(async (context) => {
4551
+ context.debug(`Initializing the processing options for the Powerlines project.`);
4552
+ await this.callHook("configResolved", {
4553
+ environment: context,
4554
+ order: "pre"
4555
+ });
4556
+ await initializeTsconfig(context);
4557
+ await this.callHook("configResolved", {
4558
+ environment: context,
4559
+ order: "normal"
4560
+ });
4561
+ if (context.entry.length > 0) context.debug(`The configuration provided ${(0, _stryke_type_checks_is_object.isObject)(context.config.input) ? Object.keys(context.config.input).length : (0, _stryke_convert_to_array.toArray)(context.config.input).length} entry point(s), Powerlines has found ${context.entry.length} entry files(s) for the ${context.config.title} project${context.entry.length > 0 && context.entry.length < 10 ? `: \n${context.entry.map((entry) => `- ${entry.file}${entry.output ? ` -> ${entry.output}` : ""}`).join(" \n")}` : ""}`);
4562
+ else context.warn(`No entry files were found for the ${context.config.title} project. Please ensure this is correct. Powerlines plugins generally require at least one entry point to function properly.`);
4563
+ await resolveTsconfig(context);
4564
+ await installDependencies(context);
4565
+ await this.callHook("configResolved", {
4566
+ environment: context,
4567
+ order: "post"
4568
+ });
4569
+ context.trace(`Powerlines configuration has been resolved: \n\n${(0, _storm_software_config_tools_logger_console.formatLogMessage)({
4570
+ ...context.config,
4571
+ userConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(context.config.userConfig) ? (0, _stryke_helpers_omit.omit)(context.config.userConfig, ["plugins"]) : void 0,
4572
+ inlineConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(context.config.inlineConfig) ? (0, _stryke_helpers_omit.omit)(context.config.inlineConfig, ["plugins"]) : void 0,
4573
+ plugins: context.plugins.map((plugin) => plugin.plugin.name)
4574
+ })}`);
4575
+ if (!context.fs.existsSync(context.cachePath)) await (0, _stryke_fs_helpers.createDirectory)(context.cachePath);
4576
+ if (!context.fs.existsSync(context.dataPath)) await (0, _stryke_fs_helpers.createDirectory)(context.dataPath);
4577
+ if (context.config.skipCache === true || context.persistedMeta?.checksum !== context.meta.checksum) context.debug(`Using previously prepared files as the meta checksum has not changed.`);
4578
+ else {
4579
+ context.info(`Running \`prepare\` command as the meta checksum has changed since the last run.`);
4580
+ await this.prepare((0, defu.default)({ output: { types: false } }, inlineConfig));
4576
4581
  }
4577
- }
4582
+ await this.handleTypes(context);
4583
+ this.context.debug("Formatting files generated during the types step.");
4584
+ await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, await context.fs.read(context.typesPath) ?? "");
4585
+ await writeMetaFile(context);
4586
+ context.persistedMeta = context.meta;
4587
+ });
4578
4588
  }
4579
4589
  /**
4580
- * Generate the Powerlines TypeScript declaration file
4590
+ * Prepare the Powerlines API
4581
4591
  *
4582
4592
  * @remarks
4583
- * This method will generate the TypeScript declaration file for the Powerlines project, including any types provided by plugins.
4593
+ * This method will prepare the Powerlines API for use, initializing any necessary resources.
4584
4594
  *
4585
- * @param context - The environment context to use for generating the TypeScript declaration file
4586
- * @returns A promise that resolves when the TypeScript declaration file has been generated
4587
- */
4588
- async #types(context) {
4589
- context.debug(`Preparing the TypeScript definitions for the Powerlines project.`);
4590
- if (context.fs.existsSync(context.typesPath)) await context.fs.remove(context.typesPath);
4591
- if (!await (0, _stryke_fs_resolve.resolvePackage)("typescript")) throw new Error("Could not resolve TypeScript package location. Please ensure TypeScript is installed.");
4592
- context.debug("Running TypeScript compiler for built-in runtime module files.");
4593
- let { code, directives } = await emitBuiltinTypes(context, (await context.getBuiltins()).reduce((ret, builtin) => {
4594
- const formatted = (0, _stryke_path_replace.replacePath)(builtin.path, context.config.cwd);
4595
- if (!ret.includes(formatted)) ret.push(formatted);
4596
- return ret;
4597
- }, []));
4598
- context.debug(`Generating TypeScript declaration file ${context.typesPath}.`);
4599
- const merge = async (currentResult, previousResult) => {
4600
- if (!(0, _stryke_type_checks_is_set_string.isSetString)(currentResult) && !(0, _stryke_type_checks_is_set_object.isSetObject)(currentResult) && !(0, _stryke_type_checks_is_set_string.isSetString)(previousResult) && !(0, _stryke_type_checks_is_set_object.isSetObject)(previousResult)) return {
4601
- code,
4602
- directives
4603
- };
4604
- const previous = (await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, (0, _stryke_type_checks_is_set_string.isSetString)(previousResult) ? previousResult : (0, _stryke_type_checks_is_set_object.isSetObject)(previousResult) ? previousResult.code : "")).trim().replace(code, "").trim();
4605
- const current = (await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, (0, _stryke_type_checks_is_set_string.isSetString)(currentResult) ? currentResult : (0, _stryke_type_checks_is_set_object.isSetObject)(currentResult) ? currentResult.code : "")).trim().replace(previous, "").trim().replace(code, "").trim();
4606
- return {
4607
- directives: [...(0, _stryke_type_checks_is_set_object.isSetObject)(currentResult) && currentResult.directives ? currentResult.directives : [], ...(0, _stryke_type_checks_is_set_object.isSetObject)(previousResult) && previousResult.directives ? previousResult.directives : []],
4608
- code: await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, `${!previous.includes((0, _powerlines_core_lib_utilities_file_header.getTypescriptFileHeader)(context)) && !current.includes((0, _powerlines_core_lib_utilities_file_header.getTypescriptFileHeader)(context)) ? `${code}\n` : ""}${previous}\n${current}`.trim())
4609
- };
4610
- };
4611
- const asNextParam = (previousResult) => (0, _stryke_type_checks_is_object.isObject)(previousResult) ? previousResult.code : previousResult;
4612
- let result = await this.callHook("types", {
4613
- environment: context,
4614
- sequential: true,
4615
- order: "pre",
4616
- result: "merge",
4617
- merge,
4618
- asNextParam
4619
- }, code);
4620
- if (result) {
4621
- if ((0, _stryke_type_checks_is_set_object.isSetObject)(result)) {
4622
- code = result.code;
4623
- if (Array.isArray(result.directives) && result.directives.length > 0) directives = (0, _stryke_helpers_get_unique.getUnique)([...directives, ...result.directives]).filter(Boolean);
4624
- } else if ((0, _stryke_type_checks_is_set_string.isSetString)(result)) code = result;
4625
- }
4626
- result = await this.callHook("types", {
4627
- environment: context,
4628
- sequential: true,
4629
- order: "normal",
4630
- result: "merge",
4631
- merge,
4632
- asNextParam
4633
- }, code);
4634
- if (result) {
4635
- if ((0, _stryke_type_checks_is_set_object.isSetObject)(result)) {
4636
- code = result.code;
4637
- if (Array.isArray(result.directives) && result.directives.length > 0) directives = (0, _stryke_helpers_get_unique.getUnique)([...directives, ...result.directives]).filter(Boolean);
4638
- } else if ((0, _stryke_type_checks_is_set_string.isSetString)(result)) code = result;
4639
- }
4640
- result = await this.callHook("types", {
4641
- environment: context,
4642
- sequential: true,
4643
- order: "post",
4644
- result: "merge",
4645
- merge,
4646
- asNextParam
4647
- }, code);
4648
- if (result) {
4649
- if ((0, _stryke_type_checks_is_set_object.isSetObject)(result)) {
4650
- code = result.code;
4651
- if (Array.isArray(result.directives) && result.directives.length > 0) directives = (0, _stryke_helpers_get_unique.getUnique)([...directives, ...result.directives]).filter(Boolean);
4652
- } else if ((0, _stryke_type_checks_is_set_string.isSetString)(result)) code = result;
4653
- }
4654
- if ((0, _stryke_type_checks_is_set_string.isSetString)(code?.trim()) || directives.length > 0) await context.fs.write(context.typesPath, `${directives.length > 0 ? `${directives.map((directive) => `/// <reference types="${directive}" />`).join("\n")}
4655
-
4656
- ` : ""}${(0, _powerlines_core_lib_utilities_file_header.getTypescriptFileHeader)(context, {
4657
- directive: null,
4658
- prettierIgnore: false
4659
- })}
4660
-
4661
- ${formatTypes(code)}
4662
- `);
4663
- }
4664
- /**
4665
- * Initialize a Powerlines API instance
4666
- *
4667
- * @param options - The options to initialize the API with
4668
- * @returns A new instance of the Powerlines API
4669
- */
4670
- static async init(options, initialConfig) {
4671
- const api = new PowerlinesExecution(await PowerlinesExecutionContext.init(options, initialConfig ?? {}));
4672
- api.#context.config.initialConfig = initialConfig ?? {};
4673
- await api.setup();
4674
- return api;
4675
- }
4676
- /**
4677
- * The Powerlines context
4678
- */
4679
- get context() {
4680
- return this.#context;
4681
- }
4682
- /**
4683
- * Initialize the execution API with the provided configuration options
4684
- */
4685
- async setup() {
4686
- await this.#context.setup();
4687
- this.#context.$$internal = {
4688
- api: this,
4689
- addPlugin: this.addPlugin.bind(this)
4690
- };
4691
- const timer = this.#context.timer("Initialization");
4692
- for (const plugin of this.#context.config.plugins.flatMap((p) => (0, _stryke_convert_to_array.toArray)(p)) ?? []) await this.addPlugin(plugin);
4693
- if (this.#context.plugins.length === 0) this.#context.warn({
4694
- meta: { category: "plugins" },
4695
- message: "No Powerlines plugins were specified in the options. Please ensure this is correct, as it is generally not recommended."
4696
- });
4697
- else this.#context.info({
4698
- meta: { category: "plugins" },
4699
- message: `Loaded ${this.#context.plugins.length} ${(0, _stryke_string_format_title_case.titleCase)(this.#context.config.framework)} plugin${this.#context.plugins.length > 1 ? "s" : ""}: \n${this.#context.plugins.map((plugin, index) => ` ${index + 1}. ${(0, _powerlines_core_plugin_utils_logging.colorText)(plugin.name)}`).join("\n")}`
4700
- });
4701
- const pluginConfig = await this.callHook("config", {
4702
- environment: await this.#context.getEnvironment(),
4703
- sequential: true,
4704
- result: "merge",
4705
- merge: mergeConfigs
4706
- });
4707
- if (pluginConfig) {
4708
- this.#context.config.pluginConfig = pluginConfig;
4709
- await this.#context.setup();
4710
- }
4711
- timer();
4712
- }
4713
- /**
4714
- * Generate the Powerlines typescript declaration file
4715
- *
4716
- * @remarks
4717
- * This method will only generate the typescript declaration file for the Powerlines project. It is generally recommended to run the full `prepare` command, which will run this method as part of its process.
4718
- *
4719
- * @param inlineConfig - The inline configuration for the types command
4720
- */
4721
- async types(inlineConfig = { command: "types" }) {
4722
- this.context.debug(" Aggregating configuration options for the Powerlines project");
4723
- inlineConfig.command ??= "types";
4724
- this.context.config.inlineConfig = inlineConfig;
4725
- await this.setup();
4726
- await this.#executeEnvironments(async (context) => {
4727
- context.debug(`Initializing the processing options for the Powerlines project.`);
4728
- await this.callHook("configResolved", {
4729
- environment: context,
4730
- order: "pre"
4731
- });
4732
- await initializeTsconfig(context);
4733
- await this.callHook("configResolved", {
4734
- environment: context,
4735
- order: "normal"
4736
- });
4737
- if (context.entry.length > 0) context.debug(`The configuration provided ${(0, _stryke_type_checks_is_object.isObject)(context.config.input) ? Object.keys(context.config.input).length : (0, _stryke_convert_to_array.toArray)(context.config.input).length} entry point(s), Powerlines has found ${context.entry.length} entry files(s) for the ${context.config.title} project${context.entry.length > 0 && context.entry.length < 10 ? `: \n${context.entry.map((entry) => `- ${entry.file}${entry.output ? ` -> ${entry.output}` : ""}`).join(" \n")}` : ""}`);
4738
- else context.warn(`No entry files were found for the ${context.config.title} project. Please ensure this is correct. Powerlines plugins generally require at least one entry point to function properly.`);
4739
- await resolveTsconfig(context);
4740
- await installDependencies(context);
4741
- await this.callHook("configResolved", {
4742
- environment: context,
4743
- order: "post"
4744
- });
4745
- context.trace(`Powerlines configuration has been resolved: \n\n${(0, _storm_software_config_tools_logger_console.formatLogMessage)({
4746
- ...context.config,
4747
- userConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(context.config.userConfig) ? (0, _stryke_helpers_omit.omit)(context.config.userConfig, ["plugins"]) : void 0,
4748
- inlineConfig: (0, _stryke_type_checks_is_set_object.isSetObject)(context.config.inlineConfig) ? (0, _stryke_helpers_omit.omit)(context.config.inlineConfig, ["plugins"]) : void 0,
4749
- plugins: context.plugins.map((plugin) => plugin.plugin.name)
4750
- })}`);
4751
- if (!context.fs.existsSync(context.cachePath)) await (0, _stryke_fs_helpers.createDirectory)(context.cachePath);
4752
- if (!context.fs.existsSync(context.dataPath)) await (0, _stryke_fs_helpers.createDirectory)(context.dataPath);
4753
- if (context.config.skipCache === true || context.persistedMeta?.checksum !== context.meta.checksum) context.debug(`Using previously prepared files as the meta checksum has not changed.`);
4754
- else {
4755
- context.info(`Running \`prepare\` command as the meta checksum has changed since the last run.`);
4756
- await this.prepare((0, defu.default)({ output: { types: false } }, inlineConfig));
4757
- }
4758
- await this.#types(context);
4759
- this.context.debug("Formatting files generated during the types step.");
4760
- await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, await context.fs.read(context.typesPath) ?? "");
4761
- await writeMetaFile(context);
4762
- context.persistedMeta = context.meta;
4763
- });
4764
- }
4765
- /**
4766
- * Prepare the Powerlines API
4767
- *
4768
- * @remarks
4769
- * This method will prepare the Powerlines API for use, initializing any necessary resources.
4770
- *
4771
- * @param inlineConfig - The inline configuration for the prepare command
4595
+ * @param inlineConfig - The inline configuration for the prepare command
4772
4596
  */
4773
4597
  async prepare(inlineConfig = { command: "prepare" }) {
4774
4598
  inlineConfig.command ??= "prepare";
4775
- this.context.config.inlineConfig = inlineConfig;
4776
- await this.setup();
4777
- await this.#executeEnvironments(async (context) => {
4599
+ await this.context.setInlineConfig(inlineConfig);
4600
+ await this.executeEnvironments(async (context) => {
4778
4601
  context.debug(`Initializing the processing options for the Powerlines project.`);
4779
4602
  await this.callHook("configResolved", {
4780
4603
  environment: context,
@@ -4824,7 +4647,7 @@ ${formatTypes(code)}
4824
4647
  environment: context,
4825
4648
  order: "post"
4826
4649
  });
4827
- if (context.config.output.types !== false) await this.#types(context);
4650
+ if (context.config.output.types !== false) await this.handleTypes(context);
4828
4651
  this.context.debug("Formatting files generated during the prepare step.");
4829
4652
  await Promise.all([(0, _powerlines_core_lib_utilities_format.formatFolder)(context, context.builtinsPath), (0, _powerlines_core_lib_utilities_format.formatFolder)(context, context.entryPath)]);
4830
4653
  await writeMetaFile(context);
@@ -4843,7 +4666,7 @@ ${formatTypes(code)}
4843
4666
  async new(inlineConfig) {
4844
4667
  inlineConfig.command ??= "new";
4845
4668
  await this.prepare(inlineConfig);
4846
- await this.#executeEnvironments(async (context) => {
4669
+ await this.executeEnvironments(async (context) => {
4847
4670
  context.debug("Initializing the processing options for the Powerlines project.");
4848
4671
  await this.callHook("new", {
4849
4672
  environment: context,
@@ -4892,7 +4715,7 @@ ${formatTypes(code)}
4892
4715
  async clean(inlineConfig = { command: "clean" }) {
4893
4716
  inlineConfig.command ??= "clean";
4894
4717
  await this.prepare(inlineConfig);
4895
- await this.#executeEnvironments(async (context) => {
4718
+ await this.executeEnvironments(async (context) => {
4896
4719
  context.debug("Cleaning the project's dist and artifacts directories.");
4897
4720
  await context.fs.remove((0, _stryke_path_join_paths.joinPaths)(context.config.cwd, context.config.output.path));
4898
4721
  await context.fs.remove((0, _stryke_path_join_paths.joinPaths)(context.config.cwd, context.config.root, context.config.output.artifactsPath));
@@ -4911,7 +4734,7 @@ ${formatTypes(code)}
4911
4734
  async lint(inlineConfig = { command: "lint" }) {
4912
4735
  inlineConfig.command ??= "lint";
4913
4736
  await this.prepare(inlineConfig);
4914
- await this.#executeEnvironments(async (context) => {
4737
+ await this.executeEnvironments(async (context) => {
4915
4738
  await this.callHook("lint", {
4916
4739
  environment: context,
4917
4740
  sequential: false
@@ -4927,7 +4750,7 @@ ${formatTypes(code)}
4927
4750
  async test(inlineConfig = { command: "test" }) {
4928
4751
  inlineConfig.command ??= "test";
4929
4752
  await this.prepare(inlineConfig);
4930
- await this.#executeEnvironments(async (context) => {
4753
+ await this.executeEnvironments(async (context) => {
4931
4754
  await this.callHook("test", {
4932
4755
  environment: context,
4933
4756
  sequential: false
@@ -4945,17 +4768,15 @@ ${formatTypes(code)}
4945
4768
  */
4946
4769
  async build(inlineConfig = { command: "build" }) {
4947
4770
  inlineConfig.command ??= "build";
4771
+ await this.context.setInlineConfig(inlineConfig);
4948
4772
  await this.context.generateChecksum();
4949
4773
  if (this.context.meta.checksum !== this.context.persistedMeta?.checksum || this.context.config.skipCache) {
4950
4774
  this.context.info(!this.context.persistedMeta?.checksum ? "No previous build cache found. Preparing the project for the initial build." : this.context.meta.checksum !== this.context.persistedMeta.checksum ? "The project has been modified since the last time `prepare` was ran. Re-preparing the project." : "The project is configured to skip cache. Re-preparing the project.");
4951
4775
  await this.prepare(inlineConfig);
4952
- } else {
4953
- this.context.config.inlineConfig = inlineConfig;
4954
- await this.context.setup();
4955
4776
  }
4956
- if (this.context.config.singleBuild) await this.#handleBuild(await this.#context.toEnvironment());
4957
- else await this.#executeEnvironments(async (context) => {
4958
- await this.#handleBuild(context);
4777
+ if (this.context.config.singleBuild) await this.handleBuild(await this.#context.toEnvironment());
4778
+ else await this.executeEnvironments(async (context) => {
4779
+ await this.handleBuild(context);
4959
4780
  });
4960
4781
  }
4961
4782
  /**
@@ -4966,8 +4787,9 @@ ${formatTypes(code)}
4966
4787
  */
4967
4788
  async docs(inlineConfig = { command: "docs" }) {
4968
4789
  inlineConfig.command ??= "docs";
4790
+ await this.context.setInlineConfig(inlineConfig);
4969
4791
  await this.prepare(inlineConfig);
4970
- await this.#executeEnvironments(async (context) => {
4792
+ await this.executeEnvironments(async (context) => {
4971
4793
  context.debug("Writing documentation for the Powerlines project artifacts.");
4972
4794
  await this.callHook("docs", { environment: context });
4973
4795
  });
@@ -4982,8 +4804,9 @@ ${formatTypes(code)}
4982
4804
  */
4983
4805
  async deploy(inlineConfig = { command: "deploy" }) {
4984
4806
  inlineConfig.command ??= "deploy";
4807
+ await this.context.setInlineConfig(inlineConfig);
4985
4808
  await this.prepare(inlineConfig);
4986
- await this.#executeEnvironments(async (context) => {
4809
+ await this.executeEnvironments(async (context) => {
4987
4810
  await this.callHook("deploy", { environment: context });
4988
4811
  });
4989
4812
  }
@@ -4996,7 +4819,7 @@ ${formatTypes(code)}
4996
4819
  * @returns A promise that resolves when the finalization process has completed
4997
4820
  */
4998
4821
  async finalize() {
4999
- await this.#executeEnvironments(async (context) => {
4822
+ await this.executeEnvironments(async (context) => {
5000
4823
  await this.callHook("finalize", { environment: context });
5001
4824
  await context.fs.dispose();
5002
4825
  if ((0, _stryke_fs_exists.existsSync)(context.cachePath) && !(await (0, _stryke_fs_list_files.listFiles)((0, _stryke_path_join_paths.joinPaths)(context.cachePath, "**/*")))?.length) await (0, _stryke_fs_helpers.removeDirectory)(context.cachePath);
@@ -5028,13 +4851,40 @@ ${formatTypes(code)}
5028
4851
  this.#context = context;
5029
4852
  }
5030
4853
  /**
4854
+ * Initialize the execution API with the provided configuration options
4855
+ */
4856
+ async init() {
4857
+ this.#context.$$internal = {
4858
+ api: this,
4859
+ addPlugin: this.addPlugin.bind(this)
4860
+ };
4861
+ const timer = this.#context.timer("Initialization");
4862
+ for (const plugin of this.#context.config.plugins.flatMap((p) => (0, _stryke_convert_to_array.toArray)(p)) ?? []) await this.addPlugin(plugin);
4863
+ if (this.#context.plugins.length === 0) this.#context.warn({
4864
+ meta: { category: "plugins" },
4865
+ message: "No Powerlines plugins were specified in the options. Please ensure this is correct, as it is generally not recommended."
4866
+ });
4867
+ else this.#context.info({
4868
+ meta: { category: "plugins" },
4869
+ message: `Loaded ${this.#context.plugins.length} ${(0, _stryke_string_format_title_case.titleCase)(this.#context.config.framework)} plugin${this.#context.plugins.length > 1 ? "s" : ""}: \n${this.#context.plugins.map((plugin, index) => ` ${index + 1}. ${(0, _powerlines_core_plugin_utils_logging.colorText)(plugin.name)}`).join("\n")}`
4870
+ });
4871
+ const pluginConfig = await this.callHook("config", {
4872
+ environment: await this.#context.getEnvironment(),
4873
+ sequential: true,
4874
+ result: "merge",
4875
+ merge: mergeConfigs
4876
+ });
4877
+ if (pluginConfig) await this.context.setPluginConfig(pluginConfig);
4878
+ timer();
4879
+ }
4880
+ /**
5031
4881
  * Add a Powerlines plugin used in the build process
5032
4882
  *
5033
4883
  * @param config - The import path of the plugin to add
5034
4884
  */
5035
4885
  async addPlugin(config) {
5036
4886
  if (config) {
5037
- const result = await this.#initPlugin(config);
4887
+ const result = await this.initPlugin(config);
5038
4888
  if (!result) return;
5039
4889
  for (const plugin of result) {
5040
4890
  this.context.debug({
@@ -5045,33 +4895,266 @@ ${formatTypes(code)}
5045
4895
  }
5046
4896
  }
5047
4897
  }
4898
+ /**
4899
+ * Get the configured environments
4900
+ *
4901
+ * @returns The configured environments
4902
+ */
4903
+ async getEnvironments() {
4904
+ if (!this.context.config.environments || Object.keys(this.context.config.environments).length <= 1) {
4905
+ this.context.debug("No environments are configured for this Powerlines project. Using the default environment.");
4906
+ return [await this.context.getEnvironment()];
4907
+ }
4908
+ this.context.debug(`Found ${Object.keys(this.context.config.environments).length} configured environment(s) for this Powerlines project.`);
4909
+ return (await Promise.all(Object.entries(this.context.config.environments).map(async ([name, config]) => {
4910
+ if (!await this.context.getEnvironmentSafe(name)) {
4911
+ const resolvedEnvironment = await this.callHook("configEnvironment", { environment: name }, name, config);
4912
+ if (resolvedEnvironment) this.context.environments[name] = await this.context.createEnvironment(resolvedEnvironment);
4913
+ }
4914
+ return this.context.environments[name];
4915
+ }))).filter((context) => (0, _stryke_type_checks_is_set.isSet)(context));
4916
+ }
4917
+ /**
4918
+ * Execute a handler function for each environment
4919
+ *
4920
+ * @param handle - The handler function to execute for each environment
4921
+ */
4922
+ async executeEnvironments(handle) {
4923
+ await Promise.all((await this.getEnvironments()).map(async (context) => {
4924
+ return Promise.resolve(handle(context));
4925
+ }));
4926
+ }
4927
+ /**
4928
+ * Initialize a Powerlines plugin
4929
+ *
4930
+ * @param config - The configuration for the plugin
4931
+ * @returns The initialized plugin instance, or null if the plugin was a duplicate
4932
+ * @throws Will throw an error if the plugin cannot be found or is invalid
4933
+ */
4934
+ async initPlugin(config) {
4935
+ let awaited = config;
4936
+ if ((0, _stryke_type_checks_is_promise.isPromiseLike)(config)) awaited = await Promise.resolve(config);
4937
+ if (!(0, _powerlines_core_plugin_utils.isPluginConfig)(awaited)) {
4938
+ const invalid = (0, _powerlines_core_plugin_utils.findInvalidPluginConfig)(awaited);
4939
+ throw new Error(`Invalid ${invalid && invalid.length > 1 ? "plugins" : "plugin"} specified in the configuration - ${invalid && invalid.length > 0 ? JSON.stringify(awaited) : invalid?.join("\n\n")} \n\nPlease ensure the value is one of the following: \n - an instance of \`Plugin\` \n - a plugin name \n - an object with the \`plugin\` and \`options\` properties \n - a tuple array with the plugin and options \n - a factory function that returns a plugin or array of plugins \n - an array of plugins or plugin configurations`);
4940
+ }
4941
+ let plugins;
4942
+ if ((0, _powerlines_core_plugin_utils.isPlugin)(awaited)) plugins = [awaited];
4943
+ else if ((0, _stryke_type_checks_is_function.isFunction)(awaited)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(awaited()));
4944
+ else if ((0, _stryke_type_checks_is_string.isString)(awaited)) {
4945
+ const resolved = await this.resolvePlugin(awaited);
4946
+ if ((0, _stryke_type_checks_is_function.isFunction)(resolved)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(resolved()));
4947
+ else plugins = (0, _stryke_convert_to_array.toArray)(resolved);
4948
+ } else if (Array.isArray(awaited) && awaited.every(_powerlines_core_plugin_utils.isPlugin)) plugins = awaited;
4949
+ else if (Array.isArray(awaited) && awaited.every(_powerlines_core_plugin_utils.isPluginConfig)) {
4950
+ plugins = [];
4951
+ for (const pluginConfig of awaited) {
4952
+ const initialized = await this.initPlugin(pluginConfig);
4953
+ if (initialized) plugins.push(...initialized);
4954
+ }
4955
+ } else if ((0, _powerlines_core_plugin_utils.isPluginConfigTuple)(awaited) || (0, _powerlines_core_plugin_utils.isPluginConfigObject)(awaited)) {
4956
+ let pluginConfig;
4957
+ let pluginOptions;
4958
+ if ((0, _powerlines_core_plugin_utils.isPluginConfigTuple)(awaited)) {
4959
+ pluginConfig = awaited[0];
4960
+ pluginOptions = awaited?.length === 2 ? awaited[1] : void 0;
4961
+ } else {
4962
+ pluginConfig = awaited.plugin;
4963
+ pluginOptions = awaited.options;
4964
+ }
4965
+ if ((0, _stryke_type_checks_is_set_string.isSetString)(pluginConfig)) {
4966
+ const resolved = await this.resolvePlugin(pluginConfig);
4967
+ if ((0, _stryke_type_checks_is_function.isFunction)(resolved)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(pluginOptions ? resolved(pluginOptions) : resolved()));
4968
+ else plugins = (0, _stryke_convert_to_array.toArray)(resolved);
4969
+ } else if ((0, _stryke_type_checks_is_function.isFunction)(pluginConfig)) plugins = (0, _stryke_convert_to_array.toArray)(await Promise.resolve(pluginConfig(pluginOptions)));
4970
+ else if (Array.isArray(pluginConfig) && pluginConfig.every(_powerlines_core_plugin_utils.isPlugin)) plugins = pluginConfig;
4971
+ else if ((0, _powerlines_core_plugin_utils.isPlugin)(pluginConfig)) plugins = (0, _stryke_convert_to_array.toArray)(pluginConfig);
4972
+ }
4973
+ if (!plugins) throw new Error(`The plugin configuration ${JSON.stringify(awaited)} is invalid. This configuration must point to a valid Powerlines plugin module.`);
4974
+ if (plugins.length > 0 && !plugins.every(_powerlines_core_plugin_utils.isPlugin)) throw new Error(`The plugin option ${JSON.stringify(plugins)} does not export a valid module. This configuration must point to a valid Powerlines plugin module.`);
4975
+ const result = [];
4976
+ for (const plugin of plugins) if ((0, _powerlines_core_plugin_utils.isDuplicate)(plugin, this.context.plugins)) this.context.trace(`Duplicate ${chalk.default.bold.cyanBright(plugin.name)} plugin dependency detected - Skipping initialization.`);
4977
+ else {
4978
+ result.push(plugin);
4979
+ this.context.trace(`Initializing the ${chalk.default.bold.cyanBright(plugin.name)} plugin...`);
4980
+ }
4981
+ return result;
4982
+ }
4983
+ async resolvePlugin(pluginPath) {
4984
+ if (pluginPath.startsWith("@") && pluginPath.split("/").filter(Boolean).length > 2) {
4985
+ const splits = pluginPath.split("/").filter(Boolean);
4986
+ pluginPath = `${splits[0]}/${splits[1]}`;
4987
+ }
4988
+ const isInstalled = (0, _stryke_fs_package_fns.isPackageExists)(pluginPath, { paths: [this.context.config.cwd, this.context.config.root] });
4989
+ if (!isInstalled && this.context.config.autoInstall) {
4990
+ this.#context.warn(`The plugin package "${pluginPath}" is not installed. It will be installed automatically.`);
4991
+ const result = await (0, _stryke_fs_install.install)(pluginPath, { cwd: this.context.config.root });
4992
+ if ((0, _stryke_type_checks_is_number.isNumber)(result.exitCode) && result.exitCode > 0) {
4993
+ this.#context.error(result.stderr);
4994
+ throw new Error(`An error occurred while installing the build plugin package "${pluginPath}" `);
4995
+ }
4996
+ }
4997
+ try {
4998
+ const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve((0, _stryke_path_join_paths.joinPaths)(pluginPath, "plugin")));
4999
+ const result = module.plugin ?? module.default;
5000
+ if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
5001
+ return result;
5002
+ } catch (error) {
5003
+ try {
5004
+ const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve(pluginPath));
5005
+ const result = module.plugin ?? module.default;
5006
+ if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
5007
+ return result;
5008
+ } catch {
5009
+ if (!isInstalled) throw new Error(`The plugin package "${pluginPath}" is not installed. Please install the package using the command: "npm install ${pluginPath} --save-dev"`);
5010
+ else throw new Error(`An error occurred while importing the build plugin package "${pluginPath}":
5011
+ ${(0, _stryke_type_checks_is_error.isError)(error) ? error.message : String(error)}
5012
+
5013
+ Note: Please ensure the plugin package's default export is a class that extends \`Plugin\` with a constructor that excepts a single arguments of type \`PluginOptions\`.`);
5014
+ }
5015
+ }
5016
+ }
5017
+ async handleBuild(context) {
5018
+ await this.callHook("build", {
5019
+ environment: context,
5020
+ order: "pre"
5021
+ });
5022
+ context.debug("Formatting the generated entry files before the build process starts.");
5023
+ await (0, _powerlines_core_lib_utilities_format.formatFolder)(context, context.entryPath);
5024
+ await this.callHook("build", {
5025
+ environment: context,
5026
+ order: "normal"
5027
+ });
5028
+ if (context.config.output.copy) {
5029
+ context.debug("Copying project's files from build output directory.");
5030
+ const destinationPath = (0, _stryke_path_is_parent_path.isParentPath)((0, _stryke_path_append.appendPath)(context.config.output.path, context.config.cwd), (0, _stryke_path_append.appendPath)(context.config.root, context.config.cwd)) ? (0, _stryke_path_join_paths.joinPaths)(context.config.output.copy.path, (0, _stryke_path_file_path_fns.relativePath)((0, _stryke_path_append.appendPath)(context.config.root, context.config.cwd), (0, _stryke_path_append.appendPath)(context.config.output.path, context.config.cwd))) : (0, _stryke_path_join_paths.joinPaths)(context.config.output.copy.path, "dist");
5031
+ const sourcePath = context.config.output.path;
5032
+ if ((0, _stryke_fs_exists.existsSync)(sourcePath) && sourcePath !== destinationPath) {
5033
+ context.debug(`Copying files from project's build output directory (${context.config.output.path}) to the project's copy/publish directory (${destinationPath}).`);
5034
+ await (0, _stryke_fs_copy_file.copyFiles)(sourcePath, destinationPath);
5035
+ } else context.warn(`The source path for the copy operation ${!(0, _stryke_fs_exists.existsSync)(sourcePath) ? "does not exist" : "is the same as the destination path"}. Source: ${sourcePath}, Destination: ${destinationPath}. Skipping copying of build output files.`);
5036
+ if (context.config.output.copy.assets && Array.isArray(context.config.output.copy.assets)) await Promise.all(context.config.output.copy.assets.map(async (asset) => {
5037
+ context.trace(`Copying asset(s): ${chalk.default.redBright(context.config.cwd === asset.input ? asset.glob : (0, _stryke_path_append.appendPath)(asset.glob, (0, _stryke_path_replace.replacePath)(asset.input, context.config.cwd)))} -> ${chalk.default.greenBright((0, _stryke_path_append.appendPath)(asset.glob, (0, _stryke_path_replace.replacePath)(asset.output, context.config.cwd)))} ${Array.isArray(asset.ignore) && asset.ignore.length > 0 ? ` (ignoring: ${asset.ignore.map((i) => chalk.default.yellowBright(i)).join(", ")})` : ""}`);
5038
+ await context.fs.copy(asset, asset.output);
5039
+ }));
5040
+ } else context.debug("No copy configuration found for the project output. Skipping the copying of build output files.");
5041
+ await this.callHook("build", {
5042
+ environment: context,
5043
+ order: "post"
5044
+ });
5045
+ }
5046
+ /**
5047
+ * Generate the Powerlines TypeScript declaration file
5048
+ *
5049
+ * @remarks
5050
+ * This method will generate the TypeScript declaration file for the Powerlines project, including any types provided by plugins.
5051
+ *
5052
+ * @param context - The environment context to use for generating the TypeScript declaration file
5053
+ * @returns A promise that resolves when the TypeScript declaration file has been generated
5054
+ */
5055
+ async handleTypes(context) {
5056
+ context.debug(`Preparing the TypeScript definitions for the Powerlines project.`);
5057
+ if (context.fs.existsSync(context.typesPath)) await context.fs.remove(context.typesPath);
5058
+ if (!await (0, _stryke_fs_resolve.resolvePackage)("typescript")) throw new Error("Could not resolve TypeScript package location. Please ensure TypeScript is installed.");
5059
+ context.debug("Running TypeScript compiler for built-in runtime module files.");
5060
+ let { code, directives } = await emitBuiltinTypes(context, (await context.getBuiltins()).reduce((ret, builtin) => {
5061
+ const formatted = (0, _stryke_path_replace.replacePath)(builtin.path, context.config.cwd);
5062
+ if (!ret.includes(formatted)) ret.push(formatted);
5063
+ return ret;
5064
+ }, []));
5065
+ context.debug(`Generating TypeScript declaration file ${context.typesPath}.`);
5066
+ const merge = async (currentResult, previousResult) => {
5067
+ if (!(0, _stryke_type_checks_is_set_string.isSetString)(currentResult) && !(0, _stryke_type_checks_is_set_object.isSetObject)(currentResult) && !(0, _stryke_type_checks_is_set_string.isSetString)(previousResult) && !(0, _stryke_type_checks_is_set_object.isSetObject)(previousResult)) return {
5068
+ code,
5069
+ directives
5070
+ };
5071
+ const previous = (await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, (0, _stryke_type_checks_is_set_string.isSetString)(previousResult) ? previousResult : (0, _stryke_type_checks_is_set_object.isSetObject)(previousResult) ? previousResult.code : "")).trim().replace(code, "").trim();
5072
+ const current = (await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, (0, _stryke_type_checks_is_set_string.isSetString)(currentResult) ? currentResult : (0, _stryke_type_checks_is_set_object.isSetObject)(currentResult) ? currentResult.code : "")).trim().replace(previous, "").trim().replace(code, "").trim();
5073
+ return {
5074
+ directives: [...(0, _stryke_type_checks_is_set_object.isSetObject)(currentResult) && currentResult.directives ? currentResult.directives : [], ...(0, _stryke_type_checks_is_set_object.isSetObject)(previousResult) && previousResult.directives ? previousResult.directives : []],
5075
+ code: await (0, _powerlines_core_lib_utilities_format.format)(context, context.typesPath, `${!previous.includes((0, _powerlines_core_lib_utilities_file_header.getTypescriptFileHeader)(context)) && !current.includes((0, _powerlines_core_lib_utilities_file_header.getTypescriptFileHeader)(context)) ? `${code}\n` : ""}${previous}\n${current}`.trim())
5076
+ };
5077
+ };
5078
+ const asNextParam = (previousResult) => (0, _stryke_type_checks_is_object.isObject)(previousResult) ? previousResult.code : previousResult;
5079
+ let result = await this.callHook("types", {
5080
+ environment: context,
5081
+ sequential: true,
5082
+ order: "pre",
5083
+ result: "merge",
5084
+ merge,
5085
+ asNextParam
5086
+ }, code);
5087
+ if (result) {
5088
+ if ((0, _stryke_type_checks_is_set_object.isSetObject)(result)) {
5089
+ code = result.code;
5090
+ if (Array.isArray(result.directives) && result.directives.length > 0) directives = (0, _stryke_helpers_get_unique.getUnique)([...directives, ...result.directives]).filter(Boolean);
5091
+ } else if ((0, _stryke_type_checks_is_set_string.isSetString)(result)) code = result;
5092
+ }
5093
+ result = await this.callHook("types", {
5094
+ environment: context,
5095
+ sequential: true,
5096
+ order: "normal",
5097
+ result: "merge",
5098
+ merge,
5099
+ asNextParam
5100
+ }, code);
5101
+ if (result) {
5102
+ if ((0, _stryke_type_checks_is_set_object.isSetObject)(result)) {
5103
+ code = result.code;
5104
+ if (Array.isArray(result.directives) && result.directives.length > 0) directives = (0, _stryke_helpers_get_unique.getUnique)([...directives, ...result.directives]).filter(Boolean);
5105
+ } else if ((0, _stryke_type_checks_is_set_string.isSetString)(result)) code = result;
5106
+ }
5107
+ result = await this.callHook("types", {
5108
+ environment: context,
5109
+ sequential: true,
5110
+ order: "post",
5111
+ result: "merge",
5112
+ merge,
5113
+ asNextParam
5114
+ }, code);
5115
+ if (result) {
5116
+ if ((0, _stryke_type_checks_is_set_object.isSetObject)(result)) {
5117
+ code = result.code;
5118
+ if (Array.isArray(result.directives) && result.directives.length > 0) directives = (0, _stryke_helpers_get_unique.getUnique)([...directives, ...result.directives]).filter(Boolean);
5119
+ } else if ((0, _stryke_type_checks_is_set_string.isSetString)(result)) code = result;
5120
+ }
5121
+ if ((0, _stryke_type_checks_is_set_string.isSetString)(code?.trim()) || directives.length > 0) await context.fs.write(context.typesPath, `${directives.length > 0 ? `${directives.map((directive) => `/// <reference types="${directive}" />`).join("\n")}
5122
+
5123
+ ` : ""}${(0, _powerlines_core_lib_utilities_file_header.getTypescriptFileHeader)(context, {
5124
+ directive: null,
5125
+ prettierIgnore: false
5126
+ })}
5127
+
5128
+ ${formatTypes(code)}
5129
+ `);
5130
+ }
5048
5131
  };
5049
5132
 
5050
5133
  //#endregion
5051
5134
  //#region src/_internal/worker.ts
5052
5135
  async function clean({ options, initialConfig, inlineConfig }) {
5053
- await (await PowerlinesExecution.init(options, initialConfig)).clean(inlineConfig);
5136
+ await (await PowerlinesExecution.from(options, initialConfig)).clean(inlineConfig);
5054
5137
  }
5055
5138
  async function prepare({ options, initialConfig, inlineConfig }) {
5056
- await (await PowerlinesExecution.init(options, initialConfig)).prepare(inlineConfig);
5139
+ await (await PowerlinesExecution.from(options, initialConfig)).prepare(inlineConfig);
5057
5140
  }
5058
5141
  async function types({ options, initialConfig, inlineConfig }) {
5059
- await (await PowerlinesExecution.init(options, initialConfig)).types(inlineConfig);
5142
+ await (await PowerlinesExecution.from(options, initialConfig)).types(inlineConfig);
5060
5143
  }
5061
5144
  async function lint({ options, initialConfig, inlineConfig }) {
5062
- await (await PowerlinesExecution.init(options, initialConfig)).lint(inlineConfig);
5145
+ await (await PowerlinesExecution.from(options, initialConfig)).lint(inlineConfig);
5063
5146
  }
5064
5147
  async function test({ options, initialConfig, inlineConfig }) {
5065
- await (await PowerlinesExecution.init(options, initialConfig)).test(inlineConfig);
5148
+ await (await PowerlinesExecution.from(options, initialConfig)).test(inlineConfig);
5066
5149
  }
5067
5150
  async function build({ options, initialConfig, inlineConfig }) {
5068
- await (await PowerlinesExecution.init(options, initialConfig)).build(inlineConfig);
5151
+ await (await PowerlinesExecution.from(options, initialConfig)).build(inlineConfig);
5069
5152
  }
5070
5153
  async function docs({ options, initialConfig, inlineConfig }) {
5071
- await (await PowerlinesExecution.init(options, initialConfig)).docs(inlineConfig);
5154
+ await (await PowerlinesExecution.from(options, initialConfig)).docs(inlineConfig);
5072
5155
  }
5073
5156
  async function deploy({ options, initialConfig, inlineConfig }) {
5074
- await (await PowerlinesExecution.init(options, initialConfig)).deploy(inlineConfig);
5157
+ await (await PowerlinesExecution.from(options, initialConfig)).deploy(inlineConfig);
5075
5158
  }
5076
5159
 
5077
5160
  //#endregion