-
Notifications
You must be signed in to change notification settings - Fork 223
Add string schema properties #587
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
09c6258
dc8eeda
82a3c4e
402034f
3df68a1
7973683
b4c04a7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -570,6 +570,79 @@ | |
| (when-let [ns-name (some-> properties :namespace name)] | ||
| (fn [x] (= (namespace x) ns-name)))) | ||
|
|
||
| ;; | ||
| ;; string schema helpers | ||
| ;; | ||
|
|
||
| #?(:cljs (defn -numeric-char? [c] (and (< 47 c) (< c 58)))) | ||
| #?(:cljs (defn -upper-alpha-char? [c] (and (< 64 c) (< c 91)))) | ||
| #?(:cljs (defn -lower-alpha-char? [c] (and (< 96 c) (< c 123)))) | ||
| #?(:cljs (defn -letter? [c] (or (-lower-alpha-char? c) (-upper-alpha-char? c)))) | ||
| #?(:cljs (defn -alphanumeric? [c] (or (-letter? c) (-numeric-char? c)))) | ||
|
|
||
| (defn -charset-predicate | ||
| [o] | ||
| (case o | ||
| :digit #?(:clj #(Character/isDigit ^char %) :cljs -numeric-char?) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Btw. there is both char and int versions of the predicates in Java: https://docs.oracle.com/javase/7/docs/api/java/lang/Character.html#isLetter(char) The int version supports unicode characters.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay, this is probably fine. Char supports 0-65535 so it is enough to support unicode range 0x0000 - 0xFFFF. Clojure characters don't support supplementary char ranges either. Though strings support: 0x2F81A: \冬 (.codePointAt "冬" 0) (char (.codePointAt "冬" 0)) (Character/isLetter (int 0x2F81A)) (int (.charAt "冬" 0))
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. JS charCodeAt works the same as JVM charAt.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Problem is I'm using
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 0x2F81A (which is \⾁) is supported under the 12161 unicode: (link) (int \⾁)
=> 12161Same with all other unicode characters: (char 8809)
=> \≩
(char 508)
=> \Ǽ
(int \Ǽ)
=> 508
(int \≩)
=> 8809
(int \Θ)
=> 920
(char 33071)
=> \脯 |
||
| :letter #?(:clj #(Character/isLetter ^char %) :cljs -letter?) | ||
| (:alphanumeric :letter-or-digit) #?(:clj #(Character/isLetterOrDigit ^char %) :cljs -alphanumeric?) | ||
| :alphabetic #?(:clj #(Character/isAlphabetic (int %)) :cljs -letter?) | ||
| (cond | ||
| (set? o) (miu/-some-pred (mapv -charset-predicate o)) | ||
| (char? o) #?(:clj #(= ^char o %) :cljs (let [i (.charCodeAt o 0)] #(= i %))) | ||
| :else (eval o)))) | ||
|
|
||
| (defn string-char-predicate | ||
| [p] | ||
| (fn charset-pred ^Boolean [^String s] | ||
| (let [n #?(:clj (.length s) :cljs (.-length s))] | ||
| (loop [i 0] | ||
| (if (= i n) | ||
| true | ||
| (if (p #?(:clj (.charAt s (unchecked-int i)) | ||
| :cljs (.charCodeAt s (unchecked-int i)))) | ||
| (recur (unchecked-inc i)) | ||
| false)))))) | ||
|
|
||
| #?(:clj | ||
| (defn find-blank-method | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we could lift the minimum java to 11 and remove this?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a huge breaking change for users. Sadly, there's still plenty of Java 8 in the world and we must accommodate
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ikitommi Definitely ~half of our work projects are still on Java 8 |
||
| [] | ||
| (try | ||
| (.getMethod String "isBlank" (into-array Class [])) | ||
| #(.isBlank ^String %) | ||
| (catch Exception _ | ||
| (require 'clojure.string) | ||
| clojure.string/blank?)))) | ||
|
|
||
| #?(:clj (def blank? (find-blank-method)) | ||
| :cljs (defn blank? [^String s] (zero? (.-length (.trim s))))) | ||
|
|
||
| (defn -string-predicates | ||
| ([{:keys [charset pattern non-blank]}] | ||
| (let [pattern | ||
| (when pattern | ||
| (let [pattern (re-pattern pattern)] | ||
| #?(:clj #(.find (.matcher ^Pattern pattern ^String %)) | ||
| :cljs #(boolean (re-find pattern %))))) | ||
| charset | ||
| (when charset | ||
| (let [p (-charset-predicate charset)] | ||
| (string-char-predicate p))) | ||
| non-blank (when non-blank #(not (blank? %)))] | ||
| (-> non-blank | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is the [:string {:non-blank true}]
[:string {:min 1}]
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. valid min 1 string:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be solved by transformers, but users can certainly want to specify they want a string with minimum length which is not blank. Blank in this case is a superset of empty, which I almost missed in the beginning |
||
| (miu/-maybe-and charset) | ||
| (miu/-maybe-and pattern))))) | ||
|
|
||
| (defn -string-property-pred | ||
| [] | ||
| (fn [properties] | ||
| (miu/-maybe-and | ||
| ((-min-max-pred | ||
| #?(:clj #(.length ^String %) | ||
| :cljs #(.-length ^String %))) | ||
| properties) | ||
| (-string-predicates properties)))) | ||
|
|
||
| ;; | ||
| ;; Schemas | ||
| ;; | ||
|
|
@@ -625,7 +698,7 @@ | |
|
|
||
| (defn -nil-schema [] (-simple-schema {:type :nil, :pred nil?})) | ||
| (defn -any-schema [] (-simple-schema {:type :any, :pred any?})) | ||
| (defn -string-schema [] (-simple-schema {:type :string, :pred string?, :property-pred (-min-max-pred count)})) | ||
| (defn -string-schema [] (-simple-schema {:type :string, :pred string?, :property-pred (-string-property-pred)})) | ||
| (defn -int-schema [] (-simple-schema {:type :int, :pred int?, :property-pred (-min-max-pred nil)})) | ||
| (defn -double-schema [] (-simple-schema {:type :double, :pred double?, :property-pred (-min-max-pred nil)})) | ||
| (defn -boolean-schema [] (-simple-schema {:type :boolean, :pred boolean?})) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -136,7 +136,18 @@ | |
| (defmethod accept :nil [_ _ _ _] {:type "null"}) | ||
|
|
||
| (defmethod accept :string [_ schema _ _] | ||
| (merge {:type "string"} (-> schema m/properties (select-keys [:min :max]) (set/rename-keys {:min :minLength, :max :maxLength})))) | ||
| (let [props (-> schema m/properties) | ||
| pattern (case (:charset props) | ||
| :digit "^[0-9]*$" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These patterns don't match the Character predicates, the predicates allow other ranges, e.g.: '\u0030' through '\u0039', ISO-LATIN-1 digits ('0' through '9') There are some classes in at least JVM Pattern which might match the predicates, but not sure if there are equivelents to all, and what does JS support. Listing all the ranges might work for some cases.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can use unicode ranges, this works: |
||
| :letter "^[a-zA-Z]*$" | ||
| (:alphanumeric :letter-or-digit) "^[a-zA-Z0-9]*$" | ||
| nil) | ||
| props (cond-> props pattern (assoc :pattern pattern))] | ||
| (merge | ||
| {:type "string"} | ||
| (-> props | ||
| (select-keys [:min :max :pattern]) | ||
| (set/rename-keys {:min :minLength, :max :maxLength}))))) | ||
|
|
||
| (defmethod accept :int [_ schema _ _] | ||
| (merge {:type "integer"} (-> schema m/properties (select-keys [:min :max]) (set/rename-keys {:min :minimum, :max :maximum})))) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These checks work differently than the JVM versions.