repo_description: Next-generation full-text search library for Browser and Node.js
repo_topics: elasticsearch full-text-search fulltext-search fuzzy fuzzy-search javascript javascript-library nodejs open-source search search-algorithm search-engine search-in-text searching searching-algorithms web web-worker
code: // COMPILER BLOCK -->
  import {
      DEBUG,
      SUPPORT_ASYNC,
      SUPPORT_CACHE,
      SUPPORT_WORKER
  } from "./config.js";
  // <-- COMPILER BLOCK
  import { IndexOptions } from "./type.js";
  import { create_object } from "./common.js";
  import { searchCache } from "./cache.js";
  import handler from "./worker/handler.js";
  import apply_async from "./async.js";
  import Encoder from "./encoder.js";
  
  let pid = 0;
  
  /**
   * @param {IndexOptions=} options
   * @param {Encoder=} encoder
   * @constructor
   */
  
  export default function WorkerIndex(options = /** @type IndexOptions */ ({}), encoder){
  
      if(!this || this.constructor !== WorkerIndex) {
          return new WorkerIndex(options);
      }
  
      // the factory is the outer wrapper from the build
      // it uses "self" as a trap for node.js
      let factory = typeof self !== "undefined"
          ? self["_factory"]
          : typeof window !== "undefined"
              ? window["_factory"]
              : null;
      if(factory){
          factory = factory.toString();
      }
  
      const is_node_js = typeof window === "undefined" /*&& self["exports"]*/;
      const _self = this;
  
      /**
       * @this {WorkerIndex}
       */
      function init(worker){
  
          this.worker = worker;
          this.resolver = create_object();
  
          if(!this.worker){
              if(DEBUG){
                  console.warn("Worker is not available on this platform. Please report on Github: https://github.com/nextapps-de/flexsearch/issues");
              }
              return;
          }
  
          function onmessage(msg){
              msg = msg["data"] || msg;
              const id = msg["id"];
              const res = id && _self.resolver[id];
              if(res){
                  res(msg["msg"]);
                  delete _self.resolver[id];
              }
          }
  
          is_node_js
              ? this.worker["on"]("message", onmessage)
              : this.worker.onmessage = onmessage;
  
          if(options.config){
  
              // when extern configuration needs to be loaded,
              // it needs to return a promise to await for
              return new Promise(function(resolve){
                  if(pid > 1e9) pid = 0;
                  _self.resolver[++pid] = function(){
                      resolve(_self);
                  };
                  _self.worker.postMessage({
                      "id": pid,
                      "task": "init",
                      "factory": factory,
                      "options": options
                  });
              });
          }
  
          if(SUPPORT_ASYNC){
              this.priority = options.priority || 4;
          }
  
          // assign encoder for result highlighting
          this.encoder = encoder || null;
  
          // initialize worker index
          this.worker.postMessage({
              "task": "init",
              "factory": factory,
              "options": options
          });
  
          return this;
      }
  
      const worker = create(factory, is_node_js, options.worker);
      return worker.then
          ? worker.then(function(worker){
              return init.call(_self, worker);
          })
          : init.call(this, worker);
  }
  
  if(SUPPORT_WORKER){
  
      register("add");
      register("append");
      register("search");
      register("update");
      register("remove");
      register("clear");
      register("export");
      register("import");
  
      if(SUPPORT_CACHE){
          WorkerIndex.prototype.searchCache = searchCache;
      }
  
      if(SUPPORT_ASYNC){
          apply_async(WorkerIndex.prototype);
      }
  }
  
  function register(key){
  
      WorkerIndex.prototype[key] = function(){
  
          const self = this;
          const args = [].slice.call(arguments);
          const arg = args[args.length - 1];
          let callback;
  
          if(typeof arg === "function"){
              callback = arg;
              args.pop();
          }
  
          const promise = new Promise(function(resolve){
              if(key === "export" && typeof args[0] === "function"){
                  // remove function handler
                  args[0] = null;
              }
              if(pid > 1e9) pid = 0;
              self.resolver[++pid] = resolve;
              self.worker.postMessage({
                  "task": key,
                  "id": pid,
                  "args": args
              });
          });
  
          if(callback){
              promise.then(callback);
              return this;
          }
          else{
              return promise;
          }
      };
  }
  
  function create(factory, is_node_js, worker_path){
  
      return is_node_js ?
          // if anyone asks me what JS has delivered the past 10 years,
          // those are the lines I definitively show up first ^^
          typeof module !== "undefined"
              // This eval will be removed when compiling
              // The issue is that this will not build by Closure Compiler
              ? (0,eval)('new(require("worker_threads")["Worker"])(__dirname+"/worker/node.js")')
              // this will need to remove in CommonJS builds,
              // otherwise the module is treated as ESM by Node.js automatic detection
              // the path src/worker/node.mjs is located at dist/node/node.mjs
              // The issue is that this will not build by Babel Compiler
              : import("worker_threads").then(function(worker){return new worker["Worker"](import.meta.dirname+"/worker/node.mjs")})
      :(
          factory ?
              new window.Worker(URL.createObjectURL(
                  new Blob(
                      ["onmessage=" + handler.toString()],
                      { "type": "text/javascript" }
                  )
              ))
          :
              new window.Worker(
                  typeof worker_path === "string"
                      ? worker_path
                      // when loaded from /src/ folder the worker file is located at /worker/worker.js
                      : import.meta.url.replace("/worker.js", "/worker/worker.js")
                                       .replace("flexsearch.bundle.module.min.js", "module/worker/worker.js")
                                       .replace("flexsearch.bundle.module.min.mjs", "module/worker/worker.js")/*"worker/worker.js"*/
                  , { type: "module" }
              )
      );
  }
  