From 1b08fa9161b3fdd27d2a3c18bb7f7ec0ea8aff34 Mon Sep 17 00:00:00 2001 From: William Wagner <44823142+williamw2@users.noreply.github.com> Date: Mon, 11 Apr 2022 16:25:11 -0700 Subject: [PATCH] chore: fix links due to ts upgrade (#5825) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Pull Request ## 📖 Description The Typescript version upgrade changes how it handles the @link JSDOC tag in comments causing them to be removed when the CEM Analyzer process the code. This results in the link URLs and text being rendered to markdown in such a way that they cannot be corrected into markdown links. This PR adds a CEM Analyzer plugin that checks for the existence of @link tags in the descriptions generated by "comment-parser" and retains the original text. ### 🎫 Issues ## 👩‍💻 Reviewer Notes ## 📑 Test Plan ## ✅ Checklist ### General - [ ] I have included a change request file using `$ yarn change` - [ ] I have added tests for my changes. - [x] I have tested my changes. - [ ] I have updated the project documentation to reflect my changes. - [ ] I have read the [CONTRIBUTING](https://github.com/Microsoft/fast/blob/master/CONTRIBUTING.md) documentation and followed the [standards](https://www.fast.design/docs/community/code-of-conduct/#our-standards) for this project. ### Component-specific - [ ] I have added a new component - [ ] I have modified an existing component - [ ] I have updated the [definition file](https://github.com/Microsoft/fast/blob/master/packages/web-components/fast-components/CONTRIBUTING.md#definition) - [ ] I have updated the [configuration file](https://github.com/Microsoft/fast/blob/master/packages/web-components/fast-components/CONTRIBUTING.md#configuration) ## ⏭ Next Steps --- .../custom-elements-manifest-plugins.mjs | 140 ++++++++++++++++++ .../custom-elements-manifest.config.mjs | 5 + .../fast-foundation/src/accordion/README.md | 2 +- .../fast-foundation/src/anchor/README.md | 16 +- .../fast-foundation/src/breadcrumb/README.md | 16 +- .../fast-foundation/src/button/README.md | 10 +- .../fast-foundation/src/checkbox/README.md | 16 +- .../src/number-field/README.md | 36 ++--- .../fast-foundation/src/radio-group/README.md | 22 +-- .../fast-foundation/src/radio/README.md | 16 +- .../fast-foundation/src/search/README.md | 30 ++-- .../fast-foundation/src/slider/README.md | 30 ++-- .../fast-foundation/src/switch/README.md | 14 +- .../fast-foundation/src/tabs/README.md | 12 +- .../fast-foundation/src/text-area/README.md | 36 ++--- .../fast-foundation/src/text-field/README.md | 32 ++-- .../fast-foundation/src/tree-item/README.md | 18 +-- 17 files changed, 298 insertions(+), 153 deletions(-) create mode 100644 packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs diff --git a/packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs b/packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs new file mode 100644 index 00000000000..a24f9b15271 --- /dev/null +++ b/packages/web-components/fast-foundation/custom-elements-manifest-plugins.mjs @@ -0,0 +1,140 @@ +import { getClassMemberDoc } from "@custom-elements-manifest/analyzer/src/utils/manifest-helpers.js"; +import { parse } from "comment-parser"; + +/** + * Code for this plugin was mostly copied from: https://github.com/bennypowers/cem-plugins/tree/main/plugins/cem-plugin-jsdoc-example + */ + +/** + * Does the AST node have JSDoc tags? + * @template {import('typescript').Node} N + * @param {N} node + * @return {node is N & { jsDoc: import('typescript').JSDoc[] }} + */ +function hasJsDocComments(node) { + return "jsDoc" in node; +} + +/** + * Given a manifest and a declaration name, get the declaration doc + * @param {Partial} moduleDoc + * @param {string} name + * @return {import("custom-elements-manifest/schema").Declaration} + */ +function getDeclarationDoc(moduleDoc, name) { + return moduleDoc.declarations.find(x => x.name === name); +} + +/** + * Fix a Node's JSDoc link comments + * @param {import('typescript').Node & { jsDoc: import('typescript').JSDoc[] }} node + * @param {import("custom-elements-manifest/schema").Declaration} doc + * @param {*} context + * @param {number} [offset=0] + */ +function fixLinks(node, doc, context, offset = 0) { + node?.jsDoc?.forEach(jsDoc => { + const parsed = parse(jsDoc?.getFullText()); + parsed?.forEach(parsedJsDoc => { + if ( + parsedJsDoc.description && + parsedJsDoc.description.indexOf("{@link") >= 0 + ) { + doc.description = parsedJsDoc.description.trim(); + } + }); + }); +} + +/** + * @return {import('@custom-elements-manifest/analyzer').Plugin} + */ +export function jsdocLinkFix() { + return { + name: "jsdoc-example", + analyzePhase({ ts, node, moduleDoc, context }) { + if (!hasJsDocComments(node)) return; + if (ts.isClassDeclaration(node)) { + const className = node.name.getText(); + const classDoc = getDeclarationDoc(moduleDoc, className); + if (!classDoc) + return ( + context.dev && + console.warn( + `[jsdoc-example]: Could not find class ${className} in module doc for path ${moduleDoc.path}` + ) + ); + fixLinks(node, classDoc, context); + } else if (ts.isPropertyDeclaration(node)) { + const propertyName = node.name.getText(); + const className = node.parent?.name?.getText?.(); + const classDoc = getDeclarationDoc(moduleDoc, className); + if (!classDoc) return; + const isStatic = node.modifiers?.some?.( + x => x.kind === ts.SyntaxKind.StaticKeyword + ); + const propertyDoc = getClassMemberDoc( + moduleDoc, + className, + propertyName, + isStatic + ); + if (!propertyDoc) + return ( + context.dev && + console.warn( + `[jsdoc-example]: Could not find property ${propertyName} of ${className} in module doc for path ${moduleDoc.path}` + ) + ); + fixLinks(node, propertyDoc, context, 1); + } else if (ts.isMethodDeclaration(node)) { + if (!ts.isClassDeclaration(node.parent)) return; + const methodName = node.name.getText(); + const className = node.parent.name.getText(); + const classDoc = getDeclarationDoc(moduleDoc, className); + if (!classDoc) return; + const isStatic = node.modifiers?.some?.( + x => x.kind === ts.SyntaxKind.StaticKeyword + ); + const methodDoc = getClassMemberDoc( + moduleDoc, + className, + methodName, + isStatic + ); + if (!methodDoc) + return ( + context.dev && + console.warn( + `[jsdoc-example]: Could not find method ${methodName} of ${className} in module doc for path ${moduleDoc.path}` + ) + ); + fixLinks(node, methodDoc, context, 1); + } else if (ts.isFunctionDeclaration(node)) { + const functionName = node.name.getText(); + const functionDoc = getDeclarationDoc(moduleDoc, functionName); + if (!functionDoc) + return ( + context.dev && + console.warn( + `[jsdoc-example]: Could not find function ${functionName} in module doc for path ${moduleDoc.path}` + ) + ); + fixLinks(node, functionDoc, context); + } else if (ts.isVariableStatement(node)) { + node.declarationList?.declarations.forEach(dec => { + const name = dec.name.getText(); + const doc = getDeclarationDoc(moduleDoc, name); + if (!doc) + return ( + context.dev && + console.warn( + `[jsdoc-example]: Could not find variable ${name} in module doc for path ${moduleDoc.path}` + ) + ); + fixLinks(node, doc, context); + }); + } + }, + }; +} diff --git a/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs b/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs index 35575baa45a..8ac9739d058 100644 --- a/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs +++ b/packages/web-components/fast-foundation/custom-elements-manifest.config.mjs @@ -1,3 +1,5 @@ +import {jsdocLinkFix} from "./custom-elements-manifest-plugins.mjs"; + export default { /** Globs to analyze */ globs: ['src/**/*.ts'], @@ -9,4 +11,7 @@ export default { dev: false, /** Enable special handling for fast */ fast: true, + plugins: [ + jsdocLinkFix(), + ] } diff --git a/packages/web-components/fast-foundation/src/accordion/README.md b/packages/web-components/fast-foundation/src/accordion/README.md index 475eb517db2..eeba5ef6eef 100644 --- a/packages/web-components/fast-foundation/src/accordion/README.md +++ b/packages/web-components/fast-foundation/src/accordion/README.md @@ -149,7 +149,7 @@ export const myAccordionItem = AccordionItem.compose({ | Name | Privacy | Type | Default | Description | Inherited From | | --------------- | ------- | ------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | -| `headinglevel` | public | `1 or 2 or 3 or 4 or 5 or 6` | `2` | Configures the https://www.w3.org/TR/wai-aria-1.1/#aria-level or level of the heading element. | | +| `headinglevel` | public | `1 or 2 or 3 or 4 or 5 or 6` | `2` | Configures the [level](https://www.w3.org/TR/wai-aria-1.1/#aria-level) of the heading element. | | | `expanded` | public | `boolean` | `false` | Expands or collapses the item. | | | `id` | public | `string` | | The item ID | | | `$presentation` | public | `ComponentPresentation or null` | | A property which resolves the ComponentPresentation instance for the current component. | FoundationElement | diff --git a/packages/web-components/fast-foundation/src/anchor/README.md b/packages/web-components/fast-foundation/src/anchor/README.md index 7bd4e585a32..46f7fdd6f8f 100644 --- a/packages/web-components/fast-foundation/src/anchor/README.md +++ b/packages/web-components/fast-foundation/src/anchor/README.md @@ -70,14 +70,14 @@ This component is built with the expectation that focus is delegated to the anch | Name | Privacy | Type | Default | Description | Inherited From | | ---------------- | ------- | -------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | -| `download` | public | `string` | | Prompts the user to save the linked URL. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `href` | public | `string` | | The URL the hyperlink references. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `hreflang` | public | `string` | | Hints at the language of the referenced resource. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `ping` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `referrerpolicy` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `rel` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `target` | public | `"_self" or "_blank" or "_parent" or "_top"` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | -| `type` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | | +| `download` | public | `string` | | Prompts the user to save the linked URL. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `href` | public | `string` | | The URL the hyperlink references. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `hreflang` | public | `string` | | Hints at the language of the referenced resource. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `ping` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `referrerpolicy` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `rel` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `target` | public | `"_self" or "_blank" or "_parent" or "_top"` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | +| `type` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | | | `control` | public | `HTMLAnchorElement` | | References the root element | | | `$presentation` | public | `ComponentPresentation or null` | | A property which resolves the ComponentPresentation instance for the current component. | FoundationElement | | `template` | public | `ElementViewTemplate or void or null` | | Sets the template of the element instance. When undefined, the element will attempt to resolve the template from the associated presentation or custom element definition. | FoundationElement | diff --git a/packages/web-components/fast-foundation/src/breadcrumb/README.md b/packages/web-components/fast-foundation/src/breadcrumb/README.md index 71a349d64e9..ecd548352ff 100644 --- a/packages/web-components/fast-foundation/src/breadcrumb/README.md +++ b/packages/web-components/fast-foundation/src/breadcrumb/README.md @@ -139,14 +139,14 @@ This component is built with the expectation that focus is delegated to the anch | Name | Privacy | Type | Default | Description | Inherited From | | ---------------- | ------- | -------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | -| `download` | public | `string` | | Prompts the user to save the linked URL. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `href` | public | `string` | | The URL the hyperlink references. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `hreflang` | public | `string` | | Hints at the language of the referenced resource. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `ping` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `referrerpolicy` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `rel` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `target` | public | `"_self" or "_blank" or "_parent" or "_top"` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | -| `type` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a or `` element for more information. | Anchor | +| `download` | public | `string` | | Prompts the user to save the linked URL. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `href` | public | `string` | | The URL the hyperlink references. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `hreflang` | public | `string` | | Hints at the language of the referenced resource. See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `ping` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `referrerpolicy` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `rel` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `target` | public | `"_self" or "_blank" or "_parent" or "_top"` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | +| `type` | public | `string` | | See [`` element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a) for more information. | Anchor | | `control` | public | `HTMLAnchorElement` | | References the root element | Anchor | | `$presentation` | public | `ComponentPresentation or null` | | A property which resolves the ComponentPresentation instance for the current component. | FoundationElement | | `template` | public | `ElementViewTemplate or void or null` | | Sets the template of the element instance. When undefined, the element will attempt to resolve the template from the associated presentation or custom element definition. | FoundationElement | diff --git a/packages/web-components/fast-foundation/src/button/README.md b/packages/web-components/fast-foundation/src/button/README.md index 71e8aa28172..b8a7f46e885 100644 --- a/packages/web-components/fast-foundation/src/button/README.md +++ b/packages/web-components/fast-foundation/src/button/README.md @@ -72,11 +72,11 @@ This component is built with the expectation that focus is delegated to the butt | ----------------------- | ------- | -------------------------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | | `autofocus` | public | `boolean` | | Determines if the element should receive document focus on page load. | | | `formId` | public | `string` | | The id of a form to associate the element to. | | -| `formaction` | public | `string` | | See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button or `