@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.
- package/dist/_internal/worker.cjs +886 -803
- package/dist/_internal/worker.mjs +889 -806
- package/dist/_internal/worker.mjs.map +1 -1
- package/dist/api.cjs +292 -323
- package/dist/api.d.cts +44 -11
- package/dist/api.d.cts.map +1 -1
- package/dist/api.d.mts +44 -11
- package/dist/api.d.mts.map +1 -1
- package/dist/api.mjs +292 -323
- package/dist/api.mjs.map +1 -1
- package/dist/{base-context-Byizvf4F.cjs → base-context-D7G_24-i.cjs} +82 -76
- package/dist/{base-context-BSAC5sO9.mjs → base-context-DU0NRHDt.mjs} +85 -79
- package/dist/base-context-DU0NRHDt.mjs.map +1 -0
- package/dist/context/index.cjs +3 -3
- package/dist/context/index.d.cts +44 -617
- package/dist/context/index.d.cts.map +1 -1
- package/dist/context/index.d.mts +44 -617
- package/dist/context/index.d.mts.map +1 -1
- package/dist/context/index.mjs +3 -3
- package/dist/engine-context-BuJQY312.cjs +91 -0
- package/dist/engine-context-BvDfqfY7.mjs +86 -0
- package/dist/engine-context-BvDfqfY7.mjs.map +1 -0
- package/dist/execution-context-BpRfsnkE.d.mts +644 -0
- package/dist/execution-context-BpRfsnkE.d.mts.map +1 -0
- package/dist/{execution-context-BYGFYty0.cjs → execution-context-BrX9i_L8.cjs} +449 -364
- package/dist/{execution-context-Bkxp1fML.mjs → execution-context-CgDuoi8o.mjs} +451 -366
- package/dist/execution-context-CgDuoi8o.mjs.map +1 -0
- package/dist/execution-context-CodQucFX.d.cts +644 -0
- package/dist/execution-context-CodQucFX.d.cts.map +1 -0
- package/dist/index.cjs +15 -16
- package/dist/index.d.cts +3 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +15 -16
- package/dist/index.mjs.map +1 -1
- package/dist/{tsconfig-QMSxSwBD.cjs → tsconfig-BUDqmOaT.cjs} +13 -13
- package/dist/{tsconfig-CI6bla4E.mjs → tsconfig-MeFEs21S.mjs} +14 -14
- package/dist/tsconfig-MeFEs21S.mjs.map +1 -0
- package/dist/typescript/index.cjs +1 -1
- package/dist/typescript/index.d.cts +6 -6
- package/dist/typescript/index.d.cts.map +1 -1
- package/dist/typescript/index.d.mts +6 -6
- package/dist/typescript/index.d.mts.map +1 -1
- package/dist/typescript/index.mjs +1 -1
- package/package.json +17 -17
- package/dist/base-context-BSAC5sO9.mjs.map +0 -1
- package/dist/engine-context-CI_0NWIk.cjs +0 -73
- package/dist/engine-context-_RMFwG4J.mjs +0 -68
- package/dist/engine-context-_RMFwG4J.mjs.map +0 -1
- package/dist/execution-context-Bkxp1fML.mjs.map +0 -1
- package/dist/tsconfig-CI6bla4E.mjs.map +0 -1
package/dist/api.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { a as mergeConfigs, i as callHook, s as writeMetaFile, t as PowerlinesExecutionContext } from "./execution-context-
|
|
2
|
-
import { a as isIncludeMatchFound, i as getTsconfigFilePath, r as getParsedTypeScriptConfig } from "./tsconfig-
|
|
1
|
+
import { a as mergeConfigs, i as callHook, s as writeMetaFile, t as PowerlinesExecutionContext } from "./execution-context-CgDuoi8o.mjs";
|
|
2
|
+
import { a as isIncludeMatchFound, i as getTsconfigFilePath, r as getParsedTypeScriptConfig } from "./tsconfig-MeFEs21S.mjs";
|
|
3
3
|
import { n as createProgram } from "./ts-morph-D0CaA37w.mjs";
|
|
4
4
|
import { toArray } from "@stryke/convert/to-array";
|
|
5
5
|
import { resolvePackage } from "@stryke/fs/resolve";
|
|
@@ -15,7 +15,6 @@ import { replaceExtension, replacePath } from "@stryke/path/replace";
|
|
|
15
15
|
import chalk from "chalk";
|
|
16
16
|
import defu from "defu";
|
|
17
17
|
import { joinPaths } from "@stryke/path/join-paths";
|
|
18
|
-
import { titleCase } from "@stryke/string-format/title-case";
|
|
19
18
|
import { getTypescriptFileHeader } from "@powerlines/core/lib/utilities/file-header";
|
|
20
19
|
import { format, formatFolder } from "@powerlines/core/lib/utilities/format";
|
|
21
20
|
import { formatLogMessage } from "@storm-software/config-tools/logger/console";
|
|
@@ -29,6 +28,7 @@ import { getUnique } from "@stryke/helpers/get-unique";
|
|
|
29
28
|
import { omit } from "@stryke/helpers/omit";
|
|
30
29
|
import { findFileName, findFilePath, relativePath } from "@stryke/path/file-path-fns";
|
|
31
30
|
import { isParentPath } from "@stryke/path/is-parent-path";
|
|
31
|
+
import { titleCase } from "@stryke/string-format/title-case";
|
|
32
32
|
import { isError } from "@stryke/type-checks/is-error";
|
|
33
33
|
import { isFunction } from "@stryke/type-checks/is-function";
|
|
34
34
|
import { isNumber } from "@stryke/type-checks/is-number";
|
|
@@ -358,11 +358,11 @@ async function installDependencies(context) {
|
|
|
358
358
|
//#endregion
|
|
359
359
|
//#region src/_internal/helpers/resolve-tsconfig.ts
|
|
360
360
|
function getTsconfigDtsPath(context) {
|
|
361
|
-
return joinPaths(relativePath(joinPaths(context.
|
|
361
|
+
return joinPaths(relativePath(joinPaths(context.config.cwd, context.config.root), findFilePath(context.typesPath)), findFileName(context.typesPath));
|
|
362
362
|
}
|
|
363
363
|
async function resolveTsconfigChanges(context) {
|
|
364
|
-
const tsconfig = getParsedTypeScriptConfig(context.
|
|
365
|
-
const tsconfigJson = await readJsonFile(getTsconfigFilePath(context.
|
|
364
|
+
const tsconfig = getParsedTypeScriptConfig(context.config.cwd, context.config.root, context.config.tsconfig, context.config.tsconfigRaw);
|
|
365
|
+
const tsconfigJson = await readJsonFile(getTsconfigFilePath(context.config.cwd, context.config.root, context.config.tsconfig));
|
|
366
366
|
tsconfigJson.compilerOptions ??= {};
|
|
367
367
|
if (context.config.output.dts !== false) {
|
|
368
368
|
const dtsRelativePath = getTsconfigDtsPath(context);
|
|
@@ -452,249 +452,15 @@ var PowerlinesExecution = class PowerlinesExecution {
|
|
|
452
452
|
* The Powerlines context
|
|
453
453
|
*/
|
|
454
454
|
#context;
|
|
455
|
-
async #handleBuild(context) {
|
|
456
|
-
await this.callHook("build", {
|
|
457
|
-
environment: context,
|
|
458
|
-
order: "pre"
|
|
459
|
-
});
|
|
460
|
-
context.debug("Formatting the generated entry files before the build process starts.");
|
|
461
|
-
await formatFolder(context, context.entryPath);
|
|
462
|
-
await this.callHook("build", {
|
|
463
|
-
environment: context,
|
|
464
|
-
order: "normal"
|
|
465
|
-
});
|
|
466
|
-
if (context.config.output.copy) {
|
|
467
|
-
context.debug("Copying project's files from build output directory.");
|
|
468
|
-
const destinationPath = isParentPath(appendPath(context.config.output.path, context.config.cwd), appendPath(context.config.root, context.config.cwd)) ? joinPaths(context.config.output.copy.path, relativePath(appendPath(context.config.root, context.config.cwd), appendPath(context.config.output.path, context.config.cwd))) : joinPaths(context.config.output.copy.path, "dist");
|
|
469
|
-
const sourcePath = context.config.output.path;
|
|
470
|
-
if (existsSync(sourcePath) && sourcePath !== destinationPath) {
|
|
471
|
-
context.debug(`Copying files from project's build output directory (${context.config.output.path}) to the project's copy/publish directory (${destinationPath}).`);
|
|
472
|
-
await copyFiles(sourcePath, destinationPath);
|
|
473
|
-
} else context.warn(`The source path for the copy operation ${!existsSync(sourcePath) ? "does not exist" : "is the same as the destination path"}. Source: ${sourcePath}, Destination: ${destinationPath}. Skipping copying of build output files.`);
|
|
474
|
-
if (context.config.output.copy.assets && Array.isArray(context.config.output.copy.assets)) await Promise.all(context.config.output.copy.assets.map(async (asset) => {
|
|
475
|
-
context.trace(`Copying asset(s): ${chalk.redBright(context.config.cwd === asset.input ? asset.glob : appendPath(asset.glob, replacePath(asset.input, context.config.cwd)))} -> ${chalk.greenBright(appendPath(asset.glob, replacePath(asset.output, context.config.cwd)))} ${Array.isArray(asset.ignore) && asset.ignore.length > 0 ? ` (ignoring: ${asset.ignore.map((i) => chalk.yellowBright(i)).join(", ")})` : ""}`);
|
|
476
|
-
await context.fs.copy(asset, asset.output);
|
|
477
|
-
}));
|
|
478
|
-
} else context.debug("No copy configuration found for the project output. Skipping the copying of build output files.");
|
|
479
|
-
await this.callHook("build", {
|
|
480
|
-
environment: context,
|
|
481
|
-
order: "post"
|
|
482
|
-
});
|
|
483
|
-
}
|
|
484
|
-
/**
|
|
485
|
-
* Get the configured environments
|
|
486
|
-
*
|
|
487
|
-
* @returns The configured environments
|
|
488
|
-
*/
|
|
489
|
-
async #getEnvironments() {
|
|
490
|
-
if (!this.context.config.environments || Object.keys(this.context.config.environments).length <= 1) {
|
|
491
|
-
this.context.debug("No environments are configured for this Powerlines project. Using the default environment.");
|
|
492
|
-
return [await this.context.getEnvironment()];
|
|
493
|
-
}
|
|
494
|
-
this.context.debug(`Found ${Object.keys(this.context.config.environments).length} configured environment(s) for this Powerlines project.`);
|
|
495
|
-
return (await Promise.all(Object.entries(this.context.config.environments).map(async ([name, config]) => {
|
|
496
|
-
if (!await this.context.getEnvironmentSafe(name)) {
|
|
497
|
-
const resolvedEnvironment = await this.callHook("configEnvironment", { environment: name }, name, config);
|
|
498
|
-
if (resolvedEnvironment) this.context.environments[name] = await this.context.in(resolvedEnvironment);
|
|
499
|
-
}
|
|
500
|
-
return this.context.environments[name];
|
|
501
|
-
}))).filter((context) => isSet(context));
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Execute a handler function for each environment
|
|
505
|
-
*
|
|
506
|
-
* @param handle - The handler function to execute for each environment
|
|
507
|
-
*/
|
|
508
|
-
async #executeEnvironments(handle) {
|
|
509
|
-
await Promise.all((await this.#getEnvironments()).map(async (context) => {
|
|
510
|
-
return Promise.resolve(handle(context));
|
|
511
|
-
}));
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Initialize a Powerlines plugin
|
|
515
|
-
*
|
|
516
|
-
* @param config - The configuration for the plugin
|
|
517
|
-
* @returns The initialized plugin instance, or null if the plugin was a duplicate
|
|
518
|
-
* @throws Will throw an error if the plugin cannot be found or is invalid
|
|
519
|
-
*/
|
|
520
|
-
async #initPlugin(config) {
|
|
521
|
-
let awaited = config;
|
|
522
|
-
if (isPromiseLike(config)) awaited = await Promise.resolve(config);
|
|
523
|
-
if (!isPluginConfig(awaited)) {
|
|
524
|
-
const invalid = findInvalidPluginConfig(awaited);
|
|
525
|
-
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`);
|
|
526
|
-
}
|
|
527
|
-
let plugins;
|
|
528
|
-
if (isPlugin(awaited)) plugins = [awaited];
|
|
529
|
-
else if (isFunction(awaited)) plugins = toArray(await Promise.resolve(awaited()));
|
|
530
|
-
else if (isString(awaited)) {
|
|
531
|
-
const resolved = await this.#resolvePlugin(awaited);
|
|
532
|
-
if (isFunction(resolved)) plugins = toArray(await Promise.resolve(resolved()));
|
|
533
|
-
else plugins = toArray(resolved);
|
|
534
|
-
} else if (Array.isArray(awaited) && awaited.every(isPlugin)) plugins = awaited;
|
|
535
|
-
else if (Array.isArray(awaited) && awaited.every(isPluginConfig)) {
|
|
536
|
-
plugins = [];
|
|
537
|
-
for (const pluginConfig of awaited) {
|
|
538
|
-
const initialized = await this.#initPlugin(pluginConfig);
|
|
539
|
-
if (initialized) plugins.push(...initialized);
|
|
540
|
-
}
|
|
541
|
-
} else if (isPluginConfigTuple(awaited) || isPluginConfigObject(awaited)) {
|
|
542
|
-
let pluginConfig;
|
|
543
|
-
let pluginOptions;
|
|
544
|
-
if (isPluginConfigTuple(awaited)) {
|
|
545
|
-
pluginConfig = awaited[0];
|
|
546
|
-
pluginOptions = awaited?.length === 2 ? awaited[1] : void 0;
|
|
547
|
-
} else {
|
|
548
|
-
pluginConfig = awaited.plugin;
|
|
549
|
-
pluginOptions = awaited.options;
|
|
550
|
-
}
|
|
551
|
-
if (isSetString(pluginConfig)) {
|
|
552
|
-
const resolved = await this.#resolvePlugin(pluginConfig);
|
|
553
|
-
if (isFunction(resolved)) plugins = toArray(await Promise.resolve(pluginOptions ? resolved(pluginOptions) : resolved()));
|
|
554
|
-
else plugins = toArray(resolved);
|
|
555
|
-
} else if (isFunction(pluginConfig)) plugins = toArray(await Promise.resolve(pluginConfig(pluginOptions)));
|
|
556
|
-
else if (Array.isArray(pluginConfig) && pluginConfig.every(isPlugin)) plugins = pluginConfig;
|
|
557
|
-
else if (isPlugin(pluginConfig)) plugins = toArray(pluginConfig);
|
|
558
|
-
}
|
|
559
|
-
if (!plugins) throw new Error(`The plugin configuration ${JSON.stringify(awaited)} is invalid. This configuration must point to a valid Powerlines plugin module.`);
|
|
560
|
-
if (plugins.length > 0 && !plugins.every(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.`);
|
|
561
|
-
const result = [];
|
|
562
|
-
for (const plugin of plugins) if (isDuplicate(plugin, this.context.plugins)) this.context.trace(`Duplicate ${chalk.bold.cyanBright(plugin.name)} plugin dependency detected - Skipping initialization.`);
|
|
563
|
-
else {
|
|
564
|
-
result.push(plugin);
|
|
565
|
-
this.context.trace(`Initializing the ${chalk.bold.cyanBright(plugin.name)} plugin...`);
|
|
566
|
-
}
|
|
567
|
-
return result;
|
|
568
|
-
}
|
|
569
|
-
async #resolvePlugin(pluginPath) {
|
|
570
|
-
if (pluginPath.startsWith("@") && pluginPath.split("/").filter(Boolean).length > 2) {
|
|
571
|
-
const splits = pluginPath.split("/").filter(Boolean);
|
|
572
|
-
pluginPath = `${splits[0]}/${splits[1]}`;
|
|
573
|
-
}
|
|
574
|
-
const isInstalled = isPackageExists(pluginPath, { paths: [this.context.config.cwd, this.context.config.root] });
|
|
575
|
-
if (!isInstalled && this.context.config.autoInstall) {
|
|
576
|
-
this.#context.warn(`The plugin package "${pluginPath}" is not installed. It will be installed automatically.`);
|
|
577
|
-
const result = await install(pluginPath, { cwd: this.context.config.root });
|
|
578
|
-
if (isNumber(result.exitCode) && result.exitCode > 0) {
|
|
579
|
-
this.#context.error(result.stderr);
|
|
580
|
-
throw new Error(`An error occurred while installing the build plugin package "${pluginPath}" `);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
try {
|
|
584
|
-
const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve(joinPaths(pluginPath, "plugin")));
|
|
585
|
-
const result = module.plugin ?? module.default;
|
|
586
|
-
if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
|
|
587
|
-
return result;
|
|
588
|
-
} catch (error) {
|
|
589
|
-
try {
|
|
590
|
-
const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve(pluginPath));
|
|
591
|
-
const result = module.plugin ?? module.default;
|
|
592
|
-
if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
|
|
593
|
-
return result;
|
|
594
|
-
} catch {
|
|
595
|
-
if (!isInstalled) throw new Error(`The plugin package "${pluginPath}" is not installed. Please install the package using the command: "npm install ${pluginPath} --save-dev"`);
|
|
596
|
-
else throw new Error(`An error occurred while importing the build plugin package "${pluginPath}":
|
|
597
|
-
${isError(error) ? error.message : String(error)}
|
|
598
|
-
|
|
599
|
-
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\`.`);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* Generate the Powerlines TypeScript declaration file
|
|
605
|
-
*
|
|
606
|
-
* @remarks
|
|
607
|
-
* This method will generate the TypeScript declaration file for the Powerlines project, including any types provided by plugins.
|
|
608
|
-
*
|
|
609
|
-
* @param context - The environment context to use for generating the TypeScript declaration file
|
|
610
|
-
* @returns A promise that resolves when the TypeScript declaration file has been generated
|
|
611
|
-
*/
|
|
612
|
-
async #types(context) {
|
|
613
|
-
context.debug(`Preparing the TypeScript definitions for the Powerlines project.`);
|
|
614
|
-
if (context.fs.existsSync(context.typesPath)) await context.fs.remove(context.typesPath);
|
|
615
|
-
if (!await resolvePackage("typescript")) throw new Error("Could not resolve TypeScript package location. Please ensure TypeScript is installed.");
|
|
616
|
-
context.debug("Running TypeScript compiler for built-in runtime module files.");
|
|
617
|
-
let { code, directives } = await emitBuiltinTypes(context, (await context.getBuiltins()).reduce((ret, builtin) => {
|
|
618
|
-
const formatted = replacePath(builtin.path, context.config.cwd);
|
|
619
|
-
if (!ret.includes(formatted)) ret.push(formatted);
|
|
620
|
-
return ret;
|
|
621
|
-
}, []));
|
|
622
|
-
context.debug(`Generating TypeScript declaration file ${context.typesPath}.`);
|
|
623
|
-
const merge = async (currentResult, previousResult) => {
|
|
624
|
-
if (!isSetString(currentResult) && !isSetObject(currentResult) && !isSetString(previousResult) && !isSetObject(previousResult)) return {
|
|
625
|
-
code,
|
|
626
|
-
directives
|
|
627
|
-
};
|
|
628
|
-
const previous = (await format(context, context.typesPath, isSetString(previousResult) ? previousResult : isSetObject(previousResult) ? previousResult.code : "")).trim().replace(code, "").trim();
|
|
629
|
-
const current = (await format(context, context.typesPath, isSetString(currentResult) ? currentResult : isSetObject(currentResult) ? currentResult.code : "")).trim().replace(previous, "").trim().replace(code, "").trim();
|
|
630
|
-
return {
|
|
631
|
-
directives: [...isSetObject(currentResult) && currentResult.directives ? currentResult.directives : [], ...isSetObject(previousResult) && previousResult.directives ? previousResult.directives : []],
|
|
632
|
-
code: await format(context, context.typesPath, `${!previous.includes(getTypescriptFileHeader(context)) && !current.includes(getTypescriptFileHeader(context)) ? `${code}\n` : ""}${previous}\n${current}`.trim())
|
|
633
|
-
};
|
|
634
|
-
};
|
|
635
|
-
const asNextParam = (previousResult) => isObject(previousResult) ? previousResult.code : previousResult;
|
|
636
|
-
let result = await this.callHook("types", {
|
|
637
|
-
environment: context,
|
|
638
|
-
sequential: true,
|
|
639
|
-
order: "pre",
|
|
640
|
-
result: "merge",
|
|
641
|
-
merge,
|
|
642
|
-
asNextParam
|
|
643
|
-
}, code);
|
|
644
|
-
if (result) {
|
|
645
|
-
if (isSetObject(result)) {
|
|
646
|
-
code = result.code;
|
|
647
|
-
if (Array.isArray(result.directives) && result.directives.length > 0) directives = getUnique([...directives, ...result.directives]).filter(Boolean);
|
|
648
|
-
} else if (isSetString(result)) code = result;
|
|
649
|
-
}
|
|
650
|
-
result = await this.callHook("types", {
|
|
651
|
-
environment: context,
|
|
652
|
-
sequential: true,
|
|
653
|
-
order: "normal",
|
|
654
|
-
result: "merge",
|
|
655
|
-
merge,
|
|
656
|
-
asNextParam
|
|
657
|
-
}, code);
|
|
658
|
-
if (result) {
|
|
659
|
-
if (isSetObject(result)) {
|
|
660
|
-
code = result.code;
|
|
661
|
-
if (Array.isArray(result.directives) && result.directives.length > 0) directives = getUnique([...directives, ...result.directives]).filter(Boolean);
|
|
662
|
-
} else if (isSetString(result)) code = result;
|
|
663
|
-
}
|
|
664
|
-
result = await this.callHook("types", {
|
|
665
|
-
environment: context,
|
|
666
|
-
sequential: true,
|
|
667
|
-
order: "post",
|
|
668
|
-
result: "merge",
|
|
669
|
-
merge,
|
|
670
|
-
asNextParam
|
|
671
|
-
}, code);
|
|
672
|
-
if (result) {
|
|
673
|
-
if (isSetObject(result)) {
|
|
674
|
-
code = result.code;
|
|
675
|
-
if (Array.isArray(result.directives) && result.directives.length > 0) directives = getUnique([...directives, ...result.directives]).filter(Boolean);
|
|
676
|
-
} else if (isSetString(result)) code = result;
|
|
677
|
-
}
|
|
678
|
-
if (isSetString(code?.trim()) || directives.length > 0) await context.fs.write(context.typesPath, `${directives.length > 0 ? `${directives.map((directive) => `/// <reference types="${directive}" />`).join("\n")}
|
|
679
|
-
|
|
680
|
-
` : ""}${getTypescriptFileHeader(context, {
|
|
681
|
-
directive: null,
|
|
682
|
-
prettierIgnore: false
|
|
683
|
-
})}
|
|
684
|
-
|
|
685
|
-
${formatTypes(code)}
|
|
686
|
-
`);
|
|
687
|
-
}
|
|
688
455
|
/**
|
|
689
456
|
* Initialize a Powerlines API instance
|
|
690
457
|
*
|
|
691
458
|
* @param options - The options to initialize the API with
|
|
692
459
|
* @returns A new instance of the Powerlines API
|
|
693
460
|
*/
|
|
694
|
-
static async
|
|
695
|
-
const api = new PowerlinesExecution(await PowerlinesExecutionContext.
|
|
696
|
-
api
|
|
697
|
-
await api.setup();
|
|
461
|
+
static async from(options, initialConfig) {
|
|
462
|
+
const api = new PowerlinesExecution(await PowerlinesExecutionContext.fromInitialConfig(options, initialConfig ?? {}));
|
|
463
|
+
await api.init();
|
|
698
464
|
return api;
|
|
699
465
|
}
|
|
700
466
|
/**
|
|
@@ -704,37 +470,6 @@ ${formatTypes(code)}
|
|
|
704
470
|
return this.#context;
|
|
705
471
|
}
|
|
706
472
|
/**
|
|
707
|
-
* Initialize the execution API with the provided configuration options
|
|
708
|
-
*/
|
|
709
|
-
async setup() {
|
|
710
|
-
await this.#context.setup();
|
|
711
|
-
this.#context.$$internal = {
|
|
712
|
-
api: this,
|
|
713
|
-
addPlugin: this.addPlugin.bind(this)
|
|
714
|
-
};
|
|
715
|
-
const timer = this.#context.timer("Initialization");
|
|
716
|
-
for (const plugin of this.#context.config.plugins.flatMap((p) => toArray(p)) ?? []) await this.addPlugin(plugin);
|
|
717
|
-
if (this.#context.plugins.length === 0) this.#context.warn({
|
|
718
|
-
meta: { category: "plugins" },
|
|
719
|
-
message: "No Powerlines plugins were specified in the options. Please ensure this is correct, as it is generally not recommended."
|
|
720
|
-
});
|
|
721
|
-
else this.#context.info({
|
|
722
|
-
meta: { category: "plugins" },
|
|
723
|
-
message: `Loaded ${this.#context.plugins.length} ${titleCase(this.#context.config.framework)} plugin${this.#context.plugins.length > 1 ? "s" : ""}: \n${this.#context.plugins.map((plugin, index) => ` ${index + 1}. ${colorText(plugin.name)}`).join("\n")}`
|
|
724
|
-
});
|
|
725
|
-
const pluginConfig = await this.callHook("config", {
|
|
726
|
-
environment: await this.#context.getEnvironment(),
|
|
727
|
-
sequential: true,
|
|
728
|
-
result: "merge",
|
|
729
|
-
merge: mergeConfigs
|
|
730
|
-
});
|
|
731
|
-
if (pluginConfig) {
|
|
732
|
-
this.#context.config.pluginConfig = pluginConfig;
|
|
733
|
-
await this.#context.setup();
|
|
734
|
-
}
|
|
735
|
-
timer();
|
|
736
|
-
}
|
|
737
|
-
/**
|
|
738
473
|
* Generate the Powerlines typescript declaration file
|
|
739
474
|
*
|
|
740
475
|
* @remarks
|
|
@@ -745,9 +480,8 @@ ${formatTypes(code)}
|
|
|
745
480
|
async types(inlineConfig = { command: "types" }) {
|
|
746
481
|
this.context.debug(" Aggregating configuration options for the Powerlines project");
|
|
747
482
|
inlineConfig.command ??= "types";
|
|
748
|
-
this.context.
|
|
749
|
-
await this.
|
|
750
|
-
await this.#executeEnvironments(async (context) => {
|
|
483
|
+
await this.context.setInlineConfig(inlineConfig);
|
|
484
|
+
await this.executeEnvironments(async (context) => {
|
|
751
485
|
context.debug(`Initializing the processing options for the Powerlines project.`);
|
|
752
486
|
await this.callHook("configResolved", {
|
|
753
487
|
environment: context,
|
|
@@ -779,7 +513,7 @@ ${formatTypes(code)}
|
|
|
779
513
|
context.info(`Running \`prepare\` command as the meta checksum has changed since the last run.`);
|
|
780
514
|
await this.prepare(defu({ output: { types: false } }, inlineConfig));
|
|
781
515
|
}
|
|
782
|
-
await this
|
|
516
|
+
await this.handleTypes(context);
|
|
783
517
|
this.context.debug("Formatting files generated during the types step.");
|
|
784
518
|
await format(context, context.typesPath, await context.fs.read(context.typesPath) ?? "");
|
|
785
519
|
await writeMetaFile(context);
|
|
@@ -796,9 +530,8 @@ ${formatTypes(code)}
|
|
|
796
530
|
*/
|
|
797
531
|
async prepare(inlineConfig = { command: "prepare" }) {
|
|
798
532
|
inlineConfig.command ??= "prepare";
|
|
799
|
-
this.context.
|
|
800
|
-
await this.
|
|
801
|
-
await this.#executeEnvironments(async (context) => {
|
|
533
|
+
await this.context.setInlineConfig(inlineConfig);
|
|
534
|
+
await this.executeEnvironments(async (context) => {
|
|
802
535
|
context.debug(`Initializing the processing options for the Powerlines project.`);
|
|
803
536
|
await this.callHook("configResolved", {
|
|
804
537
|
environment: context,
|
|
@@ -848,7 +581,7 @@ ${formatTypes(code)}
|
|
|
848
581
|
environment: context,
|
|
849
582
|
order: "post"
|
|
850
583
|
});
|
|
851
|
-
if (context.config.output.types !== false) await this
|
|
584
|
+
if (context.config.output.types !== false) await this.handleTypes(context);
|
|
852
585
|
this.context.debug("Formatting files generated during the prepare step.");
|
|
853
586
|
await Promise.all([formatFolder(context, context.builtinsPath), formatFolder(context, context.entryPath)]);
|
|
854
587
|
await writeMetaFile(context);
|
|
@@ -867,7 +600,7 @@ ${formatTypes(code)}
|
|
|
867
600
|
async new(inlineConfig) {
|
|
868
601
|
inlineConfig.command ??= "new";
|
|
869
602
|
await this.prepare(inlineConfig);
|
|
870
|
-
await this
|
|
603
|
+
await this.executeEnvironments(async (context) => {
|
|
871
604
|
context.debug("Initializing the processing options for the Powerlines project.");
|
|
872
605
|
await this.callHook("new", {
|
|
873
606
|
environment: context,
|
|
@@ -916,7 +649,7 @@ ${formatTypes(code)}
|
|
|
916
649
|
async clean(inlineConfig = { command: "clean" }) {
|
|
917
650
|
inlineConfig.command ??= "clean";
|
|
918
651
|
await this.prepare(inlineConfig);
|
|
919
|
-
await this
|
|
652
|
+
await this.executeEnvironments(async (context) => {
|
|
920
653
|
context.debug("Cleaning the project's dist and artifacts directories.");
|
|
921
654
|
await context.fs.remove(joinPaths(context.config.cwd, context.config.output.path));
|
|
922
655
|
await context.fs.remove(joinPaths(context.config.cwd, context.config.root, context.config.output.artifactsPath));
|
|
@@ -935,7 +668,7 @@ ${formatTypes(code)}
|
|
|
935
668
|
async lint(inlineConfig = { command: "lint" }) {
|
|
936
669
|
inlineConfig.command ??= "lint";
|
|
937
670
|
await this.prepare(inlineConfig);
|
|
938
|
-
await this
|
|
671
|
+
await this.executeEnvironments(async (context) => {
|
|
939
672
|
await this.callHook("lint", {
|
|
940
673
|
environment: context,
|
|
941
674
|
sequential: false
|
|
@@ -951,7 +684,7 @@ ${formatTypes(code)}
|
|
|
951
684
|
async test(inlineConfig = { command: "test" }) {
|
|
952
685
|
inlineConfig.command ??= "test";
|
|
953
686
|
await this.prepare(inlineConfig);
|
|
954
|
-
await this
|
|
687
|
+
await this.executeEnvironments(async (context) => {
|
|
955
688
|
await this.callHook("test", {
|
|
956
689
|
environment: context,
|
|
957
690
|
sequential: false
|
|
@@ -969,17 +702,15 @@ ${formatTypes(code)}
|
|
|
969
702
|
*/
|
|
970
703
|
async build(inlineConfig = { command: "build" }) {
|
|
971
704
|
inlineConfig.command ??= "build";
|
|
705
|
+
await this.context.setInlineConfig(inlineConfig);
|
|
972
706
|
await this.context.generateChecksum();
|
|
973
707
|
if (this.context.meta.checksum !== this.context.persistedMeta?.checksum || this.context.config.skipCache) {
|
|
974
708
|
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.");
|
|
975
709
|
await this.prepare(inlineConfig);
|
|
976
|
-
} else {
|
|
977
|
-
this.context.config.inlineConfig = inlineConfig;
|
|
978
|
-
await this.context.setup();
|
|
979
710
|
}
|
|
980
|
-
if (this.context.config.singleBuild) await this
|
|
981
|
-
else await this
|
|
982
|
-
await this
|
|
711
|
+
if (this.context.config.singleBuild) await this.handleBuild(await this.#context.toEnvironment());
|
|
712
|
+
else await this.executeEnvironments(async (context) => {
|
|
713
|
+
await this.handleBuild(context);
|
|
983
714
|
});
|
|
984
715
|
}
|
|
985
716
|
/**
|
|
@@ -990,8 +721,9 @@ ${formatTypes(code)}
|
|
|
990
721
|
*/
|
|
991
722
|
async docs(inlineConfig = { command: "docs" }) {
|
|
992
723
|
inlineConfig.command ??= "docs";
|
|
724
|
+
await this.context.setInlineConfig(inlineConfig);
|
|
993
725
|
await this.prepare(inlineConfig);
|
|
994
|
-
await this
|
|
726
|
+
await this.executeEnvironments(async (context) => {
|
|
995
727
|
context.debug("Writing documentation for the Powerlines project artifacts.");
|
|
996
728
|
await this.callHook("docs", { environment: context });
|
|
997
729
|
});
|
|
@@ -1006,8 +738,9 @@ ${formatTypes(code)}
|
|
|
1006
738
|
*/
|
|
1007
739
|
async deploy(inlineConfig = { command: "deploy" }) {
|
|
1008
740
|
inlineConfig.command ??= "deploy";
|
|
741
|
+
await this.context.setInlineConfig(inlineConfig);
|
|
1009
742
|
await this.prepare(inlineConfig);
|
|
1010
|
-
await this
|
|
743
|
+
await this.executeEnvironments(async (context) => {
|
|
1011
744
|
await this.callHook("deploy", { environment: context });
|
|
1012
745
|
});
|
|
1013
746
|
}
|
|
@@ -1020,7 +753,7 @@ ${formatTypes(code)}
|
|
|
1020
753
|
* @returns A promise that resolves when the finalization process has completed
|
|
1021
754
|
*/
|
|
1022
755
|
async finalize() {
|
|
1023
|
-
await this
|
|
756
|
+
await this.executeEnvironments(async (context) => {
|
|
1024
757
|
await this.callHook("finalize", { environment: context });
|
|
1025
758
|
await context.fs.dispose();
|
|
1026
759
|
if (existsSync(context.cachePath) && !(await listFiles(joinPaths(context.cachePath, "**/*")))?.length) await removeDirectory(context.cachePath);
|
|
@@ -1052,13 +785,40 @@ ${formatTypes(code)}
|
|
|
1052
785
|
this.#context = context;
|
|
1053
786
|
}
|
|
1054
787
|
/**
|
|
788
|
+
* Initialize the execution API with the provided configuration options
|
|
789
|
+
*/
|
|
790
|
+
async init() {
|
|
791
|
+
this.#context.$$internal = {
|
|
792
|
+
api: this,
|
|
793
|
+
addPlugin: this.addPlugin.bind(this)
|
|
794
|
+
};
|
|
795
|
+
const timer = this.#context.timer("Initialization");
|
|
796
|
+
for (const plugin of this.#context.config.plugins.flatMap((p) => toArray(p)) ?? []) await this.addPlugin(plugin);
|
|
797
|
+
if (this.#context.plugins.length === 0) this.#context.warn({
|
|
798
|
+
meta: { category: "plugins" },
|
|
799
|
+
message: "No Powerlines plugins were specified in the options. Please ensure this is correct, as it is generally not recommended."
|
|
800
|
+
});
|
|
801
|
+
else this.#context.info({
|
|
802
|
+
meta: { category: "plugins" },
|
|
803
|
+
message: `Loaded ${this.#context.plugins.length} ${titleCase(this.#context.config.framework)} plugin${this.#context.plugins.length > 1 ? "s" : ""}: \n${this.#context.plugins.map((plugin, index) => ` ${index + 1}. ${colorText(plugin.name)}`).join("\n")}`
|
|
804
|
+
});
|
|
805
|
+
const pluginConfig = await this.callHook("config", {
|
|
806
|
+
environment: await this.#context.getEnvironment(),
|
|
807
|
+
sequential: true,
|
|
808
|
+
result: "merge",
|
|
809
|
+
merge: mergeConfigs
|
|
810
|
+
});
|
|
811
|
+
if (pluginConfig) await this.context.setPluginConfig(pluginConfig);
|
|
812
|
+
timer();
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
1055
815
|
* Add a Powerlines plugin used in the build process
|
|
1056
816
|
*
|
|
1057
817
|
* @param config - The import path of the plugin to add
|
|
1058
818
|
*/
|
|
1059
819
|
async addPlugin(config) {
|
|
1060
820
|
if (config) {
|
|
1061
|
-
const result = await this
|
|
821
|
+
const result = await this.initPlugin(config);
|
|
1062
822
|
if (!result) return;
|
|
1063
823
|
for (const plugin of result) {
|
|
1064
824
|
this.context.debug({
|
|
@@ -1069,6 +829,239 @@ ${formatTypes(code)}
|
|
|
1069
829
|
}
|
|
1070
830
|
}
|
|
1071
831
|
}
|
|
832
|
+
/**
|
|
833
|
+
* Get the configured environments
|
|
834
|
+
*
|
|
835
|
+
* @returns The configured environments
|
|
836
|
+
*/
|
|
837
|
+
async getEnvironments() {
|
|
838
|
+
if (!this.context.config.environments || Object.keys(this.context.config.environments).length <= 1) {
|
|
839
|
+
this.context.debug("No environments are configured for this Powerlines project. Using the default environment.");
|
|
840
|
+
return [await this.context.getEnvironment()];
|
|
841
|
+
}
|
|
842
|
+
this.context.debug(`Found ${Object.keys(this.context.config.environments).length} configured environment(s) for this Powerlines project.`);
|
|
843
|
+
return (await Promise.all(Object.entries(this.context.config.environments).map(async ([name, config]) => {
|
|
844
|
+
if (!await this.context.getEnvironmentSafe(name)) {
|
|
845
|
+
const resolvedEnvironment = await this.callHook("configEnvironment", { environment: name }, name, config);
|
|
846
|
+
if (resolvedEnvironment) this.context.environments[name] = await this.context.createEnvironment(resolvedEnvironment);
|
|
847
|
+
}
|
|
848
|
+
return this.context.environments[name];
|
|
849
|
+
}))).filter((context) => isSet(context));
|
|
850
|
+
}
|
|
851
|
+
/**
|
|
852
|
+
* Execute a handler function for each environment
|
|
853
|
+
*
|
|
854
|
+
* @param handle - The handler function to execute for each environment
|
|
855
|
+
*/
|
|
856
|
+
async executeEnvironments(handle) {
|
|
857
|
+
await Promise.all((await this.getEnvironments()).map(async (context) => {
|
|
858
|
+
return Promise.resolve(handle(context));
|
|
859
|
+
}));
|
|
860
|
+
}
|
|
861
|
+
/**
|
|
862
|
+
* Initialize a Powerlines plugin
|
|
863
|
+
*
|
|
864
|
+
* @param config - The configuration for the plugin
|
|
865
|
+
* @returns The initialized plugin instance, or null if the plugin was a duplicate
|
|
866
|
+
* @throws Will throw an error if the plugin cannot be found or is invalid
|
|
867
|
+
*/
|
|
868
|
+
async initPlugin(config) {
|
|
869
|
+
let awaited = config;
|
|
870
|
+
if (isPromiseLike(config)) awaited = await Promise.resolve(config);
|
|
871
|
+
if (!isPluginConfig(awaited)) {
|
|
872
|
+
const invalid = findInvalidPluginConfig(awaited);
|
|
873
|
+
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`);
|
|
874
|
+
}
|
|
875
|
+
let plugins;
|
|
876
|
+
if (isPlugin(awaited)) plugins = [awaited];
|
|
877
|
+
else if (isFunction(awaited)) plugins = toArray(await Promise.resolve(awaited()));
|
|
878
|
+
else if (isString(awaited)) {
|
|
879
|
+
const resolved = await this.resolvePlugin(awaited);
|
|
880
|
+
if (isFunction(resolved)) plugins = toArray(await Promise.resolve(resolved()));
|
|
881
|
+
else plugins = toArray(resolved);
|
|
882
|
+
} else if (Array.isArray(awaited) && awaited.every(isPlugin)) plugins = awaited;
|
|
883
|
+
else if (Array.isArray(awaited) && awaited.every(isPluginConfig)) {
|
|
884
|
+
plugins = [];
|
|
885
|
+
for (const pluginConfig of awaited) {
|
|
886
|
+
const initialized = await this.initPlugin(pluginConfig);
|
|
887
|
+
if (initialized) plugins.push(...initialized);
|
|
888
|
+
}
|
|
889
|
+
} else if (isPluginConfigTuple(awaited) || isPluginConfigObject(awaited)) {
|
|
890
|
+
let pluginConfig;
|
|
891
|
+
let pluginOptions;
|
|
892
|
+
if (isPluginConfigTuple(awaited)) {
|
|
893
|
+
pluginConfig = awaited[0];
|
|
894
|
+
pluginOptions = awaited?.length === 2 ? awaited[1] : void 0;
|
|
895
|
+
} else {
|
|
896
|
+
pluginConfig = awaited.plugin;
|
|
897
|
+
pluginOptions = awaited.options;
|
|
898
|
+
}
|
|
899
|
+
if (isSetString(pluginConfig)) {
|
|
900
|
+
const resolved = await this.resolvePlugin(pluginConfig);
|
|
901
|
+
if (isFunction(resolved)) plugins = toArray(await Promise.resolve(pluginOptions ? resolved(pluginOptions) : resolved()));
|
|
902
|
+
else plugins = toArray(resolved);
|
|
903
|
+
} else if (isFunction(pluginConfig)) plugins = toArray(await Promise.resolve(pluginConfig(pluginOptions)));
|
|
904
|
+
else if (Array.isArray(pluginConfig) && pluginConfig.every(isPlugin)) plugins = pluginConfig;
|
|
905
|
+
else if (isPlugin(pluginConfig)) plugins = toArray(pluginConfig);
|
|
906
|
+
}
|
|
907
|
+
if (!plugins) throw new Error(`The plugin configuration ${JSON.stringify(awaited)} is invalid. This configuration must point to a valid Powerlines plugin module.`);
|
|
908
|
+
if (plugins.length > 0 && !plugins.every(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.`);
|
|
909
|
+
const result = [];
|
|
910
|
+
for (const plugin of plugins) if (isDuplicate(plugin, this.context.plugins)) this.context.trace(`Duplicate ${chalk.bold.cyanBright(plugin.name)} plugin dependency detected - Skipping initialization.`);
|
|
911
|
+
else {
|
|
912
|
+
result.push(plugin);
|
|
913
|
+
this.context.trace(`Initializing the ${chalk.bold.cyanBright(plugin.name)} plugin...`);
|
|
914
|
+
}
|
|
915
|
+
return result;
|
|
916
|
+
}
|
|
917
|
+
async resolvePlugin(pluginPath) {
|
|
918
|
+
if (pluginPath.startsWith("@") && pluginPath.split("/").filter(Boolean).length > 2) {
|
|
919
|
+
const splits = pluginPath.split("/").filter(Boolean);
|
|
920
|
+
pluginPath = `${splits[0]}/${splits[1]}`;
|
|
921
|
+
}
|
|
922
|
+
const isInstalled = isPackageExists(pluginPath, { paths: [this.context.config.cwd, this.context.config.root] });
|
|
923
|
+
if (!isInstalled && this.context.config.autoInstall) {
|
|
924
|
+
this.#context.warn(`The plugin package "${pluginPath}" is not installed. It will be installed automatically.`);
|
|
925
|
+
const result = await install(pluginPath, { cwd: this.context.config.root });
|
|
926
|
+
if (isNumber(result.exitCode) && result.exitCode > 0) {
|
|
927
|
+
this.#context.error(result.stderr);
|
|
928
|
+
throw new Error(`An error occurred while installing the build plugin package "${pluginPath}" `);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
try {
|
|
932
|
+
const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve(joinPaths(pluginPath, "plugin")));
|
|
933
|
+
const result = module.plugin ?? module.default;
|
|
934
|
+
if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
|
|
935
|
+
return result;
|
|
936
|
+
} catch (error) {
|
|
937
|
+
try {
|
|
938
|
+
const module = await this.context.resolver.plugin.import(this.context.resolver.plugin.esmResolve(pluginPath));
|
|
939
|
+
const result = module.plugin ?? module.default;
|
|
940
|
+
if (!result) throw new Error(`The plugin package "${pluginPath}" does not export a valid module.`);
|
|
941
|
+
return result;
|
|
942
|
+
} catch {
|
|
943
|
+
if (!isInstalled) throw new Error(`The plugin package "${pluginPath}" is not installed. Please install the package using the command: "npm install ${pluginPath} --save-dev"`);
|
|
944
|
+
else throw new Error(`An error occurred while importing the build plugin package "${pluginPath}":
|
|
945
|
+
${isError(error) ? error.message : String(error)}
|
|
946
|
+
|
|
947
|
+
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\`.`);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
async handleBuild(context) {
|
|
952
|
+
await this.callHook("build", {
|
|
953
|
+
environment: context,
|
|
954
|
+
order: "pre"
|
|
955
|
+
});
|
|
956
|
+
context.debug("Formatting the generated entry files before the build process starts.");
|
|
957
|
+
await formatFolder(context, context.entryPath);
|
|
958
|
+
await this.callHook("build", {
|
|
959
|
+
environment: context,
|
|
960
|
+
order: "normal"
|
|
961
|
+
});
|
|
962
|
+
if (context.config.output.copy) {
|
|
963
|
+
context.debug("Copying project's files from build output directory.");
|
|
964
|
+
const destinationPath = isParentPath(appendPath(context.config.output.path, context.config.cwd), appendPath(context.config.root, context.config.cwd)) ? joinPaths(context.config.output.copy.path, relativePath(appendPath(context.config.root, context.config.cwd), appendPath(context.config.output.path, context.config.cwd))) : joinPaths(context.config.output.copy.path, "dist");
|
|
965
|
+
const sourcePath = context.config.output.path;
|
|
966
|
+
if (existsSync(sourcePath) && sourcePath !== destinationPath) {
|
|
967
|
+
context.debug(`Copying files from project's build output directory (${context.config.output.path}) to the project's copy/publish directory (${destinationPath}).`);
|
|
968
|
+
await copyFiles(sourcePath, destinationPath);
|
|
969
|
+
} else context.warn(`The source path for the copy operation ${!existsSync(sourcePath) ? "does not exist" : "is the same as the destination path"}. Source: ${sourcePath}, Destination: ${destinationPath}. Skipping copying of build output files.`);
|
|
970
|
+
if (context.config.output.copy.assets && Array.isArray(context.config.output.copy.assets)) await Promise.all(context.config.output.copy.assets.map(async (asset) => {
|
|
971
|
+
context.trace(`Copying asset(s): ${chalk.redBright(context.config.cwd === asset.input ? asset.glob : appendPath(asset.glob, replacePath(asset.input, context.config.cwd)))} -> ${chalk.greenBright(appendPath(asset.glob, replacePath(asset.output, context.config.cwd)))} ${Array.isArray(asset.ignore) && asset.ignore.length > 0 ? ` (ignoring: ${asset.ignore.map((i) => chalk.yellowBright(i)).join(", ")})` : ""}`);
|
|
972
|
+
await context.fs.copy(asset, asset.output);
|
|
973
|
+
}));
|
|
974
|
+
} else context.debug("No copy configuration found for the project output. Skipping the copying of build output files.");
|
|
975
|
+
await this.callHook("build", {
|
|
976
|
+
environment: context,
|
|
977
|
+
order: "post"
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
/**
|
|
981
|
+
* Generate the Powerlines TypeScript declaration file
|
|
982
|
+
*
|
|
983
|
+
* @remarks
|
|
984
|
+
* This method will generate the TypeScript declaration file for the Powerlines project, including any types provided by plugins.
|
|
985
|
+
*
|
|
986
|
+
* @param context - The environment context to use for generating the TypeScript declaration file
|
|
987
|
+
* @returns A promise that resolves when the TypeScript declaration file has been generated
|
|
988
|
+
*/
|
|
989
|
+
async handleTypes(context) {
|
|
990
|
+
context.debug(`Preparing the TypeScript definitions for the Powerlines project.`);
|
|
991
|
+
if (context.fs.existsSync(context.typesPath)) await context.fs.remove(context.typesPath);
|
|
992
|
+
if (!await resolvePackage("typescript")) throw new Error("Could not resolve TypeScript package location. Please ensure TypeScript is installed.");
|
|
993
|
+
context.debug("Running TypeScript compiler for built-in runtime module files.");
|
|
994
|
+
let { code, directives } = await emitBuiltinTypes(context, (await context.getBuiltins()).reduce((ret, builtin) => {
|
|
995
|
+
const formatted = replacePath(builtin.path, context.config.cwd);
|
|
996
|
+
if (!ret.includes(formatted)) ret.push(formatted);
|
|
997
|
+
return ret;
|
|
998
|
+
}, []));
|
|
999
|
+
context.debug(`Generating TypeScript declaration file ${context.typesPath}.`);
|
|
1000
|
+
const merge = async (currentResult, previousResult) => {
|
|
1001
|
+
if (!isSetString(currentResult) && !isSetObject(currentResult) && !isSetString(previousResult) && !isSetObject(previousResult)) return {
|
|
1002
|
+
code,
|
|
1003
|
+
directives
|
|
1004
|
+
};
|
|
1005
|
+
const previous = (await format(context, context.typesPath, isSetString(previousResult) ? previousResult : isSetObject(previousResult) ? previousResult.code : "")).trim().replace(code, "").trim();
|
|
1006
|
+
const current = (await format(context, context.typesPath, isSetString(currentResult) ? currentResult : isSetObject(currentResult) ? currentResult.code : "")).trim().replace(previous, "").trim().replace(code, "").trim();
|
|
1007
|
+
return {
|
|
1008
|
+
directives: [...isSetObject(currentResult) && currentResult.directives ? currentResult.directives : [], ...isSetObject(previousResult) && previousResult.directives ? previousResult.directives : []],
|
|
1009
|
+
code: await format(context, context.typesPath, `${!previous.includes(getTypescriptFileHeader(context)) && !current.includes(getTypescriptFileHeader(context)) ? `${code}\n` : ""}${previous}\n${current}`.trim())
|
|
1010
|
+
};
|
|
1011
|
+
};
|
|
1012
|
+
const asNextParam = (previousResult) => isObject(previousResult) ? previousResult.code : previousResult;
|
|
1013
|
+
let result = await this.callHook("types", {
|
|
1014
|
+
environment: context,
|
|
1015
|
+
sequential: true,
|
|
1016
|
+
order: "pre",
|
|
1017
|
+
result: "merge",
|
|
1018
|
+
merge,
|
|
1019
|
+
asNextParam
|
|
1020
|
+
}, code);
|
|
1021
|
+
if (result) {
|
|
1022
|
+
if (isSetObject(result)) {
|
|
1023
|
+
code = result.code;
|
|
1024
|
+
if (Array.isArray(result.directives) && result.directives.length > 0) directives = getUnique([...directives, ...result.directives]).filter(Boolean);
|
|
1025
|
+
} else if (isSetString(result)) code = result;
|
|
1026
|
+
}
|
|
1027
|
+
result = await this.callHook("types", {
|
|
1028
|
+
environment: context,
|
|
1029
|
+
sequential: true,
|
|
1030
|
+
order: "normal",
|
|
1031
|
+
result: "merge",
|
|
1032
|
+
merge,
|
|
1033
|
+
asNextParam
|
|
1034
|
+
}, code);
|
|
1035
|
+
if (result) {
|
|
1036
|
+
if (isSetObject(result)) {
|
|
1037
|
+
code = result.code;
|
|
1038
|
+
if (Array.isArray(result.directives) && result.directives.length > 0) directives = getUnique([...directives, ...result.directives]).filter(Boolean);
|
|
1039
|
+
} else if (isSetString(result)) code = result;
|
|
1040
|
+
}
|
|
1041
|
+
result = await this.callHook("types", {
|
|
1042
|
+
environment: context,
|
|
1043
|
+
sequential: true,
|
|
1044
|
+
order: "post",
|
|
1045
|
+
result: "merge",
|
|
1046
|
+
merge,
|
|
1047
|
+
asNextParam
|
|
1048
|
+
}, code);
|
|
1049
|
+
if (result) {
|
|
1050
|
+
if (isSetObject(result)) {
|
|
1051
|
+
code = result.code;
|
|
1052
|
+
if (Array.isArray(result.directives) && result.directives.length > 0) directives = getUnique([...directives, ...result.directives]).filter(Boolean);
|
|
1053
|
+
} else if (isSetString(result)) code = result;
|
|
1054
|
+
}
|
|
1055
|
+
if (isSetString(code?.trim()) || directives.length > 0) await context.fs.write(context.typesPath, `${directives.length > 0 ? `${directives.map((directive) => `/// <reference types="${directive}" />`).join("\n")}
|
|
1056
|
+
|
|
1057
|
+
` : ""}${getTypescriptFileHeader(context, {
|
|
1058
|
+
directive: null,
|
|
1059
|
+
prettierIgnore: false
|
|
1060
|
+
})}
|
|
1061
|
+
|
|
1062
|
+
${formatTypes(code)}
|
|
1063
|
+
`);
|
|
1064
|
+
}
|
|
1072
1065
|
};
|
|
1073
1066
|
|
|
1074
1067
|
//#endregion
|
|
@@ -1089,37 +1082,13 @@ var PowerlinesAPI = class PowerlinesAPI extends PowerlinesExecution {
|
|
|
1089
1082
|
* @param initialConfig - The initial configuration for the API, which can be used to provide additional context or override certain configuration values during initialization. This is particularly useful when initializing the API from a CLI command, where the CLI flags can be passed as part of the initial configuration to ensure they are properly merged with the configuration file and made available to plugins during their setup and execution.
|
|
1090
1083
|
* @returns A new instance of the Powerlines API
|
|
1091
1084
|
*/
|
|
1092
|
-
static async
|
|
1093
|
-
const api = new PowerlinesAPI(await PowerlinesExecutionContext.
|
|
1085
|
+
static async from(options, initialConfig) {
|
|
1086
|
+
const api = new PowerlinesAPI(await PowerlinesExecutionContext.fromInitialConfig({
|
|
1094
1087
|
executionId: uuid(),
|
|
1095
1088
|
executionIndex: 0,
|
|
1096
1089
|
...options
|
|
1097
1090
|
}, initialConfig ?? {}));
|
|
1098
|
-
api.
|
|
1099
|
-
api,
|
|
1100
|
-
addPlugin: api.addPlugin.bind(api)
|
|
1101
|
-
};
|
|
1102
|
-
const timer = api.context.timer("Initialization");
|
|
1103
|
-
for (const plugin of api.context.config.plugins.flatMap((p) => toArray(p)) ?? []) await api.addPlugin(plugin);
|
|
1104
|
-
if (api.context.plugins.length === 0) api.context.warn({
|
|
1105
|
-
meta: { category: "plugins" },
|
|
1106
|
-
message: "No Powerlines plugins were specified in the options. Please ensure this is correct, as it is generally not recommended."
|
|
1107
|
-
});
|
|
1108
|
-
else api.context.info({
|
|
1109
|
-
meta: { category: "plugins" },
|
|
1110
|
-
message: `Loaded ${api.context.plugins.length} ${titleCase(api.context.config.framework)} plugin${api.context.plugins.length > 1 ? "s" : ""}: \n${api.context.plugins.map((plugin, index) => ` ${index + 1}. ${colorText(plugin.name)}`).join("\n")}`
|
|
1111
|
-
});
|
|
1112
|
-
const pluginConfig = await api.callHook("config", {
|
|
1113
|
-
environment: await api.context.getEnvironment(),
|
|
1114
|
-
sequential: true,
|
|
1115
|
-
result: "merge",
|
|
1116
|
-
merge: mergeConfigs
|
|
1117
|
-
});
|
|
1118
|
-
if (isSetObject(pluginConfig)) {
|
|
1119
|
-
api.context.config.pluginConfig = pluginConfig;
|
|
1120
|
-
await api.context.setup();
|
|
1121
|
-
}
|
|
1122
|
-
timer();
|
|
1091
|
+
await api.init();
|
|
1123
1092
|
return api;
|
|
1124
1093
|
}
|
|
1125
1094
|
/**
|