# HG changeset patch # User Rob Hoes # Date 1274793987 -3600 # Node ID fbf3b7184a3fd1adabb500c2261659dc8a1bb9ee # Parent 277057c7e27ade920540db458a0c1b2c07eab17d Add lifecycle info and release notes to HTML API docs Signed-off-by: Rob Hoes diff -r 277057c7e27a -r fbf3b7184a3f ocaml/doc/OMakefile --- a/ocaml/doc/OMakefile +++ b/ocaml/doc/OMakefile @@ -4,6 +4,10 @@ OCAML_LIBS += ../idl/datamodel OCAMLINCLUDES += ../idl + +CAMLP4_FILES = jsapi +UseCamlp4(rpc-light.syntax, $(CAMLP4_FILES)) + OCamlProgram(jsapi, jsapi) .PHONY: doc diff -r 277057c7e27a -r fbf3b7184a3f ocaml/doc/apidoc.html --- a/ocaml/doc/apidoc.html +++ b/ocaml/doc/apidoc.html @@ -6,10 +6,13 @@ + diff -r 277057c7e27a -r fbf3b7184a3f ocaml/doc/apidoc.js --- a/ocaml/doc/apidoc.js +++ b/ocaml/doc/apidoc.js @@ -15,6 +15,7 @@ // global variables var cls = getQuerystring('c'); +var rel = getQuerystring('r'); function qualifier(q) { @@ -74,6 +75,29 @@ return 'Unknown[' + t + ']'; } +function current_lifecycle_stage(s) +{ + if (s.length == 0) + return 'Prototype'; + else { + last_transition = s[s.length-1][0]; + switch (last_transition) { + case 'Deprecated': + return 'Deprecated'; + break; + case 'Removed': + return 'Removed'; + break; + case 'Published': + case 'Changed': + case 'Extended': + default: + return ''; + break; + } + } +} + function make_field(fld, n) { name = fld.field_name; @@ -81,20 +105,22 @@ html = ""; html = '
'; html += ''; + html += '
' + current_lifecycle_stage(fld.lifecycle) + '
'; html += '
' + transform_type(fld.ty) + ' ' + name + ' [' + qualifier(fld.qualifier) + ']
'; html += '
'; @@ -109,6 +135,7 @@ html += '
'; html += ''; + html += '
' + current_lifecycle_stage(msg.msg_lifecycle) + '
'; html += '
' + (msg.msg_result != undefined ? transform_type(msg.msg_result[0]) : 'void') + ' ' + name + ' (' + @@ -142,10 +169,12 @@ } html += ''; } - if (msg.msg_release != undefined) { - html += 'Introduced in:' + msg.msg_release.internal[1] + ''; - if (msg.msg_release.internal_deprecated_since != undefined) - html += 'Deprecated since:' + msg.msg_release.internal_deprecated_since + ''; + html += ''; + + html += ''; + for (i in msg.msg_lifecycle) { + l = msg.msg_lifecycle[i]; + html += ''; } html += '
' + l[0] + ' in:' + l[1] + '' + l[2] + '
'; @@ -164,10 +193,21 @@ messages.sort(function(a, b){return a.msg_name.toLowerCase().charCodeAt(0) - b.msg_name.toLowerCase().charCodeAt(0)}); html = ""; + html += ''; + html += '
' + current_lifecycle_stage(clsdoc.obj_lifecycle) + '
'; html += '

Class: ' + cls + '

\n'; html += '
' + clsdoc.description + '
'; + html += ''; + html += '

Fields

'; if (fields.length > 0) { for (i in fields) @@ -187,9 +227,60 @@ set_content(html); } -function build() +function compare_release_notes(a, b) { + function change_to_num(x) { + if (x.indexOf('Published') > -1) return '0'; + else if (x.indexOf('Extended') > -1) return '1'; + else if (x.indexOf('Changed') > -1) return '2'; + else if (x.indexOf('Deprecated') > -1) return '3'; + else if (x.indexOf('Removed') > -1) return '4'; + else return '5'; + } + function element_to_num(x) { + if (x.indexOf('object') > -1) return '0'; + else if (x.indexOf('field') > -1) return '1'; + else if (x.indexOf('message') > -1) return '2'; + else return '3'; + } + a = change_to_num(a[0]) + element_to_num(a[0]) + (a[1]+a[2]).toLowerCase(); + b = change_to_num(b[0]) + element_to_num(b[0]) + (b[1]+b[2]).toLowerCase(); + return a > b; +} + +function release_doc() +{ + changes = []; + + for (i in release_info) { + c = release_info[i]; + for (j in c.obj_changes) + changes.push([c.obj_changes[j][0] + ' object', c.cls, '', c.obj_changes[j][2]]); + for (j in c.field_changes) + changes.push([c.field_changes[j][0] + ' field', c.cls, c.field_changes[j][1], c.field_changes[j][2]]); + for (j in c.msg_changes) + changes.push([c.msg_changes[j][0] + ' message', c.cls, c.msg_changes[j][1], c.msg_changes[j][2]]); + } + + changes.sort(compare_release_notes); + html = ""; + html += '

Release notes: ' + rel + '

\n'; + + html += ''; + + for (i in changes) { + html += ''; + } + + html += '
ChangeElementDescription
' + changes[i][0] + '' + + changes[i][1] + (changes[i][2] != '' ? '.' + changes[i][2] : '') + '' + changes[i][3] + '
'; + + set_content(html); +} + +function class_list() +{ html = '

Classes

'; classes.sort(function(a, b){return a.toLowerCase().charCodeAt(0) - b.toLowerCase().charCodeAt(0)}); @@ -199,9 +290,35 @@ } append_sidebar(html); +} + +function release_list() +{ + html = '

Release notes

'; + for (i in releases) { + r = releases[i]; + html += '' + r + '
'; + } + + append_sidebar(html); +} + +function build() +{ if (cls != "") { + class_list(); + release_list(); class_doc(); } + else if (rel != "") { + class_list(); + release_list(); + release_doc(); + } + else { + class_list(); + release_list(); + } } diff -r 277057c7e27a -r fbf3b7184a3f ocaml/doc/jsapi.ml --- a/ocaml/doc/jsapi.ml +++ b/ocaml/doc/jsapi.ml @@ -11,17 +11,72 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. *) + +open Datamodel_types +open Stringext +type change_t = lifecycle_change * string * string +and changes_t = change_t list +with rpc + +let obj_change_in_release rel o = + let rec find_rel rel = function + | [] -> None + | (transition, release, doc) :: tl when release = rel -> Some (transition, o.name, doc) + | _ :: tl -> find_rel rel tl + in + find_rel rel o.obj_lifecycle + +let msg_change_in_release rel m = + let rec find_rel rel = function + | [] -> None + | (transition, release, doc) :: tl when release = rel -> Some (transition, m.msg_name, doc) + | _ :: tl -> find_rel rel tl + in + find_rel rel m.msg_lifecycle + +let field_change_in_release rel f = + let rec find_rel rel = function + | [] -> None + | (transition, release, doc) :: tl when release = rel -> Some (transition, f.field_name, doc) + | _ :: tl -> find_rel rel tl + in + find_rel rel f.lifecycle + let _ = - let api = (* Datamodel_utils.add_implicit_messages *) (Datamodel.all_api) in + let api = (Datamodel.all_api) in let objs = Dm_api.objects_of_api api in let create_json obj = - let name = obj.Datamodel_types.name in - let s = Jsonrpc.to_string (Datamodel_types.rpc_of_obj obj) in + let name = obj.name in + let s = Jsonrpc.to_string (rpc_of_obj obj) in Unixext.write_string_to_file ("api/" ^ name ^ ".json") ("clsdoc = " ^ s); name in let names = List.map create_json objs in let class_list = String.concat ", " (List.map (fun s -> "'" ^ s ^ "'") names) in - Unixext.write_string_to_file "api/index.json" ("classes = [" ^ class_list ^ "]") + Unixext.write_string_to_file "api/index.json" ("classes = [" ^ class_list ^ "]"); + let new_in_release rel = + let search_obj obj = + let obj_changes : changes_t = + match obj_change_in_release rel obj with + | None -> [] + | Some x -> [x] + in + + let msgs = List.filter (fun m -> not m.msg_hide_from_docs) obj.messages in + let msg_changes : changes_t = List.fold_left + (fun l m -> match msg_change_in_release rel m with None -> l | Some x -> x :: l) [] msgs in + + let flds = List.filter (function Field f -> true | _ -> false) obj.contents in + let field_changes : changes_t = List.fold_left + (fun l (Field f) -> match field_change_in_release rel f with None -> l | Some x -> x :: l) [] flds in + + "{'cls': '" ^ obj.name ^ "', 'obj_changes': " ^ Jsonrpc.to_string (rpc_of_changes_t obj_changes) ^ ", 'field_changes': " ^ Jsonrpc.to_string (rpc_of_changes_t field_changes) ^ ", 'msg_changes': " ^ Jsonrpc.to_string (rpc_of_changes_t msg_changes) ^ "}" + in + let release_info = String.concat ", " (List.map search_obj objs) in + Unixext.write_string_to_file ("api/" ^ rel ^ ".json") ("release_info = [" ^ release_info ^ "]") + in + List.iter new_in_release release_order; + let release_list = String.concat ", " (List.map (fun s -> "'" ^ s ^ "'") release_order) in + Unixext.write_string_to_file "api/releases.json" ("releases = [" ^ release_list ^ "]"); diff -r 277057c7e27a -r fbf3b7184a3f ocaml/doc/style.css --- a/ocaml/doc/style.css +++ b/ocaml/doc/style.css @@ -188,7 +188,7 @@ td { vertical-align: top; - padding: 3px; + padding: 3px 1em 3px 0; } th { @@ -274,11 +274,18 @@ margin-left: .5em; } +.lifecycle { + font-size: 90%; + float: right; + font-variant:small-caps; + color: #900; + margin: auto 0.5em; +} + .small-button { font-size: 70%; -// text-align: right; float: right; - margin: .5em 0; + margin: 0.2em 0 0.2em 0.5em; } .stat {