8
import * as t from '@babel/types';
9
import {ZodError, z} from 'zod/v4';
10
import {fromZodError} from 'zod-validation-error/v4';
11
-import {CompilerError} from '../CompilerError';
11
+import {
12
+ CompilerDiagnostic,
13
+ CompilerError,
14
+ CompilerErrorDetail,
15
+ ErrorCategory,
16
+} from '../CompilerError';
17
import {CompilerOutputMode, Logger, ProgramContext} from '../Entrypoint';
18
import {Err, Ok, Result} from '../Utils/Result';
19
import {
550
551
#flowTypeEnvironment: FlowTypeEnv | null;
552
553
+ /**
554
+ * Accumulated compilation errors. Passes record errors here instead of
555
+ * throwing, so the pipeline can continue and report all errors at once.
556
+ */
557
+ #errors: CompilerError = new CompilerError();
558
+
559
constructor(
560
scope: BabelScope,
561
fnType: ReactFunctionType,
713
}
714
}
715
716
+ /**
717
+ * Record a single diagnostic or error detail on this environment.
718
+ * If the error is an Invariant, it is immediately thrown since invariants
719
+ * represent internal bugs that cannot be recovered from.
720
+ * Otherwise, the error is accumulated and optionally logged.
721
+ */
722
+ recordError(error: CompilerDiagnostic | CompilerErrorDetail): void {
723
+ if (error.category === ErrorCategory.Invariant) {
724
+ const compilerError = new CompilerError();
725
+ if (error instanceof CompilerDiagnostic) {
726
+ compilerError.pushDiagnostic(error);
727
+ } else {
728
+ compilerError.pushErrorDetail(error);
729
+ }
730
+ throw compilerError;
731
+ }
732
+ if (error instanceof CompilerDiagnostic) {
733
+ this.#errors.pushDiagnostic(error);
734
+ } else {
735
+ this.#errors.pushErrorDetail(error);
736
+ }
737
+ }
738
+
739
+ /**
740
+ * Record all diagnostics from a CompilerError onto this environment.
741
+ */
742
+ recordErrors(error: CompilerError): void {
743
+ for (const detail of error.details) {
744
+ this.recordError(detail);
745
+ }
746
+ }
747
+
748
+ /**
749
+ * Returns true if any errors have been recorded during compilation.
750
+ */
751
+ hasErrors(): boolean {
752
+ return this.#errors.hasAnyErrors();
753
+ }
754
+
755
+ /**
756
+ * Returns the accumulated CompilerError containing all recorded diagnostics.
757
+ */
758
+ aggregateErrors(): CompilerError {
759
+ return this.#errors;
760
+ }
761
+
762
+ /**
763
+ * Wraps a callback in try/catch: if the callback throws a CompilerError
764
+ * that is NOT an invariant, the error is recorded and execution continues.
765
+ * Non-CompilerError exceptions and invariants are re-thrown.
766
+ */
767
+ tryRecord(fn: () => void): void {
768
+ try {
769
+ fn();
770
+ } catch (err) {
771
+ if (err instanceof CompilerError) {
772
+ // Check if any detail is an invariant — if so, re-throw
773
+ for (const detail of err.details) {
774
+ if (detail.category === ErrorCategory.Invariant) {
775
+ throw err;
776
+ }
777
+ }
778
+ this.recordErrors(err);
779
+ } else {
780
+ throw err;
781
+ }
782
+ }
783
+ }
784
+
785
isContextIdentifier(node: t.Identifier): boolean {
786
return this.#contextIdentifiers.has(node);
787
}