Skip to content

Commit

Permalink
Merge branch 'v2.x/staging' into v2.x/workflows-revert
Browse files Browse the repository at this point in the history
  • Loading branch information
jackjia-ibm authored Mar 8, 2022
2 parents eea7875 + 6a869b3 commit e92f580
Show file tree
Hide file tree
Showing 227 changed files with 4,758 additions and 4,510 deletions.
4 changes: 4 additions & 0 deletions .dependency/zwe_doc_generation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# ignore generated documentation
generated/*
# keep the folder but nothing else
!generated/.gitkeep
5 changes: 5 additions & 0 deletions .dependency/zwe_doc_generation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# ZWE CLI Documentation Generation

Run `node index.js` to generate documentation for the `zwe` cli in `md` format. The command [documentation files](../../bin/README.md#command-assistant-files) are used to generate documentation.

Generated documentation is added to the `generated/` folder. Files in this folder are not tracked in git.
38 changes: 38 additions & 0 deletions .dependency/zwe_doc_generation/doc-tree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright IBM Corporation 2021
*/
const path = require('path');
const fs = require('fs');
const { EXPERIMENTAL, HELP, EXAMPLES, EXCLUSIVE_PARAMETERS, PARAMETERS, ERRORS } = require('./dot-file-structure');

const documentationTypes = [EXPERIMENTAL, HELP, EXAMPLES, EXCLUSIVE_PARAMETERS, PARAMETERS, ERRORS];

function getDocumentationTree(commandDirectory) {
const documentationNode = { children: [], command: commandDirectory.command };
const objectsInDirectory = fs.readdirSync(commandDirectory.dir);

for (const file of objectsInDirectory) {
const objectPath = path.join(commandDirectory.dir, file);

if (fs.statSync(objectPath).isDirectory()) {
documentationNode.children.push(getDocumentationTree({ dir: objectPath, command: path.basename(objectPath) }));
} else {
const docFileType = documentationTypes.find((df) => df.fileName === file);
if (docFileType) {
documentationNode[docFileType.fileName] = objectPath;
}
}
}

return documentationNode;
}

module.exports = {
getDocumentationTree
};
97 changes: 97 additions & 0 deletions .dependency/zwe_doc_generation/dot-file-structure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright IBM Corporation 2021
*/

const DOT_FILE_TABLE_ENTRY_DELIMITER = '|';
const DOT_FILE_TABLE_ROW_DELIMITER = '\n';

const parameterTable = {
delimiter: '|',
orderedSegments: [
{
position: 1,
meaning: 'Full name',
transform: (content) => content ? `--${content.replace(/,/g, ',--')}` : '' // other full name options are comma delimited
},
{
position: 2,
meaning: 'Alias',
transform: (content) => content ? `-${content.replace(/,/g, ',-')}` : '' // other alias options are comma delimited
},
{
position: 3,
meaning: 'Type'
},
{
position: 4,
meaning: 'Required',
transform: (content) => content === 'required' ? 'yes' : 'no'
},
{
position: 5,
meaning: 'Reserved for future use',
ignore: true
},
{
position: 6,
meaning: 'Reserved for future use',
ignore: true
},
{
position: 7,
meaning: 'Help message'
}
]
}

const EXPERIMENTAL = {
inherit: true,
fileName: '.experimental',
meaning: 'WARNING: This command is for experimental purposes and may not fully function.'
};
const HELP = {
fileName: '.help',
};
const EXAMPLES = {
fileName: '.examples',
};
const EXCLUSIVE_PARAMETERS = {
fileName: '.exclusive-parameters',
table: parameterTable
};
const PARAMETERS = {
inherit: true,
fileName: '.parameters',
table: parameterTable
};
const ERRORS = {
inherit: true,
fileName: '.errors',
table: {
delimiter: '|',
orderedSegments: [
{
position: 1,
meaning: 'Error code',
},
{
position: 2,
meaning: 'Exit code',
},
{
position: 3,
meaning: 'Error message',
}
]
}
};

module.exports = {
EXPERIMENTAL, HELP, EXAMPLES, EXCLUSIVE_PARAMETERS, PARAMETERS, ERRORS, DOT_FILE_TABLE_ENTRY_DELIMITER, DOT_FILE_TABLE_ROW_DELIMITER
};
Empty file.
29 changes: 29 additions & 0 deletions .dependency/zwe_doc_generation/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright IBM Corporation 2021
*/
const fs = require('fs');
const path = require('path');
const { getDocumentationTree } = require('./doc-tree');
const { generateDocumentationForNode } = require('./md-content');

const generatedDocDirectory = path.join(__dirname, './generated')

const rootDocNode = getDocumentationTree({ dir: path.join(__dirname, '../../bin/commands'), command: 'zwe' });
writeMdFiles(rootDocNode);

function writeMdFiles(docNode, writtenParentNode = {}) {
const { mdContent, parts } = generateDocumentationForNode(docNode, writtenParentNode);
fs.writeFileSync(`${generatedDocDirectory}/${parts.fileName}.md`, mdContent);

if (docNode.children && docNode.children.length) {
for (const child of docNode.children) {
writeMdFiles(child, parts);
}
}
}
166 changes: 166 additions & 0 deletions .dependency/zwe_doc_generation/md-content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright IBM Corporation 2021
*/
const fs = require('fs');
const { EXPERIMENTAL, HELP, EXAMPLES, EXCLUSIVE_PARAMETERS, PARAMETERS, ERRORS, DOT_FILE_TABLE_ENTRY_DELIMITER, DOT_FILE_TABLE_ROW_DELIMITER } = require('./dot-file-structure');

const SEPARATOR = '\n\n';
const SECTION_HEADER_PREFIX = '## ';
const SUB_SECTION_HEADER_PREFIX = '#' + SECTION_HEADER_PREFIX;
const MD_TABLE_ROW_DELIMITER = '\n';
const MD_TABLE_ENTRY_DELIMITER = '|';

// order content will appear, with prefix/postfix as needed
const orderedDocumentationTypes = [
{ ...HELP, prefix: SECTION_HEADER_PREFIX + 'Description' + SEPARATOR },
{ ...EXPERIMENTAL },
{ ...EXAMPLES, prefix: SECTION_HEADER_PREFIX + 'Examples' + SEPARATOR },
{ ...EXCLUSIVE_PARAMETERS, prefix: SECTION_HEADER_PREFIX + 'Parameters only for this command' + SEPARATOR },
{ ...PARAMETERS, prefix: SECTION_HEADER_PREFIX + 'Parameters' + SEPARATOR },
{ ...ERRORS, prefix: SECTION_HEADER_PREFIX + 'Errors' + SEPARATOR }
];

function generateDocumentationForNode(curNode, assembledParentNode) {
const assembledDocNode = assembleDocumentationElementsForNode(curNode, assembledParentNode);
const { command, linkCommand, children, fileName } = assembledDocNode;

let mdContent = '# ' + command + SEPARATOR + linkCommand + SEPARATOR + '\t' + command;

if (children.length) {
mdContent += ' [sub-command [sub-command]...] [parameter [parameter]...]' + SEPARATOR;
mdContent += SECTION_HEADER_PREFIX + 'Sub-commands' + SEPARATOR + children.map(c => `* [${c.command}](./${getFileName(c.command, fileName)})`).join('\n');
} else {
mdContent += ' [parameter [parameter]...]';
}

for (const docType of orderedDocumentationTypes) {
let docContent = '';
if (hasDocType(assembledDocNode, docType)) {
docContent += createDocContent(assembledDocNode[docType.fileName].content, docType);
const parentDocContent = createDocContent(assembledDocNode[docType.fileName].parentContent, docType);
if (parentDocContent) {
docContent += SUB_SECTION_HEADER_PREFIX + 'Inherited from parent command' + SEPARATOR + parentDocContent;
}
}

if (docContent) {
mdContent += SEPARATOR;
if (docType.prefix) {
mdContent += docType.prefix;
}
mdContent += docContent;
if (docType.postfix) {
mdContent += docType.postfix;
}
}
}

return {
parts: assembledDocNode,
mdContent: mdContent
};
}

function assembleDocumentationElementsForNode(curNode, assembledParentNode) {
const fileName = getFileName(curNode.command, assembledParentNode.fileName);
const command = assembledParentNode.command ? assembledParentNode.command + ' ' + curNode.command : curNode.command;
const link = `[${curNode.command}](./${fileName})`;
const linkCommand = assembledParentNode.linkCommand ? `${assembledParentNode.linkCommand} > ${link}` : link;

const docElements = {
fileName,
command,
linkCommand,
children: curNode.children,
};

for (const docType of orderedDocumentationTypes) {
const docForType = { content: '', parentContent: '' };

if (hasDocType(curNode, docType)) {
if (docType.meaning) {
docForType.content = docType.meaning;
} else {
const docFileContent = fs.readFileSync(curNode[docType.fileName], 'utf-8');
if (docType.table) {
// filter out ignored table entries
docForType.content = docFileContent.split(/$/gm).map(line =>
line
.trim()
.split(docType.table.delimiter)
.filter((_, index) => !docType.table.orderedSegments[index] || !docType.table.orderedSegments[index].ignore)
.join(DOT_FILE_TABLE_ENTRY_DELIMITER)
)
.join(DOT_FILE_TABLE_ROW_DELIMITER);
} else {
docForType.content = docFileContent;
}
}
}

if (hasDocType(assembledParentNode, docType) && docType.inherit) {
let parentContent = '';
if (assembledParentNode[docType.fileName].content) {
parentContent += assembledParentNode[docType.fileName].content;
}
if (assembledParentNode[docType.fileName].parentContent) {
parentContent += assembledParentNode[docType.fileName].parentContent;
}
docForType.parentContent = parentContent;
}

docElements[docType.fileName] = docForType;
}

return docElements
}

function createDocContent(rawContent, docType) {
let docContent = '';
if (rawContent) {
if (docType.table) {
docContent += createMdTable(rawContent, docType.table);
} else {
docContent += rawContent;
}
}
return docContent;
}

function createMdTable(rawContent, docFileTableSyntax) {
const filteredSegments = docFileTableSyntax.orderedSegments.filter(o => !o.ignore);

let docContent = '';
docContent += filteredSegments.map(o => o.meaning).join(MD_TABLE_ENTRY_DELIMITER) + MD_TABLE_ROW_DELIMITER; // Set table headings
docContent += filteredSegments.map(_ => '|---').join('') + MD_TABLE_ROW_DELIMITER; // Set table separator between headings and fields

docContent += rawContent.split(DOT_FILE_TABLE_ROW_DELIMITER).map(line => line.trim().split(DOT_FILE_TABLE_ENTRY_DELIMITER) // transform table entries
.map((segment, index) => {
if (docFileTableSyntax.orderedSegments[index] && docFileTableSyntax.orderedSegments[index].transform) {
return docFileTableSyntax.orderedSegments[index].transform(segment);
}
return segment;
})
.join(MD_TABLE_ENTRY_DELIMITER)) // join fields in a row
.join(MD_TABLE_ROW_DELIMITER); // join rows with newline

return docContent;
}

function getFileName(command, parentFileName) {
return parentFileName ? `${parentFileName}-${command}` : command;
}

function hasDocType(docNode, type) {
return docNode[type.fileName] !== null & docNode[type.fileName] !== undefined;
}

module.exports = {
generateDocumentationForNode
};
Loading

0 comments on commit e92f580

Please sign in to comment.