diff --git a/js/js-support-bundle.js b/js/js-support-bundle.js index 3817c34..76746c4 100644 --- a/js/js-support-bundle.js +++ b/js/js-support-bundle.js @@ -1472,10 +1472,10 @@ function readPlainScalar(state, nodeIndent, withinFlowCollection) { var endIndex = state.position; var positions = { - "start-line": startLine, + "start-line": startLine + 1, "start-column": startColumn, "start-index": startIndex, - "end-line": endLine, + "end-line": endLine + 1, "end-column": endColumn, "end-index": endIndex }; @@ -1534,10 +1534,10 @@ function readSingleQuotedScalar(state, nodeIndent) { var endIndex = state.position; var positions = { - "start-line": startLine, + "start-line": startLine + 1, "start-column": startColumn, "start-index": startIndex, - "end-line": endLine, + "end-line": endLine + 1, "end-column": endColumn, "end-index": endIndex }; @@ -1599,10 +1599,10 @@ function readDoubleQuotedScalar(state, nodeIndent) { var endIndex = state.position; var positions = { - "start-line": startLine, + "start-line": startLine + 1, "start-column": startColumn, "start-index": startIndex, - "end-line": endLine, + "end-line": endLine + 1, "end-column": endColumn, "end-index": endIndex }; diff --git a/js/js-yaml/lib/js-yaml/loader.js b/js/js-yaml/lib/js-yaml/loader.js index 166031e..ec84bf7 100644 --- a/js/js-yaml/lib/js-yaml/loader.js +++ b/js/js-yaml/lib/js-yaml/loader.js @@ -512,10 +512,10 @@ function readPlainScalar(state, nodeIndent, withinFlowCollection) { var endIndex = state.position; var positions = { - "start-line": startLine, + "start-line": startLine + 1, "start-column": startColumn, "start-index": startIndex, - "end-line": endLine, + "end-line": endLine + 1, "end-column": endColumn, "end-index": endIndex }; @@ -574,10 +574,10 @@ function readSingleQuotedScalar(state, nodeIndent) { var endIndex = state.position; var positions = { - "start-line": startLine, + "start-line": startLine + 1, "start-column": startColumn, "start-index": startIndex, - "end-line": endLine, + "end-line": endLine + 1, "end-column": endColumn, "end-index": endIndex }; @@ -639,10 +639,10 @@ function readDoubleQuotedScalar(state, nodeIndent) { var endIndex = state.position; var positions = { - "start-line": startLine, + "start-line": startLine + 1, "start-column": startColumn, "start-index": startIndex, - "end-line": endLine, + "end-line": endLine + 1, "end-column": endColumn, "end-index": endIndex }; diff --git a/src/api_modeling_framework/core.cljc b/src/api_modeling_framework/core.cljc index 0cb3a7d..b772f65 100644 --- a/src/api_modeling_framework/core.cljc +++ b/src/api_modeling_framework/core.cljc @@ -236,17 +236,27 @@ (defn find-element* [model id] (cond - (map? model) (if (= id (or (:id model) (get model "@id"))) - model - (->> (vals model) - (map (fn [m] (find-element* m id))) - (filter some?) - first)) - (coll? model) (->> model - (map (fn [m] (find-element* m id))) - (filter some?) - first) - :else nil)) + ;; we prefer elements in declarations if present + (and (map? model) + (:declares model) + (some #(= id (:id %)) + (:declares model))) (->> (:declares model) + (filter #(= id (:id %))) + first) + + (map? model) (if (= id (or (:id model) (get model "@id"))) + model + (->> (vals model) + (map (fn [m] (find-element* m id))) + (filter some?) + first)) + + (coll? model) (->> model + (map (fn [m] (find-element* m id))) + (filter some?) + first) + + :else nil)) (defn to-model ([res] diff --git a/src/api_modeling_framework/generators/domain/shapes_raml_types.cljc b/src/api_modeling_framework/generators/domain/shapes_raml_types.cljc index e43e2cf..263fa0c 100644 --- a/src/api_modeling_framework/generators/domain/shapes_raml_types.cljc +++ b/src/api_modeling_framework/generators/domain/shapes_raml_types.cljc @@ -174,7 +174,8 @@ (if (utils/object-no-properties? base) (first types) (assoc base :type (first types))) - {:type types}))) + {:type "union" + :anyOf types}))) (defmethod parse-shape :raml-expression [shape _] (-> shape (get (v/shapes-ns "ramlTypeExpression")) first (get "@value"))) diff --git a/src/api_modeling_framework/parser/document/raml.cljc b/src/api_modeling_framework/parser/document/raml.cljc index 28fbde1..b6ccdaf 100644 --- a/src/api_modeling_framework/parser/document/raml.cljc +++ b/src/api_modeling_framework/parser/document/raml.cljc @@ -86,35 +86,38 @@ (mapv (fn [annotation] [(document/name annotation) annotation])) (into {})) + working-declarations library-declarations + ;; we parse traits and types and add the information into the context + types (domain-parser/process-types (syntax/<-data node) {:location (str location "#") + :fragments fragments + :references working-declarations + :document-parser parse-ast + :parsed-location location}) + working-declarations (merge working-declarations types) doc-annotations (domain-parser/process-annotations (syntax/<-data node) {:base-uri location + :references working-declarations :location (str location "#") :parsed-location (str location "#")}) annotations (merge library-declarations doc-annotations) - ;; we parse traits and types and add the information into the context traits (domain-parser/process-traits (syntax/<-data node) {:location (str location "#") :fragments fragments - :references library-declarations + :references working-declarations :document-parser parse-ast :annotations annotations :parsed-location (str location "#")}) - types (domain-parser/process-types (syntax/<-data node) {:location (str location "#") - :fragments fragments - :references library-declarations - :annotations annotations - :document-parser parse-ast - :parsed-location location}) - declarations (merge traits types) + working-declarations (merge working-declarations traits) encoded (domain-parser/parse-ast (syntax/<-data node) {:location (str location "#") :fragments fragments :parsed-location (str location "#") :annotations annotations - :references (merge declarations library-declarations) + :references working-declarations :document-parser parse-ast :is-fragment false})] (-> (document/map->ParsedDocument {:id location :location location :encodes encoded - :declares (concat (vals declarations) + :declares (concat (vals types) + (vals traits) (vals doc-annotations)) :references (compute-fragments (concat (vals @fragments) @@ -137,33 +140,36 @@ (mapv (fn [annotation] [(document/name annotation) annotation])) (into {})) + working-declarations library-declarations + ;; we parse traits and types and add the information into the context + types (domain-parser/process-types (syntax/<-data node) {:location (str location "#") + :fragments fragments + :alias-chain alias-chain + :references working-declarations + :document-parser parse-ast + :parsed-location location}) + working-declarations (merge working-declarations types) doc-annotations (domain-parser/process-annotations (syntax/<-data node) {:base-uri location :location (str location "#") :parsed-location (str location "#/annotations") - :references library-declarations}) + :references working-declarations}) annotations (merge libraries-annotation doc-annotations) - ;; we parse traits and types and add the information into the context traits (domain-parser/process-traits (syntax/<-data node) {:location (str location "#") :fragments fragments - :references library-declarations + :references working-declarations :alias-chain alias-chain :document-parser parse-ast :annotations annotations :parsed-location (str location "#")}) - types (domain-parser/process-types (syntax/<-data node) {:location (str location "#") - :fragments fragments - :alias-chain alias-chain - :references library-declarations - :annotations annotations - :document-parser parse-ast - :parsed-location location}) - declarations (merge traits types) + usage (:usage (syntax/<-data node))] (-> (document/map->ParsedModule (utils/clean-nils {:id location :location location :description usage - :declares (concat (vals declarations) (vals doc-annotations)) + :declares (concat (vals types) + (vals traits) + (vals doc-annotations)) :references (compute-fragments (concat (vals @fragments) (flatten (vals libraries)))) diff --git a/src/api_modeling_framework/parser/domain/raml.cljc b/src/api_modeling_framework/parser/domain/raml.cljc index 8eb1582..6beb985 100644 --- a/src/api_modeling_framework/parser/domain/raml.cljc +++ b/src/api_modeling_framework/parser/domain/raml.cljc @@ -345,44 +345,53 @@ (assoc acc (keyword (utils/alias-chain trait-name context)) parsed-trait))) {})))) -(defn process-types [node {:keys [location parsed-location alias-chain] :as context}] +(defn process-types [node {:keys [location parsed-location alias-chain references] :as context}] (let [types (or (:types node) (:schemas node) {}) path-label (if (some? (:types node)) "types" "schemas") location (utils/path-join parsed-location "/" path-label) nested-context (-> context (assoc :location location) (assoc :parsed-location parsed-location))] (debug "Processing " (count types) " types") - (->> types - (reduce (fn [acc [type-name type-node]] - (debug (str "Processing type " type-name)) - (let [location-meta (meta type-node) - type-node (common/purge-ast type-node) - type-node (if (syntax/fragment? type-node) - ;; avoiding situations where we transform this into an include - ;; and then we cannot transform this back into type because there's - ;; no way to tell it without source maps - {:type type-node} - type-node) - type-name (url/url-encode (utils/safe-str type-name)) - type-id (common/type-reference parsed-location type-name) - references (get nested-context :references {}) - type-fragment (parse-ast type-node (-> nested-context - (assoc :references (merge references acc)) - (assoc :location location) - (assoc :parsed-location type-id) - (assoc :is-fragment false) - (assoc :type-hint :type))) - sources (or (-> type-fragment :sources) []) - ;; we annotate the parsed type with the is-type source map so we can distinguish it from other declarations - sources (concat sources (common/generate-is-type-sources type-name - (utils/path-join location type-name) - type-id)) - parsed-type (assoc type-fragment :sources sources) - parsed-type (if (nil? (:name parsed-type)) - (assoc parsed-type :name type-name) - parsed-type) - parsed-type (assoc parsed-type :lexical location-meta)] - (assoc acc (keyword (utils/alias-chain type-name context)) parsed-type))) - {})))) + (let [;; we will mark the positions of references in the types node + ahead-references (->> types + (map (fn [[type-name _]] + (let [type-name (url/url-encode (utils/safe-str type-name)) + type-id (common/type-reference parsed-location type-name)] + [(keyword type-name) {:x-ahead-declaration type-id}]))) + (into {})) + working-references (atom (merge references ahead-references))] + (->> types + (reduce (fn [acc [type-name type-node]] + (debug (str "Processing type " type-name)) + (let [location-meta (meta type-node) + type-node (common/purge-ast type-node) + type-node (if (syntax/fragment? type-node) + ;; avoiding situations where we transform this into an include + ;; and then we cannot transform this back into type because there's + ;; no way to tell it without source maps + {:type type-node} + type-node) + type-name (url/url-encode (utils/safe-str type-name)) + type-id (common/type-reference parsed-location type-name) + type-fragment (parse-ast type-node (-> nested-context + (assoc :references @working-references) + (assoc :location location) + (assoc :parsed-location type-id) + (assoc :is-fragment false) + (assoc :type-hint :type))) + sources (or (-> type-fragment :sources) []) + ;; we annotate the parsed type with the is-type source map so we can distinguish it from other declarations + sources (concat sources (common/generate-is-type-sources type-name + (utils/path-join location type-name) + type-id)) + parsed-type (assoc type-fragment :sources sources) + parsed-type (if (nil? (:name parsed-type)) + (assoc parsed-type :name type-name) + parsed-type) + parsed-type (assoc parsed-type :lexical location-meta)] + ;; let's also update the working reference to this ahead declaration + (swap! working-references (fn [old-working-references] (assoc old-working-references (keyword type-name) parsed-type))) + (assoc acc (keyword (utils/alias-chain type-name context)) parsed-type))) + {}))))) (defn find-extend-tags [{:keys [location parsed-location references] :as context}] (->> references @@ -428,7 +437,9 @@ :scheme (utils/ensure-not-blank (root->scheme node)) :base-path (utils/ensure-not-blank (base-uri->basepath (extract-scalar (:baseUri node)))) :accepts (filterv some? (flatten [(extract-scalar (:mediaType node))])) - :content-type (filterv some? (flatten [(:mediaType node)])) + :content-type (->> (flatten [(:mediaType node)]) + (map extract-scalar) + (filterv some?)) :version (extract-scalar (:version node)) :provider nil :terms-of-service nil diff --git a/src/api_modeling_framework/parser/domain/raml_types_shapes.cljc b/src/api_modeling_framework/parser/domain/raml_types_shapes.cljc index 9f6bcc1..cdef6cf 100644 --- a/src/api_modeling_framework/parser/domain/raml_types_shapes.cljc +++ b/src/api_modeling_framework/parser/domain/raml_types_shapes.cljc @@ -186,10 +186,11 @@ (v/shapes-ns "schemaRaw") [{"@value" text}]}) -(defn check-multiple-inheritance +(defn parse-union "Computes multiple-inheritance references" - [types {:keys [parsed-location default-type] :as context}] - (let [types (mapv #(parse-type % context) types)] + [node {:keys [parsed-location default-type] :as context}] + (let [types (:anyOf node) + types (mapv #(parse-type % context) types)] {"@id" parsed-location "@type" [(v/shapes-ns "NodeShape") (v/sh-ns "Shape")] (v/shapes-ns "inherits") types})) @@ -201,10 +202,11 @@ (some? (:properties node)) (parse-type (assoc node :type "object") context) (some? (:items node)) (parse-type (assoc node :type "array") context) :else {"@id" parsed-location - "@type" [(v/shapes-ns "NodeShape") (v/sh-ns "Shape")]})] - (assoc child (v/shapes-ns "inherits") [(parse-type (:type node) (-> context - (assoc :parsed-location (utils/path-join parsed-location "type")) - (assoc :location location)))]))) + "@type" [(v/shapes-ns "NodeShape") (v/sh-ns "Shape")]}) + base-type (parse-type (:type node) (-> context + (assoc :parsed-location (utils/path-join parsed-location "type")) + (assoc :location location)))] + (assoc child (v/shapes-ns "inherits") [base-type]))) (defn check-inclusion [node {:keys [parse-ast parsed-location] :as context}] (let [parsed (parse-ast node context) @@ -277,6 +279,8 @@ (= type-ref "object") (parse-shape node context) ;; array (= type-ref "array") (parse-array node context) + ;; unions + (= type-ref "union") (parse-union node context) ;; json schema (and (string? type-ref) @@ -290,7 +294,7 @@ (defn parse-type-reference-link [type-ref with-raml-type-expression {:keys [parsed-location references] :as context}] (cond - ;; links to refernces + ;; links to references (utils/type-link? {:type type-ref} references) (check-reference type-ref context) (some? (syntax/<-data type-ref)) (check-inclusion type-ref context) @@ -325,6 +329,8 @@ (= type-ref "object") ;; array (= type-ref "array") + ;; unions + (= type-ref "union") ;; Careful with the next two, starts-with? ;; automatically transform maps into strings! diff --git a/src/api_modeling_framework/utils.cljc b/src/api_modeling_framework/utils.cljc index 97a7a44..098d6c6 100644 --- a/src/api_modeling_framework/utils.cljc +++ b/src/api_modeling_framework/utils.cljc @@ -195,8 +195,10 @@ (map? data) (->> data (map (fn [[k v]] [(v/anon-shapes-ns (safe-str k)) (annotation->jsonld v)])) - (into {})) + (into {}) + clean-nils) (coll? data) (mapv #(annotation->jsonld %) data) + (nil? data) nil :else {"@value" data})) (defn jsonld->annotation [data] diff --git a/test/api_modeling_framework/integration_test.cljc b/test/api_modeling_framework/integration_test.cljc index d708699..365e52a 100644 --- a/test/api_modeling_framework/integration_test.cljc +++ b/test/api_modeling_framework/integration_test.cljc @@ -144,9 +144,8 @@ api-resource (get paths "/api") song-resource (get paths "/songs/{songId}")] ;; checking we have lexical info in the JS parser - #?(:cljs (map (fn [parsed] - (is (some? (:lexical parsed)))) - (document/declares document-model))) + #?(:cljs (doseq [parsed (document/declares document-model)] + (is (some? (:lexical parsed))))) (doseq [ref (document/references (core/document-model model))] (is (some? (:raw ref)))) (is (= "World Music API" (document/name api-documentation))) @@ -315,17 +314,24 @@ ( " (keys node)) + ;(when (= ["@value"] (keys node)) + ; (do (println "VALUE: " (get node "@value") " => " (keys node)) + ; (prn node))) (reduce (fn [acc [k v]] - (and acc (not-nil-ids v))) - (and right-id right-class) + (and acc (valid-jsonld v))) + (and right-id right-class right-value right-value-literal) node)) (coll? node) (reduce (fn [acc node] - (and acc (not-nil-ids node))) + (and acc (valid-jsonld node))) true node) @@ -345,7 +351,7 @@ {}))) _ (is (not (error? output-jsonld))) parsed-document-jsonld-output (platform/decode-json output-jsonld)] - (is (not-nil-ids parsed-document-jsonld-output)) + (is (valid-jsonld parsed-document-jsonld-output)) (done))))) (deftest integration-test-openapi-ps->domain