Skip to content

Commit 7532c8d

Browse files
committed
feat: java and typescript generation draft
1 parent a45a45b commit 7532c8d

File tree

5 files changed

+449
-4
lines changed

5 files changed

+449
-4
lines changed

src/aidbox_sdk/cli.clj

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
["-h" "--help"]])
1212

1313
(def supported-commands #{"generate"})
14-
(def supported-languages #{"dotnet" "python"})
14+
(def supported-languages #{"dotnet" "python" "typescript" "java"})
1515

1616
(defn validate-args [args]
1717
(let [[command target-language input] args]

src/aidbox_sdk/core.clj

+4-3
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55
[aidbox-sdk.converter :as converter]
66
[aidbox-sdk.fhir :as fhir]
77
[aidbox-sdk.generator :as generator]
8+
[aidbox-sdk.generator.java :as java]
89
[aidbox-sdk.generator.dotnet :as dotnet]
9-
[aidbox-sdk.generator.helpers :refer [vector->map]]
1010
[aidbox-sdk.generator.python :as python]
11+
[aidbox-sdk.generator.typescript :as typescript]
1112
[aidbox-sdk.schema :as importer]
1213
[clojure.java.io :as io]))
1314

@@ -49,8 +50,8 @@
4950
(case lang
5051
:dotnet dotnet/generator
5152
:python python/generator
52-
#_#_#_#_:typescript typescript/generator
53-
:java java/generator))
53+
:typescript typescript/generator
54+
:java java/generator))
5455

5556
(defn generate! [target-language input options]
5657
(let [output-dir (io/file (:output-dir options))

src/aidbox_sdk/generator/java.clj

+165
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
(ns aidbox-sdk.generator.java
2+
(:require
3+
[aidbox-sdk.generator.helpers :refer [->pascal-case uppercase-first-letter]]
4+
[aidbox-sdk.generator.utils :as u]
5+
[clojure.java.io :as io]
6+
[clojure.string :as str])
7+
(:import
8+
[aidbox_sdk.generator CodeGenerator]))
9+
10+
(defn datatypes-file-path []
11+
(io/file "datatypes.java"))
12+
13+
(defn package->directory
14+
"Generates directory name from package name.
15+
16+
Example:
17+
hl7.fhir.r4.core -> hl7-fhir-r4-core"
18+
[x]
19+
(str/replace x #"[\.#]" "-"))
20+
21+
(defn url->resource-name [reference]
22+
(last (str/split (str reference) #"/")))
23+
24+
(defn class-name
25+
"Generate class name from schema url."
26+
[url]
27+
(uppercase-first-letter (url->resource-name url)))
28+
29+
(defn resource-file-path [ir-schema]
30+
(io/file (package->directory (:package ir-schema))
31+
(str (->pascal-case (:name ir-schema)) ".java")))
32+
33+
(defn ->lang-type [fhir-type]
34+
(case fhir-type
35+
;; Primitive Types
36+
"boolean" "boolean"
37+
"instant" "String"
38+
"time" "String"
39+
"date" "String"
40+
"dateTime" "String"
41+
"decimal" "float"
42+
43+
"integer" "int"
44+
"unsignedInt" "int"
45+
"positiveInt" "int"
46+
47+
"integer64" "int"
48+
"base64Binary" "String"
49+
50+
"uri" "String"
51+
"url" "String"
52+
"canonical" "String"
53+
"oid" "String"
54+
"uuid" "String"
55+
56+
"string" "String"
57+
"code" "String"
58+
"markdown" "String"
59+
"id" "String"
60+
61+
;; hardcoded just in case
62+
"Meta" "Meta"
63+
;; else
64+
fhir-type))
65+
66+
(defn generate-accessor [{:keys [name array required type base]}]
67+
(let [lang-type (->lang-type type)]
68+
(str
69+
(str "public " lang-type " get" (uppercase-first-letter name) "() {\n"
70+
u/indent "return " name ";"
71+
"\n}")
72+
"\n\n"
73+
(str "public void set" (uppercase-first-letter name) "(" lang-type " " name ") {\n"
74+
"this." name " = " name ";"
75+
"\n}"))))
76+
77+
(defn generate-property [{:keys [name array required type base]}]
78+
(let [lang-type (->lang-type type)
79+
type (if array
80+
(format "List<%s>" lang-type)
81+
lang-type)]
82+
(str "private " type " " name ";")))
83+
84+
(defn generate-class [ir-schema & [inner-classes]]
85+
(let [base-class (url->resource-name (:base ir-schema))
86+
schema-name (or (:url ir-schema) (:name ir-schema))
87+
class-name' (class-name schema-name)
88+
properties (->> (:elements ir-schema)
89+
(map generate-property)
90+
(remove nil?)
91+
(map u/add-indent)
92+
(str/join "\n"))
93+
94+
accessors (->> (:elements ir-schema)
95+
(map generate-accessor)
96+
(remove nil?)
97+
(map u/add-indent)
98+
(str/join "\n"))]
99+
(str "public class " class-name' " extends " base-class " {\n"
100+
(when (and inner-classes
101+
(seq inner-classes))
102+
"\n")
103+
(str/join "\n\n" (map #(->> % str/split-lines (map u/add-indent) (str/join "\n")) inner-classes))
104+
(when (and inner-classes
105+
(seq inner-classes))
106+
"\n")
107+
108+
properties
109+
"\n"
110+
accessors
111+
"\n}")))
112+
113+
(defn generate-deps [deps]
114+
(->> deps
115+
(map (fn [{:keys [module members]}]
116+
(if (seq members)
117+
(str "import { " (str/join ", " members) " } from '" module "';")
118+
(str "import " module ";"))))
119+
(str/join "\n")))
120+
121+
(defn generate-module
122+
[& {name' :name
123+
:keys [deps classes interfaces structs enums delegates]
124+
:or {classes []
125+
interfaces []
126+
structs []
127+
enums []
128+
delegates []}}]
129+
(->> (conj []
130+
(str "package " name' ";")
131+
(generate-deps deps)
132+
classes)
133+
(flatten)
134+
(str/join "\n\n")))
135+
136+
(defn generate-backbone-classes
137+
"Generates classes from schema's backbone elements."
138+
[ir-schema]
139+
(->> (ir-schema :backbone-elements)
140+
(map #(assoc % :base "BackboneElement"))
141+
(map generate-class)))
142+
143+
(defrecord JavaCodeGenerator []
144+
CodeGenerator
145+
(generate-datatypes [_ ir-schemas]
146+
[{:path (datatypes-file-path)
147+
:content (generate-module
148+
:deps []
149+
:classes (map (fn [ir-schema]
150+
(generate-class ir-schema
151+
(generate-backbone-classes ir-schema)))
152+
ir-schemas))}])
153+
(generate-resource-module [_ ir-schema]
154+
{:path (resource-file-path ir-schema)
155+
:content (generate-module
156+
{:name "aidbox.fhir.r4"
157+
:deps [{:module "aidbox.fhir.datatypes.*" :members []}
158+
{:module "java.util.List" :members []}]
159+
:classes [(generate-class ir-schema
160+
(generate-backbone-classes ir-schema))]})})
161+
(generate-search-params [_ ir-schemas] [])
162+
(generate-constraints [_ ir-schemas] [])
163+
(generate-sdk-files [this] []))
164+
165+
(def generator (->JavaCodeGenerator))
+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
(ns aidbox-sdk.generator.typescript
2+
(:require
3+
[aidbox-sdk.generator.helpers :refer [uppercase-first-letter ->pascal-case]]
4+
[aidbox-sdk.generator.utils :as u]
5+
[clojure.java.io :as io]
6+
[clojure.string :as str])
7+
(:import
8+
[aidbox_sdk.generator CodeGenerator]))
9+
10+
(defn package->directory
11+
"Generates directory name from package name.
12+
13+
Example:
14+
hl7.fhir.r4.core -> hl7-fhir-r4-core"
15+
[x]
16+
(str/replace x #"[\.#]" "-"))
17+
18+
(defn url->resource-name [reference]
19+
(last (str/split (str reference) #"/")))
20+
21+
(defn datatypes-file-path []
22+
(io/file "datatypes.ts"))
23+
24+
(defn resource-file-path [ir-schema]
25+
(io/file (package->directory (:package ir-schema))
26+
(str (->pascal-case (:name ir-schema)) ".ts")))
27+
28+
(defn constraint-file-path [ir-schema name]
29+
(io/file (package->directory (:package ir-schema))
30+
(str (->pascal-case (url->resource-name name)) ".ts")))
31+
32+
(defn search-param-filepath [ir-schema]
33+
(io/file "search" (str (:name ir-schema) "SearchParameters.ts")))
34+
35+
(defn ->lang-type [fhir-type]
36+
(case fhir-type
37+
;; Primitive Types
38+
"boolean" "boolean"
39+
"instant" "string"
40+
"time" "string"
41+
"date" "string"
42+
"dateTime" "string"
43+
"decimal" "number"
44+
45+
"integer" "number"
46+
"unsignedInt" "number"
47+
"positiveInt" "number"
48+
49+
"integer64" "number"
50+
"base64Binary" "string"
51+
52+
"uri" "string"
53+
"url" "string"
54+
"canonical" "string"
55+
"oid" "string"
56+
"uuid" "string"
57+
58+
"string" "string"
59+
"code" "string"
60+
"markdown" "string"
61+
"id" "string"
62+
63+
;; hardcoded just in case
64+
"Meta" "Meta"
65+
;; else
66+
fhir-type))
67+
68+
(defn class-name
69+
"Generate class name from schema url."
70+
[url]
71+
(uppercase-first-letter (url->resource-name url)))
72+
73+
(defn generate-property [{:keys [name array required type base]}]
74+
(let [lang-type (->lang-type type)]
75+
(str name (when-not required "?") ": " lang-type (when array "[]") ";")))
76+
77+
(defn generate-class
78+
"Generates Python class from IR (intermediate representation) schema."
79+
[ir-schema & [inner-classes]]
80+
(let [base-class (url->resource-name (:base ir-schema))
81+
schema-name (or (:url ir-schema) (:name ir-schema))
82+
class-name' (class-name schema-name)
83+
properties (->> (:elements ir-schema)
84+
(map generate-property)
85+
(remove nil?)
86+
(map u/add-indent)
87+
(str/join "\n"))]
88+
(str
89+
(when (seq inner-classes)
90+
(str (str/join "\n\n" inner-classes) "\n\n"))
91+
92+
"export class " class-name' " extends " base-class " {\n"
93+
properties
94+
"\n}")))
95+
96+
(defn generate-deps [deps]
97+
(->> deps
98+
(map (fn [{:keys [module members]}]
99+
(if (seq members)
100+
(str "import { " (str/join ", " members) " } from '" module "';")
101+
(str "import " module ";"))))
102+
(str/join "\n")))
103+
104+
(defn generate-module
105+
[& {:keys [deps classes]
106+
:or {classes []}}]
107+
(->> (conj []
108+
(generate-deps deps)
109+
classes)
110+
(flatten)
111+
(str/join "\n\n")))
112+
113+
(defn generate-backbone-classes
114+
"Generates classes from schema's backbone elements."
115+
[ir-schema]
116+
(->> (ir-schema :backbone-elements)
117+
(map #(assoc % :base "BackboneElement"))
118+
(map generate-class)))
119+
120+
(defrecord TypeScriptCodeGenerator []
121+
CodeGenerator
122+
(generate-datatypes [_ ir-schemas]
123+
[{:path (datatypes-file-path)
124+
:content (generate-module
125+
:deps []
126+
:classes (map (fn [ir-schema]
127+
(generate-class ir-schema
128+
(generate-backbone-classes ir-schema)))
129+
ir-schemas))}])
130+
(generate-resource-module [_ ir-schema]
131+
{:path (resource-file-path ir-schema)
132+
:content (generate-module
133+
{:deps [{:module "../datatypes" :members ["Address" "Attachment" "BackboneElement" "CodeableConcept" "ContactPoint" "HumanName" "Identifier" "Period" "Reference"]}]
134+
:classes [(generate-class ir-schema
135+
(generate-backbone-classes ir-schema))]})})
136+
137+
(generate-search-params [_ ir-schemas] [])
138+
(generate-constraints [_ ir-schemas] [])
139+
(generate-sdk-files [this] []))
140+
141+
(def generator (->TypeScriptCodeGenerator))

0 commit comments

Comments
 (0)