Skip to content

Commit

Permalink
fix: remove comments from variable type markdown (microsoft#5932)
Browse files Browse the repository at this point in the history
* Remove comment blocks from variable types

* Change files

* PR feedback

* More PR feedback

* More regular expressions

* Another PR comment

Co-authored-by: Chris Holt <chhol@microsoft.com>
  • Loading branch information
williamw2 and chrisdholt authored May 5, 2022
1 parent fbc6a7f commit 00f9a95
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 140 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "none",
"comment": "Removed comment blocks from variable type markdown in README files",
"packageName": "@microsoft/fast-foundation",
"email": "44823142+williamw2@users.noreply.github.com",
"dependentChangeType": "none"
}
199 changes: 97 additions & 102 deletions packages/web-components/fast-foundation/CEMToMarkdown.mjs
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
import fs from 'fs';
import { customElementsManifestToMarkdown } from '@custom-elements-manifest/to-markdown';
import {default as os} from 'os';
import fs from "fs";
import { default as os } from "os";
import { customElementsManifestToMarkdown } from "@custom-elements-manifest/to-markdown";

// new line and double new line shorthands
const LF = os.EOL;
const LF2 = LF + LF;

// Read the custom-elements.json file and parse the JSON
const fullManifest = JSON.parse(fs.readFileSync('dist/custom-elements.json', 'utf-8'));
const fullManifest = JSON.parse(fs.readFileSync("dist/custom-elements.json", "utf-8"));

// Filter out template modules and ensure that they are in alphabetical order
const modules = fullManifest.modules
.filter(module => module.path.indexOf("template.ts") === -1)
.sort((a,b) => getComponentNameFromPath(a.path).localeCompare(getComponentNameFromPath(b.path)));
.sort((a, b) =>
getComponentNameFromPath(a.path).localeCompare(getComponentNameFromPath(b.path))
);

// Loop through the manifest grouping modules from the same folder in order to produce one markdown file per component.
for(var i = 0, modulesLength = modules.length; i < modulesLength; i++)
{
for (var i = 0, modulesLength = modules.length; i < modulesLength; i++) {
// We only care about javascript-modules.
if(modules[i].kind === "javascript-module")
{
if (modules[i].kind === "javascript-module") {
// Create a new manifest object just for this component.
let componentManifest = {};
componentManifest.schemaVersion = fullManifest.schemaVersion;
Expand All @@ -35,74 +35,76 @@ for(var i = 0, modulesLength = modules.length; i < modulesLength; i++)
// Continue looping through the main manifest, adding modules to the small manifest until we find a module with a different name.
// Include modules with names like "component-item" so components like Accordion and Accordion-item are included in the same file.
// Include modules with names like "component-label" so components like Slider and Slider-label are included in the same file.
while(i < modules.length-1 &&
(
currName === getComponentNameFromPath(modules[i + 1].path) ||
while (
i < modules.length - 1 &&
(currName === getComponentNameFromPath(modules[i + 1].path) ||
currName + "-item" === getComponentNameFromPath(modules[i + 1].path) ||
currName + "-label" === getComponentNameFromPath(modules[i + 1].path)
)
)
{
currName + "-label" === getComponentNameFromPath(modules[i + 1].path))
) {
componentManifest.modules.push(modules[i + 1]);
i++;
}

// Special logic for the "tab" components.
// If the current module is "tabs" include the previous two modules which should be "tab" and "tab-panel".
if(currName === "tabs")
{
if (currName === "tabs") {
componentManifest.modules.push(modules[i - 1]);
componentManifest.modules.push(modules[i - 2]);
}

// enclose html tags in `` to prevent tags in comments from confusing docusaurus
// and remove new line characters from descriptions
componentManifest.modules.forEach(module=>{
module.declarations?.forEach(dec=>{
if(dec.description)
{
dec.description = replaceJSDOCLinksWithMDLinks(fixTagsInText(dec.description.replaceAll(LF, ' ')));
componentManifest.modules.forEach(module => {
module.declarations?.forEach(dec => {
if (dec.description) {
dec.description = replaceJSDOCLinksWithMDLinks(
fixTagsInText(dec.description.replaceAll(LF, " "))
);
}
if(dec.default)
{
dec.default = replaceJSDOCLinksWithMDLinks(fixTagsInText(dec.default.replaceAll(LF, ' ')));
if (dec.default) {
dec.default = replaceJSDOCLinksWithMDLinks(
fixTagsInText(dec.default.replaceAll(LF, " "))
);
}
if(dec.type)
{
dec.type.text = replaceJSDOCLinksWithMDLinks(fixTagsInText(dec.type.text.replaceAll(LF, ' ')));
if (dec.type) {
dec.type.text = cleanUpVariableTypes(dec.type.text);
}
dec.members?.forEach(member=>{
if(member.description)
{
member.description = replaceJSDOCLinksWithMDLinks(fixTagsInText(member.description.replaceAll(LF, ' ')));
dec.members?.forEach(member => {
if (member.description) {
member.description = replaceJSDOCLinksWithMDLinks(
fixTagsInText(member.description.replaceAll(LF, " "))
);
}
if(member.default)
{
member.default = replaceJSDOCLinksWithMDLinks(fixTagsInText(member.default.replaceAll(LF, ' ')));
if (member.default) {
member.default = replaceJSDOCLinksWithMDLinks(
fixTagsInText(member.default.replaceAll(LF, " "))
);
}
if(member.return?.type?.text)
{
if (member.return?.type?.text) {
// these are already rendered inside of back-ticks so we only need to remove new lines
member.return.type.text = member.return.type.text.replaceAll(LF, ' ');
member.return.type.text = member.return.type.text.replaceAll(
LF,
" "
);
}
});
dec.attributes?.forEach(attr=>{
if(attr.description)
{
attr.description = replaceJSDOCLinksWithMDLinks(fixTagsInText(attr.description.replaceAll(LF, ' ')));
dec.attributes?.forEach(attr => {
if (attr.description) {
attr.description = replaceJSDOCLinksWithMDLinks(
fixTagsInText(attr.description.replaceAll(LF, " "))
);
}
});
})
});
});

// Convert the single component manifest into a markdown string.
let markdown = customElementsManifestToMarkdown(componentManifest,
{
headingOffset: 1,
private: 'hidden',
omitDeclarations: ['exports'],
omitSections: ['static-methods']
});
let markdown = customElementsManifestToMarkdown(componentManifest, {
headingOffset: 1,
private: "hidden",
omitDeclarations: ["exports"],
omitSections: ["static-methods"],
});

// Replace our < and > markers with backticks and < >
// This is necessary because customElementsManifestToMarkdown escapes the backticks during the conversion
Expand All @@ -122,18 +124,17 @@ for(var i = 0, modulesLength = modules.length; i < modulesLength; i++)
markdown = markdown.replaceAll("\\(", "(");

// Replace \| with 'or'
markdown = markdown.replaceAll("\\|","or");
markdown = markdown.replaceAll("\\|", "or");

// Get the README.md file
let path = modules[componentIndex].path.split('/');
let path = modules[componentIndex].path.split("/");
path[path.length - 1] = "README.md";
path = path.join('/');
path = path.join("/");

// If a README.md file exists
if(fs.existsSync(path))
{
if (fs.existsSync(path)) {
// Read the contents of the file
let readMe = fs.readFileSync(path, 'utf-8');
let readMe = fs.readFileSync(path, "utf-8");

// Find the location of the "## API" section
let apiLoc = readMe.indexOf("## API");
Expand All @@ -143,80 +144,74 @@ for(var i = 0, modulesLength = modules.length; i < modulesLength; i++)

// If the API section does not exist then create it either just
// above the Additional Resources section or at the end of the file.
if(apiLoc === -1)
{
if (apiLoc === -1) {
// no API section yet so add it
if(resourcesLoc > 0)
{
if (resourcesLoc > 0) {
// add API section above Additional Resources
readMe = readMe.replace("## Additional resources","## API" + LF2 + "## Additional resources");
}
else
{
readMe = readMe.replace(
"## Additional resources",
"## API" + LF2 + "## Additional resources"
);
} else {
// add API to the end
readMe += LF2 + "## API";
}

// Get the updated locations
apiLoc = readMe.indexOf("## API");
resourcesLoc = readMe.indexOf("## Additional resources")
resourcesLoc = readMe.indexOf("## Additional resources");
}

// customElementsManifestToMarkdown() hard codes line endings as '/n'. This causes GIT to detect changes
// to the file on windows environments even if nothing but the line endings change. If the os.EOL is '\r\n'
// then replace all '\n' in the markdown with '\r\n'.
if(LF === '\r\n')
{
markdown = markdown.replaceAll('\n', '\r\n');
if (LF === "\r\n") {
markdown = markdown.replaceAll("\n", "\r\n");
}

// Replace everything in between the API and Additional Resources sections with the
// updated markdown.
const startIndex = apiLoc;
const endIndex = resourcesLoc >=0 ? resourcesLoc : readMe.length;
readMe = readMe.replace(readMe.slice(startIndex, endIndex), "## API" + LF2 + markdown + LF2);
const endIndex = resourcesLoc >= 0 ? resourcesLoc : readMe.length;
readMe = readMe.replace(
readMe.slice(startIndex, endIndex),
"## API" + LF2 + markdown + LF2
);

// Replace the README.md file with the new content.
fs.writeFileSync(path, readMe);
}

}
}

function getComponentNameFromPath(path)
{
return path.split('/')[1];
function getComponentNameFromPath(path) {
return path.split("/")[1];
}

function fixTagsInText(text)
{
function fixTagsInText(text) {
// replace < and > characters in text with something that can be easily replaced later.
return text.replaceAll(/\<.*\>/gi,(match)=>{
return match.replace('<','REPLACELT').replace('>','REPLACEGT');
return text.replaceAll(/<.*>/gi, match => {
return match.replace("<", "REPLACELT").replace(">", "REPLACEGT");
});
}

function replaceJSDOCLinksWithMDLinks(text)
{
let startIndex = text.indexOf('{@link');
if(startIndex < 0) return text;

while(startIndex>=0)
{
let endIndex = text.indexOf("}", startIndex);
if(endIndex < 0) return text;

const jsdocLink = text.slice(startIndex, endIndex + 1);
let linkParts = jsdocLink.replace("{@link ", "").replace("}", "").split('|');
if(linkParts.length === 1)
{
text = text.replace(jsdocLink, linkParts[0]);
}
else
{
text = text.replace(jsdocLink, "[" + linkParts[1].trim() + "](" + linkParts[0].trim() + ")");
}
startIndex = text.indexOf('{@link',endIndex);
}
return text;
function replaceJSDOCLinksWithMDLinks(text) {
// Replace jsdoc links with markdown links
// [TEXT]{@link URL} => [TEXT](URL)
// {@link URL} => URL
// {@link URL TEXT} => [TEXT](URL)
// {@link URL | TEXT} => [TEXT](URL)
return text
.replace(/\[(.*)\]\{@link (\S*)\}/gm, "[$1]($2)")
.replace(/\{@link (\S*)\}/gm, "$1")
.replace(/\{@link (\S*)\s*\|?\s*([^}]+?)\s*\}/gm, "[$2]($1)");
}

function cleanUpVariableTypes(text) {
// Remove block comments
text = text.replace(/\/\*(.|\s)*?\*\//gm, "");
// Remove inline comments, line breaks, and extra spaces
return text
.replace(/\/\/.*$/gm, "")
.replace(/\s+/gm, " ");
}
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,9 @@ export const myAccordionItem = AccordionItem.compose<AccordionItemOptions>({

### Variables

| Name | Description | Type |
| --------------------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AccordionExpandMode` | Expand mode for Accordion | `{ /** * Designates only a single @microsoft/fast-foundation#(AccordionItem:class) can be open a time. */ single: "single", /** * Designates multiple [AccordionItems](@microsoft/fast-foundation#(AccordionItem:class)) can be open simultaneously. */ multi: "multi", }` |
| Name | Description | Type |
| --------------------- | ------------------------- | --------------------------------------- |
| `AccordionExpandMode` | Expand mode for Accordion | `{ single: "single", multi: "multi", }` |

<hr/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,9 @@ See [listbox-option](/docs/components/listbox-option) for more information.

### Variables

| Name | Description | Type |
| ---------------------- | --------------------------------- | --------------------------------------------------------------------------------- |
| `ComboboxAutocomplete` | Autocomplete values for combobox. | `{ inline: "inline", list: "list", both: "both", none: "none", }` |
| Name | Description | Type |
| ---------------------- | --------------------------------- | ----------------------------------------------------------------- |
| `ComboboxAutocomplete` | Autocomplete values for combobox. | `{ inline: "inline", list: "list", both: "both", none: "none", }` |

<hr/>

Expand Down
10 changes: 5 additions & 5 deletions packages/web-components/fast-foundation/src/data-grid/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,11 +207,11 @@ export const myDataGrid = DataGrid.compose({

### Variables

| Name | Description | Type |
| ----------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| `GenerateHeaderOptions` | Enumerates the data grid auto generated header options default option generates a non-sticky header row | `{ none: "none", default: "default", sticky: "sticky", }` |
| `DataGridCellTypes` | Enumerates possible data grid cell types. | `{ default: "default", columnHeader: "columnheader", rowHeader: "rowheader", }` |
| `DataGridRowTypes` | Enumerates possible data grid row types | `{ default: "default", header: "header", stickyHeader: "sticky-header", }` |
| Name | Description | Type |
| ----------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `GenerateHeaderOptions` | Enumerates the data grid auto generated header options default option generates a non-sticky header row | `{ none: "none", default: "default", sticky: "sticky", }` |
| `DataGridCellTypes` | Enumerates possible data grid cell types. | `{ default: "default", columnHeader: "columnheader", rowHeader: "rowheader", }` |
| `DataGridRowTypes` | Enumerates possible data grid row types | `{ default: "default", header: "header", stickyHeader: "sticky-header", }` |

<hr/>

Expand Down
6 changes: 3 additions & 3 deletions packages/web-components/fast-foundation/src/divider/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ export const myDivider = Divider.compose({

### Variables

| Name | Description | Type |
| ------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `DividerRole` | Divider roles | `{ /** * The divider semantically separates content */ separator: "separator", /** * The divider has no semantic value and is for visual presentation only. */ presentation: "presentation", }` |
| Name | Description | Type |
| ------------- | ------------- | ----------------------------------------------------------- |
| `DividerRole` | Divider roles | `{ separator: "separator", presentation: "presentation", }` |

<hr/>

Expand Down
6 changes: 3 additions & 3 deletions packages/web-components/fast-foundation/src/flipper/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ export const myFlipper = Flipper.compose<FlipperOptions>({

### Variables

| Name | Description | Type |
| ------------------ | ---------------------------------- | ------------------------------------------------- |
| `FlipperDirection` | The direction options for flipper. | `{ next: "next", previous: "previous", }` |
| Name | Description | Type |
| ------------------ | ---------------------------------- | ----------------------------------------- |
| `FlipperDirection` | The direction options for flipper. | `{ next: "next", previous: "previous", }` |

<hr/>

Expand Down
Loading

0 comments on commit 00f9a95

Please sign in to comment.