[ADF-2969] Moved doc tools to new tools folder (#3314)

* [ADF-2969] Moved doc tools to new tools folder

* [ADF-2969] Added files missing from schematic

* [ADF-2969] Added missing files to schematic
This commit is contained in:
Andy Stark
2018-05-11 14:01:19 +01:00
committed by Eugenio Romano
parent 9d0ccff189
commit 60644d9917
43 changed files with 843 additions and 23 deletions

View File

@@ -0,0 +1,27 @@
# Review checker guide
The review checker tool queries the Github repo to look for recent
commits to the component source files. The dates of these commits
are compared against against a review date stored in the Markdown doc
file for each component. The time and the number of commits since the
last review are then combined into a "score" that gives an indication
of how urgently the doc file needs a review.
## Review date metadata
The review date is kept in the YAML metadata section at the top of each
Markdown file. The key is "Last reviewed" and the date is in the form
YYYY-MM-DD.
## Commit message stoplist
The checker will ignore any commits that match regular expressions stored
in the `commitStoplist.json` file in the `DocProcessor` folder. You could
use this, for example, to filter out JIRA tasks that don't involve any
changes in functionality (and therefore don't need documenting).
## Output format
The script sends comma-separated text to the command line. You can copy/paste
this into a spreadsheet or redirect the output to a text file with a ".csv"
suffix.

View File

@@ -0,0 +1 @@
["ADF-1769"]

186
tools/doc/docProcessor.js Normal file
View File

@@ -0,0 +1,186 @@
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 frontMatter = require("remark-frontmatter");
// "Aggregate" data collected over the whole file set.
var aggData = {};
var toolsFolderName = "tools";
var configFileName = "doctool.config.json";
var defaultFolder = path.resolve("docs");
function initPhase(aggData) {
toolList.forEach(toolName => {
toolModules[toolName].initPhase(aggData);
});
}
function readPhase(filenames, aggData) {
for (var i = 0; i < filenames.length; i++) {
var pathname = filenames[i];//path.resolve(srcFolder, filenames[i]);
var src = fs.readFileSync(pathname);
var tree = remark().use(frontMatter, ["yaml"]).parse(src);
toolList.forEach(toolName => {
toolModules[toolName].readPhase(tree, pathname, aggData);
});
}
//console.log(JSON.stringify(aggData.mdFileData));
}
function aggPhase(aggData) {
toolList.forEach(toolName => {
toolModules[toolName].aggPhase(aggData);
});
}
function updatePhase(filenames, aggData) {
var errorMessages;
for (var i = 0; i < filenames.length; i++) {
errorMessages = [];
var pathname = filenames[i]; // path.resolve(srcFolder, filenames[i]);
var src = fs.readFileSync(pathname);
var tree = remark().use(frontMatter, ["yaml"]).parse(src)
var modified = false;
toolList.forEach(toolName => {
modified |= toolModules[toolName].updatePhase(tree, pathname, aggData, errorMessages);
});
if (errorMessages.length > 0) {
showErrors(pathname, errorMessages);
}
if (modified)
fs.writeFileSync(filenames[i], remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false, gfm: false}).stringify(tree));
//console.log(JSON.stringify(tree));
}
}
function showErrors(filename, errorMessages) {
console.log(filename);
errorMessages.forEach(message => {
console.log(" " + message);
});
console.log("");
}
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 loadConfig() {
var configFilePath = path.resolve(__dirname, configFileName)
return JSON.parse(fs.readFileSync(configFilePath));
}
function getAllDocFilePaths(docFolder, files) {
var items = fs.readdirSync(docFolder);
for (var i = 0; i < items.length; i++) {
var itemPath = path.resolve(docFolder, items[i]);
var itemInfo = fs.statSync(itemPath);
if (itemInfo.isFile()){
files.push(itemPath);
} else if (itemInfo.isDirectory()) {
getAllDocFilePaths(itemPath, files);
}
}
}
program
.usage("[options] <source>")
.option("-p, --profile [profileName]", "Select named config profile", "default")
.parse(process.argv);
var sourcePath;
if (program.args.length === 0) {
sourcePath = defaultFolder;
} else {
sourcePath = path.resolve(program.args[0]);
}
var sourceInfo = fs.statSync(sourcePath);
var toolModules = loadToolModules();
var config = loadConfig();
var toolList;
if (config.profiles[program.profile]){
toolList = config.profiles[program.profile];
var toolListText = toolList.join(", ");
console.log(`Using '${program.profile}' profile: ${toolListText}`);
} else {
console.log(`Aborting: unknown profile '${program.profile}`);
return 0;
}
var files = [];
if (sourceInfo.isDirectory()) {
getAllDocFilePaths(sourcePath, files);
} else if (sourceInfo.isFile()) {
files = [ 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(files, aggData);
console.log("Computing aggregate data...");
aggPhase(aggData);
console.log("Updating Markdown files...");
updatePhase(files, aggData);

View File

@@ -0,0 +1,24 @@
{
"profiles": {
"default": [
"index",
"versionIndex",
"tutorialIndex",
"tsInfo",
"toc"
],
"index": [
"index",
"versionIndex",
"tutorialIndex"
],
"enhance": [
"tsInfo",
"toc"
],
"dev": [
"tsInfo",
"typeLinker"
]
}
}

31
tools/doc/libsearch.js Normal file
View File

@@ -0,0 +1,31 @@
var fs = require("fs");
var path = require("path");
module.exports = searchLibraryRecursive;
var angFilenameRegex = /([a-zA-Z0-9\-]+)\.((component)|(directive)|(model)|(pipe)|(service)|(widget))\.ts/;
var searchFolderOmitRegex = /(config)|(mock)|(i18n)|(assets)|(styles)/;
// 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);
}
}
}

35
tools/doc/ngHelpers.js Normal file
View File

@@ -0,0 +1,35 @@
module.exports = {
"ngNameToDisplayName": ngNameToDisplayName,
"dekebabifyName": dekebabifyName,
"kebabifyClassName": kebabifyClassName,
"classTypes": ["component", "directive", "model", "pipe", "service", "widget"]
}
function ngNameToDisplayName(ngName) {
var mainSections = ngName.split(".");
mainSections[0] = dekebabifyName(mainSections[0]);
return mainSections.join(" ");
}
function displayNameToNgName(name) {
var noSpaceName = ngName.replace(/ ([a-zA-Z])/, "$1".toUpperCase());
return noSpaceName.substr(0, 1).toUpperCase() + noSpaceName.substr(1);
}
function dekebabifyName(name) {
var result = name.replace(/-/g, " ");
result = result.substr(0, 1).toUpperCase() + result.substr(1);
return result;
}
function kebabifyClassName(name) {
var result = name.replace(/(Component|Directive|Interface|Model|Pipe|Service|Widget)$/, match => {
return "." + match.toLowerCase();
});
result = result.replace(/([A-Z])/g, "-$1");
return result.substr(1).toLowerCase();
}

103
tools/doc/reviewChecker.js Normal file
View File

@@ -0,0 +1,103 @@
"use strict";
exports.__esModule = true;
var path = require("path");
var fs = require("fs");
var process = require("process");
var graphql_request_1 = require("graphql-request");
var remark = require("remark");
var frontMatter = require("remark-frontmatter");
var yaml = require("js-yaml");
var moment = require("moment");
var Rx_1 = require("rxjs/Rx");
var libsearch = require("./libsearch");
var stoplist_1 = require("./stoplist");
var adf20StartDate = "2017-11-20";
var commitWeight = 0.1;
var scoreTimeBase = 60;
var rootFolder = ".";
var stoplistFilePath = path.resolve("..", "tools", "doc", "commitStoplist.json");
var angFilePattern = /(component)|(directive)|(model)|(pipe)|(service)|(widget)/;
var srcData = {};
var stoplist = new stoplist_1.Stoplist(stoplistFilePath);
var docsFolderPath = path.resolve("..", "docs");
var libFolders = ["core", "content-services", "process-services", "insights"];
libsearch(srcData, path.resolve(rootFolder));
/*
let keys = Object.keys(srcData);
for (let i = 0; i < keys.length; i++) {
console.log(keys[i]);
}
*/
var authToken = process.env.graphAuthToken;
var client = new graphql_request_1.GraphQLClient('https://api.github.com/graphql', {
headers: {
Authorization: 'Bearer ' + authToken
}
});
var query = "query commitHistory($path: String) {\n repository(name: \"alfresco-ng2-components\", owner: \"alfresco\") {\n ref(qualifiedName: \"development\") {\n target {\n ... on Commit {\n history(first: 15, path: $path) {\n nodes {\n pushedDate\n message\n }\n }\n }\n }\n }\n }\n}";
var docFiles = getDocFilePaths(docsFolderPath);
var docNames = Rx_1.Observable.from(docFiles);
console.log("'Name','Review date','Commits since review','Score'");
docNames.subscribe(function (x) {
var key = path.basename(x, ".md");
if (!srcData[key])
return;
var vars = {
"path": "lib/" + srcData[key].path
};
client.request(query, vars).then(function (data) {
var nodes = data["repository"].ref.target.history.nodes;
var lastReviewDate = getDocReviewDate(x); //(key + ".md");
var numUsefulCommits = extractCommitInfo(nodes, lastReviewDate, stoplist);
var dateString = lastReviewDate.format("YYYY-MM-DD");
var score = priorityScore(lastReviewDate, numUsefulCommits).toPrecision(3);
console.log("'" + key + "','" + dateString + "','" + numUsefulCommits + "','" + score + "'");
});
});
function priorityScore(reviewDate, numCommits) {
var daysSinceReview = moment().diff(reviewDate, 'days');
var commitScore = 2 + numCommits * commitWeight;
return Math.pow(commitScore, daysSinceReview / scoreTimeBase);
}
function getDocReviewDate(docFileName) {
var mdFilePath = path.resolve(docsFolderPath, docFileName);
var mdText = fs.readFileSync(mdFilePath);
var tree = remark().use(frontMatter, ["yaml"]).parse(mdText);
var lastReviewDate = moment(adf20StartDate);
if (tree.children[0].type == "yaml") {
var metadata = yaml.load(tree.children[0].value);
if (metadata["Last reviewed"])
lastReviewDate = moment(metadata["Last reviewed"]);
}
return lastReviewDate;
}
function extractCommitInfo(commitNodes, cutOffDate, stoplist) {
var numUsefulCommits = 0;
commitNodes.forEach(function (element) {
if (!stoplist.isRejected(element.message)) {
var abbr = element.message.substr(0, 15);
var commitDate = moment(element.pushedDate);
if (commitDate.isAfter(cutOffDate)) {
numUsefulCommits++;
}
}
});
return numUsefulCommits;
}
function getDocFilePaths(folderPath) {
var result = [];
libFolders.forEach(function (element) {
var libPath = path.resolve(folderPath, element);
var files = fs.readdirSync(libPath);
files = files.filter(function (filename) {
return (path.extname(filename) === ".md") &&
(filename !== "README.md") &&
(filename.match(angFilePattern));
});
files.forEach(function (element) {
result.push(path.join(libPath, element));
});
});
return result;
}

164
tools/doc/reviewChecker.ts Normal file
View File

@@ -0,0 +1,164 @@
import * as path from "path";
import * as fs from "fs";
import * as process from "process"
import { GraphQLClient } from "graphql-request";
import * as remark from "remark";
import * as frontMatter from "remark-frontmatter";
import * as yaml from "js-yaml";
import * as moment from "moment";
import { Observable } from 'rxjs/Rx';
import * as libsearch from "./libsearch";
import { Stoplist } from "./stoplist";
import { last } from "rxjs/operator/last";
const adf20StartDate = "2017-11-20";
const commitWeight = 0.1;
const scoreTimeBase = 60;
const rootFolder = ".";
const stoplistFilePath = path.resolve("..", "tools", "doc", "commitStoplist.json");
const angFilePattern = /(component)|(directive)|(model)|(pipe)|(service)|(widget)/;
let srcData = {};
let stoplist = new Stoplist(stoplistFilePath);
let docsFolderPath = path.resolve("..", "docs");
let libFolders = ["core", "content-services", "process-services", "insights"];
libsearch(srcData, path.resolve(rootFolder));
/*
let keys = Object.keys(srcData);
for (let i = 0; i < keys.length; i++) {
console.log(keys[i]);
}
*/
const authToken = process.env.graphAuthToken;
const client = new GraphQLClient('https://api.github.com/graphql', {
headers: {
Authorization: 'Bearer ' + authToken
}
});
const query = `query commitHistory($path: String) {
repository(name: "alfresco-ng2-components", owner: "alfresco") {
ref(qualifiedName: "development") {
target {
... on Commit {
history(first: 15, path: $path) {
nodes {
pushedDate
message
}
}
}
}
}
}
}`;
let docFiles = getDocFilePaths(docsFolderPath);
let docNames = Observable.from(docFiles);
console.log("'Name','Review date','Commits since review','Score'");
docNames.subscribe(x => {
let key = path.basename(x, ".md");
if (!srcData[key])
return;
let vars = {
"path": "lib/" + srcData[key].path
};
client.request(query, vars).then(data => {
let nodes = data["repository"].ref.target.history.nodes;
let lastReviewDate = getDocReviewDate(x);//(key + ".md");
let numUsefulCommits = extractCommitInfo(nodes, lastReviewDate, stoplist);
let dateString = lastReviewDate.format("YYYY-MM-DD");
let score = priorityScore(lastReviewDate, numUsefulCommits).toPrecision(3);
console.log(`'${key}','${dateString}','${numUsefulCommits}','${score}'`);
});
});
function priorityScore(reviewDate, numCommits) {
let daysSinceReview = moment().diff(reviewDate, 'days');
let commitScore = 2 + numCommits * commitWeight;
return Math.pow(commitScore, daysSinceReview / scoreTimeBase);
}
function getDocReviewDate(docFileName) {
let mdFilePath = path.resolve(docsFolderPath, docFileName);
let mdText = fs.readFileSync(mdFilePath);
let tree = remark().use(frontMatter, ["yaml"]).parse(mdText);
let lastReviewDate = moment(adf20StartDate);
if (tree.children[0].type == "yaml") {
let metadata = yaml.load(tree.children[0].value);
if (metadata["Last reviewed"])
lastReviewDate = moment(metadata["Last reviewed"]);
}
return lastReviewDate;
}
function extractCommitInfo(commitNodes, cutOffDate, stoplist) {
let numUsefulCommits = 0;
commitNodes.forEach(element => {
if (!stoplist.isRejected(element.message)) {
let abbr = element.message.substr(0, 15);
let commitDate = moment(element.pushedDate);
if (commitDate.isAfter(cutOffDate)) {
numUsefulCommits++;
}
}
});
return numUsefulCommits;
}
function getDocFilePaths(folderPath) {
let result = [];
libFolders.forEach(element => {
let libPath = path.resolve(folderPath, element);
let files = fs.readdirSync(libPath);
files = files.filter(filename =>
(path.extname(filename) === ".md") &&
(filename !== "README.md") &&
(filename.match(angFilePattern))
);
files.forEach(element => {
result.push(path.join(libPath, element));
});
});
return result;
}

29
tools/doc/stoplist.js Normal file
View File

@@ -0,0 +1,29 @@
"use strict";
exports.__esModule = true;
var fs = require("fs");
/* "Stoplist" of regular expressions to match against strings. */
var Stoplist = /** @class */ (function () {
function Stoplist(slFilePath) {
var listExpressions = JSON.parse(fs.readFileSync(slFilePath, 'utf8'));
this.regexes = [];
if (listExpressions) {
for (var i = 0; i < listExpressions.length; i++) {
this.regexes.push(new RegExp(listExpressions[i]));
}
}
else {
this.regexes = [];
}
}
// Check if an item is covered by the stoplist and reject it if so.
Stoplist.prototype.isRejected = function (itemName) {
for (var i = 0; i < this.regexes.length; i++) {
if (this.regexes[i].test(itemName)) {
return true;
}
}
return false;
};
return Stoplist;
}());
exports.Stoplist = Stoplist;

31
tools/doc/stoplist.ts Normal file
View File

@@ -0,0 +1,31 @@
import * as fs from "fs";
/* "Stoplist" of regular expressions to match against strings. */
export class Stoplist {
regexes: RegExp[];
constructor(slFilePath: string) {
let listExpressions = JSON.parse(fs.readFileSync(slFilePath, 'utf8'));
this.regexes = [];
if (listExpressions) {
for (var i = 0; i < listExpressions.length; i++) {
this.regexes.push(new RegExp(listExpressions[i]));
}
} else {
this.regexes = [];
}
}
// Check if an item is covered by the stoplist and reject it if so.
isRejected(itemName: string) {
for (var i = 0; i < this.regexes.length; i++) {
if (this.regexes[i].test(itemName)) {
return true;
}
}
return false;
}
}

23
tools/doc/templates/component.combyne vendored Normal file
View File

@@ -0,0 +1,23 @@
{% if hasInputs %}
### Properties
| Name | Type | Default value | Description |
| -- | -- | -- | -- |
{% each properties as prop %}
{% if prop.isInput %}
| {{{prop.name}}} | `{{{prop.type}}}` | {{{prop.defaultValue}}} | {{{prop.docText}}} |
{% endif %}
{% endeach %}
{% endif %}
{% if hasOutputs%}
### Events
| Name | Type | Description |
| -- | -- | -- |
{% each properties as prop %}
{% if prop.isOutput %}
| {{prop.name}} | `{{{prop.type}}}` | {{{prop.docText}}} |
{% endif %}
{% endeach %}
{% endif %}

23
tools/doc/templates/directive.combyne vendored Normal file
View File

@@ -0,0 +1,23 @@
{% if hasInputs %}
### Properties
| Name | Type | Default value | Description |
| -- | -- | -- | -- |
{% each properties as prop %}
{% if prop.isInput %}
| {{{prop.name}}} | `{{{prop.type}}}` | {{{prop.defaultValue}}} | {{{prop.docText}}} |
{% endif %}
{% endeach %}
{% endif %}
{% if hasOutputs%}
### Events
| Name | Type | Description |
| -- | -- | -- |
{% each properties as prop %}
{% if prop.isOutput %}
| {{prop.name}} | `{{{prop.type}}}` | {{{prop.docText}}} |
{% endif %}
{% endeach %}
{% endif %}

14
tools/doc/templates/service.combyne vendored Normal file
View File

@@ -0,0 +1,14 @@
{% if hasMethods %}
### Methods
{% each methods as meth %}- `{{meth.name}}{{{meth.signature}}{% if meth.returnsSomething %}: {{{meth.returnType}}}{% endif %}`<br/>
{{meth.docText}}
{% each meth.params as param %}
- `{{{param.combined}}}` - {% if param.isOptional %}(Optional){% endif %}{{{param.docText}}}
{% endeach %}
{% if meth.returnsSomething %}
- **Returns** `{{{meth.returnType}}}` - {{{meth.returnDocText}}}
{% endif %}
{% endeach %}
{% endif %}

5
tools/doc/templates/tutIndex.combyne vendored Normal file
View File

@@ -0,0 +1,5 @@
| Name | Level | Abstract |
| -- | -- | -- |
{% each tuts as tut %}
| [**{{tut.title}}**]({{tut.link}}) | {{tut.level}} | {{tut.briefDesc}} |
{% endeach %}

3
tools/doc/templates/versIndex.combyne vendored Normal file
View File

@@ -0,0 +1,3 @@
{% each items as item %}
- [{{item.title}}]({{item.link}})
{% endeach %}

401
tools/doc/tools/index.js Normal file
View File

@@ -0,0 +1,401 @@
var fs = require("fs");
var path = require("path");
var remark = require("remark");
var stringify = require("remark-stringify");
var zone = require("mdast-zone");
var yaml = require("js-yaml");
var unist = require("../unistHelpers");
var ngHelpers = require("../ngHelpers");
var searchLibraryRecursive = require("../libsearch");
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 = "lib";
var indexMdFilePath = path.resolve(docsFolderPath, "README.md");
var guideFolderName = "user-guide";
var guideSummaryFileName = path.resolve(docsFolderPath, guideFolderName, "summary.json");
var maxBriefDescLength = 180;
var adfLibNames = ["core", "content-services", "insights", "process-services"];
var deprecatedIconURL = "docassets/images/DeprecatedIcon.png";
var experimentalIconURL = "docassets/images/ExperimentalIcon.png";
function initPhase(aggData) {
aggData.stoplist = makeStoplist(undocStoplistFileName);
aggData.srcData = {};
aggData.mdFileDesc = [];
aggData.mdFileStatus = [];
aggData.mdFilePath = [];
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 at position 1 in the tree.
var s;
var briefDesc;
if (tree.children[0].type == "yaml")
s = 1;
else
s = 0;
for (;
(s < tree.children.length) && !unist.isParagraph(tree.children[s]);
s++
);
if (s < tree.children.length) {
briefDesc = tree.children[s];
}
aggData.mdFileDesc[itemName] = briefDesc;
if (tree.children[0].type == "yaml") {
var metadata = yaml.load(tree.children[0].value);
var status = metadata["Status"];
if (status) {
var compName = path.basename(pathname, ".md");
aggData.mdFileStatus[compName] = status;
}
}
var linkPath = pathname.replace(/\\/g, '/');
linkPath = linkPath.substr(linkPath.indexOf("docs") + 5);
aggData.mdFilePath[itemName] = linkPath;
}
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, false);
zone(indexFileTree, libName, (startComment, oldSection, endComment) => {
md.unshift(startComment);
md.push(endComment);
return md;
});
md = makeLibSectionMD(libSection, true);
var subIndexFilePath = path.resolve(docsFolderPath, libName, "README.md");
var subIndexText = fs.readFileSync(subIndexFilePath, "utf8");
var subIndexTree = remark().parse(subIndexText);
zone(subIndexTree, libName, (startComment, oldSection, endComment) => {
md.unshift(startComment);
md.push(endComment);
return md;
});
subIndexText = remark().data("settings", {paddedTable: false}).stringify(subIndexTree);
fs.writeFileSync(subIndexFilePath, subIndexText);
}
var guideSection = buildGuideSection(guideSummaryFileName, false);
zone(indexFileTree, "guide", (startComment, oldSection, endComment) => {
return [
startComment, guideSection, endComment
]
});
fs.writeFileSync(path.resolve("docs", "README.md"), remark().data("settings", {paddedTable: false}).stringify(indexFileTree));
guideSection = buildGuideSection(guideSummaryFileName, true);
subIndexFilePath = path.resolve(docsFolderPath, "user-guide", "README.md");
subIndexText = fs.readFileSync(subIndexFilePath, "utf8");
subIndexTree = remark().parse(subIndexText);
zone(subIndexTree, "guide", (startComment, oldSection, endComment) => {
return [
startComment, guideSection, endComment
]
});
subIndexText = remark().data("settings", {paddedTable: false}).stringify(subIndexTree);
fs.writeFileSync(subIndexFilePath, subIndexText);
//fs.writeFileSync(indexMdFilePath, remark().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;
}
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);
var pathname = aggData.mdFilePath[itemName];
var status = "";
if (aggData.mdFileStatus[itemName])
status = aggData.mdFileStatus[itemName];
if (briefDesc) {
sections[libName][srcData.type].documented.push({
"displayName": displayName,
"mdName": itemName + ".md",
"mdPath": pathname,
"srcPath": srcData.path,
"briefDesc": briefDesc,
"status": status
});
} 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 buildMDDocumentedTable(docItems, forSubFolder) {
var rows = [
];
for (var i = 0; i < docItems.length; i++) {
rows.push(makeMDDocumentedTableRow(docItems[i], forSubFolder));
}
return rows;
//return unist.makeTable([null, null, null, null], rows);
}
function buildMDUndocumentedTable(docItems, forSubFolder) {
var rows = [
];
for (var i = 0; i < docItems.length; i++) {
rows.push(makeMDUndocumentedTableRow(docItems[i], forSubFolder));
}
return rows;
//return unist.makeTable([null, null, null, null], rows);
}
function makeMDDocumentedTableRow(docItem, forSubFolder) {
var mdPath = docItem.mdPath;
if (forSubFolder) {
mdPath = path.basename(mdPath);
}
var mdFileLink = unist.makeLink(unist.makeText(docItem.displayName), mdPath);
var srcPath = "../lib/" + docItem.srcPath;
if (forSubFolder) {
srcPath = "../" + srcPath;
}
var srcFileLink = unist.makeLink(unist.makeText("Source"), srcPath);
var desc = docItem.briefDesc;
var linkCellItems = [mdFileLink];
var finalDepIconURL = deprecatedIconURL;
var finalExIconURL = experimentalIconURL;
if (forSubFolder) {
finalDepIconURL = "../" + finalDepIconURL;
finalExIconURL = "../" + finalExIconURL;
}
if (docItem.status) {
if (docItem.status === "Deprecated") {
linkCellItems.push(unist.makeText(" "));
linkCellItems.push(unist.makeImage(finalDepIconURL, "Deprecated"));
} else if (docItem.status === "Experimental") {
linkCellItems.push(unist.makeText(" "));
linkCellItems.push(unist.makeImage(finalExIconURL, "Experimental"));
}
}
return unist.makeTableRow([
unist.makeTableCell(linkCellItems),
unist.makeTableCell([desc]),
unist.makeTableCell([srcFileLink])
]);
}
function makeMDUndocumentedTableRow(docItem, forSubFolder) {
var itemName = unist.makeText(docItem.displayName);
var srcPath = "../lib/" + docItem.srcPath;
if (forSubFolder) {
srcPath = "../" + srcPath;
}
var srcFileLink = unist.makeLink(unist.makeText("Source"), srcPath);
return unist.makeTableRow([
unist.makeTableCell([unist.makeEmphasis([itemName])]),
unist.makeTableCell([unist.makeEmphasis([unist.makeText("Not currently documented")])]),
unist.makeTableCell([srcFileLink])
]);
}
function makeLibSectionMD(libSection, forSubFolder){
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, forSubFolder));
}
if (classSection.undocumented.length > 0) {
// md.push(buildMDUndocumentedSection(classSection.undocumented));
tableRows = tableRows.concat(buildMDUndocumentedTable(classSection.undocumented, forSubFolder));
}
md.push(unist.makeTable([null, null, null, null], tableRows));
}
}
return md;
}
function buildGuideSection(guideJsonFilename, forSubFolder) {
var summary = JSON.parse(fs.readFileSync(guideJsonFilename, "utf8"));
var listItems = [];
for (var i = 0; i < summary.length; i++) {
var filePath = summary[i].file;
if (!forSubFolder) {
filePath = guideFolderName + "/" + filePath;
}
if (summary[i].title !== "Tutorials") {
var link = unist.makeLink(unist.makeText(summary[i].title), filePath);
listItems.push(unist.makeListItem(link));
}
}
return unist.makeListUnordered(listItems);
}

175
tools/doc/tools/seealso.js Normal file
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");
}

93
tools/doc/tools/toc.js Normal file
View File

@@ -0,0 +1,93 @@
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 = {
"initPhase": initPhase,
"readPhase": readPhase,
"aggPhase": aggPhase,
"updatePhase": updatePhase
}
function initPhase(aggData) {}
function readPhase(tree, pathname, aggData) {}
function aggPhase(aggData) {}
// 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(unist.makeText(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 updatePhase(tree, pathname, aggData) {
// If we need a contents section then add one or update the existing one.
var numTocHeadings = establishContentsSection(tree);
if (numTocHeadings >= minHeadingsForToc) {
var newToc = tocGenerator(tree, {heading: contentsHeading, maxDepth: 3});
replaceSection(tree, contentsHeading, function(before, oldSection, after) {
return [before, newToc.map, after];
});
} else {
// Otherwise, we don't need one, so remove any existing one.
replaceSection(tree, contentsHeading, function(before, oldSection, after) {
return [after];
});
}
return true;
}

277
tools/doc/tools/tsInfo.js Normal file
View File

@@ -0,0 +1,277 @@
"use strict";
exports.__esModule = 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 libFolders = ["core", "content-services", "process-services", "insights"];
var templateFolder = path.resolve("tools", "doc", "templates");
var excludePatterns = [
"**/*.spec.ts"
];
var nameExceptions = {
"datatable.component": "DataTableComponent",
"tasklist.service": "TaskListService",
"text-mask.component": "InputMaskDirective",
"card-item-types.service": "CardItemTypeService"
};
var undocMethodNames = {
"ngOnChanges": 1
};
var PropInfo = /** @class */ (function () {
function PropInfo(rawProp) {
var _this = this;
this.errorMessages = [];
this.name = rawProp.name;
this.docText = rawProp.comment ? rawProp.comment.shortText : "";
this.docText = this.docText.replace(/[\n\r]+/g, " ").trim();
this.defaultValue = rawProp.defaultValue || "";
this.defaultValue = this.defaultValue.replace(/\|/, "\\|");
this.type = rawProp.type ? rawProp.type.toString() : "";
this.isDeprecated = rawProp.comment && rawProp.comment.hasTag("deprecated");
if (this.isDeprecated) {
this.docText = "**Deprecated:** " + rawProp.comment.getTag("deprecated").text.replace(/[\n\r]+/g, " ").trim();
}
if (rawProp.decorators) {
rawProp.decorators.forEach(function (dec) {
//console.log(dec);
if (dec.name === "Input") {
_this.isInput = true;
if (dec.arguments) {
var bindingName = dec.arguments["bindingPropertyName"];
if (bindingName && (bindingName !== ""))
_this.name = bindingName.replace(/['"]/g, "");
}
if (!_this.docText && !_this.isDeprecated) {
_this.errorMessages.push("Warning: Input \"" + rawProp.name + "\" has no doc text.");
}
}
if (dec.name === "Output") {
_this.isOutput = true;
if (!_this.docText && !_this.isDeprecated) {
_this.errorMessages.push("Warning: Output \"" + rawProp.name + "\" has no doc text.");
}
}
});
}
}
Object.defineProperty(PropInfo.prototype, "errors", {
get: function () {
return this.errorMessages;
},
enumerable: true,
configurable: true
});
return PropInfo;
}());
;
var ParamInfo = /** @class */ (function () {
function ParamInfo(rawParam) {
this.name = rawParam.name;
this.type = rawParam.type.toString();
this.defaultValue = rawParam.defaultValue;
this.docText = rawParam.comment ? rawParam.comment.text : "";
this.docText = this.docText.replace(/[\n\r]+/g, " ").trim();
this.isOptional = rawParam.flags.isOptional;
this.combined = this.name;
if (this.isOptional)
this.combined += "?";
this.combined += ": " + this.type;
if (this.defaultValue !== "")
this.combined += " = " + this.defaultValue;
}
return ParamInfo;
}());
var MethodSigInfo = /** @class */ (function () {
function MethodSigInfo(rawSig) {
var _this = this;
this.errorMessages = [];
this.name = rawSig.name;
this.returnType = rawSig.type ? rawSig.type.toString() : "";
this.returnsSomething = this.returnType != "void";
if (rawSig.hasComment()) {
this.docText = rawSig.comment.shortText + rawSig.comment.text;
this.docText = this.docText.replace(/[\n\r]+/g, " ").trim();
if (!this.docText) {
this.errorMessages.push("Warning: method \"" + rawSig.name + "\" has no doc text.");
}
this.returnDocText = rawSig.comment.returns;
this.returnDocText = this.returnDocText ? this.returnDocText.replace(/[\n\r]+/g, " ").trim() : "";
if (this.returnDocText.toLowerCase() === "nothing") {
this.returnsSomething = false;
}
if (this.returnsSomething && !this.returnDocText) {
this.errorMessages.push("Warning: Return value of method \"" + rawSig.name + "\" has no doc text.");
}
this.isDeprecated = rawSig.comment.hasTag("deprecated");
}
this.params = [];
var paramStrings = [];
if (rawSig.parameters) {
rawSig.parameters.forEach(function (rawParam) {
if (!rawParam.comment || !rawParam.comment.text) {
_this.errorMessages.push("Warning: parameter \"" + rawParam.name + "\" of method \"" + rawSig.name + "\" has no doc text.");
}
var param = new ParamInfo(rawParam);
_this.params.push(param);
paramStrings.push(param.combined);
});
}
this.signature = "(" + paramStrings.join(", ") + ")";
}
Object.defineProperty(MethodSigInfo.prototype, "errors", {
get: function () {
return this.errorMessages;
},
enumerable: true,
configurable: true
});
return MethodSigInfo;
}());
var ComponentInfo = /** @class */ (function () {
function ComponentInfo(classRef) {
var _this = this;
var props = classRef.getChildrenByKind(typedoc_1.ReflectionKind.Property);
var accessors = classRef.getChildrenByKind(typedoc_1.ReflectionKind.Accessor);
this.properties = props.concat(accessors).map(function (item) {
return new PropInfo(item);
});
var methods = classRef.getChildrenByKind(typedoc_1.ReflectionKind.Method);
this.methods = [];
methods.forEach(function (method) {
if (!(method.flags.isPrivate || method.flags.isProtected || undocMethodNames[method.name])) {
method.signatures.forEach(function (sig) {
_this.methods.push(new MethodSigInfo(sig));
});
}
});
this.properties.forEach(function (prop) {
if (prop.isInput)
_this.hasInputs = true;
if (prop.isOutput)
_this.hasOutputs = true;
});
this.hasMethods = methods.length > 0;
}
Object.defineProperty(ComponentInfo.prototype, "errors", {
get: function () {
var combinedErrors = [];
this.methods.forEach(function (method) {
method.errors.forEach(function (err) {
combinedErrors.push(err);
});
});
this.properties.forEach(function (prop) {
prop.errors.forEach(function (err) {
combinedErrors.push(err);
});
});
return combinedErrors;
},
enumerable: true,
configurable: true
});
return ComponentInfo;
}());
function initPhase(aggData) {
var app = new typedoc_1.Application({
exclude: excludePatterns,
ignoreCompilerErrors: true,
experimentalDecorators: true,
tsconfig: "tsconfig.json"
});
var sources = app.expandInputFiles(libFolders.map(function (folder) {
return path.resolve("lib", folder);
}));
aggData.projData = app.convert(sources);
/*
aggData.liq = liquid({
root: templateFolder
});
*/
}
exports.initPhase = initPhase;
function readPhase(tree, pathname, aggData) {
}
exports.readPhase = readPhase;
function aggPhase(aggData) {
}
exports.aggPhase = aggPhase;
function updatePhase(tree, pathname, aggData, errorMessages) {
var compName = angNameToClassName(path.basename(pathname, ".md"));
var classRef = aggData.projData.findReflectionByName(compName);
if (!classRef) {
// A doc file with no corresponding class (eg, Document Library Model).
return false;
}
var compData = new ComponentInfo(classRef);
var classType = compName.match(/component|directive|service/i);
if (classType) {
var templateName = path.resolve(templateFolder, classType + ".combyne");
var templateSource = fs.readFileSync(templateName, "utf8");
var template = combyne(templateSource);
var mdText = template.render(compData);
mdText = mdText.replace(/^ +\|/mg, "|");
var newSection_1 = remark().data("settings", { paddedTable: false, gfm: false }).parse(mdText.trim()).children;
replaceSection(tree, "Class members", function (before, section, after) {
newSection_1.unshift(before);
newSection_1.push(after);
return newSection_1;
});
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);
}
function angNameToClassName(rawName) {
if (nameExceptions[rawName])
return nameExceptions[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;
}

385
tools/doc/tools/tsInfo.ts Normal file
View File

@@ -0,0 +1,385 @@
import * as fs from "fs";
import * as path from "path";
import * as replaceSection from "mdast-util-heading-range";
import * as remark from "remark";
import * as stringify from "remark-stringify";
import * as frontMatter from "remark-frontmatter";
import * as combyne from "combyne";
import {
Application,
ProjectReflection,
Reflection,
DeclarationReflection,
SignatureReflection,
ParameterReflection,
ReflectionKind,
TraverseProperty,
Decorator
} from "typedoc";
import { CommentTag } from "typedoc/dist/lib/models";
let libFolders = ["core", "content-services", "process-services", "insights"];
let templateFolder = path.resolve("tools", "doc", "templates");
let excludePatterns = [
"**/*.spec.ts"
];
let nameExceptions = {
"datatable.component": "DataTableComponent",
"tasklist.service": "TaskListService",
"text-mask.component": "InputMaskDirective",
"card-item-types.service": "CardItemTypeService"
}
let undocMethodNames = {
"ngOnChanges": 1
};
class PropInfo {
name: string;
type: string;
typeLink: string;
defaultValue: string;
docText: string;
isInput: boolean;
isOutput: boolean;
isDeprecated: boolean;
errorMessages: string[];
constructor(rawProp: DeclarationReflection) {
this.errorMessages = [];
this.name = rawProp.name;
this.docText = rawProp.comment ? rawProp.comment.shortText : "";
this.docText = this.docText.replace(/[\n\r]+/g, " ").trim();
this.defaultValue = rawProp.defaultValue || "";
this.defaultValue = this.defaultValue.replace(/\|/, "\\|");
this.type = rawProp.type ? rawProp.type.toString() : "";
this.isDeprecated = rawProp.comment && rawProp.comment.hasTag("deprecated");
if (this.isDeprecated) {
this.docText = "**Deprecated:** " + rawProp.comment.getTag("deprecated").text.replace(/[\n\r]+/g, " ").trim();
}
if (rawProp.decorators) {
rawProp.decorators.forEach(dec => {
//console.log(dec);
if (dec.name === "Input") {
this.isInput = true;
if (dec.arguments) {
let bindingName = dec.arguments["bindingPropertyName"];
if (bindingName && (bindingName !== ""))
this.name = bindingName.replace(/['"]/g, "");
}
if (!this.docText && !this.isDeprecated) {
this.errorMessages.push(`Warning: Input "${rawProp.name}" has no doc text.`);
}
}
if (dec.name === "Output") {
this.isOutput = true;
if (!this.docText && !this.isDeprecated) {
this.errorMessages.push(`Warning: Output "${rawProp.name}" has no doc text.`);
}
}
});
}
}
get errors() {
return this.errorMessages;
}
};
class ParamInfo {
name: string;
type: string;
defaultValue: string;
docText: string;
combined: string;
isOptional: boolean;
constructor(rawParam: ParameterReflection) {
this.name = rawParam.name;
this.type = rawParam.type.toString();
this.defaultValue = rawParam.defaultValue;
this.docText = rawParam.comment ? rawParam.comment.text : "";
this.docText = this.docText.replace(/[\n\r]+/g, " ").trim();
this.isOptional = rawParam.flags.isOptional;
this.combined = this.name;
if (this.isOptional)
this.combined += "?";
this.combined += `: ${this.type}`;
if (this.defaultValue !== "")
this.combined += ` = ${this.defaultValue}`;
}
}
class MethodSigInfo {
name: string;
docText: string;
returnType: string;
returnDocText: string;
returnsSomething: boolean;
signature: string;
params: ParamInfo[];
isDeprecated: boolean;
errorMessages: string[];
constructor(rawSig: SignatureReflection) {
this.errorMessages = [];
this.name = rawSig.name;
this.returnType = rawSig.type ? rawSig.type.toString() : "";
this.returnsSomething = this.returnType != "void";
if (rawSig.hasComment()) {
this.docText = rawSig.comment.shortText + rawSig.comment.text;
this.docText = this.docText.replace(/[\n\r]+/g, " ").trim();
if (!this.docText) {
this.errorMessages.push(`Warning: method "${rawSig.name}" has no doc text.`);
}
this.returnDocText = rawSig.comment.returns;
this.returnDocText = this.returnDocText ? this.returnDocText.replace(/[\n\r]+/g, " ").trim() : "";
if (this.returnDocText.toLowerCase() === "nothing") {
this.returnsSomething = false;
}
if (this.returnsSomething && !this.returnDocText) {
this.errorMessages.push(`Warning: Return value of method "${rawSig.name}" has no doc text.`);
}
this.isDeprecated = rawSig.comment.hasTag("deprecated");
}
this.params = [];
let paramStrings = [];
if (rawSig.parameters) {
rawSig.parameters.forEach(rawParam => {
if (!rawParam.comment || !rawParam.comment.text) {
this.errorMessages.push(`Warning: parameter "${rawParam.name}" of method "${rawSig.name}" has no doc text.`);
}
let param = new ParamInfo(rawParam);
this.params.push(param);
paramStrings.push(param.combined);
});
}
this.signature = "(" + paramStrings.join(", ") + ")";
}
get errors() {
return this.errorMessages;
}
}
class ComponentInfo {
properties: PropInfo[];
methods: MethodSigInfo[];
hasInputs: boolean;
hasOutputs: boolean;
hasMethods: boolean;
constructor(classRef: DeclarationReflection) {
let props = classRef.getChildrenByKind(ReflectionKind.Property);
let accessors = classRef.getChildrenByKind(ReflectionKind.Accessor);
this.properties = [...props, ...accessors].map(item => {
return new PropInfo(item);
});
let methods = classRef.getChildrenByKind(ReflectionKind.Method);
this.methods = [];
methods.forEach(method =>{
if (!(method.flags.isPrivate || method.flags.isProtected || undocMethodNames[method.name])) {
method.signatures.forEach(sig => {
this.methods.push(new MethodSigInfo(sig));
});
}
});
this.properties.forEach(prop => {
if (prop.isInput)
this.hasInputs = true;
if (prop.isOutput)
this.hasOutputs = true;
});
this.hasMethods = methods.length > 0;
}
get errors() {
let combinedErrors = [];
this.methods.forEach(method => {
method.errors.forEach(err => {
combinedErrors.push(err);
})
});
this.properties.forEach(prop => {
prop.errors.forEach(err => {
combinedErrors.push(err);
});
});
return combinedErrors;
}
}
export function initPhase(aggData) {
let app = new Application({
exclude: excludePatterns,
ignoreCompilerErrors: true,
experimentalDecorators: true,
tsconfig: "tsconfig.json"
});
let sources = app.expandInputFiles(libFolders.map(folder => {
return path.resolve("lib", folder);
}));
aggData.projData = app.convert(sources);
/*
aggData.liq = liquid({
root: templateFolder
});
*/
}
export function readPhase(tree, pathname, aggData) {
}
export function aggPhase(aggData) {
}
export function updatePhase(tree, pathname, aggData, errorMessages) {
let compName = angNameToClassName(path.basename(pathname, ".md"));
let classRef = aggData.projData.findReflectionByName(compName);
if (!classRef) {
// A doc file with no corresponding class (eg, Document Library Model).
return false;
}
let compData = new ComponentInfo(classRef);
let classType = compName.match(/component|directive|service/i);
if (classType) {
let templateName = path.resolve(templateFolder, classType + ".combyne");
let templateSource = fs.readFileSync(templateName, "utf8");
let template = combyne(templateSource);
let mdText = template.render(compData);
mdText = mdText.replace(/^ +\|/mg, "|");
let newSection = remark().data("settings", {paddedTable: false, gfm: false}).parse(mdText.trim()).children;
replaceSection(tree, "Class members", (before, section, after) => {
newSection.unshift(before);
newSection.push(after);
return newSection;
});
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);
}
function angNameToClassName(rawName: string) {
if (nameExceptions[rawName])
return nameExceptions[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;
}

357
tools/doc/tools/tscProps.js Normal file
View File

@@ -0,0 +1,357 @@
"use strict";
exports.__esModule = true;
var ts = require("typescript");
var path = require("path");
var heading = require("mdast-util-heading-range");
var remark = require("remark");
var unist = require("../unistHelpers");
var typescript_1 = require("typescript");
// Max number of characters in the text for the default value column.
var maxDefaultTextLength = 20;
var nameExceptions = {
"datatable.component": "DataTableComponent",
"tasklist.service": "TaskListService"
};
function initPhase(aggData) {
}
exports.initPhase = initPhase;
function readPhase(tree, pathname, aggData) {
}
exports.readPhase = readPhase;
function aggPhase(aggData) {
}
exports.aggPhase = aggPhase;
var PropData = /** @class */ (function () {
function PropData() {
}
return PropData;
}());
var ParamData = /** @class */ (function () {
function ParamData() {
}
ParamData.prototype.getSignature = function () {
var sig = this.name;
if (this.optional)
sig += "?";
if (this.type)
sig += ": " + this.type;
if (this.initializer)
sig += " = " + this.initializer;
return sig;
};
return ParamData;
}());
var MethodData = /** @class */ (function () {
function MethodData() {
this.params = [];
}
MethodData.prototype.getSignature = function () {
var sig = this.name + "(";
if (this.params.length > 0) {
sig += this.params[0].getSignature();
}
for (var i = 1; i < this.params.length; i++) {
sig += ", " + this.params[i].getSignature();
}
sig += ")";
if (this.returnType !== "void") {
sig += ": " + this.returnType;
}
return sig;
};
return MethodData;
}());
var ComponentDocAutoContent = /** @class */ (function () {
function ComponentDocAutoContent() {
this.inputs = [];
this.outputs = [];
}
ComponentDocAutoContent.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.isPropertyDeclaration(member) ||
ts.isGetAccessorDeclaration(member) ||
ts.isSetAccessorDeclaration(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(checker));
doc = doc.replace(/\r\n/g, " ");
var propType = checker.typeToString(checker.getTypeOfSymbolAtLocation(memSymbol, memSymbol.valueDeclaration));
var dec = prop.decorators[0].getText(sourceFile);
if (dec.match(/@Input/)) {
this.inputs.push({
"name": name_1,
"type": propType,
"initializer": initializer,
"docText": doc
});
}
else if (dec.match(/@Output/)) {
this.outputs.push({
"name": name_1,
"type": propType,
"initializer": "",
"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());
if (!doc)
console.log("Warning: Method " + classDec.name.escapedText + "." + methData.name + " is not documented");
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();
if (params[p].type)
pData.type = params[p].type.getText();
else
pData.type = "";
var paramSymbol = checker.getSymbolAtLocation(params[p].name);
pData.docText = ts.displayPartsToString(paramSymbol.getDocumentationComment());
if (!pData.docText)
console.log("Warning: Parameter \"" + pData.name + "\" of " + classDec.name.escapedText + "." + methData.name + " is not documented");
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|directive|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") || (itemType[0] === "directive")) {
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) {
if (nameExceptions[rawName])
return nameExceptions[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 buildPropsTable(props, includeInitializer) {
if (includeInitializer === void 0) { includeInitializer = true; }
if (props.length === 0) {
return null;
}
var headerCells = [
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")])
];
if (includeInitializer)
headerCells.push(unist.makeTableCell([unist.makeText("Default value")]));
headerCells.push(unist.makeTableCell([unist.makeText("Description")]));
var rows = [
unist.makeTableRow(headerCells)
];
for (var i = 0; i < props.length; i++) {
var pName = props[i].name;
var pType = props[i].type;
var pDesc = props[i].docText || "";
if (pDesc) {
pDesc = pDesc.replace(/[\n\r]+/, " ");
}
var descCellContent = remark().parse(pDesc).children;
var pDefault = props[i].initializer || "";
var defaultCellContent;
if (pDefault) {
if (pDefault.length > maxDefaultTextLength) {
defaultCellContent = unist.makeText("See description");
console.log("Warning: property \"" + pName + "\" default value substituted (> " + maxDefaultTextLength + " chars)");
}
else
defaultCellContent = unist.makeInlineCode(pDefault);
}
else {
defaultCellContent = unist.makeText("");
}
var cells = [
unist.makeTableCell([unist.makeText(pName)]),
unist.makeTableCell([unist.makeInlineCode(pType)])
];
if (includeInitializer)
cells.push(unist.makeTableCell([defaultCellContent]));
cells.push(unist.makeTableCell(descCellContent));
rows.push(unist.makeTableRow(cells));
}
var spacers = [null, null, null];
if (includeInitializer)
spacers.push(null);
return unist.makeTable(spacers, rows);
}
function buildMethodsList(methods) {
if (methods.length === 0)
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)));
}
}
itemLines.push(unist.makeListUnordered(paramListItems));
listItems.push(unist.makeListItem(unist.makeParagraph(itemLines)));
}
return unist.makeListUnordered(listItems);
}
function isNodeExported(node) {
return (ts.getCombinedModifierFlags(node) & ts.ModifierFlags.Export) !== 0 || (!!node.parent && node.parent.kind === ts.SyntaxKind.SourceFile);
}

498
tools/doc/tools/tscProps.ts Normal file
View File

@@ -0,0 +1,498 @@
import * as ts from "typescript";
import * as fs from "fs";
import * as path from "path";
import * as heading from "mdast-util-heading-range";
import * as remark from "remark";
import * as unist from "../unistHelpers";
import { JsxEmit, isClassDeclaration, PropertyDeclaration } from "typescript";
// Max number of characters in the text for the default value column.
const maxDefaultTextLength = 20;
let nameExceptions = {
"datatable.component": "DataTableComponent",
"tasklist.service": "TaskListService"
}
export function initPhase(aggData) {
}
export function readPhase(tree, pathname, aggData) {
}
export function aggPhase(aggData) {
}
interface NgDocAutoContent {
extractClassInfoFromSource(checker: ts.TypeChecker, classDec: ts.ClassDeclaration);
addContentToDoc(tree);
}
class PropData {
name: string;
type: string;
initializer: string;
docText: string;
}
class ParamData {
name: string;
type: string;
docText: string;
initializer: string;
optional: boolean;
getSignature() {
let sig = this.name;
if (this.optional)
sig += "?";
if (this.type)
sig += ": " + this.type;
if (this.initializer)
sig += " = " + this.initializer;
return sig;
}
}
class MethodData {
name: string;
docText: string;
params: ParamData[];
returnType: string;
constructor() {
this.params = [];
}
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[];
constructor() {
this.inputs = [];
this.outputs = [];
}
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.isPropertyDeclaration(member) ||
ts.isGetAccessorDeclaration(member) ||
ts.isSetAccessorDeclaration(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(checker));
doc = doc.replace(/\r\n/g, " ");
let propType = checker.typeToString(checker.getTypeOfSymbolAtLocation(memSymbol, memSymbol.valueDeclaration!));
let dec = prop.decorators[0].getText(sourceFile);
if (dec.match(/@Input/)) {
this.inputs.push({
"name": name,
"type": propType,
"initializer": initializer,
"docText": doc
});
} else if (dec.match(/@Output/)) {
this.outputs.push({
"name": name,
"type": propType,
"initializer": "",
"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());
if (!doc)
console.log(`Warning: Method ${classDec.name.escapedText}.${methData.name} is not documented`);
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();
if (params[p].type)
pData.type = params[p].type.getText();
else
pData.type = "";
let paramSymbol = checker.getSymbolAtLocation(params[p].name);
pData.docText = ts.displayPartsToString(paramSymbol.getDocumentationComment());
if (!pData.docText)
console.log(`Warning: Parameter "${pData.name}" of ${classDec.name.escapedText}.${methData.name} is not documented`);
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|directive|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") || (itemType[0] === "directive")) {
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) {
if (nameExceptions[rawName])
return nameExceptions[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: 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);
}
}
}
}
// Get properties/events from main class and all inherited classes.
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;
}
var headerCells = [
unist.makeTableCell([unist.makeText("Name")]),
unist.makeTableCell([unist.makeText("Type")])
];
if (includeInitializer)
headerCells.push(unist.makeTableCell([unist.makeText("Default value")]));
headerCells.push(unist.makeTableCell([unist.makeText("Description")]));
var rows = [
unist.makeTableRow(headerCells)
];
for (var i = 0; i < props.length; i++) {
var pName = props[i].name;
var pType = props[i].type;
var pDesc = props[i].docText || "";
if (pDesc) {
pDesc = pDesc.replace(/[\n\r]+/, " ");
}
var descCellContent = remark().parse(pDesc).children;
var pDefault = props[i].initializer || "";
var defaultCellContent;
if (pDefault) {
if (pDefault.length > maxDefaultTextLength) {
defaultCellContent = unist.makeText("See description");
console.log(`Warning: property "${pName}" default value substituted (> ${maxDefaultTextLength} chars)`);
} else
defaultCellContent = unist.makeInlineCode(pDefault);
} else {
defaultCellContent = unist.makeText("");
}
var cells = [
unist.makeTableCell([unist.makeText(pName)]),
unist.makeTableCell([unist.makeInlineCode(pType)])
];
if (includeInitializer)
cells.push(unist.makeTableCell([defaultCellContent]));
cells.push(unist.makeTableCell(descCellContent));
rows.push(unist.makeTableRow(cells));
}
let spacers = [null, null, null];
if (includeInitializer)
spacers.push(null);
return unist.makeTable(spacers, rows);
}
function buildMethodsList(methods: MethodData[]) {
if (methods.length === 0)
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)));
}
}
itemLines.push(unist.makeListUnordered(paramListItems));
listItems.push(unist.makeListItem(unist.makeParagraph(itemLines)));
}
return unist.makeListUnordered(listItems);
}
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,108 @@
"use strict";
exports.__esModule = true;
var fs = require("fs");
var path = require("path");
var replaceSection = require("mdast-util-heading-range");
var remark = require("remark");
var frontMatter = require("remark-frontmatter");
var yaml = require("js-yaml");
var combyne = require("combyne");
var unist = require("../unistHelpers");
var tutFolder = path.resolve("docs", "tutorials");
var templateFolder = path.resolve("tools", "doc", "templates");
var userGuideFolder = path.resolve("docs", "user-guide");
function initPhase(aggData) { }
exports.initPhase = initPhase;
function readPhase(tree, pathname, aggData) { }
exports.readPhase = readPhase;
function aggPhase(aggData) {
var indexDocData = getIndexDocData();
var templateName = path.resolve(templateFolder, "tutIndex.combyne");
var templateSource = fs.readFileSync(templateName, "utf8");
var template = combyne(templateSource);
var mdText = template.render(indexDocData);
mdText = mdText.replace(/^ +\|/mg, "|");
var newSection = remark().data("settings", { paddedTable: false, gfm: false }).parse(mdText.trim()).children;
var tutIndexFile = path.resolve(tutFolder, "README.md");
var tutIndexText = fs.readFileSync(tutIndexFile, "utf8");
var tutIndexMD = remark().data("settings", { paddedTable: false, gfm: false }).parse(tutIndexText);
replaceSection(tutIndexMD, "Tutorials", function (before, section, after) {
newSection.unshift(before);
newSection.push(after);
return newSection;
});
fs.writeFileSync(tutIndexFile, remark().use(frontMatter, { type: 'yaml', fence: '---' }).data("settings", { paddedTable: false, gfm: false }).stringify(tutIndexMD));
}
exports.aggPhase = aggPhase;
function updatePhase(tree, pathname, aggData) {
return false;
}
exports.updatePhase = updatePhase;
function getIndexDocData() {
var indexFile = path.resolve(userGuideFolder, "summary.json");
var summaryArray = JSON.parse(fs.readFileSync(indexFile, "utf8"));
var indexArray = [];
summaryArray.forEach(function (element) {
if (element["title"] === "Tutorials") {
indexArray = element["children"];
}
});
var result = {
tuts: []
};
indexArray.forEach(function (element) {
var tutData = { link: element["file"] };
var tutFile = path.resolve(tutFolder, element["file"]);
var tutFileText = fs.readFileSync(tutFile, "utf8");
var tutMD = remark().use(frontMatter, ["yaml"]).parse(tutFileText);
var metadata = getDocMetadata(tutMD);
if (metadata["Level"]) {
tutData["level"] = metadata["Level"];
}
else {
tutData["level"] = "";
}
var briefDesc = getFirstParagraph(tutMD);
var briefDescText = remark()
.use(frontMatter, { type: 'yaml', fence: '---' })
.data("settings", { paddedTable: false, gfm: false })
.stringify(briefDesc);
tutData["briefDesc"] = briefDescText;
var title = getFirstHeading(tutMD);
var titleText = remark()
.use(frontMatter, { type: 'yaml', fence: '---' })
.data("settings", { paddedTable: false, gfm: false })
.stringify(title.children[0]);
tutData["title"] = titleText;
result.tuts.push(tutData);
});
return result;
}
function getDocMetadata(tree) {
if (tree.children[0].type == "yaml") {
return yaml.load(tree.children[0].value);
}
else {
return {};
}
}
function getFirstParagraph(tree) {
var s = 0;
for (; (s < tree.children.length) && !unist.isParagraph(tree.children[s]); s++) { }
if (s < tree.children.length) {
return tree.children[s];
}
else {
return null;
}
}
function getFirstHeading(tree) {
var s = 0;
for (; (s < tree.children.length) && !unist.isHeading(tree.children[s]); s++) { }
if (s < tree.children.length) {
return tree.children[s];
}
else {
return null;
}
}

View File

@@ -0,0 +1,142 @@
import * as fs from "fs";
import * as path from "path";
import * as replaceSection from "mdast-util-heading-range";
import * as remark from "remark";
import * as stringify from "remark-stringify";
import * as frontMatter from "remark-frontmatter";
import * as yaml from "js-yaml";
import * as combyne from "combyne";
import * as unist from "../unistHelpers";
const tutFolder = path.resolve("docs", "tutorials");
const templateFolder = path.resolve("tools", "doc", "templates");
const userGuideFolder = path.resolve("docs", "user-guide");
export function initPhase(aggData) {}
export function readPhase(tree, pathname, aggData) {}
export function aggPhase(aggData) {
let indexDocData = getIndexDocData();
let templateName = path.resolve(templateFolder, "tutIndex.combyne");
let templateSource = fs.readFileSync(templateName, "utf8");
let template = combyne(templateSource);
let mdText = template.render(indexDocData);
mdText = mdText.replace(/^ +\|/mg, "|");
let newSection = remark().data("settings", {paddedTable: false, gfm: false}).parse(mdText.trim()).children;
let tutIndexFile = path.resolve(tutFolder, "README.md");
let tutIndexText = fs.readFileSync(tutIndexFile, "utf8");
let tutIndexMD = remark().data("settings", {paddedTable: false, gfm: false}).parse(tutIndexText);
replaceSection(tutIndexMD, "Tutorials", (before, section, after) => {
newSection.unshift(before);
newSection.push(after);
return newSection;
});
fs.writeFileSync(tutIndexFile, remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false, gfm: false}).stringify(tutIndexMD));
}
export function updatePhase(tree, pathname, aggData) {
return false;
}
function getIndexDocData() {
let indexFile = path.resolve(userGuideFolder, "summary.json");
let summaryArray = JSON.parse(fs.readFileSync(indexFile, "utf8"));
let indexArray = [];
summaryArray.forEach(element => {
if (element["title"] === "Tutorials") {
indexArray = element["children"];
}
});
let result = {
tuts: []
};
indexArray.forEach(element => {
let tutData = { link: element["file"] };
let tutFile = path.resolve(tutFolder, element["file"]);
let tutFileText = fs.readFileSync(tutFile, "utf8");
let tutMD = remark().use(frontMatter, ["yaml"]).parse(tutFileText);
let metadata = getDocMetadata(tutMD);
if (metadata["Level"]){
tutData["level"] = metadata["Level"];
} else {
tutData["level"] = "";
}
let briefDesc = getFirstParagraph(tutMD);
let briefDescText = remark()
.use(frontMatter, {type: 'yaml', fence: '---'})
.data("settings", {paddedTable: false, gfm: false})
.stringify(briefDesc);
tutData["briefDesc"] = briefDescText;
let title = getFirstHeading(tutMD);
let titleText = remark()
.use(frontMatter, {type: 'yaml', fence: '---'})
.data("settings", {paddedTable: false, gfm: false})
.stringify(title.children[0]);
tutData["title"] = titleText;
result.tuts.push(tutData);
});
return result;
}
function getDocMetadata(tree) {
if (tree.children[0].type == "yaml") {
return yaml.load(tree.children[0].value);
} else {
return {};
}
}
function getFirstParagraph(tree) {
let s = 0;
for (;(s < tree.children.length) && !unist.isParagraph(tree.children[s]); s++) {}
if (s < tree.children.length) {
return tree.children[s];
} else {
return null;
}
}
function getFirstHeading(tree) {
let s = 0;
for (;(s < tree.children.length) && !unist.isHeading(tree.children[s]); s++) {}
if (s < tree.children.length) {
return tree.children[s];
} else {
return null;
}
}

View File

@@ -0,0 +1,289 @@
"use strict";
exports.__esModule = true;
var path = require("path");
var fs = require("fs");
var typedoc_1 = require("typedoc");
var unist = require("../unistHelpers");
var ngHelpers = require("../ngHelpers");
var includedNodeTypes = [
"root", "paragraph", "inlineCode", "list", "listItem",
"table", "tableRow", "tableCell", "emphasis", "strong",
"link", "text"
];
var docFolder = path.resolve("docs");
var adfLibNames = ["core", "content-services", "insights", "process-services"];
function initPhase(aggData) {
aggData.docFiles = {};
aggData.nameLookup = new SplitNameLookup();
adfLibNames.forEach(function (libName) {
var libFolderPath = path.resolve(docFolder, libName);
var files = fs.readdirSync(libFolderPath);
files.forEach(function (file) {
if (path.extname(file) === ".md") {
var relPath = libFolderPath.substr(libFolderPath.indexOf("docs") + 5).replace(/\\/, "/") + "/" + file;
var compName = path.basename(file, ".md");
aggData.docFiles[compName] = relPath;
}
});
});
var classes = aggData.projData.getReflectionsByKind(typedoc_1.ReflectionKind.Class);
classes.forEach(function (currClass) {
if (currClass.name.match(/(Component|Directive|Interface|Model|Pipe|Service|Widget)$/)) {
aggData.nameLookup.addName(currClass.name);
}
});
//console.log(JSON.stringify(aggData.nameLookup));
}
exports.initPhase = initPhase;
function readPhase(tree, pathname, aggData) { }
exports.readPhase = readPhase;
function aggPhase(aggData) {
}
exports.aggPhase = aggPhase;
function updatePhase(tree, pathname, aggData) {
traverseMDTree(tree);
return true;
function traverseMDTree(node) {
if (!includedNodeTypes.includes(node.type)) {
return;
}
if (node.type === "inlineCode") {
var link = resolveTypeLink(aggData, node.value);
if (link) {
convertNodeToTypeLink(node, node.value, link);
}
}
else if (node.type === "link") {
if (node.children && ((node.children[0].type === "inlineCode") ||
(node.children[0].type === "text"))) {
var link = resolveTypeLink(aggData, node.children[0].value);
if (link) {
convertNodeToTypeLink(node, node.children[0].value, link);
}
}
}
else if (node.type === "paragraph") {
node.children.forEach(function (child, index) {
if (child.type === "text") {
var newNodes = handleLinksInBodyText(aggData, child.value);
(_a = node.children).splice.apply(_a, [index, 1].concat(newNodes));
}
else {
traverseMDTree(child);
}
var _a;
});
}
else if (node.children) {
node.children.forEach(function (child) {
traverseMDTree(child);
});
}
}
}
exports.updatePhase = updatePhase;
var SplitNameNode = /** @class */ (function () {
function SplitNameNode(key, value) {
if (key === void 0) { key = ""; }
if (value === void 0) { value = ""; }
this.key = key;
this.value = value;
this.children = {};
}
SplitNameNode.prototype.addChild = function (child) {
this.children[child.key] = child;
};
return SplitNameNode;
}());
var SplitNameMatchElement = /** @class */ (function () {
function SplitNameMatchElement(node, textPos) {
this.node = node;
this.textPos = textPos;
}
return SplitNameMatchElement;
}());
var SplitNameMatchResult = /** @class */ (function () {
function SplitNameMatchResult(value, startPos) {
this.value = value;
this.startPos = startPos;
}
return SplitNameMatchResult;
}());
var SplitNameMatcher = /** @class */ (function () {
function SplitNameMatcher(root) {
this.root = root;
this.reset();
}
/* Returns all names that match when this word is added. */
SplitNameMatcher.prototype.nextWord = function (word, textPos) {
var result = [];
this.matches.push(new SplitNameMatchElement(this.root, textPos));
for (var i = this.matches.length - 1; i >= 0; i--) {
if (this.matches[i].node.children) {
var child = this.matches[i].node.children[word];
if (child) {
if (child.value) {
/* Using unshift to add the match to the array means that
* the longest matches will appear first in the array.
* User can then just use the first array element if only
* the longest match is needed.
*/
result.unshift(new SplitNameMatchResult(child.value, this.matches[i].textPos));
this.matches.splice(i, 1);
}
else {
this.matches[i] = new SplitNameMatchElement(child, this.matches[i].textPos);
}
}
else {
this.matches.splice(i, 1);
}
}
else {
this.matches.splice(i, 1);
}
}
if (result === []) {
return null;
}
else {
return result;
}
};
SplitNameMatcher.prototype.reset = function () {
this.matches = [];
};
return SplitNameMatcher;
}());
var SplitNameLookup = /** @class */ (function () {
function SplitNameLookup() {
this.root = new SplitNameNode();
}
SplitNameLookup.prototype.addName = function (name) {
var spacedName = name.replace(/([A-Z])/g, " $1");
var segments = spacedName.trim().toLowerCase().split(" ");
var currNode = this.root;
segments.forEach(function (segment, index) {
var value = "";
if (index == (segments.length - 1)) {
value = name;
}
var childNode = currNode.children[segment];
if (!childNode) {
childNode = new SplitNameNode(segment, value);
currNode.addChild(childNode);
}
currNode = childNode;
});
};
return SplitNameLookup;
}());
var WordScanner = /** @class */ (function () {
function WordScanner(text) {
this.text = text;
this.separators = " \n\r\t.;:";
this.index = 0;
this.nextSeparator = 0;
this.next();
}
WordScanner.prototype.finished = function () {
return this.index >= this.text.length;
};
WordScanner.prototype.next = function () {
this.advanceIndex();
this.advanceNextSeparator();
this.current = this.text.substring(this.index, this.nextSeparator);
};
WordScanner.prototype.advanceNextSeparator = function () {
for (var i = this.index; i < this.text.length; i++) {
if (this.separators.indexOf(this.text[i]) !== -1) {
this.nextSeparator = i;
return;
}
}
this.nextSeparator = this.text.length;
};
WordScanner.prototype.advanceIndex = function () {
for (var i = this.nextSeparator; i < this.text.length; i++) {
if (this.separators.indexOf(this.text[i]) === -1) {
this.index = i;
return;
}
}
this.index = this.text.length;
};
return WordScanner;
}());
function handleLinksInBodyText(aggData, text) {
var result = [];
var currTextStart = 0;
var matcher = new SplitNameMatcher(aggData.nameLookup.root);
for (var scanner = new WordScanner(text); !scanner.finished(); scanner.next()) {
var word = scanner.current
.replace(/'s$/, "")
.replace(/^[;:,\."']+/g, "")
.replace(/[;:,\."']+$/g, "");
var link = resolveTypeLink(aggData, word);
var matchStart = void 0;
if (!link) {
var match = matcher.nextWord(word.toLowerCase(), scanner.index);
if (match && match[0]) {
link = resolveTypeLink(aggData, match[0].value);
matchStart = match[0].startPos;
}
}
else {
matchStart = scanner.index;
}
if (link) {
var linkText = text.substring(matchStart, scanner.nextSeparator);
var linkNode = unist.makeLink(unist.makeText(linkText), link);
var prevText = text.substring(currTextStart, matchStart);
result.push(unist.makeText(prevText));
result.push(linkNode);
currTextStart = scanner.nextSeparator;
matcher.reset();
}
}
var remainingText = text.substring(currTextStart, text.length);
if (remainingText) {
result.push(unist.makeText(remainingText));
}
return result;
}
function resolveTypeLink(aggData, text) {
var possTypeName = cleanTypeName(text);
var ref = aggData.projData.findReflectionByName(possTypeName);
if (ref && isLinkable(ref.kind)) {
var kebabName = ngHelpers.kebabifyClassName(possTypeName);
var possDocFile = aggData.docFiles[kebabName];
var url = "../../lib/" + ref.sources[0].fileName;
if (possDocFile) {
url = "../" + possDocFile;
}
return url;
}
else {
return "";
}
}
function cleanTypeName(text) {
var matches = text.match(/[a-zA-Z0-9_]+<([a-zA-Z0-9_]+)>/);
if (matches) {
return matches[1];
}
else {
return text;
}
}
function isLinkable(kind) {
return (kind === typedoc_1.ReflectionKind.Class) ||
(kind === typedoc_1.ReflectionKind.Interface) ||
(kind === typedoc_1.ReflectionKind.Enum);
}
function convertNodeToTypeLink(node, text, url) {
var linkDisplayText = unist.makeInlineCode(text);
node.type = "link";
node.url = url;
node.children = [linkDisplayText];
}

View File

@@ -0,0 +1,359 @@
import * as path from "path";
import * as fs from "fs";
import * as remark from "remark";
import * as stringify from "remark-stringify";
import * as frontMatter from "remark-frontmatter";
import {
Application,
ProjectReflection,
Reflection,
DeclarationReflection,
SignatureReflection,
ParameterReflection,
ReflectionKind,
TraverseProperty,
Decorator
} from "typedoc";
import { CommentTag } from "typedoc/dist/lib/models";
import * as unist from "../unistHelpers";
import * as ngHelpers from "../ngHelpers";
const includedNodeTypes = [
"root", "paragraph", "inlineCode", "list", "listItem",
"table", "tableRow", "tableCell", "emphasis", "strong",
"link", "text"
];
const docFolder = path.resolve("docs");
const adfLibNames = ["core", "content-services", "insights", "process-services"];
export function initPhase(aggData) {
aggData.docFiles = {};
aggData.nameLookup = new SplitNameLookup();
adfLibNames.forEach(libName => {
let libFolderPath = path.resolve(docFolder, libName);
let files = fs.readdirSync(libFolderPath);
files.forEach(file => {
if (path.extname(file) === ".md") {
let relPath = libFolderPath.substr(libFolderPath.indexOf("docs") + 5).replace(/\\/, "/") + "/" + file;
let compName = path.basename(file, ".md");
aggData.docFiles[compName] = relPath;
}
});
});
let classes = aggData.projData.getReflectionsByKind(ReflectionKind.Class);
classes.forEach(currClass => {
if (currClass.name.match(/(Component|Directive|Interface|Model|Pipe|Service|Widget)$/)) {
aggData.nameLookup.addName(currClass.name);
}
});
//console.log(JSON.stringify(aggData.nameLookup));
}
export function readPhase(tree, pathname, aggData) {}
export function aggPhase(aggData) {
}
export function updatePhase(tree, pathname, aggData) {
traverseMDTree(tree);
return true;
function traverseMDTree(node) {
if (!includedNodeTypes.includes(node.type)) {
return;
}
if (node.type === "inlineCode") {
let link = resolveTypeLink(aggData, node.value);
if (link) {
convertNodeToTypeLink(node, node.value, link);
}
} else if (node.type === "link") {
if (node.children && (
(node.children[0].type === "inlineCode") ||
(node.children[0].type === "text")
)) {
let link = resolveTypeLink(aggData, node.children[0].value);
if (link) {
convertNodeToTypeLink(node, node.children[0].value, link);
}
}
} else if (node.type === "paragraph") {
node.children.forEach((child, index) => {
if (child.type === "text") {
let newNodes = handleLinksInBodyText(aggData, child.value);
node.children.splice(index, 1, ...newNodes);
} else {
traverseMDTree(child);
}
});
} else if (node.children) {
node.children.forEach(child => {
traverseMDTree(child);
});
}
}
}
class SplitNameNode {
children: {};
constructor(public key: string = "", public value: string = "") {
this.children = {};
}
addChild(child: SplitNameNode) {
this.children[child.key] = child;
}
}
class SplitNameMatchElement {
constructor(public node: SplitNameNode, public textPos: number) {}
}
class SplitNameMatchResult {
constructor(public value: string, public startPos: number) {}
}
class SplitNameMatcher {
matches: SplitNameMatchElement[];
constructor(public root: SplitNameNode) {
this.reset();
}
/* Returns all names that match when this word is added. */
nextWord(word: string, textPos: number): SplitNameMatchResult[] {
let result = [];
this.matches.push(new SplitNameMatchElement(this.root, textPos));
for (let i = this.matches.length - 1; i >= 0; i--) {
if (this.matches[i].node.children) {
let child = this.matches[i].node.children[word];
if (child) {
if (child.value) {
/* Using unshift to add the match to the array means that
* the longest matches will appear first in the array.
* User can then just use the first array element if only
* the longest match is needed.
*/
result.unshift(new SplitNameMatchResult(child.value, this.matches[i].textPos));
this.matches.splice(i, 1);
} else {
this.matches[i] = new SplitNameMatchElement(child, this.matches[i].textPos);
}
} else {
this.matches.splice(i, 1);
}
} else {
this.matches.splice(i, 1);
}
}
if (result === []) {
return null;
} else {
return result;
}
}
reset() {
this.matches = [];
}
}
class SplitNameLookup {
root: SplitNameNode;
constructor() {
this.root = new SplitNameNode();
}
addName(name: string) {
let spacedName = name.replace(/([A-Z])/g, " $1");
let segments = spacedName.trim().toLowerCase().split(" ");
let currNode = this.root;
segments.forEach((segment, index) => {
let value = "";
if (index == (segments.length - 1)) {
value = name;
}
let childNode = currNode.children[segment];
if (!childNode) {
childNode = new SplitNameNode(segment, value);
currNode.addChild(childNode);
}
currNode = childNode;
});
}
}
class WordScanner {
separators: string;
index: number;
nextSeparator: number;
current: string;
constructor(public text: string) {
this.separators = " \n\r\t.;:";
this.index = 0;
this.nextSeparator = 0;
this.next();
}
finished() {
return this.index >= this.text.length;
}
next(): void {
this.advanceIndex();
this.advanceNextSeparator();
this.current = this.text.substring(this.index, this.nextSeparator);
}
advanceNextSeparator() {
for (let i = this.index; i < this.text.length; i++) {
if (this.separators.indexOf(this.text[i]) !== -1) {
this.nextSeparator = i;
return;
}
}
this.nextSeparator = this.text.length;
}
advanceIndex() {
for (let i = this.nextSeparator; i < this.text.length; i++) {
if (this.separators.indexOf(this.text[i]) === -1) {
this.index = i;
return;
}
}
this.index = this.text.length;
}
}
function handleLinksInBodyText(aggData, text: string): Node[] {
let result = [];
let currTextStart = 0;
let matcher = new SplitNameMatcher(aggData.nameLookup.root);
for (let scanner = new WordScanner(text); !scanner.finished(); scanner.next()) {
let word = scanner.current
.replace(/'s$/, "")
.replace(/^[;:,\."']+/g, "")
.replace(/[;:,\."']+$/g, "");
let link = resolveTypeLink(aggData, word);
let matchStart;
if (!link) {
let match = matcher.nextWord(word.toLowerCase(), scanner.index);
if (match && match[0]) {
link = resolveTypeLink(aggData, match[0].value);
matchStart = match[0].startPos;
}
} else {
matchStart = scanner.index
}
if (link) {
let linkText = text.substring(matchStart, scanner.nextSeparator);
let linkNode = unist.makeLink(unist.makeText(linkText), link);
let prevText = text.substring(currTextStart, matchStart);
result.push(unist.makeText(prevText));
result.push(linkNode);
currTextStart = scanner.nextSeparator;
matcher.reset();
}
}
let remainingText = text.substring(currTextStart, text.length);
if (remainingText) {
result.push(unist.makeText(remainingText));
}
return result;
}
function resolveTypeLink(aggData, text): string {
let possTypeName = cleanTypeName(text);
let ref: Reflection = aggData.projData.findReflectionByName(possTypeName);
if (ref && isLinkable(ref.kind)) {
let kebabName = ngHelpers.kebabifyClassName(possTypeName);
let possDocFile = aggData.docFiles[kebabName];
let url = "../../lib/" + ref.sources[0].fileName;
if (possDocFile) {
url = "../" + possDocFile;
}
return url;
} else {
return "";
}
}
function cleanTypeName(text) {
let matches = text.match(/[a-zA-Z0-9_]+<([a-zA-Z0-9_]+)>/);
if (matches) {
return matches[1];
} else {
return text;
}
}
function isLinkable(kind: ReflectionKind) {
return (kind === ReflectionKind.Class) ||
(kind === ReflectionKind.Interface) ||
(kind === ReflectionKind.Enum);
}
function convertNodeToTypeLink(node, text, url) {
let linkDisplayText = unist.makeInlineCode(text);
node.type = "link";
node.url = url;
node.children = [linkDisplayText];
}

View File

@@ -0,0 +1,128 @@
var fs = require("fs");
var path = require("path");
var yaml = require("js-yaml");
var remark = require("remark");
var stringify = require("remark-stringify");
var zone = require("mdast-zone");
var frontMatter = require("remark-frontmatter");
var combyne = require("combyne");
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 docsFolderPath = path.resolve("docs");
var histFilePath = path.resolve(docsFolderPath, "versionIndex.md");
var histSectionName = "history";
var initialVersion = "v2.0.0";
var templateFolder = path.resolve("tools", "doc", "templates");
function initPhase(aggData) {
aggData.versions = { "v2.0.0":[] };
}
function readPhase(tree, pathname, aggData) {
var compName = pathname;
var angNameRegex = /([a-zA-Z0-9\-]+)\.((component)|(directive)|(model)|(pipe)|(service)|(widget))/;
if (!compName.match(angNameRegex))
return;
if (compName.match(/boilerplate/))
return;
if (tree.children[0].type == "yaml") {
var metadata = yaml.load(tree.children[0].value);
var version = metadata["Added"];
if (version) {
if (aggData.versions[version]) {
aggData.versions[version].push(compName);
} else {
aggData.versions[version] = [compName];
}
} else {
aggData.versions[initialVersion].push(compName);
}
} else {
aggData.versions[initialVersion].push(compName);
}
}
function aggPhase(aggData) {
var histFileText = fs.readFileSync(histFilePath, "utf8");
var histFileTree = remark().data("settings", {paddedTable: false, gfm: false}).parse(histFileText);
var keys = Object.keys(aggData.versions);
keys.sort((a, b) => {
if (a > b)
return -1;
else if (b > a)
return 1;
else
return 0;
});
var templateName = path.resolve(templateFolder, "versIndex.combyne");
var templateSource = fs.readFileSync(templateName, "utf8");
var template = combyne(templateSource);
for (var i = 0; i < keys.length; i++) {
var version = keys[i];
var versionItems = aggData.versions[version];
versionItems.sort((a, b) => {
var aa = path.basename(a, ".md");
var bb = path.basename(b, ".md");
return aa.localeCompare(bb);
});
var versionTemplateData = {items: []};
for (var v = 0; v < versionItems.length; v++) {
var displayName = ngHelpers.ngNameToDisplayName(path.basename(versionItems[v], ".md"));
var pageLink = versionItems[v];// + ".md";
pageLink = pageLink.replace(/\\/g, '/');
pageLink = pageLink.substr(pageLink.indexOf("docs") + 5);
versionTemplateData.items.push({
title: displayName,
link: pageLink
});
}
var mdText = template.render(versionTemplateData);
mdText = mdText.replace(/^ +-/mg, "-");
var newSection = remark().data("settings", {paddedTable: false, gfm: false}).parse(mdText.trim()).children;
var versSectionName = version.replace(/\./g, "");;
zone(histFileTree, versSectionName, (startComment, oldSection, endComment) => {
newSection.unshift(startComment);
newSection.push(endComment);
return newSection;
});
}
fs.writeFileSync(histFilePath, remark().use(frontMatter, {type: 'yaml', fence: '---'}).data("settings", {paddedTable: false, gfm: false}).stringify(histFileTree));
}
function updatePhase(tree, pathname, aggData) {
return false;
}

136
tools/doc/unistHelpers.js Normal file
View File

@@ -0,0 +1,136 @@
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
};
},
makeStrong: function (content) {
return {
"type": "strong",
"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
};
},
makeInlineCode: function (codeText) {
return {
"type": "inlineCode",
"value": codeText
}
},
makeHTML: function (htmlText) {
return {
"type": "html",
"value": htmlText
};
},
makeBreak: function () {
return {
"type": "break"
}
},
makeImage: function (url, alt) {
return {
"type": "image",
"url": url,
"alt": alt
}
},
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";
}
}

18
tools/schematics/adf/.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
# Outputs
src/**/*.js
src/**/*.js.map
src/**/*.d.ts
# IDEs
.idea/
jsconfig.json
.vscode/
# Misc
node_modules/
npm-debug.log*
yarn-error.log*
# Mac OSX Finder files.
**/.DS_Store
.DS_Store

View File

@@ -0,0 +1,3 @@
# Ignores TypeScript files, but keeps definitions.
*.ts
!*.d.ts

View File

@@ -0,0 +1,34 @@
# ADF doc generator schematic
**Caution:** Although this tool should not be able to do any harm, it is still at the
experimental stage. Check the results if you use it for anything "serious".
This [schematic](https://github.com/angular/devkit/tree/master/packages/angular_devkit/schematics)
works with [Angular CLI](https://cli.angular.io/) to make it easier to generate new
component doc files for ADF.
## Setup
The schematic uses Angular CLI, so you must first install this tool using the instructions
on their [GitHub page](https://github.com/angular/angular-cli), if you have not already done so.
To set up the schematic itself for use, `cd` into the root `alfresco-ng2-components` folder and type:
npm link tools\schematics\adf
## Usage
The schematic works with the `ng generate` command. The name of the schematic is `adf:docpage` and
it also requires the library name and filename as parameters. The general format is:
ng generate adf:docpage lib/comp-name.type.md
Here, `lib` is one of the ADF libraries (`content-services`, `core`, `process-services`
or `insights`). The `type` portion refers to the class type the doc page refers to
(component, service, model, etc). So,
ng generate adf:docpage core/arc-reactor.service.md
...will generate a page for the Arc Reactor service in the core library. Note that the name of the
doc file should match the name of the Typescript file where the class is defined
(arc-reactor.service.ts, in this case).

600
tools/schematics/adf/package-lock.json generated Normal file
View File

@@ -0,0 +1,600 @@
{
"name": "adf",
"version": "0.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@angular-devkit/core": {
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.5.9.tgz",
"integrity": "sha512-SH2/tvs9IGzfDDaUZ1uqLlNPTzaidPWdcT3AA3lYi4hS6ZU8zF1kGw+8Xa9CZR/3JhjMAxmNoqtIcTzt2WmlqQ==",
"requires": {
"ajv": "6.4.0",
"chokidar": "1.7.0",
"rxjs": "6.0.0",
"source-map": "0.5.7"
}
},
"@angular-devkit/schematics": {
"version": "0.5.9",
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.5.9.tgz",
"integrity": "sha512-4DSjQUFthXqoDlZ5+ml2UvxlP29fv08FeVRbkKgofNSqC3N4QiCn/8I2PksGzcdHAXTiBGmBcgXwGbDb5zTkqA==",
"requires": {
"@angular-devkit/core": "0.5.9",
"@ngtools/json-schema": "1.1.0",
"rxjs": "6.0.0"
}
},
"@ngtools/json-schema": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz",
"integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI="
},
"@types/jasmine": {
"version": "2.8.6",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.6.tgz",
"integrity": "sha512-clg9raJTY0EOo5pVZKX3ZlMjlYzVU73L71q5OV1jhE2Uezb7oF94jh4CvwrW6wInquQAdhOxJz5VDF2TLUGmmA=="
},
"@types/node": {
"version": "8.10.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.10.tgz",
"integrity": "sha512-p3W/hFzQs76RlYRIZsZc5a9bht6m0TspmWYYbKhRswmLnwj9fsE40EbuGifeu/XWR/c0UJQ1DDbvTxIsm/OOAA=="
},
"ajv": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.4.0.tgz",
"integrity": "sha1-06/3jpJ3VJdx2vAWTP9ISCt1T8Y=",
"requires": {
"fast-deep-equal": "1.1.0",
"fast-json-stable-stringify": "2.0.0",
"json-schema-traverse": "0.3.1",
"uri-js": "3.0.2"
}
},
"anymatch": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
"integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
"requires": {
"micromatch": "2.3.11",
"normalize-path": "2.1.1"
}
},
"arr-diff": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
"integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
"requires": {
"arr-flatten": "1.1.0"
}
},
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
"integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
},
"array-unique": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
"integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
},
"async-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
"integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"binary-extensions": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "1.0.0",
"concat-map": "0.0.1"
}
},
"braces": {
"version": "1.8.5",
"resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
"integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
"requires": {
"expand-range": "1.8.2",
"preserve": "0.2.0",
"repeat-element": "1.1.2"
}
},
"chokidar": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
"integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
"requires": {
"anymatch": "1.3.2",
"async-each": "1.0.1",
"glob-parent": "2.0.0",
"inherits": "2.0.3",
"is-binary-path": "1.0.1",
"is-glob": "2.0.1",
"path-is-absolute": "1.0.1",
"readdirp": "2.1.0"
}
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"ejs": {
"version": "2.5.9",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.9.tgz",
"integrity": "sha512-GJCAeDBKfREgkBtgrYSf9hQy9kTb3helv0zGdzqhM7iAkW8FA/ZF97VQDbwFiwIT8MQLLOe5VlPZOEvZAqtUAQ=="
},
"exit": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
"integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw="
},
"expand-brackets": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
"integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
"requires": {
"is-posix-bracket": "0.1.1"
}
},
"expand-range": {
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
"integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
"requires": {
"fill-range": "2.2.3"
}
},
"extglob": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
"integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
"requires": {
"is-extglob": "1.0.0"
}
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"filename-regex": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
"integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY="
},
"fill-range": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
"integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
"requires": {
"is-number": "2.1.0",
"isobject": "2.1.0",
"randomatic": "1.1.7",
"repeat-element": "1.1.2",
"repeat-string": "1.6.1"
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
},
"for-own": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
"integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
"requires": {
"for-in": "1.0.2"
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "1.0.0",
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
},
"glob-base": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
"integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
"requires": {
"glob-parent": "2.0.0",
"is-glob": "2.0.1"
}
},
"glob-parent": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
"integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
"requires": {
"is-glob": "2.0.1"
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "1.4.0",
"wrappy": "1.0.2"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
"requires": {
"binary-extensions": "1.11.0"
}
},
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
},
"is-dotfile": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
"integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="
},
"is-equal-shallow": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
"integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
"requires": {
"is-primitive": "2.0.0"
}
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
},
"is-extglob": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
"integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
},
"is-glob": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
"integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
"requires": {
"is-extglob": "1.0.0"
}
},
"is-number": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
"integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
"requires": {
"kind-of": "3.2.2"
}
},
"is-posix-bracket": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
"integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q="
},
"is-primitive": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
"integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isobject": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
"requires": {
"isarray": "1.0.0"
}
},
"jasmine": {
"version": "2.99.0",
"resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.99.0.tgz",
"integrity": "sha1-jKctEC5jm4Z8ZImFbg4YqceqQrc=",
"requires": {
"exit": "0.1.2",
"glob": "7.1.2",
"jasmine-core": "2.99.1"
}
},
"jasmine-core": {
"version": "2.99.1",
"resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz",
"integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"requires": {
"is-buffer": "1.1.6"
}
},
"micromatch": {
"version": "2.3.11",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
"integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
"requires": {
"arr-diff": "2.0.0",
"array-unique": "0.2.1",
"braces": "1.8.5",
"expand-brackets": "0.1.5",
"extglob": "0.3.2",
"filename-regex": "2.0.1",
"is-extglob": "1.0.0",
"is-glob": "2.0.1",
"kind-of": "3.2.2",
"normalize-path": "2.1.1",
"object.omit": "2.0.1",
"parse-glob": "3.0.4",
"regex-cache": "0.4.4"
}
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "1.1.11"
}
},
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
"requires": {
"remove-trailing-separator": "1.1.0"
}
},
"object.omit": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
"integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
"requires": {
"for-own": "0.1.5",
"is-extendable": "0.1.1"
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1.0.2"
}
},
"parse-glob": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
"integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
"requires": {
"glob-base": "0.3.0",
"is-dotfile": "1.0.3",
"is-extglob": "1.0.0",
"is-glob": "2.0.1"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"preserve": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"punycode": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz",
"integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0="
},
"randomatic": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
"integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
"requires": {
"is-number": "3.0.0",
"kind-of": "4.0.0"
},
"dependencies": {
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"requires": {
"kind-of": "3.2.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"requires": {
"is-buffer": "1.1.6"
}
}
}
},
"kind-of": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
"integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
"requires": {
"is-buffer": "1.1.6"
}
}
}
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"requires": {
"core-util-is": "1.0.2",
"inherits": "2.0.3",
"isarray": "1.0.0",
"process-nextick-args": "2.0.0",
"safe-buffer": "5.1.2",
"string_decoder": "1.1.1",
"util-deprecate": "1.0.2"
}
},
"readdirp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
"integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
"requires": {
"graceful-fs": "4.1.11",
"minimatch": "3.0.4",
"readable-stream": "2.3.6",
"set-immediate-shim": "1.0.1"
}
},
"regex-cache": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
"integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
"requires": {
"is-equal-shallow": "0.1.3"
}
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
},
"repeat-element": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
"integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
},
"repeat-string": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
},
"rxjs": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.0.0.tgz",
"integrity": "sha512-2MgLQr1zvks8+Kip4T6hcJdiBhV+SIvxguoWjhwtSpNPTp/5e09HJbgclCwR/nW0yWzhubM+6Q0prl8G5RuoBA==",
"requires": {
"tslib": "1.9.0"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"set-immediate-shim": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "5.1.2"
}
},
"tslib": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
"integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ=="
},
"typescript": {
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-2.8.3.tgz",
"integrity": "sha512-K7g15Bb6Ra4lKf7Iq2l/I5/En+hLIHmxWZGq3D4DIRNFxMNV6j2SHSvDOqs2tGd4UvD/fJvrwopzQXjLrT7Itw=="
},
"uri-js": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-3.0.2.tgz",
"integrity": "sha1-+QuFhQf4HepNz7s8TD2/orVX+qo=",
"requires": {
"punycode": "2.1.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
}
}
}

View File

@@ -0,0 +1,24 @@
{
"name": "adf",
"version": "0.0.0",
"description": "A blank schematics",
"scripts": {
"build": "tsc -p tsconfig.json",
"test": "npm run build && jasmine **/*_spec.js"
},
"keywords": [
"schematics"
],
"author": "",
"license": "MIT",
"schematics": "./src/collection.json",
"dependencies": {
"@angular-devkit/core": "^0.5.8",
"@angular-devkit/schematics": "^0.5.8",
"@types/jasmine": "^2.6.0",
"@types/node": "^8.0.31",
"ejs": "^2.5.9",
"jasmine": "^2.8.0",
"typescript": "^2.5.2"
}
}

View File

@@ -0,0 +1,2 @@
import { Rule } from '@angular-devkit/schematics';
export declare function docpage(options: any): Rule;

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular-devkit/schematics");
function docpage(options) {
let nameParts = options.name.match(/([a-zA-Z-0-9_\-]+)\.(component|directive|interface|model|pipe|service|widget)/);
if (!nameParts) {
throw new schematics_1.SchematicsException('Doc filename in wrong format. Must be "lib-name/file-name.type.md"');
}
let libFolder = options.path.match(/\/([a-zA-Z-0-9_\-]+)/)[1];
if (!libFolder.match(/content-services|core|process-services|insights/)) {
throw new schematics_1.SchematicsException(`Folder "${libFolder}" is not a valid ADF library (must be "content-services", "core", "process-services" or "insights".`);
}
let templateContext = {
"name": options.name,
"basename": nameParts[1],
"displayName": dekebabifyName(nameParts[1]),
"type": nameParts[2]
};
const templateSource = schematics_1.apply(schematics_1.url('./templates'), [
schematics_1.template(templateContext),
schematics_1.move("docs/" + libFolder)
]);
return schematics_1.chain([
schematics_1.mergeWith(templateSource)
]);
}
exports.docpage = docpage;
function dekebabifyName(name) {
var result = name.replace(/-/g, " ");
result = result.substr(0, 1).toUpperCase() + result.substr(1);
return result;
}
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;AAAA,2DAGoC;AAIpC,iBAAwB,OAAY;IAClC,IAAI,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;IAEpH,IAAI,CAAC,SAAS,EAAE;QACd,MAAM,IAAI,gCAAmB,CAAC,oEAAoE,CAAC,CAAC;KACrG;IAED,IAAI,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,CAAC;IAE9D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,iDAAiD,CAAC,EAAE;QACvE,MAAM,IAAI,gCAAmB,CAAC,WAAW,SAAS,qGAAqG,CAAC,CAAC;KAC1J;IAED,IAAI,eAAe,GAAG;QAClB,MAAM,EAAE,OAAO,CAAC,IAAI;QACpB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;QACxB,aAAa,EAAE,cAAc,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,EAAE,SAAS,CAAC,CAAC,CAAC;KACvB,CAAA;IAED,MAAM,cAAc,GAAG,kBAAK,CAAC,gBAAG,CAAC,aAAa,CAAC,EAAE;QAC/C,qBAAQ,CAAC,eAAe,CAAC;QACzB,iBAAI,CAAC,OAAO,GAAG,SAAS,CAAC;KAC1B,CAAC,CAAC;IAEH,OAAO,kBAAK,CAAC;QACX,sBAAS,CAAC,cAAc,CAAC;KAC1B,CAAC,CAAC;AAEL,CAAC;AA7BD,0BA6BC;AAGD,wBAAwB,IAAY;IAClC,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACrC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC9D,OAAO,MAAM,CAAC;AAChB,CAAC"}

View File

@@ -0,0 +1 @@
export {};

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const schematics_1 = require("@angular-devkit/schematics");
const testing_1 = require("@angular-devkit/schematics/testing");
const path = require("path");
const collectionPath = path.join(__dirname, '../collection.json');
describe('adf', () => {
it('works', () => {
const runner = new testing_1.SchematicTestRunner('schematics', collectionPath);
const tree = runner.runSchematic('adf', {}, schematics_1.Tree.empty());
expect(tree.files).toEqual([]);
});
});
//# sourceMappingURL=index_spec.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index_spec.js","sourceRoot":"","sources":["index_spec.ts"],"names":[],"mappings":";;AAAA,2DAAkD;AAClD,gEAAyE;AACzE,6BAA6B;AAG7B,MAAM,cAAc,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;AAGlE,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE;IACnB,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACf,MAAM,MAAM,GAAG,IAAI,6BAAmB,CAAC,YAAY,EAAE,cAAc,CAAC,CAAC;QACrE,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,EAAE,EAAE,iBAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAE1D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}

View File

@@ -0,0 +1,34 @@
---
Added: v2.4.0
Status: Active
---
# <%= displayName + " " + type %>
One-line description for the index page goes here.
![Screenshot if required](../docassets/images/<%= basename + "." + type %>.png)
## Basic usage
Typescript and/or HTML usage sample goes here. Delete this section if you
don't need it.
## Class members
Don't add anything here. Use "npm run docbuild" from the "lib"
folder to generate property and method tables from the JSDocs.
## Details
Main text goes here.
### Subsection
Use level 3 subsections within the Details section to introduce
topics.
## See also
- [Delete this section](link1.md)
- [if you don't need it](link2.md)

View File

@@ -0,0 +1,9 @@
{
"$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
"schematics": {
"docpage": {
"description": "Creates a new documentation file for an ADF component.",
"factory": "./adf/index#docpage"
}
}
}

View File

@@ -0,0 +1,34 @@
{
"compilerOptions": {
"baseUrl": "tsconfig",
"lib": [
"es2017",
"dom"
],
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"rootDir": "src/",
"skipDefaultLibCheck": true,
"skipLibCheck": true,
"sourceMap": true,
"strictNullChecks": true,
"target": "es6",
"types": [
"jasmine",
"node"
]
},
"include": [
"src/**/*"
],
"exclude": [
"src/*/files/**/*"
]
}