<commit_before>(ns puppetlabs.trapperkeeper.services-internal
  (:import (clojure.lang IFn))
  (:require [clojure.walk :refer [postwalk]]
            [clojure.set :refer [difference union intersection]]
            [plumbing.core :refer [fnk]]
            [schema.core :as schema]
            [puppetlabs.kitchensink.core :as ks]))

(def ServiceSymbol
  "For internal use only; this schema gives us a way to differentiate between
  a symbol representing the name of a service, and a symbol representing the
  name of the *protocol* for a service.  This is necessary because the `service`
  macro accepts both as optional leading arguments when defining a service."
  {:service-symbol (schema/pred symbol?)})

(defn protocol?
  "A predicate to determine whether or not an object is a protocol definition"
  [p]
  ;; there might be a better way to do this, but it seems to work
  (and (map? p)
       (contains? p :on)
       (instance? Class (resolve (:on p)))))

(defn fn-sig?
  "A predicate to determine whether or not a form represents a valid function signature
  in the context of a service definition."
  [sig]
  (and (seq? sig)
       (> (count sig) 1)
       (symbol? (first sig))
       (vector? (second sig))))

(defn fns-map?
  "A predicate to determine whether or not an object is a map of fns, as
  used internally by the `service` macro"
  [m]
  (and (map? m)
       (every? keyword? (keys m))
       (every? seq? (vals m))
       (every? fn-sig? (apply concat (vals m)))))

(defn validate-fn-forms!
  "Validate that all of the fn forms in the service body appear to be
  valid fn definitions.  Throws `IllegalArgumentException` otherwise."
  [fns]
  {:pre [(seq? fns)]
   :post [(map? %)
          (= #{:fns} (set (keys %)))]}
  (if (every? seq? fns)
    {:fns fns}
    (throw (IllegalArgumentException.
             (format
               "Invalid service definition; expected function definitions following dependency list, invalid value: '\"hi\"'"
               (pr-str (first (filter #(not (seq? %)) fns))))))))

(defn validate-deps-form!
  "Validate that the service body has a valid dependency specification.
  Throws `IllegalArgumentException` otherwise."
  [forms]
  {:pre [(seq? forms)]
   :post [(map? %)
          (= #{:fns :dependencies} (set (keys %)))]}
  (let [f (first forms)]
    (if (vector? f)
      (merge {:dependencies f} (validate-fn-forms! (rest forms)))
      (throw (IllegalArgumentException.
               (format
                 "Invalid service definition; expected dependency list following protocol, found: '%s'"
                 (pr-str f)))))))

(defn find-prot-and-deps-forms!
  "Given the forms passed to the service macro, find the service protocol
  (if one is provided), the dependency list, and the function definitions.
  Throws `IllegalArgumentException` if the forms do not represent a valid service.
  Returns a map containing the protocol, dependency list, and fn forms."
  [forms]
  {:pre [(seq? forms)]
   :post [(map? %)
          (= #{:fns :dependencies :service-protocol-sym} (set (keys %)))
          ((some-fn nil? symbol?) (:service-protocol-sym %))
          (vector? (:dependencies %))
          (seq? (:fns %))]}
  (let [f (first forms)]
    (cond
      (symbol? f) (merge {:service-protocol-sym f} (validate-deps-form! (rest forms)))
      (vector? f) (merge {:service-protocol-sym nil} (validate-deps-form! forms))
      :else (throw (IllegalArgumentException.
                     (format
                       "Invalid service definition; first form must be protocol or dependency list; found '%s'"
                       (pr-str f)))))))

(defn parse-service-forms!*
  "Given the forms passed to the service macro, find the service symbol (if one
  is provided), the service protocol (if one is provided), the dependency list,
  and the function definitions.  Throws `IllegalArgumentException` if the forms
  do not represent a valid service.  Returns a vector containing the symbol,
  protocol, dependency list, and fn forms."
  [forms]
  {:pre [(seq? forms)]
   :post [(map? %)
          (= #{:fns :dependencies :service-protocol-sym :service-sym}
             (set (keys %)))
          ((some-fn nil? symbol?) (:service-sym %))<commit_msg>(TK-18) Remove duplicate precondition<commit_after>(ns puppetlabs.trapperkeeper.services-internal
  (:import (clojure.lang IFn))
  (:require [clojure.walk :refer [postwalk]]
            [clojure.set :refer [difference union intersection]]
            [plumbing.core :refer [fnk]]
            [schema.core :as schema]
            [puppetlabs.kitchensink.core :as ks]))

(def ServiceSymbol
  "For internal use only; this schema gives us a way to differentiate between
  a symbol representing the name of a service, and a symbol representing the
  name of the *protocol* for a service.  This is necessary because the `service`
  macro accepts both as optional leading arguments when defining a service."
  {:service-symbol (schema/pred symbol?)})

(defn protocol?
  "A predicate to determine whether or not an object is a protocol definition"
  [p]
  ;; there might be a better way to do this, but it seems to work
  (and (map? p)
       (contains? p :on)
       (instance? Class (resolve (:on p)))))

(defn fn-sig?
  "A predicate to determine whether or not a form represents a valid function signature
  in the context of a service definition."
  [sig]
  (and (seq? sig)
       (> (count sig) 1)
       (symbol? (first sig))
       (vector? (second sig))))

(defn fns-map?
  "A predicate to determine whether or not an object is a map of fns, as
  used internally by the `service` macro"
  [m]
  (and (map? m)
       (every? keyword? (keys m))
       (every? seq? (vals m))
       (every? fn-sig? (apply concat (vals m)))))

(defn validate-fn-forms!
  "Validate that all of the fn forms in the service body appear to be
  valid fn definitions.  Throws `IllegalArgumentException` otherwise."
  [fns]
  {:pre [(seq? fns)]
   :post [(map? %)
          (= #{:fns} (set (keys %)))]}
  (if (every? seq? fns)
    {:fns fns}
    (throw (IllegalArgumentException.
             (format
               "Invalid service definition; expected function definitions following dependency list, invalid value: '\"hi\"'"
               (pr-str (first (filter #(not (seq? %)) fns))))))))

(defn validate-deps-form!
  "Validate that the service body has a valid dependency specification.
  Throws `IllegalArgumentException` otherwise."
  [forms]
  {:pre [(seq? forms)]
   :post [(map? %)
          (= #{:fns :dependencies} (set (keys %)))]}
  (let [f (first forms)]
    (if (vector? f)
      (merge {:dependencies f} (validate-fn-forms! (rest forms)))
      (throw (IllegalArgumentException.
               (format
                 "Invalid service definition; expected dependency list following protocol, found: '%s'"
                 (pr-str f)))))))

(defn find-prot-and-deps-forms!
  "Given the forms passed to the service macro, find the service protocol
  (if one is provided), the dependency list, and the function definitions.
  Throws `IllegalArgumentException` if the forms do not represent a valid service.
  Returns a map containing the protocol, dependency list, and fn forms."
  [forms]
  {:pre [(seq? forms)]
   :post [(map? %)
          (= #{:fns :dependencies :service-protocol-sym} (set (keys %)))
          ((some-fn nil? symbol?) (:service-protocol-sym %))
          (vector? (:dependencies %))
          (seq? (:fns %))]}
  (let [f (first forms)]
    (cond
      (symbol? f) (merge {:service-protocol-sym f} (validate-deps-form! (rest forms)))
      (vector? f) (merge {:service-protocol-sym nil} (validate-deps-form! forms))
      :else (throw (IllegalArgumentException.
                     (format
                       "Invalid service definition; first form must be protocol or dependency list; found '%s'"
                       (pr-str f)))))))

(defn parse-service-forms!*
  "Given the forms passed to the service macro, find the service symbol (if one
  is provided), the service protocol (if one is provided), the dependency list,
  and the function definitions.  Throws `IllegalArgumentException` if the forms
  do not represent a valid service.  Returns a vector containing the symbol,
  protocol, dependency list, and fn forms."
  [forms]
  {:pre [(seq? forms)]
   :post [(map? %)
          (= #{:fns :dependencies :service-protocol-sym :service-sym}
             (set (keys %)))
{'fraction_non_alphanumeric': 0.12422729434141702, 'fraction_numerical': 0.00047551117451260106, 'mean_word_length': 2.9203168685927308, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1210661', 'n_tokens_mistral': 2515, 'n_tokens_neox': 2425, 'n_words': 965}