ソースを参照

Fix: guard pending promise

SukkaW 1 年間 前
コミット
c24fae555a
1 ファイル変更18 行追加5 行削除
  1. 18 5
      Build/lib/rules/base.ts

+ 18 - 5
Build/lib/rules/base.ts

@@ -35,7 +35,7 @@ export abstract class RuleOutput<TPreprocessed = unknown> {
   protected otherRules: string[] = [];
   protected abstract type: 'domainset' | 'non_ip' | 'ip';
 
-  protected pendingPromise = Promise.resolve();
+  private pendingPromise: Promise<void> | null = null;
 
   static readonly jsonToLines = (json: unknown): string[] => stringify(json).split('\n');
 
@@ -125,7 +125,7 @@ export abstract class RuleOutput<TPreprocessed = unknown> {
   }
 
   addFromDomainset(source: AsyncIterable<string> | Iterable<string> | string[]) {
-    this.pendingPromise = this.pendingPromise.then(() => this.addFromDomainsetPromise(source));
+    this.pendingPromise = (this.pendingPromise ||= Promise.resolve()).then(() => this.addFromDomainsetPromise(source));
     return this;
   }
 
@@ -193,7 +193,7 @@ export abstract class RuleOutput<TPreprocessed = unknown> {
   }
 
   addFromRuleset(source: AsyncIterable<string> | Iterable<string>) {
-    this.pendingPromise = this.pendingPromise.then(() => this.addFromRulesetPromise(source));
+    this.pendingPromise = (this.pendingPromise ||= Promise.resolve()).then(() => this.addFromRulesetPromise(source));
     return this;
   }
 
@@ -235,13 +235,26 @@ export abstract class RuleOutput<TPreprocessed = unknown> {
 
   protected abstract preprocess(): NonNullable<TPreprocessed>;
 
-  done() {
-    return this.pendingPromise;
+  async done() {
+    await this.pendingPromise;
+    this.pendingPromise = null;
+  }
+
+  private guardPendingPromise() {
+    console.log('Pending promise:', this.pendingPromise);
+
+    // reverse invariant
+    if (this.pendingPromise !== null) {
+      console.trace('Pending promise:', this.pendingPromise);
+      throw new Error('You should call done() before calling this method');
+    }
   }
 
   private $$preprocessed: TPreprocessed | null = null;
   get $preprocessed() {
     if (this.$$preprocessed === null) {
+      this.guardPendingPromise();
+
       this.$$preprocessed = this.span.traceChildSync('RuleOutput#preprocess: ' + this.id, () => this.preprocess());
     }
     return this.$$preprocessed;