@qlover/scripts-context 2.1.1 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -18
- package/dist/index.d.ts +1965 -601
- package/dist/index.js +753 -243
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -12,21 +12,23 @@ var defaultFeConfig = {
|
|
|
12
12
|
commitlint: {
|
|
13
13
|
extends: ["@commitlint/config-conventional"]
|
|
14
14
|
},
|
|
15
|
-
release: {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
15
|
+
// release: {
|
|
16
|
+
// publishPath: '',
|
|
17
|
+
// autoMergeReleasePR: false,
|
|
18
|
+
// autoMergeType: 'squash',
|
|
19
|
+
// branchName: 'release-${pkgName}-${tagName}',
|
|
20
|
+
// PRTitle:
|
|
21
|
+
// '[${pkgName} Release] Branch:${branch}, Tag:${tagName}, Env:${env}',
|
|
22
|
+
// PRBody:
|
|
23
|
+
// '## Publish Details\n\n- 🏷️ Version: ${tagName}\n- 🌲 Branch: ${branch}\n- 🔧 Environment: ${env}\n\n## Changelog\n\n${changelog}\n\n## Notes\n\n- [ ] Please check if the version number is correct\n- [ ] Please confirm all tests have passed\n- [ ] Please confirm the documentation has been updated\n\n> This PR is auto created by release process, please contact the frontend team if there are any questions.',
|
|
24
|
+
// label: {
|
|
25
|
+
// color: '1A7F37',
|
|
26
|
+
// description: 'Release PR',
|
|
27
|
+
// name: 'CI-Release'
|
|
28
|
+
// },
|
|
29
|
+
// packagesDirectories: [],
|
|
30
|
+
// changePackagesLabel: 'changes:${name}'
|
|
31
|
+
// },
|
|
30
32
|
envOrder: [".env.local", ".env.production", ".env"]
|
|
31
33
|
};
|
|
32
34
|
|
|
@@ -67,6 +69,7 @@ var ColorFormatter = class {
|
|
|
67
69
|
}) {
|
|
68
70
|
this.levelColors = levelColors;
|
|
69
71
|
}
|
|
72
|
+
levelColors;
|
|
70
73
|
/**
|
|
71
74
|
* Format log event by applying color to the level and preserving original arguments
|
|
72
75
|
*
|
|
@@ -478,11 +481,395 @@ var ConfigSearch = class {
|
|
|
478
481
|
};
|
|
479
482
|
|
|
480
483
|
// src/implement/ScriptContext.ts
|
|
481
|
-
import { merge as
|
|
482
|
-
|
|
484
|
+
import { merge as merge4, get as get2 } from "lodash-es";
|
|
485
|
+
|
|
486
|
+
// ../fe-corekit/src/aborter/Aborter.ts
|
|
487
|
+
import { isString } from "lodash-es";
|
|
488
|
+
|
|
489
|
+
// ../fe-corekit/src/executor/impl/ExecutorContextImpl.ts
|
|
490
|
+
var runtimesStorage = /* @__PURE__ */ new WeakMap();
|
|
491
|
+
var ExecutorContextImpl = class {
|
|
492
|
+
_parameters;
|
|
493
|
+
_error;
|
|
494
|
+
_returnValue;
|
|
495
|
+
/**
|
|
496
|
+
* Creates a new ExecutorContextImpl instance
|
|
497
|
+
*
|
|
498
|
+
* **Important**: Parameters are stored by reference, not cloned.
|
|
499
|
+
* If you need parameter isolation, clone them before passing to the constructor.
|
|
500
|
+
*
|
|
501
|
+
* @param parameters - The initial parameters for the context
|
|
502
|
+
*
|
|
503
|
+
* @example Without isolation (parameters will be modified)
|
|
504
|
+
* ```typescript
|
|
505
|
+
* const params = { value: 1 };
|
|
506
|
+
* const context = new ExecutorContextImpl(params);
|
|
507
|
+
* context.setParameters({ value: 2 });
|
|
508
|
+
* console.log(params.value); // 2 - original object is modified
|
|
509
|
+
* ```
|
|
510
|
+
*
|
|
511
|
+
* @example With isolation (clone parameters first)
|
|
512
|
+
* ```typescript
|
|
513
|
+
* const params = { value: 1 };
|
|
514
|
+
* const context = new ExecutorContextImpl({ ...params }); // shallow clone
|
|
515
|
+
* context.setParameters({ value: 2 });
|
|
516
|
+
* console.log(params.value); // 1 - original object is unchanged
|
|
517
|
+
* ```
|
|
518
|
+
*/
|
|
519
|
+
constructor(parameters) {
|
|
520
|
+
this._parameters = parameters;
|
|
521
|
+
runtimesStorage.set(this, {
|
|
522
|
+
pluginName: "",
|
|
523
|
+
pluginIndex: void 0,
|
|
524
|
+
hookName: "",
|
|
525
|
+
returnValue: void 0,
|
|
526
|
+
returnBreakChain: false,
|
|
527
|
+
times: 0,
|
|
528
|
+
breakChain: false
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
532
|
+
* Get the context parameters
|
|
533
|
+
*
|
|
534
|
+
* **Important**: Returns the parameters by reference.
|
|
535
|
+
* Modifications to the returned object will affect the context's internal state.
|
|
536
|
+
*
|
|
537
|
+
* @override
|
|
538
|
+
* @returns The parameters object (by reference)
|
|
539
|
+
*/
|
|
540
|
+
get parameters() {
|
|
541
|
+
return this._parameters;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Get the error, if any
|
|
545
|
+
*
|
|
546
|
+
* @override
|
|
547
|
+
* @returns The error, if any
|
|
548
|
+
*/
|
|
549
|
+
get error() {
|
|
550
|
+
return this._error;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Get the return value, if any
|
|
554
|
+
*
|
|
555
|
+
* @override
|
|
556
|
+
* @returns The return value, if any
|
|
557
|
+
*/
|
|
558
|
+
get returnValue() {
|
|
559
|
+
return this._returnValue;
|
|
560
|
+
}
|
|
561
|
+
/**
|
|
562
|
+
* Get read-only snapshot of hooks runtime information
|
|
563
|
+
*
|
|
564
|
+
* Core concept:
|
|
565
|
+
* Provides safe read-only access to runtime tracking information.
|
|
566
|
+
* Returns a frozen shallow copy to prevent accidental modifications.
|
|
567
|
+
*
|
|
568
|
+
* Security features:
|
|
569
|
+
* - Stored in WeakMap, truly private (cannot access via ._hooksRuntimes)
|
|
570
|
+
* - Returns a new frozen object (not the internal reference)
|
|
571
|
+
* - Object is frozen to prevent modifications
|
|
572
|
+
* - Setter throws error to prevent assignment
|
|
573
|
+
*
|
|
574
|
+
* Why WeakMap?
|
|
575
|
+
* - TypeScript's `private` is only compile-time protection
|
|
576
|
+
* - JavaScript runtime can still access `._hooksRuntimes`
|
|
577
|
+
* - WeakMap provides true runtime privacy
|
|
578
|
+
* - No way to access the internal state from outside
|
|
579
|
+
*
|
|
580
|
+
* @override
|
|
581
|
+
* @returns Frozen shallow copy of hook runtime state
|
|
582
|
+
*
|
|
583
|
+
* @example Safe read access
|
|
584
|
+
* ```typescript
|
|
585
|
+
* const runtimes = context.hooksRuntimes;
|
|
586
|
+
* console.log(`Hook ${runtimes.hookName} executed ${runtimes.times} times`);
|
|
587
|
+
* ```
|
|
588
|
+
*
|
|
589
|
+
* @example Modification attempts fail
|
|
590
|
+
* ```typescript
|
|
591
|
+
* const runtimes = context.hooksRuntimes;
|
|
592
|
+
* runtimes.times = 10; // Error: Cannot assign to read only property
|
|
593
|
+
* context.hooksRuntimes = {}; // Error: hooksRuntimes is read-only
|
|
594
|
+
* context._hooksRuntimes; // undefined - truly private!
|
|
595
|
+
* ```
|
|
596
|
+
*/
|
|
597
|
+
get hooksRuntimes() {
|
|
598
|
+
const runtimes = runtimesStorage.get(this);
|
|
599
|
+
if (!runtimes) {
|
|
600
|
+
throw new Error("Runtime state not initialized");
|
|
601
|
+
}
|
|
602
|
+
return Object.freeze({ ...runtimes });
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Set error in context
|
|
606
|
+
*
|
|
607
|
+
* Automatically converts standard Error objects to ExecutorError for consistency.
|
|
608
|
+
* If the error is already an ExecutorError, it is stored as-is.
|
|
609
|
+
* If the error is a standard Error, it is wrapped in an ExecutorError with id 'EXECUTOR_ERROR'.
|
|
610
|
+
*
|
|
611
|
+
* @override
|
|
612
|
+
* @param error - The error to set in context (ExecutorError or standard Error)
|
|
613
|
+
*
|
|
614
|
+
* @example With ExecutorError
|
|
615
|
+
* ```typescript
|
|
616
|
+
* context.setError(new ExecutorError('VALIDATION_ERROR', 'Invalid input'));
|
|
617
|
+
* console.log(context.error.id); // 'VALIDATION_ERROR'
|
|
618
|
+
* ```
|
|
619
|
+
*
|
|
620
|
+
* @example With standard Error (auto-converted)
|
|
621
|
+
* ```typescript
|
|
622
|
+
* try {
|
|
623
|
+
* JSON.parse('invalid');
|
|
624
|
+
* } catch (error) {
|
|
625
|
+
* context.setError(error); // Auto-converted to ExecutorError
|
|
626
|
+
* console.log(context.error.id); // 'EXECUTOR_ERROR'
|
|
627
|
+
* console.log(context.error.cause); // Original SyntaxError
|
|
628
|
+
* }
|
|
629
|
+
* ```
|
|
630
|
+
*/
|
|
631
|
+
setError(error) {
|
|
632
|
+
this._error = error;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* Set return value in context
|
|
636
|
+
*
|
|
637
|
+
* @override
|
|
638
|
+
* @param value - The value to set as return value
|
|
639
|
+
*/
|
|
640
|
+
setReturnValue(value) {
|
|
641
|
+
this._returnValue = value;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Set parameters in context
|
|
645
|
+
*
|
|
646
|
+
* **Important**: Parameters are stored by reference, not cloned.
|
|
647
|
+
* The provided parameters object will be used directly.
|
|
648
|
+
*
|
|
649
|
+
* @override
|
|
650
|
+
* @param params - The parameters to set (stored by reference)
|
|
651
|
+
*
|
|
652
|
+
* @example
|
|
653
|
+
* ```typescript
|
|
654
|
+
* const newParams = { value: 2 };
|
|
655
|
+
* context.setParameters(newParams);
|
|
656
|
+
* // context.parameters === newParams (same reference)
|
|
657
|
+
* ```
|
|
658
|
+
*/
|
|
659
|
+
setParameters(params) {
|
|
660
|
+
this._parameters = params;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* Reset hooks runtime state to initial values
|
|
664
|
+
*
|
|
665
|
+
* Core concept:
|
|
666
|
+
* Clears all runtime tracking information for fresh execution
|
|
667
|
+
*
|
|
668
|
+
* Reset operations:
|
|
669
|
+
* - Clears plugin name and hook name
|
|
670
|
+
* - Resets return value and chain breaking flags
|
|
671
|
+
* - Resets execution counter and index
|
|
672
|
+
*
|
|
673
|
+
* @override
|
|
674
|
+
*/
|
|
675
|
+
resetHooksRuntimes(hookName) {
|
|
676
|
+
const runtimes = runtimesStorage.get(this);
|
|
677
|
+
if (!runtimes) {
|
|
678
|
+
throw new Error("Runtime state not initialized");
|
|
679
|
+
}
|
|
680
|
+
if (hookName) {
|
|
681
|
+
runtimesStorage.set(this, {
|
|
682
|
+
...runtimes,
|
|
683
|
+
hookName,
|
|
684
|
+
times: 0,
|
|
685
|
+
returnValue: void 0
|
|
686
|
+
});
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
runtimesStorage.set(this, {
|
|
690
|
+
pluginName: "",
|
|
691
|
+
pluginIndex: void 0,
|
|
692
|
+
hookName: "",
|
|
693
|
+
returnValue: void 0,
|
|
694
|
+
returnBreakChain: false,
|
|
695
|
+
times: 0,
|
|
696
|
+
breakChain: false
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
/**
|
|
700
|
+
* Reset entire context to initial state
|
|
701
|
+
*
|
|
702
|
+
* Core concept:
|
|
703
|
+
* Complete context cleanup for new execution cycle
|
|
704
|
+
*
|
|
705
|
+
* Reset operations:
|
|
706
|
+
* - Resets hooks runtime state
|
|
707
|
+
* - Clears return value
|
|
708
|
+
* - Clears error state
|
|
709
|
+
*
|
|
710
|
+
* @override
|
|
711
|
+
*/
|
|
712
|
+
reset() {
|
|
713
|
+
this.resetHooksRuntimes();
|
|
714
|
+
this._returnValue = void 0;
|
|
715
|
+
this._error = void 0;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* Check if a plugin hook should be skipped
|
|
719
|
+
* Returns true if the hook should be skipped (invalid or disabled)
|
|
720
|
+
*
|
|
721
|
+
* Core concept:
|
|
722
|
+
* Plugin hook validation and enablement checking
|
|
723
|
+
*
|
|
724
|
+
* Validation criteria:
|
|
725
|
+
* - Hook method exists and is callable
|
|
726
|
+
* - Plugin is enabled for the specific hook
|
|
727
|
+
* - Plugin enablement function returns true
|
|
728
|
+
*
|
|
729
|
+
* @override
|
|
730
|
+
* @template Ctx - Type of task context
|
|
731
|
+
* @param plugin - The plugin to check
|
|
732
|
+
* @param hookName - The name of the hook to validate
|
|
733
|
+
* @returns True if the hook should be skipped, false otherwise
|
|
734
|
+
*/
|
|
735
|
+
shouldSkipPluginHook(plugin, hookName) {
|
|
736
|
+
return typeof plugin[hookName] !== "function" || typeof plugin.enabled === "function" && !plugin.enabled(hookName, this);
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* Update runtime tracking information for plugin execution
|
|
740
|
+
*
|
|
741
|
+
* Core concept:
|
|
742
|
+
* Track plugin execution metadata for debugging and flow control.
|
|
743
|
+
* Creates a new runtime object with merged updates to ensure immutability.
|
|
744
|
+
*
|
|
745
|
+
* Security:
|
|
746
|
+
* - Always creates a new object (immutable updates)
|
|
747
|
+
* - Stored in WeakMap (truly private)
|
|
748
|
+
* - Cannot be accessed or modified from outside
|
|
749
|
+
*
|
|
750
|
+
* Tracking information:
|
|
751
|
+
* - Current plugin name
|
|
752
|
+
* - Current hook name
|
|
753
|
+
* - Execution counter (times)
|
|
754
|
+
* - Plugin index in execution chain
|
|
755
|
+
*
|
|
756
|
+
* @override
|
|
757
|
+
* @param updates - Partial runtime updates to merge
|
|
758
|
+
* @example
|
|
759
|
+
* ```typescript
|
|
760
|
+
* context.runtimes({
|
|
761
|
+
* pluginName: 'testPlugin',
|
|
762
|
+
* hookName: 'onBefore',
|
|
763
|
+
* times: 1,
|
|
764
|
+
* pluginIndex: 0
|
|
765
|
+
* });
|
|
766
|
+
* ```
|
|
767
|
+
*/
|
|
768
|
+
runtimes(updates) {
|
|
769
|
+
const current = runtimesStorage.get(this);
|
|
770
|
+
if (!current) {
|
|
771
|
+
throw new Error("Runtime state not initialized");
|
|
772
|
+
}
|
|
773
|
+
runtimesStorage.set(this, {
|
|
774
|
+
...current,
|
|
775
|
+
...updates
|
|
776
|
+
});
|
|
777
|
+
}
|
|
778
|
+
/**
|
|
779
|
+
* Set return value in context runtime tracking
|
|
780
|
+
*
|
|
781
|
+
* Core concept:
|
|
782
|
+
* Store plugin hook return value for chain control and debugging.
|
|
783
|
+
* Creates a new runtime object with updated return value.
|
|
784
|
+
*
|
|
785
|
+
* Security:
|
|
786
|
+
* - Creates new object (immutable update)
|
|
787
|
+
* - Stored in WeakMap (truly private)
|
|
788
|
+
*
|
|
789
|
+
* Usage scenarios:
|
|
790
|
+
* - Track plugin hook return values
|
|
791
|
+
* - Enable chain breaking based on return values
|
|
792
|
+
* - Debug plugin execution flow
|
|
793
|
+
*
|
|
794
|
+
* @override
|
|
795
|
+
* @param returnValue - The value to set as return value
|
|
796
|
+
*/
|
|
797
|
+
runtimeReturnValue(returnValue) {
|
|
798
|
+
const current = runtimesStorage.get(this);
|
|
799
|
+
if (!current) {
|
|
800
|
+
throw new Error("Runtime state not initialized");
|
|
801
|
+
}
|
|
802
|
+
runtimesStorage.set(this, {
|
|
803
|
+
...current,
|
|
804
|
+
returnValue
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Check if the execution chain should be broken
|
|
809
|
+
*
|
|
810
|
+
* Core concept:
|
|
811
|
+
* Chain breaking control for plugin execution flow
|
|
812
|
+
*
|
|
813
|
+
* Chain breaking scenarios:
|
|
814
|
+
* - Plugin explicitly sets breakChain flag
|
|
815
|
+
* - Error conditions requiring immediate termination
|
|
816
|
+
* - Business logic requiring early exit
|
|
817
|
+
*
|
|
818
|
+
* @override
|
|
819
|
+
* @returns True if the chain should be broken, false otherwise
|
|
820
|
+
*/
|
|
821
|
+
shouldBreakChain() {
|
|
822
|
+
const runtimes = runtimesStorage.get(this);
|
|
823
|
+
return !!runtimes?.breakChain;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Check if the execution chain should be broken due to return value
|
|
827
|
+
*
|
|
828
|
+
* Core concept:
|
|
829
|
+
* Return value-based chain breaking control
|
|
830
|
+
*
|
|
831
|
+
* Usage scenarios:
|
|
832
|
+
* - Plugin returns a value that should terminate execution
|
|
833
|
+
* - Error handling hooks return error objects
|
|
834
|
+
* - Business logic requires return value-based flow control
|
|
835
|
+
*
|
|
836
|
+
* @override
|
|
837
|
+
* @returns True if the chain should be broken due to return value, false otherwise
|
|
838
|
+
*/
|
|
839
|
+
shouldBreakChainOnReturn() {
|
|
840
|
+
const runtimes = runtimesStorage.get(this);
|
|
841
|
+
return !!runtimes?.returnBreakChain;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Check if execution should continue on error
|
|
845
|
+
*
|
|
846
|
+
* Core concept:
|
|
847
|
+
* Determines whether to continue executing subsequent plugins when a plugin hook
|
|
848
|
+
* throws an error, enabling resilient execution pipelines
|
|
849
|
+
*
|
|
850
|
+
* @override
|
|
851
|
+
* @returns True if execution should continue on error, false otherwise
|
|
852
|
+
*/
|
|
853
|
+
shouldContinueOnError() {
|
|
854
|
+
const runtimes = runtimesStorage.get(this);
|
|
855
|
+
return !!runtimes?.continueOnError;
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
// ../fe-corekit/src/request/adapter/RequestAdapterFetch.ts
|
|
860
|
+
import { merge, pick } from "lodash-es";
|
|
861
|
+
|
|
862
|
+
// ../fe-corekit/src/request/impl/RequestExecutor.ts
|
|
863
|
+
import { clone } from "lodash-es";
|
|
864
|
+
|
|
865
|
+
// ../fe-corekit/src/request/impl/RequestPlugin.ts
|
|
866
|
+
import { clone as clone2 } from "lodash-es";
|
|
867
|
+
|
|
868
|
+
// ../fe-corekit/src/request/impl/ResponsePlugin.ts
|
|
869
|
+
import { isFunction } from "lodash-es";
|
|
483
870
|
|
|
484
871
|
// src/utils/initializeOptions.ts
|
|
485
|
-
import { merge, get } from "lodash-es";
|
|
872
|
+
import { merge as merge2, get } from "lodash-es";
|
|
486
873
|
import { Env } from "@qlover/env-loader";
|
|
487
874
|
var DEFAULT_ENV_ORDER = [".env.local", ".env"];
|
|
488
875
|
function getDefaultOptions(options, feConfig, logger) {
|
|
@@ -513,7 +900,7 @@ function getDefaultStore(scriptName, sources, logger) {
|
|
|
513
900
|
}
|
|
514
901
|
function initializeOptions(scriptName, feConfig, options, logger) {
|
|
515
902
|
const store = getDefaultStore(scriptName, feConfig, logger);
|
|
516
|
-
const mergedOptions =
|
|
903
|
+
const mergedOptions = merge2({}, store, options);
|
|
517
904
|
const defaultOptions = getDefaultOptions(
|
|
518
905
|
mergedOptions,
|
|
519
906
|
feConfig,
|
|
@@ -524,7 +911,7 @@ function initializeOptions(scriptName, feConfig, options, logger) {
|
|
|
524
911
|
|
|
525
912
|
// src/utils/contextDefaults.ts
|
|
526
913
|
import { exec } from "child_process";
|
|
527
|
-
import { merge as
|
|
914
|
+
import { merge as merge3 } from "lodash-es";
|
|
528
915
|
|
|
529
916
|
// ../logger/src/interface/LogEvent.ts
|
|
530
917
|
var LogEvent = class {
|
|
@@ -535,6 +922,10 @@ var LogEvent = class {
|
|
|
535
922
|
this.context = context;
|
|
536
923
|
this.timestamp = Date.now();
|
|
537
924
|
}
|
|
925
|
+
level;
|
|
926
|
+
args;
|
|
927
|
+
loggerName;
|
|
928
|
+
context;
|
|
538
929
|
/**
|
|
539
930
|
* Timestamp when the log event was created
|
|
540
931
|
*
|
|
@@ -650,6 +1041,7 @@ var LogContext = class {
|
|
|
650
1041
|
constructor(value) {
|
|
651
1042
|
this.value = value;
|
|
652
1043
|
}
|
|
1044
|
+
value;
|
|
653
1045
|
};
|
|
654
1046
|
|
|
655
1047
|
// ../logger/src/Logger.ts
|
|
@@ -678,6 +1070,7 @@ var Logger = class {
|
|
|
678
1070
|
options.levels = options.levels || defaultLevels;
|
|
679
1071
|
options.handlers = Array.isArray(options.handlers) ? options.handlers : options.handlers ? [options.handlers] : [];
|
|
680
1072
|
}
|
|
1073
|
+
options;
|
|
681
1074
|
/**
|
|
682
1075
|
* Adds a new log handler to the logger
|
|
683
1076
|
*
|
|
@@ -994,6 +1387,7 @@ var ConsoleHandler = class {
|
|
|
994
1387
|
constructor(formatter = null) {
|
|
995
1388
|
this.formatter = formatter;
|
|
996
1389
|
}
|
|
1390
|
+
formatter;
|
|
997
1391
|
/**
|
|
998
1392
|
* Sets or updates the formatter for this handler
|
|
999
1393
|
*
|
|
@@ -1172,6 +1566,7 @@ var TimestampFormatter = class {
|
|
|
1172
1566
|
constructor(options = {}) {
|
|
1173
1567
|
this.options = options;
|
|
1174
1568
|
}
|
|
1569
|
+
options;
|
|
1175
1570
|
/**
|
|
1176
1571
|
* Updates formatter options at runtime.
|
|
1177
1572
|
* Merges the given partial options into the current options; subsequent formatting uses the updated values.
|
|
@@ -1298,8 +1693,270 @@ var TimestampFormatter = class {
|
|
|
1298
1693
|
}
|
|
1299
1694
|
};
|
|
1300
1695
|
|
|
1696
|
+
// src/implement/TemplateEngine.ts
|
|
1697
|
+
var interpolatePreset = {
|
|
1698
|
+
/**
|
|
1699
|
+
* ES6 template-literal style: `${ variable }`
|
|
1700
|
+
*
|
|
1701
|
+
* This is the default for {@link TemplateEngine}.
|
|
1702
|
+
*
|
|
1703
|
+
* @example
|
|
1704
|
+
* ```typescript
|
|
1705
|
+
* engine.render('${user.name}', { user: { name: 'Bob' } });
|
|
1706
|
+
* ```
|
|
1707
|
+
*/
|
|
1708
|
+
ES6: /\$\{([\s\S]+?)\}/g,
|
|
1709
|
+
/**
|
|
1710
|
+
* Lodash / EJS style: `<%= variable %>`
|
|
1711
|
+
*
|
|
1712
|
+
* Useful when migrating existing lodash templates.
|
|
1713
|
+
*
|
|
1714
|
+
* @example
|
|
1715
|
+
* ```typescript
|
|
1716
|
+
* new TemplateEngine({ interpolate: interpolatePreset.LODASH })
|
|
1717
|
+
* .render('<%= repo.url %>', { repo: { url: 'https://example.com' } });
|
|
1718
|
+
* ```
|
|
1719
|
+
*/
|
|
1720
|
+
LODASH: /<%=([\s\S]+?)%>/g,
|
|
1721
|
+
/**
|
|
1722
|
+
* Mustache / Handlebars style: `{{ variable }}`
|
|
1723
|
+
*
|
|
1724
|
+
* @example
|
|
1725
|
+
* ```typescript
|
|
1726
|
+
* new TemplateEngine({ interpolate: interpolatePreset.MUSTACHE })
|
|
1727
|
+
* .render('{{ user.name }}', { user: { name: 'Alice' } });
|
|
1728
|
+
* ```
|
|
1729
|
+
*/
|
|
1730
|
+
MUSTACHE: /\{\{([\s\S]+?)\}\}/g
|
|
1731
|
+
};
|
|
1732
|
+
var DANGEROUS_KEYS = /* @__PURE__ */ new Set([
|
|
1733
|
+
"__proto__",
|
|
1734
|
+
"constructor",
|
|
1735
|
+
"prototype",
|
|
1736
|
+
"__defineGetter__",
|
|
1737
|
+
"__defineSetter__",
|
|
1738
|
+
"__lookupGetter__",
|
|
1739
|
+
"__lookupSetter__"
|
|
1740
|
+
]);
|
|
1741
|
+
var SAFE_PATH = /^[\w.[\]]+$/;
|
|
1742
|
+
var PATH_SEGMENT = /^(\d+|\w+)$/;
|
|
1743
|
+
function cloneGlobalRegExp(regex) {
|
|
1744
|
+
const flags = regex.flags.includes("g") ? regex.flags : `${regex.flags}g`;
|
|
1745
|
+
return new RegExp(regex.source, flags);
|
|
1746
|
+
}
|
|
1747
|
+
function normalizePath(path) {
|
|
1748
|
+
return path.replace(/\[(\d+)\]/g, ".$1");
|
|
1749
|
+
}
|
|
1750
|
+
function parsePathKeys(path, variablePrefix) {
|
|
1751
|
+
const trimmed = path.trim();
|
|
1752
|
+
if (!trimmed || !SAFE_PATH.test(trimmed)) {
|
|
1753
|
+
return null;
|
|
1754
|
+
}
|
|
1755
|
+
let actualPath = trimmed;
|
|
1756
|
+
if (variablePrefix) {
|
|
1757
|
+
if (actualPath === variablePrefix) {
|
|
1758
|
+
return [];
|
|
1759
|
+
}
|
|
1760
|
+
const prefix = `${variablePrefix}.`;
|
|
1761
|
+
if (!actualPath.startsWith(prefix)) {
|
|
1762
|
+
return null;
|
|
1763
|
+
}
|
|
1764
|
+
actualPath = actualPath.slice(prefix.length);
|
|
1765
|
+
if (!actualPath) {
|
|
1766
|
+
return null;
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
const keys = normalizePath(actualPath).split(".");
|
|
1770
|
+
if (keys.length === 0 || keys.some((key) => !key || !PATH_SEGMENT.test(key))) {
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
return keys;
|
|
1774
|
+
}
|
|
1775
|
+
function escapeHtml(str) {
|
|
1776
|
+
return str.replace(/[&<>"']/g, (char) => {
|
|
1777
|
+
switch (char) {
|
|
1778
|
+
case "&":
|
|
1779
|
+
return "&";
|
|
1780
|
+
case "<":
|
|
1781
|
+
return "<";
|
|
1782
|
+
case ">":
|
|
1783
|
+
return ">";
|
|
1784
|
+
case '"':
|
|
1785
|
+
return """;
|
|
1786
|
+
case "'":
|
|
1787
|
+
return "'";
|
|
1788
|
+
default:
|
|
1789
|
+
return char;
|
|
1790
|
+
}
|
|
1791
|
+
});
|
|
1792
|
+
}
|
|
1793
|
+
function formatValue(value, stringifyObject) {
|
|
1794
|
+
if (value === void 0 || value === null) {
|
|
1795
|
+
return "";
|
|
1796
|
+
}
|
|
1797
|
+
if (typeof value === "object") {
|
|
1798
|
+
return stringifyObject ? JSON.stringify(value) : String(value);
|
|
1799
|
+
}
|
|
1800
|
+
return String(value);
|
|
1801
|
+
}
|
|
1802
|
+
function getValueByKeys(data, keys, safePrototype) {
|
|
1803
|
+
if (keys === null) {
|
|
1804
|
+
return void 0;
|
|
1805
|
+
}
|
|
1806
|
+
if (keys.length === 0) {
|
|
1807
|
+
return data;
|
|
1808
|
+
}
|
|
1809
|
+
let current = data;
|
|
1810
|
+
for (const key of keys) {
|
|
1811
|
+
if (safePrototype && DANGEROUS_KEYS.has(key)) {
|
|
1812
|
+
return void 0;
|
|
1813
|
+
}
|
|
1814
|
+
if (current === null || typeof current !== "object") {
|
|
1815
|
+
return void 0;
|
|
1816
|
+
}
|
|
1817
|
+
const record = current;
|
|
1818
|
+
if (safePrototype) {
|
|
1819
|
+
if (!Object.hasOwn(record, key)) {
|
|
1820
|
+
return void 0;
|
|
1821
|
+
}
|
|
1822
|
+
} else if (!(key in record)) {
|
|
1823
|
+
return void 0;
|
|
1824
|
+
}
|
|
1825
|
+
current = record[key];
|
|
1826
|
+
}
|
|
1827
|
+
return current;
|
|
1828
|
+
}
|
|
1829
|
+
function tokenize(template, interpolate) {
|
|
1830
|
+
const tokens = [];
|
|
1831
|
+
const regex = cloneGlobalRegExp(interpolate);
|
|
1832
|
+
let lastIndex = 0;
|
|
1833
|
+
let match;
|
|
1834
|
+
while ((match = regex.exec(template)) !== null) {
|
|
1835
|
+
if (match[0].length === 0) {
|
|
1836
|
+
regex.lastIndex += 1;
|
|
1837
|
+
continue;
|
|
1838
|
+
}
|
|
1839
|
+
if (match.index > lastIndex) {
|
|
1840
|
+
tokens.push(template.slice(lastIndex, match.index));
|
|
1841
|
+
}
|
|
1842
|
+
const rawPath = match[1]?.trim() ?? "";
|
|
1843
|
+
tokens.push({
|
|
1844
|
+
type: "variable",
|
|
1845
|
+
path: rawPath,
|
|
1846
|
+
raw: match[0],
|
|
1847
|
+
keys: null
|
|
1848
|
+
});
|
|
1849
|
+
lastIndex = regex.lastIndex;
|
|
1850
|
+
}
|
|
1851
|
+
if (lastIndex < template.length) {
|
|
1852
|
+
tokens.push(template.slice(lastIndex));
|
|
1853
|
+
}
|
|
1854
|
+
return tokens;
|
|
1855
|
+
}
|
|
1856
|
+
var TemplateEngine = class {
|
|
1857
|
+
options;
|
|
1858
|
+
/**
|
|
1859
|
+
* @param options - Engine configuration. All fields are optional;
|
|
1860
|
+
* defaults to ES6 `${}` interpolation with safe prototype access.
|
|
1861
|
+
*/
|
|
1862
|
+
constructor(options = {}) {
|
|
1863
|
+
const defaults = {
|
|
1864
|
+
interpolate: interpolatePreset.ES6,
|
|
1865
|
+
variable: "",
|
|
1866
|
+
defaultValue: "",
|
|
1867
|
+
escapeHtml: false,
|
|
1868
|
+
stringifyObject: true,
|
|
1869
|
+
keepUnmatched: false,
|
|
1870
|
+
safePrototype: true
|
|
1871
|
+
};
|
|
1872
|
+
this.options = {
|
|
1873
|
+
...defaults,
|
|
1874
|
+
...options,
|
|
1875
|
+
interpolate: cloneGlobalRegExp(
|
|
1876
|
+
options.interpolate ?? defaults.interpolate
|
|
1877
|
+
)
|
|
1878
|
+
};
|
|
1879
|
+
}
|
|
1880
|
+
/**
|
|
1881
|
+
* Compile a template into a reusable render function.
|
|
1882
|
+
*
|
|
1883
|
+
* Path parsing and validation happen once at compile time; subsequent
|
|
1884
|
+
* renders only perform value lookup and string assembly.
|
|
1885
|
+
*
|
|
1886
|
+
* @param template - Template string containing placeholders
|
|
1887
|
+
* @returns Render function bound to the compiled template
|
|
1888
|
+
* @throws {TypeError} When template is not a string
|
|
1889
|
+
*/
|
|
1890
|
+
compile(template) {
|
|
1891
|
+
if (typeof template !== "string") {
|
|
1892
|
+
throw new TypeError("Template must be a string");
|
|
1893
|
+
}
|
|
1894
|
+
const {
|
|
1895
|
+
variable,
|
|
1896
|
+
defaultValue,
|
|
1897
|
+
escapeHtml: shouldEscapeHtml,
|
|
1898
|
+
stringifyObject,
|
|
1899
|
+
keepUnmatched,
|
|
1900
|
+
safePrototype
|
|
1901
|
+
} = this.options;
|
|
1902
|
+
const tokens = tokenize(template, this.options.interpolate).map(
|
|
1903
|
+
(token) => {
|
|
1904
|
+
if (typeof token === "string") {
|
|
1905
|
+
return token;
|
|
1906
|
+
}
|
|
1907
|
+
return {
|
|
1908
|
+
...token,
|
|
1909
|
+
keys: parsePathKeys(token.path, variable)
|
|
1910
|
+
};
|
|
1911
|
+
}
|
|
1912
|
+
);
|
|
1913
|
+
return (input) => {
|
|
1914
|
+
const data = input !== null && typeof input === "object" ? input : {};
|
|
1915
|
+
const parts = [];
|
|
1916
|
+
for (const token of tokens) {
|
|
1917
|
+
if (typeof token === "string") {
|
|
1918
|
+
parts.push(token);
|
|
1919
|
+
continue;
|
|
1920
|
+
}
|
|
1921
|
+
const value = getValueByKeys(data, token.keys, safePrototype);
|
|
1922
|
+
if (value === void 0 || value === null) {
|
|
1923
|
+
if (keepUnmatched) {
|
|
1924
|
+
parts.push(token.raw);
|
|
1925
|
+
continue;
|
|
1926
|
+
}
|
|
1927
|
+
let resolvedDefault = defaultValue;
|
|
1928
|
+
if (typeof defaultValue === "function") {
|
|
1929
|
+
resolvedDefault = defaultValue(token.path, data);
|
|
1930
|
+
}
|
|
1931
|
+
const defaultStr = formatValue(resolvedDefault, stringifyObject);
|
|
1932
|
+
parts.push(shouldEscapeHtml ? escapeHtml(defaultStr) : defaultStr);
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
let output = formatValue(value, stringifyObject);
|
|
1936
|
+
if (shouldEscapeHtml) {
|
|
1937
|
+
output = escapeHtml(output);
|
|
1938
|
+
}
|
|
1939
|
+
parts.push(output);
|
|
1940
|
+
}
|
|
1941
|
+
return parts.join("");
|
|
1942
|
+
};
|
|
1943
|
+
}
|
|
1944
|
+
/**
|
|
1945
|
+
* Render a template in one shot.
|
|
1946
|
+
*
|
|
1947
|
+
* Convenience wrapper around `compile(template)(data)`.
|
|
1948
|
+
* Prefer {@link compile} when the same template is rendered multiple times.
|
|
1949
|
+
*
|
|
1950
|
+
* @param template - Template string containing placeholders
|
|
1951
|
+
* @param data - Context object for variable substitution
|
|
1952
|
+
*/
|
|
1953
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1954
|
+
render(template, data) {
|
|
1955
|
+
return this.compile(template)(data);
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
|
|
1301
1959
|
// src/implement/Shell.ts
|
|
1302
|
-
import { template as lodashTemplate } from "lodash-es";
|
|
1303
1960
|
var Shell = class _Shell {
|
|
1304
1961
|
/**
|
|
1305
1962
|
* Creates a new Shell instance with the specified configuration
|
|
@@ -1348,6 +2005,9 @@ var Shell = class _Shell {
|
|
|
1348
2005
|
this.config = config;
|
|
1349
2006
|
this.cache = cache;
|
|
1350
2007
|
}
|
|
2008
|
+
config;
|
|
2009
|
+
cache;
|
|
2010
|
+
static templateEngine = new TemplateEngine();
|
|
1351
2011
|
/**
|
|
1352
2012
|
* Gets the logger instance for command logging and error reporting
|
|
1353
2013
|
*
|
|
@@ -1373,60 +2033,32 @@ var Shell = class _Shell {
|
|
|
1373
2033
|
return this.config.logger;
|
|
1374
2034
|
}
|
|
1375
2035
|
/**
|
|
1376
|
-
* Formats a template string with context using
|
|
2036
|
+
* Formats a template string with context using {@link TemplateEngine}.
|
|
1377
2037
|
*
|
|
1378
|
-
*
|
|
1379
|
-
* Provides static template formatting functionality using
|
|
1380
|
-
* lodash template for string interpolation with context data.
|
|
1381
|
-
*
|
|
1382
|
-
* Template features:
|
|
1383
|
-
* - Uses lodash template for powerful string interpolation
|
|
1384
|
-
* - Supports complex template expressions and logic
|
|
1385
|
-
* - Handles undefined and null context values gracefully
|
|
1386
|
-
* - Returns formatted string with context values substituted
|
|
1387
|
-
*
|
|
1388
|
-
* Template syntax:
|
|
1389
|
-
* - `<%= variable %>` for escaped output
|
|
1390
|
-
* - `<%- variable %>` for unescaped output
|
|
1391
|
-
* - `<% code %>` for JavaScript code execution
|
|
1392
|
-
* - Supports nested object access and function calls
|
|
1393
|
-
*
|
|
1394
|
-
* Context handling:
|
|
1395
|
-
* - Accepts any object with string/number/boolean values
|
|
1396
|
-
* - Handles undefined and null values safely
|
|
1397
|
-
* - Supports nested object property access
|
|
1398
|
-
* - Provides fallback for missing context values
|
|
2038
|
+
* Uses ES6-style `${ path }` placeholders via {@link TemplateEngine}.
|
|
1399
2039
|
*
|
|
1400
2040
|
* @param template - Template string with interpolation placeholders
|
|
1401
2041
|
* @param context - Context object for template variable substitution
|
|
1402
2042
|
* @returns Formatted string with context values substituted
|
|
1403
2043
|
*
|
|
1404
|
-
* @example Basic
|
|
2044
|
+
* @example Basic formatting
|
|
1405
2045
|
* ```typescript
|
|
1406
|
-
* const result = Shell.format('Hello
|
|
2046
|
+
* const result = Shell.format('Hello ${name}!', { name: 'World' });
|
|
1407
2047
|
* // Returns: 'Hello World!'
|
|
1408
2048
|
* ```
|
|
1409
2049
|
*
|
|
1410
2050
|
* @example Complex template with nested objects
|
|
1411
2051
|
* ```typescript
|
|
1412
2052
|
* const result = Shell.format(
|
|
1413
|
-
* 'git clone
|
|
2053
|
+
* 'git clone ${repo.url} ${repo.branch}',
|
|
1414
2054
|
* { repo: { url: 'https://github.com/user/repo.git', branch: 'main' } }
|
|
1415
2055
|
* );
|
|
1416
2056
|
* // Returns: 'git clone https://github.com/user/repo.git main'
|
|
1417
2057
|
* ```
|
|
1418
|
-
*
|
|
1419
|
-
* @example Template with conditional logic
|
|
1420
|
-
* ```typescript
|
|
1421
|
-
* const result = Shell.format(
|
|
1422
|
-
* 'npm install<% if (dev) { %> --save-dev<% } %>',
|
|
1423
|
-
* { dev: true }
|
|
1424
|
-
* );
|
|
1425
|
-
* // Returns: 'npm install --save-dev'
|
|
1426
|
-
* ```
|
|
1427
2058
|
*/
|
|
1428
2059
|
static format(template = "", context = {}) {
|
|
1429
|
-
|
|
2060
|
+
const data = context !== null && typeof context === "object" ? context : {};
|
|
2061
|
+
return _Shell.templateEngine.render(template, data);
|
|
1430
2062
|
}
|
|
1431
2063
|
/**
|
|
1432
2064
|
* Formats a template string with context and comprehensive error handling
|
|
@@ -1461,14 +2093,14 @@ var Shell = class _Shell {
|
|
|
1461
2093
|
*
|
|
1462
2094
|
* @example Basic formatting
|
|
1463
2095
|
* ```typescript
|
|
1464
|
-
* const result = shell.format('Hello
|
|
2096
|
+
* const result = shell.format('Hello ${name}!', { name: 'World' });
|
|
1465
2097
|
* // Returns: 'Hello World!'
|
|
1466
2098
|
* ```
|
|
1467
2099
|
*
|
|
1468
2100
|
* @example Error handling
|
|
1469
2101
|
* ```typescript
|
|
1470
2102
|
* try {
|
|
1471
|
-
* const result = shell.format('Hello
|
|
2103
|
+
* const result = shell.format('Hello ${name}!', {});
|
|
1472
2104
|
* } catch (error) {
|
|
1473
2105
|
* // Error is logged with template and context information
|
|
1474
2106
|
* console.error('Template formatting failed:', error.message);
|
|
@@ -1522,7 +2154,7 @@ ${JSON.stringify(context)}`
|
|
|
1522
2154
|
*
|
|
1523
2155
|
* @example String command with template
|
|
1524
2156
|
* ```typescript
|
|
1525
|
-
* const output = await shell.exec('git clone
|
|
2157
|
+
* const output = await shell.exec('git clone ${repo}', {
|
|
1526
2158
|
* context: { repo: 'https://github.com/user/repo.git' }
|
|
1527
2159
|
* });
|
|
1528
2160
|
* ```
|
|
@@ -1795,7 +2427,7 @@ var contextDefaults = {
|
|
|
1795
2427
|
getConfig(feConfig) {
|
|
1796
2428
|
return new ConfigSearch({
|
|
1797
2429
|
name: "fe-config",
|
|
1798
|
-
defaultConfig:
|
|
2430
|
+
defaultConfig: merge3({}, defaultFeConfig, feConfig)
|
|
1799
2431
|
});
|
|
1800
2432
|
},
|
|
1801
2433
|
/**
|
|
@@ -1914,7 +2546,7 @@ var contextDefaults = {
|
|
|
1914
2546
|
dryRun,
|
|
1915
2547
|
execPromise: _options.execPromise || contextDefaults.exec
|
|
1916
2548
|
});
|
|
1917
|
-
const _feConfig =
|
|
2549
|
+
const _feConfig = merge3({}, feConfig, { [name]: ctxOpts.options });
|
|
1918
2550
|
return {
|
|
1919
2551
|
options: _options,
|
|
1920
2552
|
dryRun: !!dryRun,
|
|
@@ -1986,8 +2618,9 @@ var ScriptContext = class extends ExecutorContextImpl {
|
|
|
1986
2618
|
this.shell = shell;
|
|
1987
2619
|
this.dryRun = dryRun;
|
|
1988
2620
|
this.verbose = verbose;
|
|
1989
|
-
this.
|
|
2621
|
+
this.setParameters(initializeOptions(name, feConfig, options, logger));
|
|
1990
2622
|
}
|
|
2623
|
+
name;
|
|
1991
2624
|
/**
|
|
1992
2625
|
* Logger instance for structured logging
|
|
1993
2626
|
*
|
|
@@ -2024,7 +2657,22 @@ var ScriptContext = class extends ExecutorContextImpl {
|
|
|
2024
2657
|
*/
|
|
2025
2658
|
verbose;
|
|
2026
2659
|
/**
|
|
2660
|
+
* 该属性只是一个 parameters 的别名
|
|
2661
|
+
*
|
|
2662
|
+
* 当你需要设置最新的参数时可以直接使用 setParameters 方法
|
|
2663
|
+
*
|
|
2027
2664
|
* @override
|
|
2665
|
+
* @example
|
|
2666
|
+
* ```ts
|
|
2667
|
+
* context.setParameters({
|
|
2668
|
+
* target: 'production'
|
|
2669
|
+
* });
|
|
2670
|
+
*
|
|
2671
|
+
* console.log(context.options);
|
|
2672
|
+
* // { target: 'production' }
|
|
2673
|
+
* console.log(context.parameters);
|
|
2674
|
+
* // { target: 'production' }
|
|
2675
|
+
* ```
|
|
2028
2676
|
*/
|
|
2029
2677
|
get options() {
|
|
2030
2678
|
return this.parameters;
|
|
@@ -2071,10 +2719,10 @@ var ScriptContext = class extends ExecutorContextImpl {
|
|
|
2071
2719
|
* ```
|
|
2072
2720
|
*/
|
|
2073
2721
|
get env() {
|
|
2074
|
-
if (!this.
|
|
2722
|
+
if (!this.parameters.env) {
|
|
2075
2723
|
throw new Error("Environment is not initialized");
|
|
2076
2724
|
}
|
|
2077
|
-
return this.
|
|
2725
|
+
return this.parameters.env;
|
|
2078
2726
|
}
|
|
2079
2727
|
/**
|
|
2080
2728
|
* Updates script options with deep merging support
|
|
@@ -2119,9 +2767,10 @@ var ScriptContext = class extends ExecutorContextImpl {
|
|
|
2119
2767
|
* });
|
|
2120
2768
|
* // Merges nested build configuration
|
|
2121
2769
|
* ```
|
|
2770
|
+
*
|
|
2122
2771
|
*/
|
|
2123
|
-
|
|
2124
|
-
|
|
2772
|
+
setParameters(params) {
|
|
2773
|
+
super.setParameters(merge4(this.parameters, params));
|
|
2125
2774
|
}
|
|
2126
2775
|
/**
|
|
2127
2776
|
* Retrieves environment variable with optional default value
|
|
@@ -2224,16 +2873,16 @@ var ScriptContext = class extends ExecutorContextImpl {
|
|
|
2224
2873
|
* // Returns the complete options object
|
|
2225
2874
|
* ```
|
|
2226
2875
|
*/
|
|
2227
|
-
|
|
2876
|
+
getParameters(key, defaultValue) {
|
|
2228
2877
|
if (!key) {
|
|
2229
|
-
return this.
|
|
2878
|
+
return this.parameters;
|
|
2230
2879
|
}
|
|
2231
|
-
return get2(this.
|
|
2880
|
+
return get2(this.parameters, key, defaultValue);
|
|
2232
2881
|
}
|
|
2233
2882
|
};
|
|
2234
2883
|
|
|
2235
2884
|
// src/implement/ScriptPlugin.ts
|
|
2236
|
-
import { merge as
|
|
2885
|
+
import { merge as merge5 } from "lodash-es";
|
|
2237
2886
|
var ScriptPlugin = class {
|
|
2238
2887
|
/**
|
|
2239
2888
|
* Creates a new script plugin instance
|
|
@@ -2265,6 +2914,9 @@ var ScriptPlugin = class {
|
|
|
2265
2914
|
this.props = props;
|
|
2266
2915
|
this.setConfig(this.getInitialProps(props));
|
|
2267
2916
|
}
|
|
2917
|
+
context;
|
|
2918
|
+
pluginName;
|
|
2919
|
+
props;
|
|
2268
2920
|
/** Ensures only one instance of this plugin can be registered */
|
|
2269
2921
|
onlyOne = true;
|
|
2270
2922
|
/**
|
|
@@ -2292,9 +2944,9 @@ var ScriptPlugin = class {
|
|
|
2292
2944
|
return {};
|
|
2293
2945
|
}
|
|
2294
2946
|
const pluginConfig = this.context.options[this.pluginName];
|
|
2295
|
-
const fileConfig = this.context.
|
|
2947
|
+
const fileConfig = this.context.getParameters(this.pluginName);
|
|
2296
2948
|
const baseConfig = pluginConfig || fileConfig;
|
|
2297
|
-
return props ?
|
|
2949
|
+
return props ? merge5({}, baseConfig, props) : baseConfig || {};
|
|
2298
2950
|
}
|
|
2299
2951
|
/**
|
|
2300
2952
|
* Logger instance for structured logging
|
|
@@ -2357,8 +3009,8 @@ var ScriptPlugin = class {
|
|
|
2357
3009
|
* }
|
|
2358
3010
|
* ```
|
|
2359
3011
|
*/
|
|
2360
|
-
get
|
|
2361
|
-
return this.context.
|
|
3012
|
+
get config() {
|
|
3013
|
+
return this.context.getParameters(this.pluginName, {});
|
|
2362
3014
|
}
|
|
2363
3015
|
/**
|
|
2364
3016
|
* Determines whether a lifecycle method should be executed
|
|
@@ -2385,12 +3037,18 @@ var ScriptPlugin = class {
|
|
|
2385
3037
|
* plugin.enabled('onExec', context); // Returns true
|
|
2386
3038
|
* ```
|
|
2387
3039
|
*/
|
|
2388
|
-
enabled(
|
|
3040
|
+
enabled(name, _context) {
|
|
2389
3041
|
const skip = this.getConfig("skip");
|
|
2390
|
-
if (skip ===
|
|
3042
|
+
if (typeof skip === "string" && name === skip) {
|
|
3043
|
+
this.logger.debug(
|
|
3044
|
+
`Skip ${this.pluginName}.${name}, ${this.pluginName}.skip is set to '${skip}'`
|
|
3045
|
+
);
|
|
2391
3046
|
return false;
|
|
2392
3047
|
}
|
|
2393
|
-
if (
|
|
3048
|
+
if (skip === true) {
|
|
3049
|
+
this.logger.debug(
|
|
3050
|
+
`Skip ${this.pluginName}.${name}, ${this.pluginName}.skip is set to true`
|
|
3051
|
+
);
|
|
2394
3052
|
return false;
|
|
2395
3053
|
}
|
|
2396
3054
|
return true;
|
|
@@ -2428,9 +3086,9 @@ var ScriptPlugin = class {
|
|
|
2428
3086
|
*/
|
|
2429
3087
|
getConfig(keys, defaultValue) {
|
|
2430
3088
|
if (!keys) {
|
|
2431
|
-
return this.context.
|
|
3089
|
+
return this.context.getParameters(this.pluginName, defaultValue);
|
|
2432
3090
|
}
|
|
2433
|
-
return this.context.
|
|
3091
|
+
return this.context.getParameters(
|
|
2434
3092
|
[this.pluginName, ...Array.isArray(keys) ? keys : [keys]],
|
|
2435
3093
|
defaultValue
|
|
2436
3094
|
);
|
|
@@ -2467,167 +3125,10 @@ var ScriptPlugin = class {
|
|
|
2467
3125
|
* ```
|
|
2468
3126
|
*/
|
|
2469
3127
|
setConfig(config) {
|
|
2470
|
-
this.context.
|
|
3128
|
+
this.context.setParameters({
|
|
2471
3129
|
[this.pluginName]: config
|
|
2472
3130
|
});
|
|
2473
3131
|
}
|
|
2474
|
-
/**
|
|
2475
|
-
* Lifecycle method called before script execution
|
|
2476
|
-
*
|
|
2477
|
-
* Override this method to perform setup tasks such as:
|
|
2478
|
-
* - Environment validation
|
|
2479
|
-
* - Configuration verification
|
|
2480
|
-
* - Resource preparation
|
|
2481
|
-
* - Pre-execution checks
|
|
2482
|
-
*
|
|
2483
|
-
* @override
|
|
2484
|
-
* @param _context - Executor context containing execution state
|
|
2485
|
-
*
|
|
2486
|
-
* @example
|
|
2487
|
-
* ```typescript
|
|
2488
|
-
* async onBefore(context: ExecutorContext<MyContext>): Promise<void> {
|
|
2489
|
-
* // Validate required environment variables
|
|
2490
|
-
* const apiKey = this.context.getEnv('API_KEY');
|
|
2491
|
-
* if (!apiKey) {
|
|
2492
|
-
* throw new Error('API_KEY environment variable is required');
|
|
2493
|
-
* }
|
|
2494
|
-
*
|
|
2495
|
-
* // Check if output directory exists
|
|
2496
|
-
* const outputDir = this.getConfig('outputDir', './dist');
|
|
2497
|
-
* if (!(await this.shell.exists(outputDir))) {
|
|
2498
|
-
* await this.shell.mkdir(outputDir);
|
|
2499
|
-
* }
|
|
2500
|
-
* }
|
|
2501
|
-
* ```
|
|
2502
|
-
*/
|
|
2503
|
-
onBefore(_context) {
|
|
2504
|
-
return void 0;
|
|
2505
|
-
}
|
|
2506
|
-
/**
|
|
2507
|
-
* Lifecycle method called during script execution
|
|
2508
|
-
*
|
|
2509
|
-
* Override this method to implement the main plugin logic:
|
|
2510
|
-
* - Core functionality execution
|
|
2511
|
-
* - Business logic implementation
|
|
2512
|
-
* - Task orchestration
|
|
2513
|
-
* - Process management
|
|
2514
|
-
*
|
|
2515
|
-
* @override
|
|
2516
|
-
* @param _context - Executor context containing execution state
|
|
2517
|
-
*
|
|
2518
|
-
* @example
|
|
2519
|
-
* ```typescript
|
|
2520
|
-
* async onExec(context: Context): Promise<void> {
|
|
2521
|
-
* await this.step({
|
|
2522
|
-
* label: 'Building project',
|
|
2523
|
-
* task: async () => {
|
|
2524
|
-
* await this.shell.exec('npm run build');
|
|
2525
|
-
* return 'build completed';
|
|
2526
|
-
* }
|
|
2527
|
-
* });
|
|
2528
|
-
*
|
|
2529
|
-
* await this.step({
|
|
2530
|
-
* label: 'Running tests',
|
|
2531
|
-
* task: async () => {
|
|
2532
|
-
* await this.shell.exec('npm test');
|
|
2533
|
-
* return 'tests passed';
|
|
2534
|
-
* }
|
|
2535
|
-
* });
|
|
2536
|
-
* }
|
|
2537
|
-
* ```
|
|
2538
|
-
*/
|
|
2539
|
-
onExec(_context) {
|
|
2540
|
-
}
|
|
2541
|
-
/**
|
|
2542
|
-
* Lifecycle method called after successful script execution
|
|
2543
|
-
*
|
|
2544
|
-
* Override this method to perform cleanup tasks such as:
|
|
2545
|
-
* - Resource cleanup
|
|
2546
|
-
* - Success notifications
|
|
2547
|
-
* - Result processing
|
|
2548
|
-
* - Post-execution reporting
|
|
2549
|
-
*
|
|
2550
|
-
* @override
|
|
2551
|
-
* @param _context - Executor context containing execution state
|
|
2552
|
-
*
|
|
2553
|
-
* @example
|
|
2554
|
-
* ```typescript
|
|
2555
|
-
* async onSuccess(context: Context): Promise<void> {
|
|
2556
|
-
* // Send success notification
|
|
2557
|
-
* await this.sendNotification('Build completed successfully');
|
|
2558
|
-
*
|
|
2559
|
-
* // Generate success report
|
|
2560
|
-
* await this.generateReport({
|
|
2561
|
-
* status: 'success',
|
|
2562
|
-
* timestamp: new Date(),
|
|
2563
|
-
* duration: context.duration
|
|
2564
|
-
* });
|
|
2565
|
-
*
|
|
2566
|
-
* // Clean up temporary files
|
|
2567
|
-
* await this.shell.rmdir('./temp');
|
|
2568
|
-
* }
|
|
2569
|
-
* ```
|
|
2570
|
-
*/
|
|
2571
|
-
onSuccess(_context) {
|
|
2572
|
-
return void 0;
|
|
2573
|
-
}
|
|
2574
|
-
/**
|
|
2575
|
-
* Lifecycle method called when script execution fails
|
|
2576
|
-
*
|
|
2577
|
-
* Override this method to handle errors such as:
|
|
2578
|
-
* - Error logging and reporting
|
|
2579
|
-
* - Resource cleanup on failure
|
|
2580
|
-
* - Error notifications
|
|
2581
|
-
* - Failure recovery attempts
|
|
2582
|
-
*
|
|
2583
|
-
* @override
|
|
2584
|
-
* @param _context - Executor context containing execution state
|
|
2585
|
-
*
|
|
2586
|
-
* @example
|
|
2587
|
-
* ```typescript
|
|
2588
|
-
* async onError(context: Context): Promise<void> {
|
|
2589
|
-
* // Log detailed error information
|
|
2590
|
-
* this.logger.error('Script execution failed', {
|
|
2591
|
-
* error: context.error,
|
|
2592
|
-
* duration: context.duration,
|
|
2593
|
-
* config: this.options
|
|
2594
|
-
* });
|
|
2595
|
-
*
|
|
2596
|
-
* // Send error notification
|
|
2597
|
-
* await this.sendNotification('Build failed', {
|
|
2598
|
-
* error: context.error.message
|
|
2599
|
-
* });
|
|
2600
|
-
*
|
|
2601
|
-
* // Clean up partial results
|
|
2602
|
-
* await this.shell.rmdir('./partial-build');
|
|
2603
|
-
* }
|
|
2604
|
-
* ```
|
|
2605
|
-
*/
|
|
2606
|
-
onError(_context) {
|
|
2607
|
-
}
|
|
2608
|
-
/**
|
|
2609
|
-
* Lifecycle method called after script execution
|
|
2610
|
-
*
|
|
2611
|
-
* Override this method to perform cleanup tasks such as:
|
|
2612
|
-
* - Resource cleanup
|
|
2613
|
-
* - Success notifications
|
|
2614
|
-
* - Result processing
|
|
2615
|
-
* - Post-execution reporting
|
|
2616
|
-
*
|
|
2617
|
-
* @override
|
|
2618
|
-
* @param _context - Executor context containing execution state
|
|
2619
|
-
*
|
|
2620
|
-
* @example
|
|
2621
|
-
* ```typescript
|
|
2622
|
-
* async onFinally(context: Context): Promise<void> {
|
|
2623
|
-
* // Clean up temporary files
|
|
2624
|
-
* await this.shell.rmdir('./temp');
|
|
2625
|
-
* }
|
|
2626
|
-
* ```
|
|
2627
|
-
*/
|
|
2628
|
-
onFinally(_context) {
|
|
2629
|
-
return void 0;
|
|
2630
|
-
}
|
|
2631
3132
|
/**
|
|
2632
3133
|
* Executes a step with structured logging and error handling
|
|
2633
3134
|
*
|
|
@@ -2688,18 +3189,25 @@ var ScriptPlugin = class {
|
|
|
2688
3189
|
* ```
|
|
2689
3190
|
*/
|
|
2690
3191
|
async step(options) {
|
|
2691
|
-
this.
|
|
2692
|
-
this.logger.info(
|
|
2693
|
-
this.logger.log();
|
|
3192
|
+
const stepBase = this.createStepLabel(options.label);
|
|
3193
|
+
this.logger.info(`${stepBase} - beginning`);
|
|
2694
3194
|
try {
|
|
2695
3195
|
const res = await options.task();
|
|
2696
|
-
this.logger.info(`${
|
|
3196
|
+
this.logger.info(`${stepBase} - success`);
|
|
2697
3197
|
return res;
|
|
2698
3198
|
} catch (e) {
|
|
2699
|
-
this.logger.error(
|
|
3199
|
+
this.logger.error(`${stepBase} - failed
|
|
3200
|
+
`, e);
|
|
2700
3201
|
throw e;
|
|
2701
3202
|
}
|
|
2702
3203
|
}
|
|
3204
|
+
/**
|
|
3205
|
+
* Builds the shared step log prefix (plugin context + dry-run)
|
|
3206
|
+
*/
|
|
3207
|
+
createStepLabel(label) {
|
|
3208
|
+
const stepLabel = `${this.pluginName}: ${label}`;
|
|
3209
|
+
return this.context.dryRun ? `[dry-run] ${stepLabel}` : stepLabel;
|
|
3210
|
+
}
|
|
2703
3211
|
};
|
|
2704
3212
|
export {
|
|
2705
3213
|
ColorFormatter,
|
|
@@ -2707,5 +3215,7 @@ export {
|
|
|
2707
3215
|
ScriptContext,
|
|
2708
3216
|
ScriptPlugin,
|
|
2709
3217
|
Shell,
|
|
2710
|
-
|
|
3218
|
+
TemplateEngine,
|
|
3219
|
+
defaultFeConfig,
|
|
3220
|
+
interpolatePreset
|
|
2711
3221
|
};
|