[ADF-2127] Started introducing new doc tools (#2809)

This commit is contained in:
Andy Stark
2018-01-09 10:36:24 +00:00
committed by Eugenio Romano
parent 1d0670a826
commit da9d0e0ec2
27 changed files with 1599 additions and 223 deletions

View File

@@ -0,0 +1,175 @@
var fs = require("fs");
var path = require("path");
var program = require("commander");
var remark = require("remark");
var parse = require("remark-parse");
var stringify = require("remark-stringify");
/*
var managetoc = require("./managetoc");
var sa = require("./seealso");
var index = require("./index");
*/
// "Aggregate" data collected over the whole file set.
var aggData = {};
var toolsFolderName = "tools";
var configFileName = "doctool.config.json";
function initPhase(aggData) {
/*
toolModules.seealso.initPhase(aggData);
toolModules.index.initPhase(aggData);
*/
toolList.forEach(toolName => {
toolModules[toolName].initPhase(aggData);
});
}
function readPhase(srcFolder, filenames, aggData) {
for (var i = 0; i < filenames.length; i++) {
var pathname = path.resolve(srcFolder, filenames[i]);
var src = fs.readFileSync(pathname);
var tree = remark().parse(src)
toolList.forEach(toolName => {
toolModules[toolName].readPhase(tree, pathname, aggData);
});
/*
toolModules.seealso.readPhase(tree, pathname, aggData);
toolModules.index.readPhase(tree, pathname, aggData);
*/
}
//console.log(JSON.stringify(aggData.mdFileData));
}
function aggPhase(aggData) {
toolList.forEach(toolName => {
toolModules[toolName].aggPhase(aggData);
});
/*
toolModules.seealso.aggPhase(aggData);
toolModules.index.aggPhase(aggData);
*/
}
function updatePhase(srcFolder, destFolder, filenames, aggData) {
for (var i = 0; i < filenames.length; i++) {
var pathname = path.resolve(srcFolder, filenames[i]);
var src = fs.readFileSync(pathname);
var tree = remark().parse(src)
var modified = false;
toolList.forEach(toolName => {
modified |= toolModules[toolName].updatePhase(tree, pathname, aggData);
});
if (modified)
fs.writeFileSync(path.resolve(destFolder, filenames[i]), remark().stringify(tree));
//console.log(JSON.stringify(tree));
}
}
function loadToolModules() {
var mods = {};
var toolsFolderPath = path.resolve(__dirname, toolsFolderName);
var modFiles = fs.readdirSync(toolsFolderPath);
for (var i = 0; i < modFiles.length; i++) {
var modPath = path.resolve(toolsFolderPath, modFiles[i])
if (path.extname(modPath) === ".js") {
var toolName = path.basename(modPath, ".js");
mods[toolName] = require(modPath);
}
}
return mods;
}
function loadToolConfig(configFilePath) {
var config = JSON.parse(fs.readFileSync(configFilePath));
return config.enabledTools;
}
program
.usage("[options] <source> [dest]")
.parse(process.argv);
if (program.args.length === 0) {
console.log("Error: source argument required");
return 0;
}
var sourcePath = path.resolve(program.args[0]);
var sourceInfo = fs.statSync(sourcePath);
var destPath;
var destInfo;
if (program.args.length >= 2) {
destPath = path.resolve(program.args[1]);
destInfo = fs.statSync(sourcePath);
} else {
destPath = sourcePath;
destInfo = sourceInfo;
}
if (sourceInfo.isDirectory() && !destInfo.isDirectory()) {
console.log("Error: The <dest> argument must be a directory");
return 0;
}
var toolModules = loadToolModules();
var toolList = loadToolConfig(path.resolve(__dirname, configFileName));
var files;
if (sourceInfo.isDirectory()) {
files = fs.readdirSync(sourcePath);
} else if (sourceInfo.isFile()) {
files = [ path.basename(sourcePath) ];
sourcePath = path.dirname(sourcePath);
}
files = files.filter(filename =>
(path.extname(filename) === ".md") &&
(filename !== "README.md")
);
//files.forEach(element => console.log(element));
console.log("Initialising...");
initPhase(aggData);
console.log("Analysing Markdown files...");
readPhase(sourcePath, files, aggData);
console.log("Computing aggregate data...");
aggPhase(aggData);
console.log("Updating Markdown files...");
updatePhase(sourcePath, destPath, files, aggData);

View File

@@ -0,0 +1,5 @@
{
"enabledTools": [
"index"
]
}

View File

@@ -0,0 +1,19 @@
module.exports = {
"ngNameToDisplayName": ngNameToDisplayName,
"dekebabifyName": dekebabifyName,
"classTypes": ["component", "directive", "model", "pipe", "service", "widget"]
}
function ngNameToDisplayName(ngName) {
var mainSections = ngName.split(".");
mainSections[0] = dekebabifyName(mainSections[0]);
return mainSections.join(" ");
}
function dekebabifyName(name) {
var result = name.replace(/-/g, " ");
result = result.substr(0, 1).toUpperCase() + result.substr(1);
return result;
}

View File

@@ -0,0 +1,362 @@
var fs = require("fs");
var path = require("path");
var remark = require("remark");
var stringify = require("remark-stringify");
var zone = require("mdast-zone");
var unist = require("../unistHelpers");
var ngHelpers = require("../ngHelpers");
module.exports = {
"initPhase": initPhase,
"readPhase": readPhase,
"aggPhase": aggPhase,
"updatePhase": updatePhase
}
var angFilenameRegex = /([a-zA-Z0-9\-]+)\.((component)|(directive)|(model)|(pipe)|(service)|(widget))\.ts/;
var searchFolderOmitRegex = /(config)|(mock)|(i18n)|(assets)|(styles)/;
var docsFolderPath = path.resolve("..", "docs");
var undocStoplistFileName = path.resolve(docsFolderPath, "undocStoplist.json");
var rootFolder = ".";
var indexMdFilePath = path.resolve(docsFolderPath, "README.md");
var guideSummaryFileName = path.resolve(docsFolderPath, "summary.json");
var maxBriefDescLength = 180;
var adfLibNames = ["core", "content-services", "insights", "process-services"];
function initPhase(aggData) {
aggData.stoplist = makeStoplist(undocStoplistFileName);
aggData.srcData = {};
aggData.mdFileDesc = [];
searchLibraryRecursive(aggData.srcData, path.resolve(rootFolder));
//console.log(JSON.stringify(aggData.srcData));
}
function readPhase(tree, pathname, aggData) {
var itemName = path.basename(pathname, ".md");
// Look for the first paragraph in the file by skipping other items.
// Should usually be a position 1 in the tree.
var s;
var briefDesc;
for (
s = 0;
(s < tree.children.length) && !unist.isParagraph(tree.children[s]);
s++
);
if (s < tree.children.length) {
briefDesc = tree.children[s];
}
aggData.mdFileDesc[itemName] = briefDesc;
}
function aggPhase(aggData) {
var sections = prepareIndexSections(aggData);
//console.log(JSON.stringify(sections));
var indexFileText = fs.readFileSync(indexMdFilePath, "utf8");
var indexFileTree = remark().parse(indexFileText);
for (var l = 0; l < adfLibNames.length; l++) {
var libName = adfLibNames[l];
var libSection = sections[libName];
var md = makeLibSectionMD(libSection);
zone(indexFileTree, libName, (startComment, oldSection, endComment) => {
md.unshift(startComment);
md.push(endComment);
return md;
});
}
var guideSection = buildGuideSection(guideSummaryFileName);
zone(indexFileTree, "guide", (startComment, oldSection, endComment) => {
return [
startComment, guideSection, endComment
]
});
fs.writeFileSync(path.resolve("..", "docs", "README.md"), remark().stringify(indexFileTree));
//fs.writeFileSync(indexMdFilePath, remark().stringify(indexFileTree));
//fs.writeFileSync(path.resolve(".", "testJson.md"), JSON.stringify(indexFileTree));
}
function updatePhase(tree, pathname, aggData) {
return false;
}
// Create a stoplist of regular expressions.
function makeStoplist(slFilePath) {
var listExpressions = JSON.parse(fs.readFileSync(slFilePath, 'utf8'));
var result = [];
for (var i = 0; i < listExpressions.length; i++) {
result.push(new RegExp(listExpressions[i]));
}
return result;
}
// Check if an item is covered by the stoplist and reject it if so.
function rejectItemViaStoplist(stoplist, itemName) {
for (var i = 0; i < stoplist.length; i++) {
if (stoplist[i].test(itemName)) {
return true;
}
}
return false;
}
// Search source folders for .ts files to discover all components, directives, etc.
function searchLibraryRecursive(srcData, folderPath) {
var items = fs.readdirSync(folderPath);
for (var i = 0; i < items.length; i++) {
var itemPath = path.resolve(folderPath, items[i]);
var info = fs.statSync(itemPath);
if (info.isFile() && (items[i].match(angFilenameRegex))) {
var nameNoSuffix = path.basename(items[i], '.ts');
var displayPath = itemPath.replace(/\\/g, '/');
displayPath = displayPath.substr(displayPath.indexOf("lib") + 4);
// Type == "component", "directive", etc.
var itemType = nameNoSuffix.split('.')[1];
srcData[nameNoSuffix] = { "path": displayPath, "type": itemType };
} else if (info.isDirectory() && !items[i].match(searchFolderOmitRegex)) {
searchLibraryRecursive(srcData, itemPath);
}
}
}
function prepareIndexSections(aggData) {
var srcNames = Object.keys(aggData.srcData);
var sections = initEmptySections();
for (var i = 0; i < srcNames.length; i++) {
var itemName = srcNames[i];
var srcData = aggData.srcData[itemName];
var libName = srcData.path.substr(0, srcData.path.indexOf("/"));
var briefDesc = aggData.mdFileDesc[itemName];
var displayName = ngHelpers.ngNameToDisplayName(itemName);
if (briefDesc) {
sections[libName][srcData.type].documented.push({
"displayName": displayName,
"mdName": itemName + ".md",
"srcPath": srcData.path,
"briefDesc": briefDesc
});
} else if (!rejectItemViaStoplist(aggData.stoplist, itemName)) {
sections[libName][srcData.type].undocumented.push({
"displayName": displayName,
"mdName": itemName + ".md",
"srcPath": srcData.path
});
}
}
return sections;
}
function initEmptySections() {
var result = {};
for (var l = 0; l < adfLibNames.length; l++) {
var lib = result[adfLibNames[l]] = {};
for (var c = 0; c < ngHelpers.classTypes.length; c++) {
var classType = lib[ngHelpers.classTypes[c]] = {};
classType.undocumented = [];
classType.documented = [];
}
}
return result;
}
function buildMDDocumentedSection(docItems) {
var listItems = [];
for (var i = 0; i < docItems.length; i++) {
listItems.push(makeMDDocumentedListItem(docItems[i]));
}
return unist.makeListUnordered(listItems);
}
function buildMDUndocumentedSection(docItems) {
var listItems = [];
for (var i = 0; i < docItems.length; i++) {
listItems.push(makeMDUndocumentedListItem(docItems[i]));
}
return unist.makeListUnordered(listItems);
}
function buildMDDocumentedTable(docItems) {
var rows = [
];
for (var i = 0; i < docItems.length; i++) {
rows.push(makeMDDocumentedTableRow(docItems[i]));
}
return rows;
//return unist.makeTable([null, null, null, null], rows);
}
function buildMDUndocumentedTable(docItems) {
var rows = [
];
for (var i = 0; i < docItems.length; i++) {
rows.push(makeMDUndocumentedTableRow(docItems[i]));
}
return rows;
//return unist.makeTable([null, null, null, null], rows);
}
function makeMDDocumentedListItem(docItem) {
var mdFileLink = unist.makeLink(unist.makeText(docItem.displayName), docItem.mdName);
var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);
var desc = docItem.briefDesc;
var para = unist.makeParagraph([
mdFileLink, unist.makeText(" ("), srcFileLink, unist.makeText(") "), desc
]);
return unist.makeListItem(para);
}
function makeMDUndocumentedListItem(docItem) {
var itemName = unist.makeText(docItem.displayName);
var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);
var para = unist.makeParagraph([
unist.makeText("* "), itemName, unist.makeText(" ("), srcFileLink, unist.makeText(")")
]);
return unist.makeListItem(para);
}
function makeMDDocumentedTableRow(docItem) {
var mdFileLink = unist.makeLink(unist.makeText(docItem.displayName), docItem.mdName);
var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);
var desc = docItem.briefDesc;
return unist.makeTableRow([
unist.makeTableCell([mdFileLink]),
unist.makeTableCell([desc]),
unist.makeTableCell([srcFileLink])
]);
}
function makeMDUndocumentedTableRow(docItem) {
var itemName = unist.makeText(docItem.displayName);
var srcFileLink = unist.makeLink(unist.makeText("Source"), "../lib/" + docItem.srcPath);
return unist.makeTableRow([
unist.makeTableCell([unist.makeEmphasis([itemName])]),
unist.makeTableCell([unist.makeEmphasis([unist.makeText("Not currently documented")])]),
unist.makeTableCell([srcFileLink])
]);
}
function makeLibSectionMD(libSection){
var md = [];
var libClassTypes = Object.keys(libSection);
for (var i = 0; i < libClassTypes.length; i++) {
var classType = libClassTypes[i];
var classSection = libSection[classType];
if (!classSection)
continue;
var displayNameNode;
if ((classSection.documented.length > 0) || (classSection.undocumented.length > 0)) {
displayNameNode = unist.makeText(ngHelpers.dekebabifyName(classType + "s"));
md.push(unist.makeHeading(displayNameNode, 2));
var tableRows = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Description")]),
unist.makeTableCell([unist.makeText("Source link")])
])
];
if (classSection.documented.length > 0) {
//md.push(buildMDDocumentedSection(classSection.documented));
tableRows = tableRows.concat(buildMDDocumentedTable(classSection.documented));
}
if (classSection.undocumented.length > 0) {
// md.push(buildMDUndocumentedSection(classSection.undocumented));
tableRows = tableRows.concat(buildMDUndocumentedTable(classSection.undocumented));
}
md.push(unist.makeTable([null, null, null, null], tableRows));
}
}
return md;
}
function buildGuideSection(guideJsonFilename) {
var summary = JSON.parse(fs.readFileSync(guideJsonFilename, "utf8"));
var listItems = [];
for (var i = 0; i < summary.length; i++) {
var link = unist.makeLink(unist.makeText(summary[i].title), summary[i].file);
listItems.push(unist.makeListItem(link));
}
return unist.makeListUnordered(listItems);
}

View File

@@ -0,0 +1,175 @@
var path = require("path");
var getSection = require("mdast-util-heading-range");
var unist = require("../unistHelpers");
var seeAlsoHeading = "See Also";
module.exports = {
"initPhase": initPhase,
"readPhase": readPhase,
"aggPhase": aggPhase,
"updatePhase": updatePhase
}
function initPhase(aggData) {
aggData.saGraph = {};
aggData.saUpdateGraph = {};
}
function readPhase(tree, pathname, aggData) {
var saHeadingOffset = findSeeAlsoSection(tree);
var saNode = [];
if (saHeadingOffset !== -1) {
// Skip over non-list parts.
var s;
for (
s = saHeadingOffset;
(s < tree.children.length) && !unist.isListUnordered(tree.children[s]);
s++
);
if ((s < tree.children.length) && unist.isListUnordered(tree.children[s])) {
var list = tree.children[s];
for (var i = 0; i < list.children.length; i++) {
var itemLink = getItemLinkInfo(list.children[i]);
if (itemLink) {
saNode.push(itemLink);
}
}
}
}
aggData.saGraph[path.basename(pathname, ".md")] = saNode;
}
function aggPhase(aggData) {
aggData.saUpdateGraph = tidyGraph(aggData.saGraph);
}
function updatePhase(tree, pathname, aggData) {
var currNodeName = path.basename(pathname, ".md");
var currNodeArcs = aggData.saUpdateGraph[currNodeName];
if (currNodeArcs.length > 0) {
var saListItems = [];
for (var i = 0; i < currNodeArcs.length; i++) {
var linkText = graphKeyToLinkName(currNodeArcs[i]);
var linkTarget = currNodeArcs[i] + ".md";
var link = unist.makeLink(unist.makeText(linkText), linkTarget);
saListItems.push(unist.makeListItem(link));
}
var saHeadingOffset = findSeeAlsoSection(tree);
if (saHeadingOffset !== -1) {
// Skip over non-list parts.
var s;
for (
s = saHeadingOffset;
(s < tree.children.length) && !unist.isListUnordered(tree.children[s]);
s++
);
// Push all elements of the items array as if they were separate elements.
Array.prototype.push.apply(tree.children[s].children, saListItems);
} else {
// This file doesn't currently have a See Also section, so add one at the end.
tree.children.push(unist.makeHeading(unist.makeText(seeAlsoHeading), 2));
tree.children.push(unist.makeListUnordered(saListItems));
}
}
return true;
}
function graphKeyToLinkName(key) {
var mainSections = key.split(".");
mainSections[0] = tidyName(mainSections[0]);
return mainSections.join(" ");
}
// Convert an Angular-style name (eg, "card-view") into one with correct spaces and uppercase (eg, "Card view").
function tidyName(name) {
var result = name.replace(/-/g, " ");
result = result.substr(0, 1).toUpperCase() + result.substr(1);
return result;
}
function makeEmptySAList() {
var result = [];
}
// Makes link symmetrical between items (ie, if A links to B but not the other way
// around then it adds the missing link).
function tidyGraph(graph) {
var nodeNames = Object.keys(graph);
var result = {};
for (var n = 0; n < nodeNames.length; n++) {
result[nodeNames[n]] = [];
}
for (var n = 0; n < nodeNames.length; n++) {
var currNodeName = nodeNames[n];
var currNodeArcs = graph[currNodeName];
for (var a = 0; a < currNodeArcs.length; a++) {
var linkedNode = graph[currNodeArcs[a]];
var resultNode = result[currNodeArcs[a]];
if (!linkedNode) {
console.log(`Warning: item '${currNodeArcs[a]}' (in See Also section of '${currNodeName}') has no corresponding file`);
} else if (linkedNode.indexOf(currNodeName) === -1) {
linkedNode.push(currNodeName);
resultNode.push(currNodeName);
}
}
}
return result;
}
function findSeeAlsoSection(tree) {
var i;
for (i = 0; i < tree.children.length; i++) {
var child = tree.children[i];
if (unist.isHeading(child) && (child.children[0].value.toLowerCase() === seeAlsoHeading.toLowerCase()))
return i;
}
return -1;
}
function getItemLinkInfo(listItem) {
var linkTarget = listItem.children[0].children[0].url;
if (linkTarget.startsWith("http:") ||
linkTarget.startsWith("#") ||
!linkTarget.endsWith(".md"))
return null;
else
return path.basename(linkTarget, ".md");
}

View File

@@ -0,0 +1,82 @@
var remark = require("remark");
var tocGenerator = require("mdast-util-toc");
var replaceSection = require("mdast-util-heading-range");
var unist = require("../unistHelpers");
const contentsHeading = "Contents";
const minHeadingsForToc = 8;
const maxTocHeadingDepth = 3;
module.exports = process;
// Find an existing Contents section or add a new empty one if needed.
// Returns true if section is present/needed, false if not needed.
function establishContentsSection(mdTree) {
var firstL2HeadingPos = -1;
var numTocHeadings = 0;
var foundContentsHeading = false;
for (var i = 0; i < mdTree.children.length; i++) {
var child = mdTree.children[i];
// Look through all headings.
if (child.type === "heading") {
if ((child.depth > 1) && (child.depth <= maxTocHeadingDepth)) {
numTocHeadings++;
}
if (child.depth === 2) {
// Note where the first L2 heading is.
if (firstL2HeadingPos === -1) {
firstL2HeadingPos = i;
}
// If it is also a Contents heading then we're done. We don't include the
// Contents heading itself within the ToC, so decrement the count for that.
if ((child.children[0].value === contentsHeading) && !foundContentsHeading) {
foundContentsHeading = true;
numTocHeadings--;
}
}
}
}
// If we get here then a level 2 Contents heading was not found.
// If there are enough headings for a ToC to be necessary then
// add one in the right place.
if (!foundContentsHeading) {
var newContsHeading = unist.makeHeading(contentsHeading, 2);
// If we found another L2 heading then add the Contents in just before it.
if (firstL2HeadingPos != -1) {
mdTree.children.splice(firstL2HeadingPos, 0, newContsHeading);
} else {
// Otherwise, the unlikely situation where a ToC is required but there
// are no L2 headings! Add it as the second element in the document.
mdTree.children.splice(1, 0, newContsHeading);
}
}
return numTocHeadings;
}
function process(mdTree, file) {
// If we need a contents section then add one or update the existing one.
var numTocHeadings = establishContentsSection(mdTree);
if (numTocHeadings >= minHeadingsForToc) {
var newToc = tocGenerator(mdTree, {heading: contentsHeading, maxDepth: 3});
replaceSection(mdTree, contentsHeading, function(before, oldSection, after) {
return [before, newToc.map, after];
});
} else {
// Otherwise, we don't need one, so remove any existing one.
replaceSection(mdTree, contentsHeading, function(before, oldSection, after) {
return [after];
});
}
}

View File

@@ -0,0 +1,181 @@
"use strict";
exports.__esModule = true;
var ts = require("typescript");
var path = require("path");
var program = require("commander");
var heading = require("mdast-util-heading-range");
var unist = require("../unistHelpers");
function initPhase(aggData) {
}
exports.initPhase = initPhase;
function readPhase(tree, pathname, aggData) {
}
exports.readPhase = readPhase;
function aggPhase(aggData) {
}
exports.aggPhase = aggPhase;
function updatePhase(tree, pathname, aggData) {
var fileNameNoSuffix = path.basename(pathname, ".md");
if (fileNameNoSuffix.match(/component/)) {
var srcData = aggData.srcData[fileNameNoSuffix];
if (srcData) {
var srcPath = srcData.path;
var className = fixCompodocFilename(fileNameNoSuffix);
var inputs = [];
var outputs = [];
getPropDocData(path.resolve(".", srcPath), className, inputs, outputs);
var inTable_1 = buildInputsTable(inputs);
var outTable_1 = buildOutputsTable(outputs);
if (inTable_1) {
console.log("Made a props table");
heading(tree, "Properties", function (before, section, after) {
return [before, inTable_1, after];
});
}
if (outTable_1) {
console.log("Made an events table");
heading(tree, "Events", function (before, section, after) {
return [before, outTable_1, after];
});
}
}
}
}
exports.updatePhase = updatePhase;
function initialCap(str) {
return str[0].toUpperCase() + str.substr(1);
}
function fixCompodocFilename(rawName) {
var name = rawName.replace(/\]|\(|\)/g, '');
var fileNameSections = name.split('.');
var compNameSections = fileNameSections[0].split('-');
var outCompName = '';
for (var i = 0; i < compNameSections.length; i++) {
outCompName = outCompName + initialCap(compNameSections[i]);
}
var itemTypeIndicator = '';
if (fileNameSections.length > 1) {
itemTypeIndicator = initialCap(fileNameSections[1]);
}
var finalName = outCompName + itemTypeIndicator;
return finalName;
}
function getPropDocData(srcPath, docClassName, inputs, outputs) {
var prog = ts.createProgram(program.args, {
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
});
var sourceFiles = prog.getSourceFiles();
var checker = prog.getTypeChecker();
for (var i = 0; i < sourceFiles.length; i++) {
if (!sourceFiles[i].isDeclarationFile)
ts.forEachChild(sourceFiles[i], visit);
}
function visit(node) {
if (!isNodeExported(node))
return;
if (ts.isClassDeclaration(node) && node.name) {
var classDec = node;
var sourceFile = classDec.getSourceFile();
if (classDec.name.escapedText === docClassName) {
getPropDataFromClass(checker, classDec, inputs, outputs);
}
}
}
}
function getPropDataFromClass(checker, classDec, inputs, outputs) {
var sourceFile = classDec.getSourceFile();
for (var i = 0; i < classDec.members.length; i++) {
var member = classDec.members[i];
if (ts.isPropertyDeclaration(member)) {
var prop = member;
var mods = ts.getCombinedModifierFlags(prop);
var nonPrivate = (mods & ts.ModifierFlags.Private) === 0;
var memSymbol = checker.getSymbolAtLocation(prop.name);
if (nonPrivate && memSymbol && prop.decorators) {
var name_1 = memSymbol.getName();
var initializer = "";
if (prop.initializer) {
initializer = prop.initializer.getText(sourceFile);
}
var doc = ts.displayPartsToString(memSymbol.getDocumentationComment());
var propType = checker.typeToString(checker.getTypeOfSymbolAtLocation(memSymbol, memSymbol.valueDeclaration));
var dec = prop.decorators[0].getText(sourceFile);
if (dec.match(/@Input/)) {
inputs.push({
"name": name_1,
"type": propType,
"init": initializer,
"docText": doc
});
}
else if (dec.match(/@Output/)) {
outputs.push({
"name": name_1,
"type": propType,
"docText": doc
});
}
}
}
}
}
function buildInputsTable(inputs) {
if (inputs.length === 0) {
return null;
}
var rows = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")]),
unist.makeTableCell([unist.makeText("Default value")]),
unist.makeTableCell([unist.makeText("Description")])
])
];
for (var i = 0; i < inputs.length; i++) {
var pName = inputs[i].name;
var pType = inputs[i].type;
var pDefault = inputs[i].defaultValue || "";
var pDesc = inputs[i].description || "";
if (pDesc) {
pDesc = pDesc.trim().replace(/[\n\r]+/, " ");
}
var cells = [
unist.makeTableCell([unist.makeText(pName)]),
unist.makeTableCell([unist.makeText(pType)]),
unist.makeTableCell([unist.makeText(pDefault)]),
unist.makeTableCell([unist.makeText(pDesc)])
];
rows.push(unist.makeTableRow(cells));
}
return unist.makeTable([null, null, null, null], rows);
}
function buildOutputsTable(outputs) {
if (outputs.length === 0) {
return null;
}
var rows = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")]),
unist.makeTableCell([unist.makeText("Description")])
])
];
for (var i = 0; i < outputs.length; i++) {
var eName = outputs[i].name;
var eType = outputs[i].type;
var eDesc = outputs[i].description || "";
if (eDesc) {
eDesc = eDesc.trim().replace(/[\n\r]+/, ' ');
}
var cells = [
unist.makeTableCell([unist.makeText(eName)]),
unist.makeTableCell([unist.makeText(eType)]),
unist.makeTableCell([unist.makeText(eDesc)])
];
rows.push(unist.makeTableRow(cells));
}
return unist.makeTable([null, null, null], rows);
}
function isNodeExported(node) {
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);
}

View File

@@ -0,0 +1,237 @@
import * as ts from "typescript";
import * as fs from "fs";
import * as path from "path";
import * as program from "commander";
import * as heading from "mdast-util-heading-range";
import * as unist from "../unistHelpers";
export function initPhase(aggData) {
}
export function readPhase(tree, pathname, aggData) {
}
export function aggPhase(aggData) {
}
export function updatePhase(tree, pathname, aggData) {
let fileNameNoSuffix = path.basename(pathname, ".md");
if (fileNameNoSuffix.match(/component/)) {
let srcData = aggData.srcData[fileNameNoSuffix];
if (srcData) {
let srcPath = srcData.path;
let className = fixCompodocFilename(fileNameNoSuffix);
let inputs = [];
let outputs = [];
getPropDocData(path.resolve(".", srcPath), className, inputs, outputs);
let inTable = buildInputsTable(inputs);
let outTable = buildOutputsTable(outputs);
if (inTable) {
console.log("Made a props table");
heading(tree, "Properties", (before, section, after) => {
return [before, inTable, after];
});
}
if (outTable) {
console.log("Made an events table");
heading(tree, "Events", (before, section, after) => {
return [before, outTable, after];
});
}
}
}
}
function initialCap(str: string) {
return str[0].toUpperCase() + str.substr(1);
}
function fixCompodocFilename(rawName: string) {
var name = rawName.replace(/\]|\(|\)/g, '');
var fileNameSections = name.split('.');
var compNameSections = fileNameSections[0].split('-');
var outCompName = '';
for (var i = 0; i < compNameSections.length; i++) {
outCompName = outCompName + initialCap(compNameSections[i]);
}
var itemTypeIndicator = '';
if (fileNameSections.length > 1) {
itemTypeIndicator = initialCap(fileNameSections[1]);
}
var finalName = outCompName + itemTypeIndicator;
return finalName;
}
function getPropDocData(srcPath: string, docClassName: string, inputs: any[], outputs: any[]) {
let prog = ts.createProgram(program.args, {
target: ts.ScriptTarget.ES5, module: ts.ModuleKind.CommonJS
});
let sourceFiles = prog.getSourceFiles();
let checker = prog.getTypeChecker();
for (var i = 0; i < sourceFiles.length; i++) {
if (!sourceFiles[i].isDeclarationFile)
ts.forEachChild(sourceFiles[i], visit);
}
function visit(node: ts.Node) {
if (!isNodeExported(node))
return;
if (ts.isClassDeclaration(node) && node.name) {
let classDec: ts.ClassDeclaration = node;
let sourceFile = classDec.getSourceFile();
if (classDec.name.escapedText === docClassName) {
getPropDataFromClass(checker, classDec, inputs, outputs);
}
}
}
}
function getPropDataFromClass(
checker: ts.TypeChecker,
classDec:ts.ClassDeclaration,
inputs: any[],
outputs: any[]
){
let sourceFile = classDec.getSourceFile();
for (var i = 0; i < classDec.members.length; i++) {
let member = classDec.members[i];
if (ts.isPropertyDeclaration(member)) {
let prop: ts.PropertyDeclaration = member;
let mods = ts.getCombinedModifierFlags(prop);
let nonPrivate = (mods & ts.ModifierFlags.Private) === 0;
let memSymbol = checker.getSymbolAtLocation(prop.name);
if (nonPrivate && memSymbol && prop.decorators) {
let name = memSymbol.getName();
let initializer = "";
if (prop.initializer) {
initializer = prop.initializer.getText(sourceFile);
}
let doc = ts.displayPartsToString(memSymbol.getDocumentationComment());
let propType = checker.typeToString(checker.getTypeOfSymbolAtLocation(memSymbol, memSymbol.valueDeclaration!));
let dec = prop.decorators[0].getText(sourceFile);
if (dec.match(/@Input/)) {
inputs.push({
"name": name,
"type": propType,
"init": initializer,
"docText": doc
});
} else if (dec.match(/@Output/)) {
outputs.push({
"name": name,
"type": propType,
"docText": doc
});
}
}
}
}
}
function buildInputsTable(inputs: any[]) {
if (inputs.length === 0) {
return null;
}
var rows = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")]),
unist.makeTableCell([unist.makeText("Default value")]),
unist.makeTableCell([unist.makeText("Description")])
])
];
for (var i = 0; i < inputs.length; i++) {
var pName = inputs[i].name;
var pType = inputs[i].type;
var pDefault = inputs[i].defaultValue || "";
var pDesc = inputs[i].description || "";
if (pDesc) {
pDesc = pDesc.trim().replace(/[\n\r]+/, " ");
}
var cells = [
unist.makeTableCell([unist.makeText(pName)]),
unist.makeTableCell([unist.makeText(pType)]),
unist.makeTableCell([unist.makeText(pDefault)]),
unist.makeTableCell([unist.makeText(pDesc)])
];
rows.push(unist.makeTableRow(cells));
}
return unist.makeTable([null, null, null, null], rows);
}
function buildOutputsTable(outputs: any[]) {
if (outputs.length === 0) {
return null;
}
var rows = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")]),
unist.makeTableCell([unist.makeText("Description")])
])
];
for (var i = 0; i < outputs.length; i++){
var eName = outputs[i].name;
var eType = outputs[i].type;
var eDesc = outputs[i].description || "";
if (eDesc) {
eDesc = eDesc.trim().replace(/[\n\r]+/, ' ');
}
var cells = [
unist.makeTableCell([unist.makeText(eName)]),
unist.makeTableCell([unist.makeText(eType)]),
unist.makeTableCell([unist.makeText(eDesc)])
];
rows.push(unist.makeTableRow(cells));
}
return unist.makeTable([null, null, null], rows);
}
function isNodeExported(node: ts.Node): boolean {
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);
}

View File

@@ -0,0 +1,101 @@
module.exports = {
makeRoot: function (children) {
return {
"type": "root",
"children": children
};
},
makeText: function (textVal) {
return {
"type": "text",
"value": textVal
};
},
makeEmphasis: function (content) {
return {
"type": "emphasis",
"children": content
};
},
makeHeading: function (caption, depth) {
return {
"type": "heading",
"depth": depth,
"children": [caption]
};
},
makeLink: function (caption, url) {
return {
"type": "link",
"url": url,
"children": [ caption ]
};
},
makeListItem: function (itemValue) {
return {
"type": "listItem",
"loose": false,
"children": [ itemValue ]
};
},
makeListUnordered: function (itemsArray) {
return {
"type": "list",
"ordered": false,
"children": itemsArray,
"loose": false
};
},
makeParagraph: function (itemsArray) {
return {
"type": "paragraph",
"children": itemsArray
}
},
makeTable: function (colAlignArray, rowArray) {
return {
"type": "table",
"align": colAlignArray,
"children": rowArray
};
},
makeTableRow: function (cellArray) {
return {
"type": "tableRow",
"children": cellArray
};
},
makeTableCell: function (content) {
return {
"type": "tableCell",
"children": content
};
},
isHeading: function (node) {
return node.type === "heading";
},
isListUnordered: function (node) {
return (node.type === "list") && !node.ordered;
},
isParagraph: function (node) {
return node.type === "paragraph";
},
isText: function (node) {
return node.type === "text";
}
}