[ADF-1769] Added support for methods to JSDoc tool (#2925)

* [ADF-1769] Refactored component props features

* [ADF-1769] Added methods list feature to doc tool

* [ADF-1769] Added support for optional parameters and initialisers

* [ADF-1769] Switched off prop generator tool
This commit is contained in:
Andy Stark
2018-02-09 10:22:41 +00:00
committed by Eugenio Romano
parent 0e51208333
commit 3114fa4862
5 changed files with 587 additions and 259 deletions

View File

@@ -4,29 +4,38 @@ Displays and manages dialogs for selecting content to open, copy or upload.
## Methods ## Methods
`openFileBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]>`<br/> - `openFileBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]>`
Opens a file browser at a chosen folder location. Opens a file browser at a chosen folder location.
- `folderNodeId` - ID of the folder to use
- `openFileBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]>`
Opens a file browser at a chosen site location.
`openFolderBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]>`<br/> - `openFolderBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]>`
Opens a folder browser at a chosen folder location. Opens a folder browser at a chosen site location.
`openFileBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]>`<br/> - `openFolderBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]>`
Opens a file browser at a chosen site location. Opens a folder browser at a chosen folder location.
- `folderNodeId` - ID of the folder to use
- `openCopyMoveDialog(action: string, contentEntry: MinimalNodeEntryEntity, permission?: string): Observable<MinimalNodeEntryEntity[]>`
Opens a dialog to copy or move an item to a new location.
- `action` - Name of the action (eg, "Copy" or "Move") to show in the title
- `contentEntry` - Item to be copied or moved
- `permission` - (Optional) Permission for the operation
- `getTitleTranslation(action: string, name: string): string`
Gets the translation of the dialog title.
- `action` - Name of the action to display in the dialog title
- `name` - Name of the item on which the action is being performed
- `openUploadFolderDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]>`
Opens a dialog to choose a folder to upload.
- `action` - Name of the action to show in the title
- `contentEntry` - Item to upload
- `openUploadFileDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]>`
Opens a dialog to choose a file to upload.
- `action` - Name of the action to show in the title
- `contentEntry` - Item to upload
- `close()`
Closes the currently open dialog.
`openFolderBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]>`<br/>
Opens a folder browser at a chosen site location.
`openCopyMoveDialog(action: string, contentEntry: MinimalNodeEntryEntity, permission?: string): Observable<MinimalNodeEntryEntity[]>`<br/>
Opens a dialog to copy or move an item to a new location.
`openUploadFileDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]>`<br/>
Opens a dialog to choose a file to upload.
`openUploadFolderDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]>`<br/>
Opens a dialog to choose a folder to upload.
`close()`<br/>
Closes the currently open dialog.
## Details ## Details

View File

@@ -15,95 +15,51 @@ exports.readPhase = readPhase;
function aggPhase(aggData) { function aggPhase(aggData) {
} }
exports.aggPhase = aggPhase; exports.aggPhase = aggPhase;
function updatePhase(tree, pathname, aggData) { var PropData = /** @class */ (function () {
var fileNameNoSuffix = path.basename(pathname, ".md"); function PropData() {
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) {
heading(tree, "Properties", function (before, section, after) {
return [before, inTable_1, after];
});
} }
if (outTable_1) { return PropData;
heading(tree, "Events", function (before, section, after) { }());
return [before, outTable_1, after]; var ParamData = /** @class */ (function () {
}); function ParamData() {
} }
ParamData.prototype.getSignature = function () {
var sig = this.name;
if (this.optional)
sig += "?";
sig += ": " + this.type;
if (this.initializer)
sig += " = " + this.initializer;
return sig;
};
return ParamData;
}());
var MethodData = /** @class */ (function () {
function MethodData() {
this.params = [];
} }
return true; MethodData.prototype.getSignature = function () {
var sig = this.name + "(";
if (this.params.length > 0) {
sig += this.params[0].getSignature();
} }
else { for (var i = 1; i < this.params.length; i++) {
return false; sig += ", " + this.params[i].getSignature();
} }
} sig += ")";
exports.updatePhase = updatePhase; if (this.returnType !== "void") {
function initialCap(str) { sig += ": " + this.returnType;
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 = ''; return sig;
if (fileNameSections.length > 1) { };
itemTypeIndicator = initialCap(fileNameSections[1]); return MethodData;
}());
var ComponentDocAutoContent = /** @class */ (function () {
function ComponentDocAutoContent() {
this.inputs = [];
this.outputs = [];
} }
var finalName = outCompName + itemTypeIndicator; ComponentDocAutoContent.prototype.extractClassInfoFromSource = function (checker, classDec) {
return finalName;
}
function getPropDocData(srcPath, docClassName, inputs, outputs) {
var prog = ts.createProgram([srcPath], {
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) {
getPropDataFromClassChain(checker, classDec, inputs, outputs);
}
}
}
}
// Get properties/events from main class and all inherited classes.
function getPropDataFromClassChain(checker, classDec, inputs, outputs) {
// Main class
getPropDataFromClass(checker, classDec, inputs, outputs);
// Inherited classes
if (classDec.heritageClauses) {
for (var _i = 0, _a = classDec.heritageClauses; _i < _a.length; _i++) {
var hc = _a[_i];
var hcType = checker.getTypeFromTypeNode(hc.types[0]);
for (var _b = 0, _c = hcType.symbol.declarations; _b < _c.length; _b++) {
var dec = _c[_b];
if (typescript_1.isClassDeclaration(dec)) {
getPropDataFromClassChain(checker, dec, inputs, outputs);
}
}
}
}
}
function getPropDataFromClass(checker, classDec, inputs, outputs) {
var sourceFile = classDec.getSourceFile(); var sourceFile = classDec.getSourceFile();
for (var i = 0; i < classDec.members.length; i++) { for (var i = 0; i < classDec.members.length; i++) {
var member = classDec.members[i]; var member = classDec.members[i];
@@ -125,53 +81,209 @@ function getPropDataFromClass(checker, classDec, inputs, outputs) {
var propType = checker.typeToString(checker.getTypeOfSymbolAtLocation(memSymbol, memSymbol.valueDeclaration)); var propType = checker.typeToString(checker.getTypeOfSymbolAtLocation(memSymbol, memSymbol.valueDeclaration));
var dec = prop.decorators[0].getText(sourceFile); var dec = prop.decorators[0].getText(sourceFile);
if (dec.match(/@Input/)) { if (dec.match(/@Input/)) {
inputs.push({ this.inputs.push({
"name": name_1, "name": name_1,
"type": propType, "type": propType,
"init": initializer, "initializer": initializer,
"docText": doc "docText": doc
}); });
} }
else if (dec.match(/@Output/)) { else if (dec.match(/@Output/)) {
outputs.push({ this.outputs.push({
"name": name_1, "name": name_1,
"type": propType, "type": propType,
"initializer": "",
"docText": doc "docText": doc
}); });
} }
} }
} }
} }
};
ComponentDocAutoContent.prototype.addContentToDoc = function (tree) {
var inTable = buildPropsTable(this.inputs);
var outTable = buildPropsTable(this.outputs, false);
if (inTable) {
heading(tree, "Properties", function (before, section, after) {
return [before, inTable, after];
});
}
if (outTable) {
heading(tree, "Events", function (before, section, after) {
return [before, outTable, after];
});
}
};
return ComponentDocAutoContent;
}());
var ServiceDocAutoContent = /** @class */ (function () {
function ServiceDocAutoContent() {
this.props = [];
this.methods = [];
}
ServiceDocAutoContent.prototype.extractClassInfoFromSource = function (checker, classDec) {
var sourceFile = classDec.getSourceFile();
for (var i = 0; i < classDec.members.length; i++) {
var member = classDec.members[i];
if (ts.isMethodDeclaration(member)) {
var method = member;
var mods = ts.getCombinedModifierFlags(method);
var nonPrivate = (mods & ts.ModifierFlags.Private) === 0;
var memSymbol = checker.getSymbolAtLocation(method.name);
if (nonPrivate && memSymbol) {
var methData = new MethodData();
methData.name = memSymbol.getName();
var doc = ts.displayPartsToString(memSymbol.getDocumentationComment());
methData.docText = doc.replace(/\r\n/g, " ");
var sig = checker.getSignatureFromDeclaration(method);
var returnType = sig.getReturnType();
methData.returnType = checker.typeToString(returnType);
var returnSymbol = returnType.getSymbol();
var params = method.parameters;
for (var p = 0; p < params.length; p++) {
var pData = new ParamData();
pData.name = params[p].name.getText();
pData.type = params[p].type.getText();
var paramSymbol = checker.getSymbolAtLocation(params[p].name);
pData.docText = ts.displayPartsToString(paramSymbol.getDocumentationComment());
pData.optional = params[p].questionToken ? true : false;
if (params[p].initializer) {
var initText = params[p].initializer.getText();
if (initText !== "undefined")
pData.initializer = initText;
}
methData.params.push(pData);
}
this.methods.push(methData);
}
}
}
};
ServiceDocAutoContent.prototype.addContentToDoc = function (tree) {
var propsTable = buildPropsTable(this.props);
var methodsList = buildMethodsList(this.methods);
if (propsTable) {
heading(tree, "Properties", function (before, section, after) {
return [before, propsTable, after];
});
}
if (methodsList) {
heading(tree, "Methods", function (before, section, after) {
return [before, methodsList, after];
});
}
};
return ServiceDocAutoContent;
}());
function updatePhase(tree, pathname, aggData) {
var fileNameNoSuffix = path.basename(pathname, ".md");
var itemType = fileNameNoSuffix.match(/component|service/);
if (itemType) {
var srcData = aggData.srcData[fileNameNoSuffix];
if (srcData) {
var srcPath = srcData.path;
var className = fixAngularFilename(fileNameNoSuffix);
var classData = void 0;
if (itemType[0] === "component") {
classData = new ComponentDocAutoContent();
}
else if (itemType[0] === "service") {
classData = new ServiceDocAutoContent();
}
getDocSourceData(path.resolve(".", srcPath), className, classData);
classData.addContentToDoc(tree);
}
return true;
}
else {
return false;
}
}
exports.updatePhase = updatePhase;
function initialCap(str) {
return str[0].toUpperCase() + str.substr(1);
}
function fixAngularFilename(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 getDocSourceData(srcPath, docClassName, classData) {
var prog = ts.createProgram([srcPath], {
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) {
getPropDataFromClassChain(checker, classDec, classData);
}
}
}
}
// Get properties/events from main class and all inherited classes.
function getPropDataFromClassChain(checker, classDec, classData) {
// Main class
classData.extractClassInfoFromSource(checker, classDec);
// Inherited classes
if (classDec.heritageClauses) {
for (var _i = 0, _a = classDec.heritageClauses; _i < _a.length; _i++) {
var hc = _a[_i];
var hcType = checker.getTypeFromTypeNode(hc.types[0]);
for (var _b = 0, _c = hcType.symbol.declarations; _b < _c.length; _b++) {
var dec = _c[_b];
if (typescript_1.isClassDeclaration(dec)) {
getPropDataFromClassChain(checker, dec, classData);
}
}
}
}
} }
function buildInputsTable(inputs) { function buildPropsTable(props, includeInitializer) {
if (inputs.length === 0) { if (includeInitializer === void 0) { includeInitializer = true; }
if (props.length === 0) {
return null; return null;
} }
var rows = [ var headerCells = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]), unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")]), unist.makeTableCell([unist.makeText("Type")])
unist.makeTableCell([unist.makeText("Default value")]),
unist.makeTableCell([unist.makeText("Description")])
])
]; ];
for (var i = 0; i < inputs.length; i++) { if (includeInitializer)
var pName = inputs[i].name; headerCells.push(unist.makeTableCell([unist.makeText("Default value")]));
var pType = inputs[i].type; headerCells.push(unist.makeTableCell([unist.makeText("Description")]));
var pDefault = inputs[i].init || ""; var rows = [
var pDesc = inputs[i].docText || ""; unist.makeTableRow(headerCells)
];
for (var i = 0; i < props.length; i++) {
var pName = props[i].name;
var pType = props[i].type;
var pDefault = props[i].initializer || "";
var pDesc = props[i].docText || "";
if (pDesc) { if (pDesc) {
//pDesc = pDesc.trim().replace(/[\n\r]+/, " ");
pDesc = pDesc.replace(/[\n\r]+/, " "); pDesc = pDesc.replace(/[\n\r]+/, " ");
} }
var descCellContent = remark().parse(pDesc).children; var descCellContent = remark().parse(pDesc).children;
var defaultCellContent; var defaultCellContent;
if (pDefault) { if (pDefault) {
/*
descCellContent.push(unist.makeHTML("<br/>"));
descCellContent.push(unist.makeText(" Default value: "));
descCellContent.push(unist.makeInlineCode(pDefault));
*/
defaultCellContent = unist.makeInlineCode(pDefault); defaultCellContent = unist.makeInlineCode(pDefault);
} }
else { else {
@@ -179,41 +291,45 @@ function buildInputsTable(inputs) {
} }
var cells = [ var cells = [
unist.makeTableCell([unist.makeText(pName)]), unist.makeTableCell([unist.makeText(pName)]),
unist.makeTableCell([unist.makeInlineCode(pType)]), unist.makeTableCell([unist.makeInlineCode(pType)])
//unist.makeTableCell([unist.makeInlineCode(pDefault)]),
unist.makeTableCell([defaultCellContent]),
unist.makeTableCell(descCellContent)
]; ];
if (includeInitializer)
cells.push(unist.makeTableCell([defaultCellContent]));
cells.push(unist.makeTableCell(descCellContent));
rows.push(unist.makeTableRow(cells)); rows.push(unist.makeTableRow(cells));
} }
return unist.makeTable([null, null, null, null], rows); var spacers = [null, null, null];
if (includeInitializer)
spacers.push(null);
return unist.makeTable(spacers, rows);
} }
function buildOutputsTable(outputs) { function buildMethodsList(methods) {
if (outputs.length === 0) { if (methods.length === 0)
return null; return null;
var listItems = [];
for (var _i = 0, methods_1 = methods; _i < methods_1.length; _i++) {
var method = methods_1[_i];
var itemLines = [];
itemLines.push(unist.makeInlineCode(method.getSignature()));
itemLines.push(unist.makeBreak());
itemLines.push(unist.makeParagraph(remark().parse(method.docText).children));
itemLines.push(unist.makeBreak());
var paramListItems = [];
for (var _a = 0, _b = method.params; _a < _b.length; _a++) {
var param = _b[_a];
var currParamSections = [];
if (param.docText !== "") {
currParamSections.push(unist.makeInlineCode(param.name));
var optionalPart = param.optional ? "(Optional) " : "";
currParamSections.push(unist.makeText(" - " + optionalPart + param.docText));
//currParamSections.push(unist.makeBreak());
paramListItems.push(unist.makeListItem(unist.makeParagraph(currParamSections)));
} }
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].docText || "";
if (eDesc) {
eDesc = eDesc.trim().replace(/[\n\r]+/, ' ');
} }
var cells = [ itemLines.push(unist.makeListUnordered(paramListItems));
unist.makeTableCell([unist.makeText(eName)]), listItems.push(unist.makeListItem(unist.makeParagraph(itemLines)));
unist.makeTableCell([unist.makeInlineCode(eType)]),
unist.makeTableCell(remark().parse(eDesc).children)
];
rows.push(unist.makeTableRow(cells));
} }
return unist.makeTable([null, null, null], rows); return unist.makeListUnordered(listItems);
} }
function isNodeExported(node) { function isNodeExported(node) {
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile); return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);

View File

@@ -7,7 +7,7 @@ import * as heading from "mdast-util-heading-range";
import * as remark from "remark"; import * as remark from "remark";
import * as unist from "../unistHelpers"; import * as unist from "../unistHelpers";
import { JsxEmit, isClassDeclaration } from "typescript"; import { JsxEmit, isClassDeclaration, PropertyDeclaration } from "typescript";
export function initPhase(aggData) { export function initPhase(aggData) {
} }
@@ -18,135 +18,83 @@ export function readPhase(tree, pathname, aggData) {
export function aggPhase(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) {
heading(tree, "Properties", (before, section, after) => {
return [before, inTable, after];
});
}
if (outTable) {
heading(tree, "Events", (before, section, after) => {
return [before, outTable, after];
});
}
}
return true;
} else {
return false;
}
interface NgDocAutoContent {
extractClassInfoFromSource(checker: ts.TypeChecker, classDec: ts.ClassDeclaration);
addContentToDoc(tree);
} }
class PropData {
function initialCap(str: string) { name: string;
return str[0].toUpperCase() + str.substr(1); type: string;
initializer: string;
docText: string;
} }
class ParamData {
name: string;
type: string;
docText: string;
initializer: string;
optional: boolean;
function fixCompodocFilename(rawName: string) { getSignature() {
var name = rawName.replace(/\]|\(|\)/g, ''); let sig =this.name;
var fileNameSections = name.split('.'); if (this.optional)
var compNameSections = fileNameSections[0].split('-'); sig += "?";
var outCompName = ''; sig += ": " + this.type;
for (var i = 0; i < compNameSections.length; i++) { if (this.initializer)
outCompName = outCompName + initialCap(compNameSections[i]); sig += " = " + this.initializer;
}
var itemTypeIndicator = ''; return sig;
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([srcPath], {
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) {
getPropDataFromClassChain(checker, classDec, inputs, outputs);
}
}
} }
} }
class MethodData {
name: string;
docText: string;
params: ParamData[];
returnType: string;
// Get properties/events from main class and all inherited classes. constructor() {
function getPropDataFromClassChain( this.params = [];
checker: ts.TypeChecker,
classDec: ts.ClassDeclaration,
inputs: any[],
outputs: any[]
){
// Main class
getPropDataFromClass(checker, classDec, inputs, outputs);
// Inherited classes
if (classDec.heritageClauses) {
for(const hc of classDec.heritageClauses) {
let hcType = checker.getTypeFromTypeNode(hc.types[0]);
for (const dec of hcType.symbol.declarations) {
if (isClassDeclaration(dec)) {
getPropDataFromClassChain(checker, dec, inputs, outputs);
}
}
}
} }
getSignature() {
let sig = this.name + "(";
if (this.params.length > 0) {
sig += this.params[0].getSignature();
}
for (let i = 1; i < this.params.length; i++) {
sig += ", " + this.params[i].getSignature();
}
sig += ")";
if (this.returnType !== "void") {
sig += ": " + this.returnType;
}
return sig;
}
} }
class ComponentDocAutoContent implements NgDocAutoContent {
inputs: PropData[];
outputs: PropData[];
function getPropDataFromClass( constructor() {
checker: ts.TypeChecker, this.inputs = [];
classDec: ts.ClassDeclaration, this.outputs = [];
inputs: any[], }
outputs: any[]
){
extractClassInfoFromSource(checker: ts.TypeChecker, classDec: ts.ClassDeclaration) {
let sourceFile = classDec.getSourceFile(); let sourceFile = classDec.getSourceFile();
for (var i = 0; i < classDec.members.length; i++) { for (var i = 0; i < classDec.members.length; i++) {
@@ -177,47 +125,268 @@ function getPropDataFromClass(
let dec = prop.decorators[0].getText(sourceFile); let dec = prop.decorators[0].getText(sourceFile);
if (dec.match(/@Input/)) { if (dec.match(/@Input/)) {
inputs.push({ this.inputs.push({
"name": name, "name": name,
"type": propType, "type": propType,
"init": initializer, "initializer": initializer,
"docText": doc "docText": doc
}); });
} else if (dec.match(/@Output/)) { } else if (dec.match(/@Output/)) {
outputs.push({ this.outputs.push({
"name": name, "name": name,
"type": propType, "type": propType,
"initializer": "",
"docText": doc "docText": doc
}); });
} }
} }
} }
} }
}
addContentToDoc(tree) {
let inTable = buildPropsTable(this.inputs);
let outTable = buildPropsTable(this.outputs, false);
if (inTable) {
heading(tree, "Properties", (before, section, after) => {
return [before, inTable, after];
});
}
if (outTable) {
heading(tree, "Events", (before, section, after) => {
return [before, outTable, after];
});
}
}
}
class ServiceDocAutoContent implements NgDocAutoContent {
props: PropData[];
methods: MethodData[];
constructor() {
this.props = [];
this.methods = [];
}
extractClassInfoFromSource(checker: ts.TypeChecker, classDec: ts.ClassDeclaration) {
let sourceFile = classDec.getSourceFile();
for (var i = 0; i < classDec.members.length; i++) {
let member = classDec.members[i];
if (ts.isMethodDeclaration(member)) {
let method: ts.MethodDeclaration = member;
let mods = ts.getCombinedModifierFlags(method);
let nonPrivate = (mods & ts.ModifierFlags.Private) === 0;
let memSymbol = checker.getSymbolAtLocation(method.name);
if (nonPrivate && memSymbol) {
let methData = new MethodData();
methData.name = memSymbol.getName();
let doc = ts.displayPartsToString(memSymbol.getDocumentationComment());
methData.docText = doc.replace(/\r\n/g, " ");
let sig = checker.getSignatureFromDeclaration(method);
let returnType = sig.getReturnType();
methData.returnType = checker.typeToString(returnType);
let returnSymbol = returnType.getSymbol();
let params = method.parameters;
for (let p = 0; p < params.length; p++){
let pData = new ParamData();
pData.name = params[p].name.getText();
pData.type = params[p].type.getText();
let paramSymbol = checker.getSymbolAtLocation(params[p].name);
pData.docText = ts.displayPartsToString(paramSymbol.getDocumentationComment());
pData.optional = params[p].questionToken ? true : false;
if (params[p].initializer) {
let initText = params[p].initializer.getText();
if (initText !== "undefined")
pData.initializer = initText;
}
methData.params.push(pData);
}
this.methods.push(methData);
}
}
}
}
addContentToDoc(tree) {
let propsTable = buildPropsTable(this.props);
let methodsList = buildMethodsList(this.methods);
if (propsTable) {
heading(tree, "Properties", (before, section, after) => {
return [before, propsTable, after];
});
}
if (methodsList) {
heading(tree, "Methods", (before, section, after) => {
return [before, methodsList, after];
});
}
}
}
export function updatePhase(tree, pathname, aggData) {
let fileNameNoSuffix = path.basename(pathname, ".md");
let itemType = fileNameNoSuffix.match(/component|service/);
if (itemType) {
let srcData = aggData.srcData[fileNameNoSuffix];
if (srcData) {
let srcPath = srcData.path;
let className = fixAngularFilename(fileNameNoSuffix);
let classData: NgDocAutoContent;
if (itemType[0] === "component") {
classData = new ComponentDocAutoContent();
} else if (itemType[0] === "service") {
classData = new ServiceDocAutoContent();
}
getDocSourceData(path.resolve(".", srcPath), className, classData);
classData.addContentToDoc(tree);
}
return true;
} else {
return false;
}
}
function initialCap(str: string) {
return str[0].toUpperCase() + str.substr(1);
}
function fixAngularFilename(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 getDocSourceData(srcPath: string, docClassName: string, classData: NgDocAutoContent) {
let prog = ts.createProgram([srcPath], {
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) {
getPropDataFromClassChain(checker, classDec, classData);
}
}
}
} }
function buildInputsTable(inputs: any[]) { // Get properties/events from main class and all inherited classes.
if (inputs.length === 0) { function getPropDataFromClassChain(
checker: ts.TypeChecker,
classDec: ts.ClassDeclaration,
classData: NgDocAutoContent
){
// Main class
classData.extractClassInfoFromSource(checker, classDec);
// Inherited classes
if (classDec.heritageClauses) {
for(const hc of classDec.heritageClauses) {
let hcType = checker.getTypeFromTypeNode(hc.types[0]);
for (const dec of hcType.symbol.declarations) {
if (isClassDeclaration(dec)) {
getPropDataFromClassChain(checker, dec, classData);
}
}
}
}
}
function buildPropsTable(props: PropData[], includeInitializer: boolean = true) {
if (props.length === 0) {
return null; return null;
} }
var rows = [ var headerCells = [
unist.makeTableRow([
unist.makeTableCell([unist.makeText("Name")]), unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")]), unist.makeTableCell([unist.makeText("Type")])
unist.makeTableCell([unist.makeText("Default value")]),
unist.makeTableCell([unist.makeText("Description")])
])
]; ];
for (var i = 0; i < inputs.length; i++) { if (includeInitializer)
var pName = inputs[i].name; headerCells.push(unist.makeTableCell([unist.makeText("Default value")]));
var pType = inputs[i].type;
var pDefault = inputs[i].init || ""; headerCells.push(unist.makeTableCell([unist.makeText("Description")]));
var pDesc = inputs[i].docText || "";
var rows = [
unist.makeTableRow(headerCells)
];
for (var i = 0; i < props.length; i++) {
var pName = props[i].name;
var pType = props[i].type;
var pDefault = props[i].initializer || "";
var pDesc = props[i].docText || "";
if (pDesc) { if (pDesc) {
//pDesc = pDesc.trim().replace(/[\n\r]+/, " ");
pDesc = pDesc.replace(/[\n\r]+/, " "); pDesc = pDesc.replace(/[\n\r]+/, " ");
} }
@@ -226,11 +395,6 @@ function buildInputsTable(inputs: any[]) {
var defaultCellContent; var defaultCellContent;
if (pDefault) { if (pDefault) {
/*
descCellContent.push(unist.makeHTML("<br/>"));
descCellContent.push(unist.makeText(" Default value: "));
descCellContent.push(unist.makeInlineCode(pDefault));
*/
defaultCellContent = unist.makeInlineCode(pDefault); defaultCellContent = unist.makeInlineCode(pDefault);
} else { } else {
defaultCellContent = unist.makeText(""); defaultCellContent = unist.makeText("");
@@ -238,53 +402,66 @@ function buildInputsTable(inputs: any[]) {
var cells = [ var cells = [
unist.makeTableCell([unist.makeText(pName)]), unist.makeTableCell([unist.makeText(pName)]),
unist.makeTableCell([unist.makeInlineCode(pType)]), unist.makeTableCell([unist.makeInlineCode(pType)])
//unist.makeTableCell([unist.makeInlineCode(pDefault)]),
unist.makeTableCell([defaultCellContent]),
unist.makeTableCell(descCellContent)
]; ];
if (includeInitializer)
cells.push(unist.makeTableCell([defaultCellContent]));
cells.push(unist.makeTableCell(descCellContent));
rows.push(unist.makeTableRow(cells)); rows.push(unist.makeTableRow(cells));
} }
return unist.makeTable([null, null, null, null], rows); let spacers = [null, null, null];
if (includeInitializer)
spacers.push(null);
return unist.makeTable(spacers, rows);
} }
function buildOutputsTable(outputs: any[]) { function buildMethodsList(methods: MethodData[]) {
if (outputs.length === 0) { if (methods.length === 0)
return null; return null;
let listItems = [];
for (let method of methods) {
let itemLines = [];
itemLines.push(unist.makeInlineCode(method.getSignature()));
itemLines.push(unist.makeBreak());
itemLines.push(unist.makeParagraph(remark().parse(method.docText).children));
itemLines.push(unist.makeBreak());
let paramListItems = [];
for (let param of method.params) {
let currParamSections = [];
if (param.docText !== "") {
currParamSections.push(unist.makeInlineCode(param.name));
let optionalPart = param.optional ? "(Optional) " : "";
currParamSections.push(unist.makeText(" - " + optionalPart + param.docText));
//currParamSections.push(unist.makeBreak());
paramListItems.push(unist.makeListItem(unist.makeParagraph(currParamSections)));
}
} }
var rows = [ itemLines.push(unist.makeListUnordered(paramListItems));
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].docText || "";
if (eDesc) { listItems.push(unist.makeListItem(unist.makeParagraph(itemLines)));
eDesc = eDesc.trim().replace(/[\n\r]+/, ' ');
} }
var cells = [ return unist.makeListUnordered(listItems);
unist.makeTableCell([unist.makeText(eName)]),
unist.makeTableCell([unist.makeInlineCode(eType)]),
unist.makeTableCell(remark().parse(eDesc).children)
];
rows.push(unist.makeTableRow(cells));
}
return unist.makeTable([null, null, null], rows);
} }
function isNodeExported(node: ts.Node): boolean { function isNodeExported(node: ts.Node): boolean {
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile); return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);
} }

View File

@@ -104,6 +104,12 @@ module.exports = {
}; };
}, },
makeBreak: function () {
return {
"type": "break"
}
},
isHeading: function (node) { isHeading: function (node) {
return node.type === "heading"; return node.type === "heading";
}, },

View File

@@ -36,6 +36,8 @@ export class ContentNodeDialogService {
private siteService: SitesService, private siteService: SitesService,
private translation: TranslationService) { } private translation: TranslationService) { }
/** Opens a file browser at a chosen folder location. */
/** @param folderNodeId ID of the folder to use */
openFileBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]> { openFileBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]> {
return Observable.fromPromise(this.documentListService.getFolderNode(folderNodeId)) return Observable.fromPromise(this.documentListService.getFolderNode(folderNodeId))
.switchMap((node: MinimalNodeEntryEntity) => { .switchMap((node: MinimalNodeEntryEntity) => {
@@ -43,18 +45,22 @@ export class ContentNodeDialogService {
}); });
} }
/** Opens a file browser at a chosen site location. */
openFileBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]> { openFileBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]> {
return this.siteService.getSites().switchMap((response: SitePaging) => { return this.siteService.getSites().switchMap((response: SitePaging) => {
return this.openFileBrowseDialogByFolderId(response.list.entries[0].entry.guid); return this.openFileBrowseDialogByFolderId(response.list.entries[0].entry.guid);
}); });
} }
/** Opens a folder browser at a chosen site location. */
openFolderBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]> { openFolderBrowseDialogBySite(): Observable<MinimalNodeEntryEntity[]> {
return this.siteService.getSites().switchMap((response: SitePaging) => { return this.siteService.getSites().switchMap((response: SitePaging) => {
return this.openFolderBrowseDialogByFolderId(response.list.entries[0].entry.guid); return this.openFolderBrowseDialogByFolderId(response.list.entries[0].entry.guid);
}); });
} }
/** Opens a folder browser at a chosen folder location. */
/** @param folderNodeId ID of the folder to use */
openFolderBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]> { openFolderBrowseDialogByFolderId(folderNodeId: string): Observable<MinimalNodeEntryEntity[]> {
return Observable.fromPromise(this.documentListService.getFolderNode(folderNodeId)) return Observable.fromPromise(this.documentListService.getFolderNode(folderNodeId))
.switchMap((node: MinimalNodeEntryEntity) => { .switchMap((node: MinimalNodeEntryEntity) => {
@@ -62,6 +68,10 @@ export class ContentNodeDialogService {
}); });
} }
/** Opens a dialog to copy or move an item to a new location. */
/** @param action Name of the action (eg, "Copy" or "Move") to show in the title */
/** @param contentEntry Item to be copied or moved */
/** @param permission Permission for the operation */
openCopyMoveDialog(action: string, contentEntry: MinimalNodeEntryEntity, permission?: string): Observable<MinimalNodeEntryEntity[]> { openCopyMoveDialog(action: string, contentEntry: MinimalNodeEntryEntity, permission?: string): Observable<MinimalNodeEntryEntity[]> {
if (this.contentService.hasPermission(contentEntry, permission)) { if (this.contentService.hasPermission(contentEntry, permission)) {
@@ -91,10 +101,16 @@ export class ContentNodeDialogService {
} }
} }
/** Gets the translation of the dialog title. */
/** @param action Name of the action to display in the dialog title */
/** @param name Name of the item on which the action is being performed */
getTitleTranslation(action: string, name: string): string { getTitleTranslation(action: string, name: string): string {
return this.translation.instant(`NODE_SELECTOR.${action.toUpperCase()}_ITEM`, {name}); return this.translation.instant(`NODE_SELECTOR.${action.toUpperCase()}_ITEM`, {name});
} }
/** Opens a dialog to choose a folder to upload. */
/** @param action Name of the action to show in the title */
/** @param contentEntry Item to upload */
openUploadFolderDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]> { openUploadFolderDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]> {
const select = new Subject<MinimalNodeEntryEntity[]>(); const select = new Subject<MinimalNodeEntryEntity[]>();
select.subscribe({ select.subscribe({
@@ -115,6 +131,9 @@ export class ContentNodeDialogService {
return select; return select;
} }
/** Opens a dialog to choose a file to upload. */
/** @param action Name of the action to show in the title */
/** @param contentEntry Item to upload */
openUploadFileDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]> { openUploadFileDialog(action: string, contentEntry: MinimalNodeEntryEntity): Observable<MinimalNodeEntryEntity[]> {
const select = new Subject<MinimalNodeEntryEntity[]>(); const select = new Subject<MinimalNodeEntryEntity[]>();
select.subscribe({ select.subscribe({
@@ -173,6 +192,7 @@ export class ContentNodeDialogService {
return this.contentService.hasPermission(entry, 'create'); return this.contentService.hasPermission(entry, 'create');
} }
/** Closes the currently open dialog. */
close() { close() {
this.dialog.closeAll(); this.dialog.closeAll();
} }