diff --git a/tools/doc/doctool.config.json b/tools/doc/doctool.config.json
index 10a5f713c7..6eff020804 100644
--- a/tools/doc/doctool.config.json
+++ b/tools/doc/doctool.config.json
@@ -17,8 +17,7 @@
"toc"
],
"dev": [
- "tsInfo",
- "typeLinker"
+ "tsInfo"
]
}
}
\ No newline at end of file
diff --git a/tools/doc/mdNav.js b/tools/doc/mdNav.js
index 8e389652a2..93e533152b 100644
--- a/tools/doc/mdNav.js
+++ b/tools/doc/mdNav.js
@@ -26,6 +26,34 @@ var MDNav = /** @class */ (function () {
}
return new MDNav(this.root, this.root.children.length);
};
+ MDNav.prototype.findAll = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ if (!this.root || !this.root.children) {
+ return [];
+ }
+ var result = [];
+ var currIndex = 0;
+ for (var i = this.pos; i < this.root.children.length; i++) {
+ var child = this.root.children[i];
+ if (test(child)) {
+ if (currIndex === index) {
+ result.push(new MDNav(this.root, i));
+ }
+ else {
+ currIndex++;
+ }
+ }
+ }
+ return result;
+ };
+ MDNav.prototype.emph = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "emphasis" && test(h);
+ }, index);
+ };
MDNav.prototype.heading = function (test, index) {
if (test === void 0) { test = function () { return true; }; }
if (index === void 0) { index = 0; }
@@ -33,6 +61,48 @@ var MDNav = /** @class */ (function () {
return h.type === "heading" && test(h);
}, index);
};
+ MDNav.prototype.html = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "html" && test(h);
+ }, index);
+ };
+ MDNav.prototype.list = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "list" && test(h);
+ }, index);
+ };
+ MDNav.prototype.listItem = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "listItem" && test(h);
+ }, index);
+ };
+ MDNav.prototype.listItems = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.findAll(function (h) {
+ return h.type === "listItem" && test(h);
+ }, index);
+ };
+ MDNav.prototype.paragraph = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "paragraph" && test(h);
+ }, index);
+ };
+ MDNav.prototype.strong = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "strong" && test(h);
+ }, index);
+ };
MDNav.prototype.table = function (test, index) {
if (test === void 0) { test = function () { return true; }; }
if (index === void 0) { index = 0; }
@@ -40,13 +110,6 @@ var MDNav = /** @class */ (function () {
return h.type === "table" && test(h);
}, index);
};
- MDNav.prototype.text = function (test, index) {
- if (test === void 0) { test = function () { return true; }; }
- if (index === void 0) { index = 0; }
- return this.find(function (h) {
- return h.type === "text" && test(h);
- }, index);
- };
MDNav.prototype.tableRow = function (test, index) {
if (test === void 0) { test = function () { return true; }; }
if (index === void 0) { index = 0; }
@@ -61,6 +124,13 @@ var MDNav = /** @class */ (function () {
return h.type === "tableCell" && test(h);
}, index);
};
+ MDNav.prototype.text = function (test, index) {
+ if (test === void 0) { test = function () { return true; }; }
+ if (index === void 0) { index = 0; }
+ return this.find(function (h) {
+ return h.type === "text" && test(h);
+ }, index);
+ };
Object.defineProperty(MDNav.prototype, "item", {
get: function () {
if (!this.root || !this.root.children) {
@@ -89,6 +159,18 @@ var MDNav = /** @class */ (function () {
enumerable: true,
configurable: true
});
+ Object.defineProperty(MDNav.prototype, "value", {
+ get: function () {
+ if (this.item && this.item["value"]) {
+ return this.item.value;
+ }
+ else {
+ return undefined;
+ }
+ },
+ enumerable: true,
+ configurable: true
+ });
return MDNav;
}());
exports.MDNav = MDNav;
diff --git a/tools/doc/mdNav.ts b/tools/doc/mdNav.ts
index fdf01cac87..0138bf11b7 100644
--- a/tools/doc/mdNav.ts
+++ b/tools/doc/mdNav.ts
@@ -26,6 +26,38 @@ export class MDNav {
}
+ findAll(test: (element: any) => boolean = () => true, index: number = 0): MDNav[] {
+ if (!this.root || !this.root.children) {
+ return [];
+ }
+
+ let result = [];
+
+ let currIndex = 0;
+
+ for (let i = this.pos; i < this.root.children.length; i++) {
+ let child = this.root.children[i];
+
+ if (test(child)) {
+ if (currIndex === index) {
+ result.push(new MDNav(this.root, i));
+ } else {
+ currIndex++;
+ }
+ }
+ }
+
+ return result;
+ }
+
+
+ emph(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ return this.find((h) => {
+ return h.type === "emphasis" && test(h);
+ }, index);
+ }
+
+
heading(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
return h.type === "heading" && test(h);
@@ -33,16 +65,49 @@ export class MDNav {
}
- table(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ html(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
- return h.type === "table" && test(h);
+ return h.type === "html" && test(h);
}, index);
}
- text(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ list(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
- return h.type === "text" && test(h);
+ return h.type === "list" && test(h);
+ }, index);
+ }
+
+
+ listItem(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ return this.find((h) => {
+ return h.type === "listItem" && test(h);
+ }, index);
+ }
+
+ listItems(test: (element: any) => boolean = () => true, index: number = 0): MDNav[] {
+ return this.findAll((h) => {
+ return h.type === "listItem" && test(h);
+ }, index);
+ }
+
+ paragraph(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ return this.find((h) => {
+ return h.type === "paragraph" && test(h);
+ }, index);
+ }
+
+
+ strong(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ return this.find((h) => {
+ return h.type === "strong" && test(h);
+ }, index);
+ }
+
+
+ table(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ return this.find((h) => {
+ return h.type === "table" && test(h);
}, index);
}
@@ -60,6 +125,14 @@ export class MDNav {
}, index);
}
+
+ text(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
+ return this.find((h) => {
+ return h.type === "text" && test(h);
+ }, index);
+ }
+
+
get item(): any {
if (!this.root || !this.root.children) {
return undefined;
@@ -75,7 +148,16 @@ export class MDNav {
}
- get childNav() {
+ get childNav(): MDNav {
return new MDNav(this.item);
}
+
+
+ get value(): any {
+ if (this.item && this.item["value"]) {
+ return this.item.value;
+ } else {
+ return undefined;
+ }
+ }
}
\ No newline at end of file
diff --git a/tools/doc/templates/service.combyne b/tools/doc/templates/service.combyne
index 78de73243a..5254efb138 100644
--- a/tools/doc/templates/service.combyne
+++ b/tools/doc/templates/service.combyne
@@ -2,10 +2,10 @@
{% if hasMethods %}
### Methods
-{% each methods as meth %}- `{{meth.name}}{{{meth.signature}}{% if meth.returnsSomething %}: {{{meth.returnType}}}{% endif %}`
+{% each methods as meth %}- **{{meth.name}}**{{{meth.signature}}}{% if meth.returnsSomething %}: `{{{meth.returnType}}}`{% endif %}
{{meth.docText}}
{% each meth.params as param %}
- - `{{{param.combined}}}` - {% if param.isOptional %}(Optional){% endif %}{{{param.docText}}}
+ - *{{{param.name}}}:* `{{{param.type}}}` - {% if param.isOptional %}(Optional){% endif %}{{{param.docText}}}
{% endeach %}
{% if meth.returnsSomething %}
- **Returns** `{{{meth.returnType}}}` - {{{meth.returnDocText}}}
diff --git a/tools/doc/tools/tsInfo.js b/tools/doc/tools/tsInfo.js
index 8c06d5c7e5..651a17ba7e 100644
--- a/tools/doc/tools/tsInfo.js
+++ b/tools/doc/tools/tsInfo.js
@@ -196,8 +196,6 @@ function aggPhase(aggData) {
}
exports.aggPhase = aggPhase;
function updatePhase(tree, pathname, aggData, errorMessages) {
- var inputMD = getPropDocsFromMD(tree, "Properties", 3);
- var outputMD = getPropDocsFromMD(tree, "Events", 2);
var compName = angNameToClassName(path.basename(pathname, ".md"));
var classRef = aggData.projData.findReflectionByName(compName);
if (!classRef) {
@@ -208,7 +206,13 @@ function updatePhase(tree, pathname, aggData, errorMessages) {
var classType = compName.match(/component|directive|service/i);
if (classType) {
// Copy docs back from the .md file when the JSDocs are empty.
+ var inputMD = getPropDocsFromMD(tree, "Properties", 3);
+ var outputMD = getPropDocsFromMD(tree, "Events", 2);
updatePropDocsFromMD(compData, inputMD, outputMD, errorMessages);
+ if (classType === "service") {
+ var methodMD = getMethodDocsFromMD(tree);
+ updateMethodDocsFromMD(compData, methodMD, errorMessages);
+ }
var templateName = path.resolve(templateFolder, classType + ".combyne");
var templateSource = fs.readFileSync(templateName, "utf8");
var template = combyne(templateSource);
@@ -277,6 +281,74 @@ function getPropDocsFromMD(tree, sectionHeading, docsColumn) {
}
return result;
}
+function getMethodDocsFromMD(tree) {
+ var result = {};
+ var nav = new mdNav_1.MDNav(tree);
+ var classMemHeading = nav
+ .heading(function (h) {
+ return (h.children[0].type === "text") && (h.children[0].value === "Class members");
+ });
+ var methListItems = classMemHeading
+ .heading(function (h) {
+ return (h.children[0].type === "text") && (h.children[0].value === "Methods");
+ }).list().childNav;
+ var methItem = methListItems
+ .listItem();
+ var i = 0;
+ while (!methItem.empty) {
+ var methNameSection = methItem.childNav
+ .paragraph().childNav
+ .strong().childNav;
+ var methName = '';
+ // Method docs must be in "new" format with names and types styled separately.
+ if (!methNameSection.empty) {
+ methName = methNameSection.text().item.value;
+ var methDoc = methItem.childNav
+ .paragraph().childNav
+ .html()
+ .text().item.value;
+ var params = getMDMethodParams(methItem);
+ result[methName] = {
+ "docText": methDoc.replace(/^\n/, ""),
+ "params": params
+ };
+ }
+ i++;
+ methItem = methListItems
+ .listItem(function (l) { return true; }, i);
+ }
+ /*
+ let newRoot = unist.makeRoot([methList.item]);
+ console.log(remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false, gfm: false}).stringify(tree));
+ */
+ return result;
+}
+function getMDMethodParams(methItem) {
+ var result = {};
+ var paramList = methItem.childNav.list().childNav;
+ var paramListItems = paramList
+ .listItems();
+ paramListItems.forEach(function (paramListItem) {
+ var paramNameNode = paramListItem.childNav
+ .paragraph().childNav
+ .emph().childNav;
+ var paramName;
+ if (!paramNameNode.empty) {
+ paramName = paramNameNode.text().item.value.replace(/:/, "");
+ }
+ else {
+ paramName = paramListItem.childNav
+ .paragraph().childNav
+ .strong().childNav
+ .text().item.value;
+ }
+ var paramDoc = paramListItem.childNav
+ .paragraph().childNav
+ .text(function (t) { return true; }, 1).item.value;
+ result[paramName] = paramDoc.replace(/^[ -]+/, "");
+ });
+ return result;
+}
function updatePropDocsFromMD(comp, inputDocs, outputDocs, errorMessages) {
comp.properties.forEach(function (prop) {
var propMDDoc;
@@ -293,3 +365,19 @@ function updatePropDocsFromMD(comp, inputDocs, outputDocs, errorMessages) {
}
});
}
+function updateMethodDocsFromMD(comp, methodDocs, errorMessages) {
+ comp.methods.forEach(function (meth) {
+ var currMethMD = methodDocs[meth.name];
+ // If JSDocs are empty but MD docs aren't then the Markdown is presumably more up-to-date.
+ if (!meth.docText && currMethMD.docText) {
+ meth.docText = currMethMD.docText;
+ errorMessages.push("Warning: empty JSDocs for method sig \"" + meth.name + "\" may need sync with the .md file.");
+ }
+ meth.params.forEach(function (param) {
+ if (!param.docText && currMethMD.params[param.name]) {
+ param.docText = currMethMD.params[param.name];
+ errorMessages.push("Warning: empty JSDocs for parameter \"" + param.name + " (" + meth.name + ")\" may need sync with the .md file.");
+ }
+ });
+ });
+}
diff --git a/tools/doc/tools/tsInfo.ts b/tools/doc/tools/tsInfo.ts
index 4ad471acb5..ec7b5bad28 100644
--- a/tools/doc/tools/tsInfo.ts
+++ b/tools/doc/tools/tsInfo.ts
@@ -285,9 +285,6 @@ export function aggPhase(aggData) {
export function updatePhase(tree, pathname, aggData, errorMessages) {
- let inputMD = getPropDocsFromMD(tree, "Properties", 3);
- let outputMD = getPropDocsFromMD(tree, "Events", 2);
-
let compName = angNameToClassName(path.basename(pathname, ".md"));
let classRef = aggData.projData.findReflectionByName(compName);
@@ -301,7 +298,14 @@ export function updatePhase(tree, pathname, aggData, errorMessages) {
if (classType) {
// Copy docs back from the .md file when the JSDocs are empty.
+ let inputMD = getPropDocsFromMD(tree, "Properties", 3);
+ let outputMD = getPropDocsFromMD(tree, "Events", 2);
updatePropDocsFromMD(compData, inputMD, outputMD, errorMessages);
+
+ if (classType === "service") {
+ let methodMD = getMethodDocsFromMD(tree);
+ updateMethodDocsFromMD(compData, methodMD, errorMessages);
+ }
let templateName = path.resolve(templateFolder, classType + ".combyne");
let templateSource = fs.readFileSync(templateName, "utf8");
@@ -401,6 +405,99 @@ function getPropDocsFromMD(tree, sectionHeading, docsColumn) {
}
+function getMethodDocsFromMD(tree) {
+ let result = {}
+
+ let nav = new MDNav(tree);
+
+ let classMemHeading = nav
+ .heading(h => {
+ return (h.children[0].type === "text") && (h.children[0].value === "Class members");
+ });
+
+ let methListItems = classMemHeading
+ .heading(h => {
+ return (h.children[0].type === "text") && (h.children[0].value === "Methods");
+ }).list().childNav;
+
+ let methItem = methListItems
+ .listItem();
+
+ let i = 0;
+
+ while (!methItem.empty) {
+ let methNameSection = methItem.childNav
+ .paragraph().childNav
+ .strong().childNav;
+
+ let methName = '';
+
+ // Method docs must be in "new" format with names and types styled separately.
+ if (!methNameSection.empty) {
+ methName = methNameSection.text().item.value;
+
+ let methDoc = methItem.childNav
+ .paragraph().childNav
+ .html()
+ .text().item.value;
+
+ let params = getMDMethodParams(methItem);
+
+ result[methName] = {
+ "docText": methDoc.replace(/^\n/, ""),
+ "params": params
+ };
+ }
+
+ i++;
+
+ methItem = methListItems
+ .listItem(l=>true, i);
+ }
+ /*
+ let newRoot = unist.makeRoot([methList.item]);
+ console.log(remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false, gfm: false}).stringify(tree));
+ */
+
+ return result;
+}
+
+
+function getMDMethodParams(methItem: MDNav) {
+ let result = {};
+
+ let paramList = methItem.childNav.list().childNav;
+
+ let paramListItems = paramList
+ .listItems();
+
+ paramListItems.forEach(paramListItem => {
+ let paramNameNode = paramListItem.childNav
+ .paragraph().childNav
+ .emph().childNav;
+
+ let paramName;
+
+ if (!paramNameNode.empty) {
+ paramName = paramNameNode.text().item.value.replace(/:/, "");
+ } else {
+ paramName = paramListItem.childNav
+ .paragraph().childNav
+ .strong().childNav
+ .text().item.value;
+ }
+
+ let paramDoc = paramListItem.childNav
+ .paragraph().childNav
+ .text(t=>true, 1).item.value;
+
+ result[paramName] = paramDoc.replace(/^[ -]+/, "");
+ });
+
+ return result;
+}
+
+
function updatePropDocsFromMD(comp: ComponentInfo, inputDocs, outputDocs, errorMessages) {
comp.properties.forEach(prop => {
let propMDDoc: string;
@@ -417,4 +514,25 @@ function updatePropDocsFromMD(comp: ComponentInfo, inputDocs, outputDocs, errorM
errorMessages.push(`Warning: empty JSDocs for property "${prop.name}" may need sync with the .md file.`);
}
});
+}
+
+
+function updateMethodDocsFromMD(comp: ComponentInfo, methodDocs, errorMessages) {
+ comp.methods.forEach(meth => {
+ let currMethMD = methodDocs[meth.name]
+
+ // If JSDocs are empty but MD docs aren't then the Markdown is presumably more up-to-date.
+ if (!meth.docText && currMethMD.docText) {
+ meth.docText = currMethMD.docText;
+ errorMessages.push(`Warning: empty JSDocs for method sig "${meth.name}" may need sync with the .md file.`);
+ }
+
+ meth.params.forEach(param => {
+ if (!param.docText && currMethMD.params[param.name])
+ {
+ param.docText = currMethMD.params[param.name];
+ errorMessages.push(`Warning: empty JSDocs for parameter "${param.name} (${meth.name})" may need sync with the .md file.`);
+ }
+ });
+ });
}
\ No newline at end of file