Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docs: add '..auto generated..' to .html documentation files #3420

Merged
Changes from 16 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
0c85e8e
eslint (mostly use double quotes)
weedySeaDragon Sep 6, 2022
703b7eb
rename vars so intent is clearer, add doc, use constants
weedySeaDragon Sep 6, 2022
d38f0e9
adjust console log message if only verifying, if copied actually happ…
weedySeaDragon Sep 6, 2022
6554a41
transform HTML (insert comment); add console msgs and clarify; add fi…
weedySeaDragon Sep 6, 2022
0832b24
use single quotes; use const instead of let (2); use const instead of…
weedySeaDragon Sep 6, 2022
b534a5c
Merge remote-tracking branch 'MERMAID/develop' into docs/3418_auto_ge…
weedySeaDragon Sep 7, 2022
1a0fe0a
(comments only) reword main docblock; clarify other comments; grammar…
weedySeaDragon Sep 7, 2022
a878edf
add and use constants; DRY glob patterns in main
weedySeaDragon Sep 7, 2022
411d641
simplfy method to copy transformation to /docs; extract logging
weedySeaDragon Sep 7, 2022
c6ce5a8
fix: pass in doCopy param
weedySeaDragon Sep 7, 2022
d007435
fix: cannot use __dirname with .mts and latest Node
weedySeaDragon Sep 7, 2022
73abcd8
fix: also check other files
weedySeaDragon Sep 7, 2022
7fe8f26
minor cleanup, clarify var names, add @todos
weedySeaDragon Sep 7, 2022
d18624b
change references from /docs to /src/docs; rework doc section in CONT…
weedySeaDragon Sep 5, 2022
be28160
unmangle sentence about doc changes committed and showing up on docsi…
weedySeaDragon Sep 6, 2022
e690da6
(formatting) prettier fix
weedySeaDragon Sep 7, 2022
5f81e3d
chore: Run postbuild with prepare
sidharthv96 Sep 7, 2022
a800cb6
Update prettier
sidharthv96 Sep 7, 2022
48b0076
Merge remote-tracking branch 'MERMAID/develop' into docs/3418_auto_ge…
weedySeaDragon Sep 7, 2022
6376c9a
switch order of params so the last one can be omitted
weedySeaDragon Sep 7, 2022
fd567f8
(minor) clarify var names (file -> filename); comments
weedySeaDragon Sep 7, 2022
9acf63f
(formatting only) sort imports just to force a new CI lint check
weedySeaDragon Sep 8, 2022
2826bf6
fix: Formatting issue
sidharthv96 Sep 8, 2022
b0559df
chore: Updated doc files
sidharthv96 Sep 8, 2022
f8eaccb
fix: Run precommit hook for doc.mts changes too
sidharthv96 Sep 8, 2022
8ca91d6
add eslint-disable no-console for file
weedySeaDragon Sep 10, 2022
ad56a22
Merge remote-tracking branch 'MERMAID/develop' into docs/3418_auto_ge…
weedySeaDragon Sep 10, 2022
6ad9208
eslint fixes
weedySeaDragon Sep 11, 2022
9cc7da0
formatting
weedySeaDragon Sep 11, 2022
7f56112
change wording of console log message (use comma)
weedySeaDragon Sep 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 113 additions & 72 deletions src/docs.mts
Original file line number Diff line number Diff line change
@@ -1,24 +1,35 @@
/**
* @overview Process and potentially transform documentation source files into files suitable for publishing.
* Copy files from the source directory (/src/docs) to the directory used for the final, published documentation (/docs).
* The list of files changed (transformed) and copied to /docs are logged to the console.
* If a file in /src/docs has the same contents in /docs, nothing is done (it is not copied to /docs).
* @file Transform documentation source files into files suitable for publishing and optionally copy the transformed files from the source directory
* to the directory used for the final, published documentation directory. The list of files transformed and copied to final documentation directory
* are logged to the console. If a file in the source directory has the same contents in the final directory, nothing is done (the final directory
* is up-to-date).
* @example
* docs
* Run with no option flags
*
* @example docs
* @example docs --verify
* If the --verify option is used, no files will be copied to /docs, but the list of files to be changed is still shown on the console.
* A message to the console will show that this command should be run without the --verify flag so that the 'docs' folder is be updated.
* Note that the command will return an exit code (1), which will show that it failed.
* @example docs --git
* If the --git option is used, the command `git add docs` will be run
* @example
* docs --verify
* If the --verify option is used, it only _verifies_ that the final directory has been updated with the transformed files in the source directory.
* No files will be copied to the final documentation directory, but the list of files to be changed is shown on the console.
* If the final documentation directory does not have the transformed files from source directory
* - a message to the console will show that this command should be run without the --verify flag so that the final directory is updated, and
* - it will return a fail exit code (1)
*
* @example
* docs --git
* If the --git option is used, the command `git add docs` will be run after all transformations (and/or verifications) have completed successfully
* If not files were transformed, the git command is not run.
*
* @todo Ensure that the documentation source and final paths are correct by using process.cwd() to get their absolute paths. Ensures that the
* location of those 2 directories is not dependent on where this file resides.
*
* @todo Write a test file for this. (Will need to be able to deal .mts file. Jest has trouble with it.)
*/

import { remark } from 'remark';
import type { Code, Root } from 'mdast';
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
import { JSDOM } from 'jsdom';

// @ts-ignore
import flatmap from 'unist-util-flatmap';
import { globby } from 'globby';
Expand All @@ -27,70 +38,92 @@ import { exec } from 'child_process';
// @ts-ignore
import prettier from 'prettier';

const SOURCE_DOCS_DIR = 'src/docs/';
const FINAL_DOCS_DIR = 'docs/';
const AUTOGENERATED_TEXT =
'# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in src/docs.';
const SOURCE_DOCS_DIR = 'src/docs';
const FINAL_DOCS_DIR = 'docs';

const AUTOGENERATED_TEXT = `# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT. Please edit the corresponding file in ${SOURCE_DOCS_DIR}.`;

const LOGMSG_TRANSFORMED = 'transformed';
const LOGMSG_TO_BE_TRANSFORMED = 'to be transformed';
const LOGMSG_COPIED = ` ...and copied to ${FINAL_DOCS_DIR}`;
weedySeaDragon marked this conversation as resolved.
Show resolved Hide resolved

const WARN_DOCSDIR_DOESNT_MATCH = `Changed files were transformed in ${SOURCE_DOCS_DIR} but do not match the files in ${FINAL_DOCS_DIR}. Please run yarn docs:build after making changes to ${SOURCE_DOCS_DIR} to update the ${FINAL_DOCS_DIR} directory with the transformed files.`;

const verifyOnly = process.argv.includes('--verify');
const git = process.argv.includes('--git');
const verifyOnly: boolean = process.argv.includes('--verify');
const git: boolean = process.argv.includes('--git');

let filesWereChanged = false;
let filesWereTransformed = false;

/**
* Given a source file name and path, return the documentation destination full path and file name
* Create the destination path if it does not already exist.
* Possible Improvement: combine with lint-staged to only copy files that have changed
* Given a source file name and path, return the documentation destination full path and file name Create the destination path if it does not already exist.
*
* @param file {string} name of the file (including full path)
* @returns {string} name of the file with the path changed from src/docs to docs
* @param {string} file - Name of the file (including full path)
* @returns {string} Name of the file with the path changed from the source directory to final documentation directory
* @todo Possible Improvement: combine with lint-staged to only copy files that have changed
*/
const prepareOutFile = (file: string): string => {
const outFile = join(FINAL_DOCS_DIR, file.replace(SOURCE_DOCS_DIR, ''));
mkdirSync(dirname(outFile), { recursive: true });
return outFile;
const changeToFinalDocDir = (file: string): string => {
const newDir = file.replace(SOURCE_DOCS_DIR, FINAL_DOCS_DIR);
mkdirSync(dirname(newDir), { recursive: true });
return newDir;
};

/**
* Verify that a file was changed and (potentially) write the new contents out to the file. Log a message to the console
* If the file was not changed, do nothing. (No message is logged to the console.)
* Log messages to the console showing if the transformed file copied to the final documentation directory or still needs to be copied.
*
* @param file {string} name of the file that will be verified
* @param content {string} new contents for the file
* @param {string} filename Name of the file that was transformed
* @param {boolean} wasCopied Whether or not the file was copied
*/
const verifyAndCopy = (file: string, content?: string) => {
const outFile = prepareOutFile(file);
const existingBuffer = existsSync(outFile) ? readFileSync(outFile) : Buffer.from('#NEW FILE#');
const newBuffer = content ? Buffer.from(content) : readFileSync(file);
if (existingBuffer.equals(newBuffer)) {
// Files are same, skip.
return;
const logWasOrShouldBeTransformed = (filename: string, wasCopied: boolean) => {
let changeMsg: string;
let logMsg: string;
changeMsg = wasCopied ? LOGMSG_TRANSFORMED : LOGMSG_TO_BE_TRANSFORMED;
logMsg = ` File ${changeMsg}: ${filename}`;
sidharthv96 marked this conversation as resolved.
Show resolved Hide resolved
if (wasCopied) {
logMsg += LOGMSG_COPIED;
}
let changeMsg = 'changed';
if (verifyOnly) {
changeMsg = 'to be changed';
console.log(logMsg);
};

/**
* If the file contents were transformed, set the _filesWereTransformed_ flag to true and copy the transformed contents to the final documentation
* directory if the doCopy flag is true. Log messages to the console.
*
* @param {string} filename Name of the file that will be verified
* @param {string} [transformedContent] New contents for the file
* @param {boolean} [doCopy=false] Whether we should copy that transformedContents to the final documentation directory. Default is `false`
*/
const copyTransformedContents = (
filename: string,
doCopy: boolean = false,
transformedContent?: string
) => {
const fileInFinalDocDir = changeToFinalDocDir(filename);
const existingBuffer = existsSync(fileInFinalDocDir)
? readFileSync(fileInFinalDocDir)
: Buffer.from('#NEW FILE#');
const newBuffer = transformedContent ? Buffer.from(transformedContent) : readFileSync(filename);
if (existingBuffer.equals(newBuffer)) {
return; // Files are same, skip.
}
let logMsg = ` File ${changeMsg}: ${outFile}`;

filesWereChanged = true;
if (!verifyOnly) {
writeFileSync(outFile, newBuffer);
logMsg += ' ...and copied to /docs';
filesWereTransformed = true;
if (doCopy) {
writeFileSync(fileInFinalDocDir, newBuffer);
}
console.log(logMsg);
logWasOrShouldBeTransformed(fileInFinalDocDir, doCopy);
};

const readSyncedUTF8file = (file: string): string => {
return readFileSync(file, 'utf8');
const readSyncedUTF8file = (filename: string): string => {
return readFileSync(filename, 'utf8');
};

/**
* Transform a markdown file and write the transformed file to the directory for published documentation
* 1. add a `mermaid-example` block before every `mermaid` or `mmd` block
* On the docsify site (one place where the documentation is published), this will show the code used for the mermaid diagram
* 2. add the text that says the file is automatically generated
* 3. use prettier to format the file
* Verify that the file has been changed and write out the changes
*
* 1. Add a `mermaid-example` block before every `mermaid` or `mmd` block On the docsify site (one place where the documentation is published), this will
* show the code used for the mermaid diagram
* 2. Add the text that says the file is automatically generated
* 3. Use prettier to format the file Verify that the file has been changed and write out the changes
*
* @param file {string} name of the file that will be verified
*/
Expand All @@ -110,8 +143,9 @@ const transformMarkdown = (file: string) => {
// Add the AUTOGENERATED_TEXT to the start of the file
const transformed = `${AUTOGENERATED_TEXT}\n${remark.stringify(out)}`;

verifyAndCopy(
copyTransformedContents(
file,
!verifyOnly,
prettier.format(transformed, {
parser: 'markdown',
useTabs: false,
Expand All @@ -124,9 +158,9 @@ const transformMarkdown = (file: string) => {
};

/**
* Transform a HTML file and write the transformed file to the directory for published documentation
* - add the text that says the file is automatically generated
* Verify that the file has been changed and write out the changes
* Transform an HTML file and write the transformed file to the directory for published documentation
*
* - Add the text that says the file is automatically generated Verify that the file has been changed and write out the changes
*
* @param filename {string} name of the HTML file to transform
*/
Expand All @@ -135,7 +169,7 @@ const transformHtml = (filename: string) => {
* Insert the '...auto generated...' comment into an HTML file after the <html> element
*
* @param fileName {string} file name that should have the comment inserted
* @returns {string} the contents of the file with the comment inserted
* @returns {string} The contents of the file with the comment inserted
*/
const insertAutoGeneratedComment = (fileName: string): string => {
const fileContents = readSyncedUTF8file(fileName);
Expand All @@ -146,35 +180,42 @@ const transformHtml = (filename: string) => {
const rootElement = htmlDoc.documentElement;
rootElement.prepend(autoGeneratedComment);
return jsdom.serialize();
}
};

const transformedHTML = insertAutoGeneratedComment(filename);
verifyAndCopy(filename, transformedHTML);
copyTransformedContents(filename, !verifyOnly, transformedHTML);
};

/** Main method (entry point) */
(async () => {
const sourceDirGlob = join('.', SOURCE_DOCS_DIR, '**');
const includeFilesStartingWithDot = true;

console.log('Transforming markdown files...');
const mdFiles = await globby(['./src/docs/**/*.md'], { dot: true });
const mdFiles = await globby([join(sourceDirGlob, '*.md')], { dot: includeFilesStartingWithDot });
mdFiles.forEach(transformMarkdown);

console.log('Transforming html files...');
const htmlFiles = await globby(['./src/docs/**/*.html'], { dot: true });
const htmlFiles = await globby([join(sourceDirGlob, '*.html')], {
dot: includeFilesStartingWithDot,
});
htmlFiles.forEach(transformHtml);

console.log('Transforming all other files...');
const otherFiles = await globby(['src/docs/**', '!**/*.md', '!**/*.html'], { dot: true });
otherFiles.forEach((file) => {
verifyAndCopy(file);
const otherFiles = await globby([sourceDirGlob, '!**/*.md', '!**/*.html'], {
dot: includeFilesStartingWithDot,
});
if (filesWereChanged) {
otherFiles.forEach((file: string) => {
copyTransformedContents(file, !verifyOnly); // no transformation
});

if (filesWereTransformed) {
if (verifyOnly) {
console.log(
"Changes detected in files in `src/docs`. Please run `yarn docs:build` after making changes to 'src/docs' to update the `docs` folder."
);
console.log(WARN_DOCSDIR_DOESNT_MATCH);
process.exit(1);
}
if (git) {
console.log('Adding changes in docs folder to git');
console.log('Adding changes in ${FINAL_DOCS_DIR} folder to git');
exec('git add docs');
}
}
Expand Down