<commit_before>;   Copyright (c) <NAME>. All rights reserved.
;   The use and distribution terms for this software are covered by the
;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;   which can be found in the file LICENSE at the root of this distribution.
;   By using this software in any fashion, you are agreeing to be bound by
;   the terms of this license.
;   You must not remove this notice, or any other, from this software.


(ns calfpath.route.uri-token-match
  "Internal namespace to implement URI-tokens based URI match."
  (:require
    [clojure.string :as string]
    [calfpath.type :as t])
  #?(:clj (:import
            [java.util HashMap]
            [clojure.lang Associative]
            [calfpath.route UriTokenContext])))


;; ----- URI and URI-template parsing -----


(defn parse-uri-tokens*
  [uri]
  (let [uri-len (count uri)]
    (loop [tcoll (transient [])
           token ""
           index 1]
      (if (< index uri-len)
        (let [ch (get uri index)]
          (if (= ch \/)
            (recur (conj! tcoll token) "" (unchecked-inc index))
            (recur tcoll (str token ch) (unchecked-inc index))))
        (persistent! (conj! tcoll token))))))


(defn parse-uri-tokens
  [uri]
  #?(:cljs (parse-uri-tokens* uri)
      :clj (UriTokenContext/parseUriTokens uri)))


(defn parse-uri-template
  "Given a URI pattern string, e.g. '/user/:id/profile/:descriptor/' parse it and return a vector of alternating string
  and keyword tokens, e.g. [['user' :id 'profile' :descriptor ''] false]. The marker char is ':'."
  [uri-pattern]
  (let [pattern-length  (count uri-pattern)
        [path partial?] (if (and (> pattern-length 1)
                              (string/ends-with? uri-pattern "*"))
                          [(subs uri-pattern 0 (dec pattern-length)) true]  ; chop off last wildcard char
                          [uri-pattern false])
        tokens (cond
                 (= "" path) []
                 (string/starts-with?
                   path "/") (parse-uri-tokens path)
                 :otherwise  (throw (ex-info (str "Expected URI pattern to start with '/', but found "
                                               (pr-str path)) {:path path})))]
    (as-> tokens <>
      (mapv (fn [t]
              (if (string/starts-with? t ":")
                (keyword (subs t 1))
                t)) <>)
      (vector <> partial?))))


;; ----- request state management -----


(defprotocol ITokenContext
  (-get-uri-tokens   [this])
  (-get-path-params  [this])<commit_msg>add docstring for uri-token-match/parse-uri-tokens<commit_after>;   Copyright (c) <NAME>. All rights reserved.
;   The use and distribution terms for this software are covered by the
;   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
;   which can be found in the file LICENSE at the root of this distribution.
;   By using this software in any fashion, you are agreeing to be bound by
;   the terms of this license.
;   You must not remove this notice, or any other, from this software.


(ns calfpath.route.uri-token-match
  "Internal namespace to implement URI-tokens based URI match."
  (:require
    [clojure.string :as string]
    [calfpath.type :as t])
  #?(:clj (:import
            [java.util HashMap]
            [clojure.lang Associative]
            [calfpath.route UriTokenContext])))


;; ----- URI and URI-template parsing -----


(defn parse-uri-tokens*
  [uri]
  (let [uri-len (count uri)]
    (loop [tcoll (transient [])
           token ""
           index 1]
      (if (< index uri-len)
        (let [ch (get uri index)]
          (if (= ch \/)
            (recur (conj! tcoll token) "" (unchecked-inc index))
            (recur tcoll (str token ch) (unchecked-inc index))))
        (persistent! (conj! tcoll token))))))


(defn parse-uri-tokens
  [uri]
  #?(:cljs (parse-uri-tokens* uri)
      :clj (UriTokenContext/parseUriTokens uri)))


(defn parse-uri-template
  "Given a URI pattern string, e.g. '/user/:id/profile/:descriptor/' parse it and return a vector [tokens partial?] of
  string and keyword tokens, e.g. [['user' :id 'profile' :descriptor ''] false]. The marker char is ':'."
  [uri-pattern]
  (let [pattern-length  (count uri-pattern)
        [path partial?] (if (and (> pattern-length 1)
                              (string/ends-with? uri-pattern "*"))
                          [(subs uri-pattern 0 (dec pattern-length)) true]  ; chop off last wildcard char
                          [uri-pattern false])
        tokens (cond
                 (= "" path) []
                 (string/starts-with?
                   path "/") (parse-uri-tokens path)
                 :otherwise  (throw (ex-info (str "Expected URI pattern to start with '/', but found "
                                               (pr-str path)) {:path path})))]
    (as-> tokens <>
      (mapv (fn [t]
              (if (string/starts-with? t ":")
                (keyword (subs t 1))
                t)) <>)
      (vector <> partial?))))


;; ----- request state management -----


(defprotocol ITokenContext
  (-get-uri-tokens   [this])
  (-get-path-params  [this])
{'fraction_non_alphanumeric': 0.13818463324946778, 'fraction_numerical': 0.0030965744145539, 'mean_word_length': 2.0186915887850465, 'pattern_counts': {'":': 2, '<': 13, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2543616', 'n_tokens_mistral': 1568, 'n_tokens_neox': 1512, 'n_words': 505}