[ADF-2979] Updated props script to avoid copying missing JSDocs (#3327)

* [ADF-2979] Updated tools to ignore blank JSDocs for inputs/outputs

* [ADF-2979] Bug fixes for handling missing tables, etc
This commit is contained in:
Andy Stark 2018-05-15 16:03:52 +01:00 committed by Eugenio Romano
parent 25f20dbec9
commit 92e0809a16
4 changed files with 297 additions and 69 deletions

94
tools/doc/mdNav.js Normal file
View File

@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var MDNav = /** @class */ (function () {
function MDNav(root, pos) {
if (pos === void 0) { pos = 0; }
this.root = root;
this.pos = pos;
}
MDNav.prototype.find = function (test, index) {
if (test === void 0) { test = function () { return true; }; }
if (index === void 0) { index = 0; }
if (!this.root || !this.root.children) {
return new MDNav(null);
}
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) {
return new MDNav(this.root, i);
}
else {
currIndex++;
}
}
}
return new MDNav(this.root, this.root.children.length);
};
MDNav.prototype.heading = 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 === "heading" && test(h);
}, index);
};
MDNav.prototype.table = 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 === "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; }
return this.find(function (h) {
return h.type === "tableRow" && test(h);
}, index);
};
MDNav.prototype.tableCell = 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 === "tableCell" && test(h);
}, index);
};
Object.defineProperty(MDNav.prototype, "item", {
get: function () {
if (!this.root || !this.root.children) {
return undefined;
}
else {
return this.root.children[this.pos];
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(MDNav.prototype, "empty", {
get: function () {
return !this.root ||
!this.root.children ||
(this.pos >= this.root.children.length);
},
enumerable: true,
configurable: true
});
Object.defineProperty(MDNav.prototype, "childNav", {
get: function () {
return new MDNav(this.item);
},
enumerable: true,
configurable: true
});
return MDNav;
}());
exports.MDNav = MDNav;

81
tools/doc/mdNav.ts Normal file
View File

@ -0,0 +1,81 @@
export class MDNav {
constructor(public root: any, public pos: number = 0) {}
find(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
if (!this.root || !this.root.children) {
return new MDNav(null);
}
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) {
return new MDNav(this.root, i);
} else {
currIndex++;
}
}
}
return new MDNav(this.root, this.root.children.length);
}
heading(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
return h.type === "heading" && test(h);
}, index);
}
table(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
return h.type === "table" && test(h);
}, index);
}
text(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
return h.type === "text" && test(h);
}, index);
}
tableRow(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
return h.type === "tableRow" && test(h);
}, index);
}
tableCell(test: (element: any) => boolean = () => true, index: number = 0): MDNav {
return this.find((h) => {
return h.type === "tableCell" && test(h);
}, index);
}
get item(): any {
if (!this.root || !this.root.children) {
return undefined;
} else {
return this.root.children[this.pos];
}
}
get empty(): boolean {
return !this.root ||
!this.root.children ||
(this.pos >= this.root.children.length);
}
get childNav() {
return new MDNav(this.item);
}
}

View File

@ -1,11 +1,12 @@
"use strict";
exports.__esModule = true;
Object.defineProperty(exports, "__esModule", { value: true });
var fs = require("fs");
var path = require("path");
var replaceSection = require("mdast-util-heading-range");
var remark = require("remark");
var combyne = require("combyne");
var typedoc_1 = require("typedoc");
var mdNav_1 = require("../mdNav");
var libFolders = ["core", "content-services", "process-services", "insights"];
var templateFolder = path.resolve("tools", "doc", "templates");
var excludePatterns = [
@ -186,11 +187,6 @@ function initPhase(aggData) {
return path.resolve("lib", folder);
}));
aggData.projData = app.convert(sources);
/*
aggData.liq = liquid({
root: templateFolder
});
*/
}
exports.initPhase = initPhase;
function readPhase(tree, pathname, aggData) {
@ -200,6 +196,8 @@ 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) {
@ -209,6 +207,8 @@ function updatePhase(tree, pathname, aggData, errorMessages) {
var compData = new ComponentInfo(classRef);
var classType = compName.match(/component|directive|service/i);
if (classType) {
// Copy docs back from the .md file when the JSDocs are empty.
updatePropDocsFromMD(compData, inputMD, outputMD, errorMessages);
var templateName = path.resolve(templateFolder, classType + ".combyne");
var templateSource = fs.readFileSync(templateName, "utf8");
var template = combyne(templateSource);
@ -223,38 +223,10 @@ function updatePhase(tree, pathname, aggData, errorMessages) {
compData.errors.forEach(function (err) {
errorMessages.push(err);
});
/*
let templateName = classType[0] + ".liquid";
aggData.liq
.renderFile(templateName, compData)
.then(mdText => {
let newSection = remark().parse(mdText).children;
replaceSection(tree, "Class members", (before, section, after) => {
newSection.unshift(before);
newSection.push(after);
return newSection;
});
fs.writeFileSync(pathname, remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false}).stringify(tree));
});
*/
}
return true;
}
exports.updatePhase = updatePhase;
/*
function renderInputs(comp: ComponentInfo): string {
var result = "";
comp.properties.forEach(prop => {
result += `| ${prop.name} | \`${prop.type}\` | ${prop.defaultValue} | ${prop.docText} |\n`;
});
return result;
}
*/
function initialCap(str) {
return str[0].toUpperCase() + str.substr(1);
}
@ -275,3 +247,49 @@ function angNameToClassName(rawName) {
var finalName = outCompName + itemTypeIndicator;
return finalName;
}
function getPropDocsFromMD(tree, sectionHeading, docsColumn) {
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 propsTable = classMemHeading
.heading(function (h) {
return (h.children[0].type === "text") && (h.children[0].value === sectionHeading);
}).table();
var propTableRow = propsTable.childNav
.tableRow(function () { return true; }, 1).childNav;
var i = 1;
while (!propTableRow.empty) {
var propName = propTableRow
.tableCell().childNav
.text().item.value;
var propDocText = propTableRow
.tableCell(function () { return true; }, docsColumn).childNav
.text().item;
if (propDocText) {
result[propName] = propDocText.value;
}
i++;
propTableRow = propsTable.childNav
.tableRow(function () { return true; }, i).childNav;
}
return result;
}
function updatePropDocsFromMD(comp, inputDocs, outputDocs, errorMessages) {
comp.properties.forEach(function (prop) {
var propMDDoc;
if (prop.isInput) {
propMDDoc = inputDocs[prop.name];
}
else if (prop.isOutput) {
propMDDoc = outputDocs[prop.name];
}
// If JSDocs are empty but MD docs aren't then the Markdown is presumably more up-to-date.
if (!prop.docText && propMDDoc) {
prop.docText = propMDDoc;
errorMessages.push("Warning: empty JSDocs for property \"" + prop.name + "\" may need sync with the .md file.");
}
});
}

View File

@ -21,6 +21,9 @@ import {
} from "typedoc";
import { CommentTag } from "typedoc/dist/lib/models";
import { MDNav } from "../mdNav";
import * as unist from "../unistHelpers";
let libFolders = ["core", "content-services", "process-services", "insights"];
let templateFolder = path.resolve("tools", "doc", "templates");
@ -270,12 +273,6 @@ export function initPhase(aggData) {
}));
aggData.projData = app.convert(sources);
/*
aggData.liq = liquid({
root: templateFolder
});
*/
}
@ -288,6 +285,9 @@ 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);
@ -300,6 +300,9 @@ export function updatePhase(tree, pathname, aggData, errorMessages) {
let classType = compName.match(/component|directive|service/i);
if (classType) {
// Copy docs back from the .md file when the JSDocs are empty.
updatePropDocsFromMD(compData, inputMD, outputMD, errorMessages);
let templateName = path.resolve(templateFolder, classType + ".combyne");
let templateSource = fs.readFileSync(templateName, "utf8");
let template = combyne(templateSource);
@ -318,40 +321,11 @@ export function updatePhase(tree, pathname, aggData, errorMessages) {
compData.errors.forEach(err => {
errorMessages.push(err);
})
/*
let templateName = classType[0] + ".liquid";
aggData.liq
.renderFile(templateName, compData)
.then(mdText => {
let newSection = remark().parse(mdText).children;
replaceSection(tree, "Class members", (before, section, after) => {
newSection.unshift(before);
newSection.push(after);
return newSection;
});
fs.writeFileSync(pathname, remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false}).stringify(tree));
});
*/
}
return true;
}
/*
function renderInputs(comp: ComponentInfo): string {
var result = "";
comp.properties.forEach(prop => {
result += `| ${prop.name} | \`${prop.type}\` | ${prop.defaultValue} | ${prop.docText} |\n`;
});
return result;
}
*/
function initialCap(str: string) {
return str[0].toUpperCase() + str.substr(1);
@ -383,3 +357,64 @@ function angNameToClassName(rawName: string) {
return finalName;
}
function getPropDocsFromMD(tree, sectionHeading, docsColumn) {
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 propsTable = classMemHeading
.heading(h => {
return (h.children[0].type === "text") && (h.children[0].value === sectionHeading);
}).table();
let propTableRow = propsTable.childNav
.tableRow(()=>true, 1).childNav;
let i = 1;
while (!propTableRow.empty) {
let propName = propTableRow
.tableCell().childNav
.text().item.value;
let propDocText = propTableRow
.tableCell(()=>true, docsColumn).childNav
.text().item;
if (propDocText) {
result[propName] = propDocText.value;
}
i++;
propTableRow = propsTable.childNav
.tableRow(()=>true, i).childNav;
}
return result;
}
function updatePropDocsFromMD(comp: ComponentInfo, inputDocs, outputDocs, errorMessages) {
comp.properties.forEach(prop => {
let propMDDoc: string;
if (prop.isInput) {
propMDDoc = inputDocs[prop.name];
} else if (prop.isOutput) {
propMDDoc = outputDocs[prop.name];
}
// If JSDocs are empty but MD docs aren't then the Markdown is presumably more up-to-date.
if (!prop.docText && propMDDoc) {
prop.docText = propMDDoc;
errorMessages.push(`Warning: empty JSDocs for property "${prop.name}" may need sync with the .md file.`);
}
});
}