Просмотр исходного кода

convert fractional-index js to cljs

Tienson Qin 1 год назад
Родитель
Сommit
cdf546dce7

+ 158 - 0
deps/common/src/logseq/common/fractional_index.cljs

@@ -0,0 +1,158 @@
+(ns logseq.common.fractional-index
+  "Fractional indexing to create an ordering that can be used for Realtime Editing of Ordered Sequences")
+
+;; Original code from https://github.com/rocicorp/fractional-indexing,
+;; It's converted to cljs by using AI.
+
+(def base-62-digits
+  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
+
+(defn char->int
+  [^js c]
+  (.charCodeAt c))
+
+(defn get-integer-length
+  [head]
+  (let [head-char (char->int head)]
+    (cond
+      (and (>= head-char (char->int \a)) (<= head-char (char->int \z)))
+      (+ (- head-char (char->int \a)) 2)
+
+      (and (>= head-char (char->int \A)) (<= head-char (char->int \Z)))
+      (+ (- (char->int \Z) head-char) 2)
+
+      :else
+      (throw (js/Error. (str "invalid order key head: " head))))))
+
+(defn validate-integer
+  [int]
+  (when-not (= (count int) (get-integer-length (first int)))
+    (throw (js/Error. (str "invalid integer part of order key: " int)))))
+
+(defn get-integer-part
+  [key]
+  (let [integer-part-length (get-integer-length (first key))]
+    (when (> integer-part-length (count key))
+      (throw (js/Error. (str "invalid order key: " key))))
+    (subs key 0 integer-part-length)))
+
+(defn validate-order-key
+  [key digits]
+  (when (= key (str "A" (repeat 26 (first digits))))
+    (throw (js/Error. (str "invalid order key: " key))))
+  (let [i (get-integer-part key)
+        f (subs key (count i))]
+    (when (= (last f) (first digits))
+      (throw (js/Error. (str "invalid order key: " key))))))
+
+(defn increment-integer
+  [x digits]
+  (validate-integer x)
+  (let [[head & digs] (seq x)
+        [carry digs] (reduce
+                      (fn [[_ digs] dig]
+                        (let [d (inc (.indexOf digits dig))]
+                          (if (= d (count digits))
+                            [true (conj digs (first digits))]
+                            [false (conj digs (nth digits d))])))
+                      [true []]
+                      (reverse digs))]
+    (if carry
+      (cond
+        (= head \Z) (str "a" (first digits))
+        (= head \z) nil
+        :else (let [h (char (inc (.charCodeAt head 0)))
+                    digs (if (> (compare h \a) 0)
+                           (conj digs (first digits))
+                           (pop digs))]
+                (str h (apply str digs))))
+      (str head (apply str digs)))))
+
+(defn decrement-integer
+  [x digits]
+  (validate-integer x)
+  (let [[head & digs] (seq x)
+        [borrow digs] (reduce
+                       (fn [[_ digs] dig]
+                         (let [d (dec (.indexOf digits dig))]
+                           (if (= d -1)
+                             [true (conj digs (last digits))]
+                             [false (conj digs (nth digits d))])))
+                       [true []]
+                       (reverse digs))]
+    (if borrow
+      (cond
+        (= head \a) (str "Z" (last digits))
+        (= head \A) nil
+        :else (let [h (char (- (.charCodeAt head 0) 1))
+                    digs (if (< (compare h \Z) 0)
+                           (conj digs (last digits))
+                           (pop digs))]
+                (str h (apply str digs))))
+      (str head (apply str digs)))))
+
+(defn midpoint
+  [a b digits]
+  (let [zero (first digits)]
+    (when (and b (or (>= (compare a b) 0) (= (last a) zero) (= (last b) zero)))
+      (throw (js/Error. (str a " >= " b " or trailing zero"))))
+    (let [n (when b
+              (first (keep-indexed (fn [i _c] (when-not (= (nth a i zero) (nth b i)) i)) b)))]
+      (if (> n 0)
+        (str (subs b 0 n) (midpoint (subs a n) (subs b n) digits))
+        (let [digit-a (if a (.indexOf digits (first a)) 0)
+              digit-b (if b (.indexOf digits (first b)) (count digits))]
+          (if (> (- digit-b digit-a) 1)
+            (str (nth digits (Math/round (* 0.5 (+ digit-a digit-b)))))
+            (if (and b (> (count b) 1))
+              (subs b 0 1)
+              (str (nth digits digit-a) (midpoint (subs a 1) nil digits)))))))))
+
+(defn generate-key-between
+  [a b & {:keys [digits]
+          :or {digits base-62-digits}}]
+  (when a (validate-order-key a digits))
+  (when b (validate-order-key b digits))
+  (when (and a b (>= (compare a b) 0))
+    (throw (js/Error. (str a " >= " b))))
+  (cond
+    (nil? a) (if (nil? b)
+               (str "a" (first digits))
+               (let [ib (get-integer-part b)
+                     fb (subs b (count ib))]
+                 (if (= ib (str "A" (apply str (repeat 26 (first digits)))))
+                   (str ib (midpoint "" fb digits))
+                   (if (< (compare ib b) 0)
+                     ib
+                     (let [res (decrement-integer ib digits)]
+                       (if (nil? res)
+                         (throw (js/Error. "cannot decrement any more"))
+                         res))))))
+    (nil? b) (let [ia (get-integer-part a)
+                   fa (subs a (count ia))
+                   i (increment-integer ia digits)]
+               (if (nil? i)
+                 (str ia (midpoint fa nil digits))
+                 i))
+    :else (let [ia (get-integer-part a)
+                fa (subs a (count ia))
+                ib (get-integer-part b)
+                fb (subs b (count ib))]
+            (if (= ia ib)
+              (str ia (midpoint fa fb digits))
+              (let [i (increment-integer ia digits)]
+                (if (nil? i)
+                  (throw (js/Error. "cannot increment any more"))
+                  (if (< (compare i b) 0) i (str ia (midpoint fa nil digits)))))))))
+
+(defn generate-n-keys-between
+  [a b n & {:keys [digits]
+            :or {digits base-62-digits}}]
+  (cond
+    (= n 0) []
+    (= n 1) [(generate-key-between a b digits)]
+    :else (let [c (generate-key-between a b digits)]
+            (concat
+             (generate-n-keys-between a c (Math/floor (/ n 2)) digits)
+             [c]
+             (generate-n-keys-between c b (- n (Math/floor (/ n 2)) 1) digits)))))

+ 1 - 2
deps/db/package.json

@@ -6,8 +6,7 @@
     "@logseq/nbb-logseq": "logseq/nbb-logseq#feat-db-v11"
   },
   "dependencies": {
-    "better-sqlite3": "9.3.0",
-    "fractional-indexing": "^3.2.0"
+    "better-sqlite3": "9.3.0"
   },
   "scripts": {
     "test": "yarn nbb-logseq -cp test -m nextjournal.test-runner"

+ 4 - 7
deps/db/src/logseq/db/frontend/order.cljs

@@ -1,7 +1,6 @@
 (ns logseq.db.frontend.order
   "Use fractional-indexing order for blocks/properties/closed values/etc."
-  (:require ["fractional-indexing" :as index]
-            [goog.object :as gobj]
+  (:require [logseq.common.fractional-index :as index]
             [datascript.core :as d]))
 
 (defonce *max-key (atom nil))
@@ -16,7 +15,7 @@
   ([end]
    (gen-key @*max-key end))
   ([start end]
-   (let [k ((gobj/get index "generateKeyBetween") start end)]
+   (let [k (index/generate-key-between start end)]
     (reset-max-key! k)
     k)))
 
@@ -35,8 +34,6 @@
 (comment
   (defn gen-n-keys
     [n start end]
-    (let [ks (js->clj ((gobj/get index "generateNKeysBetween") start end n))]
+    (let [ks (index/generate-n-keys-between start end n)]
       (reset! *max-key (last ks))
-      ks))
-
-  )
+      ks)))

+ 0 - 5
deps/db/yarn.lock

@@ -84,11 +84,6 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
   integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
 
-fractional-indexing@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/fractional-indexing/-/fractional-indexing-3.2.0.tgz#1193e63d54ff4e0cbe0c79a9ed6cfbab25d91628"
-  integrity sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==
-
 fs-constants@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"

+ 0 - 1
package.json

@@ -123,7 +123,6 @@
         "electron": "27.1.3",
         "electron-dl": "3.3.0",
         "emoji-mart": "^5.5.2",
-        "fractional-indexing": "^3.2.0",
         "fs": "0.0.1-security",
         "fs-extra": "9.1.0",
         "fuse.js": "6.4.6",

+ 0 - 5
yarn.lock

@@ -3254,11 +3254,6 @@ fraction.js@^4.3.6:
   resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d"
   integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==
 
-fractional-indexing@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/fractional-indexing/-/fractional-indexing-3.2.0.tgz#1193e63d54ff4e0cbe0c79a9ed6cfbab25d91628"
-  integrity sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==
-
 fragment-cache@^0.2.1:
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"