|
400 | 400 | (defn remove-multiple-non-indenting-spaces [form]
|
401 | 401 | (transform form edit-all non-indenting-whitespace? replace-with-one-space))
|
402 | 402 |
|
| 403 | +(def ^:private ns-reference-symbols |
| 404 | + #{:import :require :require-macros :use}) |
| 405 | + |
| 406 | +(defn- ns-reference? [zloc] |
| 407 | + (and (z/list? zloc) |
| 408 | + (some-> zloc z/up ns-form?) |
| 409 | + (-> zloc z/sexpr first ns-reference-symbols))) |
| 410 | + |
| 411 | +(defn- re-indexes [re s] |
| 412 | + (let [matcher #?(:clj (re-matcher re s) |
| 413 | + :cljs (js/RegExp. (.-source re) "g")) |
| 414 | + next-match #?(:clj #(when (.find matcher) |
| 415 | + [(.start matcher) (.end matcher)]) |
| 416 | + :cljs #(when-let [result (.exec matcher s)] |
| 417 | + [(.-index result) (.-lastIndex matcher)]))] |
| 418 | + (take-while some? (repeatedly next-match)))) |
| 419 | + |
| 420 | +(defn- re-seq-matcher [re charmap coll] |
| 421 | + {:pre (every? charmap coll)} |
| 422 | + (let [s (apply str (map charmap coll)) |
| 423 | + v (vec coll)] |
| 424 | + (for [[start end] (re-indexes re s)] |
| 425 | + {:value (subvec v start end) |
| 426 | + :start start |
| 427 | + :end end}))) |
| 428 | + |
| 429 | +(defn- find-elements-with-comments [nodes] |
| 430 | + (re-seq-matcher #"(CNS*)*E(S*C)?" |
| 431 | + #(case (n/tag %) |
| 432 | + (:whitespace :comma) \S |
| 433 | + :comment \C |
| 434 | + :newline \N |
| 435 | + \E) |
| 436 | + nodes)) |
| 437 | + |
| 438 | +(defn- splice-into [coll splices] |
| 439 | + (letfn [(splice [v i splices] |
| 440 | + (when-let [[{:keys [value start end]} & splices] (seq splices)] |
| 441 | + (lazy-cat (subvec v i start) value (splice v end splices))))] |
| 442 | + (splice (vec coll) 0 splices))) |
| 443 | + |
| 444 | +(defn- add-newlines-after-comments [nodes] |
| 445 | + (mapcat #(if (n/comment? %) [% (n/newlines 1)] [%]) nodes)) |
| 446 | + |
| 447 | +(defn- remove-newlines-after-comments [nodes] |
| 448 | + (mapcat #(when-not (and %1 (n/comment? %1) (n/linebreak? %2)) [%2]) |
| 449 | + (cons nil nodes) |
| 450 | + nodes)) |
| 451 | + |
| 452 | +(defn- sort-node-arguments-by [f nodes] |
| 453 | + (let [nodes (add-newlines-after-comments nodes) |
| 454 | + args (rest (find-elements-with-comments nodes)) |
| 455 | + sorted (sort-by f (map :value args))] |
| 456 | + (->> sorted |
| 457 | + (map #(assoc %1 :value %2) args) |
| 458 | + (splice-into nodes) |
| 459 | + (remove-newlines-after-comments)))) |
| 460 | + |
| 461 | +(defn- update-children [zloc f] |
| 462 | + (let [node (z/node zloc)] |
| 463 | + (z/replace zloc (n/replace-children node (f (n/children node)))))) |
| 464 | + |
| 465 | +(defn- nodes-string [nodes] |
| 466 | + (apply str (map n/string nodes))) |
| 467 | + |
| 468 | +(defn- remove-node-metadata [nodes] |
| 469 | + (mapcat #(if (= (n/tag %) :meta) |
| 470 | + (rest (n/children %)) |
| 471 | + [%]) |
| 472 | + nodes)) |
| 473 | + |
| 474 | +(defn- node-sort-string [nodes] |
| 475 | + (-> (remove (some-fn n/comment? n/whitespace?) nodes) |
| 476 | + (remove-node-metadata) |
| 477 | + (nodes-string) |
| 478 | + (str/replace #"[\[\]\(\)\{\}]" "") |
| 479 | + (str/trim))) |
| 480 | + |
| 481 | +(defn sort-arguments [zloc] |
| 482 | + (update-children zloc #(sort-node-arguments-by node-sort-string %))) |
| 483 | + |
| 484 | +(defn sort-ns-references [form] |
| 485 | + (transform form edit-all ns-reference? sort-arguments)) |
| 486 | + |
403 | 487 | (def default-options
|
404 | 488 | {:indentation? true
|
405 | 489 | :insert-missing-whitespace? true
|
|
408 | 492 | :remove-surrounding-whitespace? true
|
409 | 493 | :remove-trailing-whitespace? true
|
410 | 494 | :split-keypairs-over-multiple-lines? false
|
| 495 | + :sort-ns-references? false |
411 | 496 | :indents default-indents
|
412 | 497 | :alias-map {}})
|
413 | 498 |
|
|
417 | 502 | ([form opts]
|
418 | 503 | (let [opts (merge default-options opts)]
|
419 | 504 | (-> form
|
| 505 | + (cond-> (:sort-ns-references? opts) |
| 506 | + sort-ns-references) |
420 | 507 | (cond-> (:split-keypairs-over-multiple-lines? opts)
|
421 | 508 | (split-keypairs-over-multiple-lines))
|
422 | 509 | (cond-> (:remove-consecutive-blank-lines? opts)
|
|
0 commit comments