diff --git a/.travis.yml b/.travis.yml index 83025741..ba33eac8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,7 @@ dist: focal language: node_js node_js: - lts/* - - node + #- node sudo: false install: - npm config set prefer-offline false diff --git a/CHANGELOG.md b/CHANGELOG.md index c49bc424..29e134e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ The following is a curated list of changes in the Enact docs-utils module, newest changes on the top. +## [4.6.0] - 2023-05-23 + +- Updated `jsonata` version to ^2.0.2. + ## [4.5.0] - 2023-04-06 -- Changed to require node 14 or later +- Changed to require node 14 or later. diff --git a/gatsby-browser.js b/gatsby-browser.js index fab8ac2f..3037098d 100644 --- a/gatsby-browser.js +++ b/gatsby-browser.js @@ -4,12 +4,20 @@ import 'prismjs/plugins/command-line/prism-command-line.css'; export const onRouteUpdate = ({location}) => { if (location.hash) { setTimeout(() => { - const node = document.querySelector(`${location.hash}`); + let node; + if (location.hash.includes('.')) { + // To select the element using `querySelector()` we escape the period in the ID with two backslashes + const parsedHashLocation = location.hash.replace(/\./g, '\\.'); + node = document.querySelector(parsedHashLocation); + } else { + node = document.querySelector(`${location.hash}`); + } + if (node) { node.scrollIntoView(); } else { console.log(`Invalid location: ${location.hash}`); // eslint-disable-line no-console } - }, 0); + }, 5); } }; diff --git a/package.json b/package.json index 9711d16c..3b127261 100644 --- a/package.json +++ b/package.json @@ -6,10 +6,10 @@ "node": ">=14" }, "dependencies": { - "@enact/core": "^4.6.0", - "@enact/docs-utils": "^0.4.0", - "@enact/ui": "^4.6.0", - "@primer/octicons": "^17.10.2", + "@enact/core": "^4.6.2", + "@enact/docs-utils": "^0.4.2", + "@enact/ui": "^4.6.2", + "@primer/octicons": "^18.3.0", "babel-plugin-dev-expression": "^0.2.3", "broken-link-checker": "^0.7.8", "chokidar": "^3.5.3", @@ -20,7 +20,7 @@ "css-loader": "^6.7.3", "elasticlunr": "^0.9.5", "find-cache-dir": "^3.3.2", - "gatsby": "^4.25.4", + "gatsby": "^4.25.6", "gatsby-plugin-catch-links": "^4.25.0", "gatsby-plugin-google-gtag": "^4.25.0", "gatsby-plugin-image": "^2.25.0", @@ -29,7 +29,7 @@ "gatsby-plugin-offline": "^5.25.0", "gatsby-plugin-postcss": "^5.25.0", "gatsby-plugin-react-helmet": "^5.25.0", - "gatsby-plugin-sharp": "^4.25.0", + "gatsby-plugin-sharp": "^4.25.1", "gatsby-plugin-typography": "^4.25.0", "gatsby-remark-autolink-headers": "^5.25.0", "gatsby-remark-copy-linked-files": "^5.25.0", @@ -45,7 +45,7 @@ "global-modules": "^2.0.0", "gray-matter": "^4.0.3", "json-loader": "^0.5.7", - "jsonata": "^1.8.6", + "jsonata": "^2.0.2", "jsonfile": "^6.1.0", "less": "~4.1.3", "less-loader": "^11.1.0", @@ -53,14 +53,13 @@ "markdown-it": "^13.0.1", "markdown-it-jsx": "^1.1.0", "markdown-toc": "^1.2.0", - "minimist": "^1.2.7", - "mkdirp": "^1.0.4", + "minimist": "^1.2.8", "postcss": "^8.4.21", - "postcss-loader": "^7.0.2", + "postcss-loader": "^7.2.4", "prismjs": "^1.29.0", "progress": "~2.0.3", "prop-types": "^15.8.1", - "ramda": "^0.28.0", + "ramda": "^0.29.0", "react": "^18.2.0", "react-document-title": "^2.0.3", "react-dom": "^18.2.0", diff --git a/sample-runner/agate/package.json b/sample-runner/agate/package.json index 7037499a..5b8426a7 100644 --- a/sample-runner/agate/package.json +++ b/sample-runner/agate/package.json @@ -30,12 +30,12 @@ "dist/*" ], "dependencies": { - "@enact/core": "^4.6.0", - "@enact/i18n": "^4.6.0", + "@enact/core": "^4.6.2", + "@enact/i18n": "^4.6.2", "@enact/agate": "enactjs/agate#develop", - "@enact/spotlight": "^4.6.0", - "@enact/ui": "^4.6.0", - "ilib": "^14.15.1", + "@enact/spotlight": "^4.6.2", + "@enact/ui": "^4.6.2", + "ilib": "^14.17.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/sample-runner/core/package.json b/sample-runner/core/package.json index 88386455..b2204b22 100644 --- a/sample-runner/core/package.json +++ b/sample-runner/core/package.json @@ -27,11 +27,11 @@ "dist/*" ], "dependencies": { - "@enact/core": "^4.6.0", - "@enact/i18n": "^4.6.0", - "@enact/spotlight": "^4.6.0", - "@enact/ui": "^4.6.0", - "ilib": "^14.16.0", + "@enact/core": "^4.6.2", + "@enact/i18n": "^4.6.2", + "@enact/spotlight": "^4.6.2", + "@enact/ui": "^4.6.2", + "ilib": "^14.17.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/sample-runner/moonstone/package.json b/sample-runner/moonstone/package.json index 84ad8ec8..af4958d2 100644 --- a/sample-runner/moonstone/package.json +++ b/sample-runner/moonstone/package.json @@ -30,12 +30,12 @@ "dist/*" ], "dependencies": { - "@enact/core": "^4.6.0", - "@enact/i18n": "^4.6.0", + "@enact/core": "^4.6.2", + "@enact/i18n": "^4.6.2", "@enact/moonstone": "^4.5.2", - "@enact/spotlight": "^4.6.0", - "@enact/ui": "^4.6.0", - "ilib": "^14.16.0", + "@enact/spotlight": "^4.6.2", + "@enact/ui": "^4.6.2", + "ilib": "^14.17.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/sample-runner/sandstone/package.json b/sample-runner/sandstone/package.json index 26c512b2..229a15ed 100644 --- a/sample-runner/sandstone/package.json +++ b/sample-runner/sandstone/package.json @@ -30,12 +30,12 @@ "dist/*" ], "dependencies": { - "@enact/core": "^4.6.0", - "@enact/i18n": "^4.6.0", + "@enact/core": "^4.6.2", + "@enact/i18n": "^4.6.2", "@enact/sandstone": "enactjs/sandstone#develop", - "@enact/spotlight": "^4.6.0", - "@enact/ui": "^4.6.0", - "ilib": "^14.16.0", + "@enact/spotlight": "^4.6.2", + "@enact/ui": "^4.6.2", + "ilib": "^14.17.0", "prop-types": "^15.8.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/sample-runner/sandstone/src/EnactImporter.js b/sample-runner/sandstone/src/EnactImporter.js index 607db7b7..f50b4065 100644 --- a/sample-runner/sandstone/src/EnactImporter.js +++ b/sample-runner/sandstone/src/EnactImporter.js @@ -17,6 +17,7 @@ import FlexiblePopupPanels from '@enact/sandstone/FlexiblePopupPanels'; import FormCheckboxItem from '@enact/sandstone/FormCheckboxItem'; import Heading from '@enact/sandstone/Heading'; import Icon from '@enact/sandstone/Icon'; +import IconItem from '@enact/sandstone/IconItem'; import Image from '@enact/sandstone/Image'; import ImageItem from '@enact/sandstone/ImageItem'; import Input, {InputField} from '@enact/sandstone/Input'; @@ -77,6 +78,7 @@ const sandstoneExports = { Header, Heading, Icon, + IconItem, Image, ImageItem, Input, diff --git a/src/pages/docs/tutorials/tutorial-kitten-browser/reusable-components/index.md b/src/pages/docs/tutorials/tutorial-kitten-browser/reusable-components/index.md index dbfc9198..8c4342bb 100644 --- a/src/pages/docs/tutorials/tutorial-kitten-browser/reusable-components/index.md +++ b/src/pages/docs/tutorials/tutorial-kitten-browser/reusable-components/index.md @@ -97,7 +97,7 @@ const sum = (a, b) => (a + b); > When using Advanced arrow functions with JSX, we recommend wrapping the JSX with parenthesis. They aren't required but the result is more readable and consistent with traditional functions or basic arrow functions that must use parenthesis for multi-line JSX. -> More on [how `return` behaves with new lines](http://lucumr.pocoo.org/2011/2/6/automatic-semicolon-insertion/) and [examples with JSX](https://goo.gl/7kI5oT) and the transpiled result. +> More on [how `return` behaves with new lines](http://lucumr.pocoo.org/2011/2/6/automatic-semicolon-insertion/) and [examples with JSX](https://babeljs.io/repl#?browsers=defaults&build=&builtIns=false&corejs=false&spec=false&loose=false&code_lz=MYewdgzgLgBATgUzAEwXAQgQwgS2ASTADdMAbHZGAXhgAoBKagPhgG8AoGeBKAVzjCcuMADzIcRJkOGiIAB0xgm0XgDNVIgPTzFUmVvGSA3OwC-J9qEixEKNFlzAAamQrU6jKiw5dEfAXTSooZ6MrIKSirqWjpKQQYSofQm5uyW4NDcdnAAgsgkYMAIyC7klDQMzDBCYonxscp80doRoQnGaVaZtqi5-YpFJa7IAAqIqmiI5R5VtDUh9a1RGi26NZoLyUA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&circleciRepo=&evaluate=true&fileSize=false&timeTravel=false&sourceType=module&lineWrap=false&presets=react&prettier=false&targets=&version=7.21.8&externalPlugins=&assumptions=%7B%7D) and the transpiled result. You may notice that we used both methods of returning data from an arrow function in our `Kitten` component (in the `computed` property and the `render` method). diff --git a/src/templates/json.js b/src/templates/json.js index 8a87cc0b..410bdb61 100644 --- a/src/templates/json.js +++ b/src/templates/json.js @@ -16,8 +16,26 @@ export default class JSONWrapper extends Component { location: PropTypes.object }; - render () { + constructor (props) { + super(props); + this.state = { + renderDoc: null, + responseRenderModuleDescription: null, + responseRenderModuleMembers: null + }; + } + + async componentDidMount () { const doc = JSON.parse(this.props.data.jsonDoc.internal.content); + this.setState({ + renderDoc: doc[0], + responseRenderModuleDescription: await renderModuleDescription(doc), + responseRenderModuleMembers: await renderModuleMembers(doc[0].members) + }); + } + + render () { + const {renderDoc, responseRenderModuleDescription, responseRenderModuleMembers} = this.state; const path = this.props.location.pathname.replace(/.*\/docs\/modules\//, '').replace(/\/$/, ''); const pathParts = path.replace(/([A-Z])/g, ' $1').split(' '); // Find all uppercase letters and allow a linebreak to happen before each one. // The is an optional line-break. It only line-breaks if it needs to, and only on the specified points. Long lines won't get cut off in the middle of words. @@ -34,11 +52,11 @@ export default class JSONWrapper extends Component {
- {doc[0]} + {renderDoc}

{pathParts.map((part, idx) => [, part])}

- {renderModuleDescription(doc)} - {renderModuleMembers(doc[0].members)} + {responseRenderModuleDescription} + {responseRenderModuleMembers}
diff --git a/src/utils/common.js b/src/utils/common.js index b933a749..c37e1311 100644 --- a/src/utils/common.js +++ b/src/utils/common.js @@ -4,10 +4,10 @@ import jsonata from 'jsonata'; // http://docs.jsonata.org/ import css from '../css/main.module.less'; -export const processDefaultTag = (tags) => { +export const processDefaultTag = async (tags) => { // Find any tag field whose `title` is 'default' (won't be there if no default) const expression = "$[title='default'].description"; - const result = jsonata(expression).evaluate(tags); + const result = await jsonata(expression).evaluate(tags); return result || 'undefined'; }; @@ -33,16 +33,16 @@ export const renderDefaultTag = (defaultStr) => { return Default: {defaultStr}; }; -export const hasRequiredTag = (member) => { +export const hasRequiredTag = async (member) => { // Find any tag field whose `title` is 'required' (won't be there if not required) const expression = "$[title='required']"; - const result = jsonata(expression).evaluate(member.tags); + const result = await jsonata(expression).evaluate(member.tags); return !!result; }; -export const hasDeprecatedTag = (member) => { +export const hasDeprecatedTag = async (member) => { // Find any tag field whose `title` is 'deprecated' const expression = "$[title='deprecated']"; - const result = jsonata(expression).evaluate(member.tags); + const result = await jsonata(expression).evaluate(member.tags); return !!result; }; diff --git a/src/utils/functions.js b/src/utils/functions.js index 9d0e20d1..ae4840cf 100644 --- a/src/utils/functions.js +++ b/src/utils/functions.js @@ -1,6 +1,8 @@ // Utilities for working with functions. Primary use is in rendering functions // as part of /wrappers/json.js +import {useEffect, useState} from 'react'; + import DocParse from '../components/DocParse.js'; import FloatingAnchor from '../components/FloatingAnchor'; import jsonata from 'jsonata'; // http://docs.jsonata.org/ @@ -12,18 +14,18 @@ import {renderType, jsonataTypeParser} from './types'; import css from '../css/main.module.less'; -const processTypes = (member) => { +const processTypes = async (member) => { // see types.jsonataTypeParser const expression = `$.type.[( ${jsonataTypeParser} )]`; - const result = jsonata(expression).evaluate(member); + const result = await jsonata(expression).evaluate(member); return result || []; }; // Pass `func.returns` for return types -const renderTypeStrings = (member, separator) => { - const types = processTypes(member); +const renderTypeStrings = async (member, separator) => { + const types = await processTypes(member); let typeList = types.map(renderType); if (separator) { // eslint-disable-next-line no-sequences @@ -32,10 +34,10 @@ const renderTypeStrings = (member, separator) => { return typeList; }; -const paramIsRestType = (param) => { +const paramIsRestType = async (param) => { // Find any type === RestType in any descendant const expression = "$.**[type='RestType']"; - return jsonata(expression).evaluate(param); + return await jsonata(expression).evaluate(param); }; const paramIsOptional = (param) => { @@ -46,10 +48,10 @@ const requiredParamCount = (params) => { return params.length - params.filter(paramIsOptional).length; }; -const decoratedParamName = (param) => { +const decoratedParamName = async (param) => { let name = param.name; - if (paramIsRestType(param)) { + if (await paramIsRestType(param)) { name = '…' + name; } @@ -60,14 +62,15 @@ const decoratedParamName = (param) => { return name; }; -const buildParamList = (params) => { - return params.map(decoratedParamName).join(', '); +const buildParamList = async (params) => { + const paramsListPromise = await Promise.all(await params.map(await decoratedParamName)); + return paramsListPromise.join(', '); }; -const paramCountString = (params) => { +const paramCountString = async (params) => { const reqCount = requiredParamCount(params); const hasOptional = reqCount < params.length; - const hasRest = params.length && paramIsRestType(params[params.length - 1]); + const hasRest = params.length && await paramIsRestType(params[params.length - 1]); let result = reqCount; let suffix = ' Param'; @@ -81,20 +84,20 @@ const paramCountString = (params) => { return result; }; -const renderProperties = (param) => { +const renderProperties = async (param) => { if (param.properties) { return (
Object keys for {param.name}
- {param.properties.map((prop) => { + {await Promise.all(param.properties.map(async (prop) => { // Make the keyName just "key" not "prop.key" const keyName = prop.name.replace(param.name + '.', ''); return [ -
{keyName} {renderTypeStrings(prop)}
, +
{keyName} {await renderTypeStrings(prop)}
, {prop.description} ]; - })} + }))}
); @@ -103,28 +106,62 @@ const renderProperties = (param) => { // eslint-disable-next-line enact/prop-types const Parameters = ({func, params, hasReturns}) => { + const [paramType, setParamType] = useState({}); + const [methodReturnValue, setMethodReturnValue] = useState([]); + const [responseParamCountString, setResponseParamCountString] = useState([]); + const [responseRenderProperties, setResponseRenderProperties] = useState({}); + + useEffect(() => { + const renderParamCountString = async () => { + const data = await paramCountString(params); + setResponseParamCountString(data); + }; + renderParamCountString() + .catch(console.error); // eslint-disable-line no-console + + // map over all parameters, extract their type and render properties inside an object with the name of the property/type as the key + const renderParamTypeAndPropertiesEffect = Promise.all(params.map(async (param) => { + const paramTypeData = await renderTypeStrings(param); + setParamType(obj => Object.assign(obj, {[param.name]: paramTypeData})); + + const renderPropertiesData = await renderProperties(param); + setResponseRenderProperties(obj => Object.assign(obj, {[param.name]: renderPropertiesData})); + })); + renderParamTypeAndPropertiesEffect + .catch(console.error); // eslint-disable-line no-console + + // get the return value of any methods + const renderMethodReturnValue = async () => { + const data = await renderTypeStrings(func.returns); + setMethodReturnValue(array => [...array, data]); + }; + renderMethodReturnValue() + .catch(console.error); // eslint-disable-line no-console + + }, [func.returns, params]); + if (params.length === 0 && !hasReturns) return null; return (
{params.length ?
-
{paramCountString(params)}
+
{responseParamCountString}
{params.map((param, subIndex) => (
-
{param.name} {renderTypeStrings(param)}
+
{param.name} {paramType[param.name]}
{paramIsOptional(param) ?
optional
: null} {param.default ?
default: {param.default}
: null} {param.description} - {renderProperties(param)} + {responseRenderProperties[param.name]}
))}
: null} {hasReturns ?
Returns
-
{renderTypeStrings(func.returns)}
+
{methodReturnValue}
{func.returns[0].description}
: null} @@ -132,9 +169,9 @@ const Parameters = ({func, params, hasReturns}) => { ); }; -export const renderExportedFunction = (func) => { +export const renderExportedFunction = async (func) => { const params = func.params || []; - const paramStr = buildParamList(params); + const paramStr = await buildParamList(params); const name = func.name; const hasReturns = !!func.returns.length; @@ -142,7 +179,7 @@ export const renderExportedFunction = (func) => {
 				
-					{name}( {paramStr} ){hasReturns ? {renderTypeStrings(func.returns, '|')} : null}
+					{name}( {paramStr} ){hasReturns ? {await renderTypeStrings(func.returns, '|')} : null}
 				
 			
{func.description} @@ -152,9 +189,9 @@ export const renderExportedFunction = (func) => { ); }; -const renderFunction = (func, index, funcName) => { +const renderFunction = async (func, index, funcName) => { const params = func.params || []; - const paramStr = buildParamList(params); + const paramStr = await buildParamList(params); const parent = func.memberof ? func.memberof.match(/[^.]*\.(.*)/) : null; const name = funcName ? funcName : func.name; const id = (parent ? parent[1] + '.' : '') + name; @@ -162,7 +199,7 @@ const renderFunction = (func, index, funcName) => { return (
- {name}({paramStr}){hasReturns ? {renderTypeStrings(func.returns, '|')} : null} + {name}({paramStr}){hasReturns ? {await renderTypeStrings(func.returns, '|')} : null} {func.description} {renderSeeTags(func)} @@ -170,7 +207,7 @@ const renderFunction = (func, index, funcName) => { ); }; -export const renderConstructor = (member) => { +export const renderConstructor = async (member) => { if (!member.constructorComment) { return; } @@ -179,7 +216,7 @@ export const renderConstructor = (member) => {
Constructor
- {renderFunction(member.constructorComment, 1, member.name)} + {await renderFunction(member.constructorComment, 1, member.name)}
); diff --git a/src/utils/modules.js b/src/utils/modules.js index 3c7a4a07..a239b478 100644 --- a/src/utils/modules.js +++ b/src/utils/modules.js @@ -26,44 +26,44 @@ import css from '../css/main.module.less'; const H4 = (props) => FloatingAnchor.inline({component: 'h4', ...props}); -const hasFactoryTag = (member) => { +const hasFactoryTag = async (member) => { // Find any tag field whose `title` is 'factory' const expression = "$[title='factory']"; - const result = jsonata(expression).evaluate(member.tags); + const result = await jsonata(expression).evaluate(member.tags); return !!result; }; -const hasHOCTag = (member) => { +const hasHOCTag = async (member) => { // Find any tag field whose `title` is 'hoc' const expression = "$[title='hoc']"; - const result = jsonata(expression).evaluate(member.tags); + const result = await jsonata(expression).evaluate(member.tags); return !!result; }; -const hasUITag = (member) => { +const hasUITag = async (member) => { // Find any tag field whose `title` is 'ui' const expression = "$[title='ui']"; - const result = jsonata(expression).evaluate(member.tags); + const result = await jsonata(expression).evaluate(member.tags); return !!result; }; -const getExampleTags = (member) => { +const getExampleTags = async (member) => { // Find any tag field whose `title` is 'example' // Updated style that works in jsonata 1.6.4 and always returns array! const expression = "$.[tags[title='example']]"; - return jsonata(expression).evaluate(member); + return await jsonata(expression).evaluate(member); }; -const getBaseComponents = (member) => { +const getBaseComponents = async (member) => { // Find any tag field whose `title` is 'extends' and extract the name(s) const expression = "$.[tags[title='extends'].name]"; - return jsonata(expression).evaluate(member); + return await jsonata(expression).evaluate(member); }; -const getHocs = (member) => { +const getHocs = async (member) => { // Find any tag field whose `title` is 'mixes' and extract the name(s) const expression = "$.[tags[title='mixes'].name]"; - return jsonata(expression).evaluate(member); + return await jsonata(expression).evaluate(member); }; const MemberHeading = kind({ @@ -95,8 +95,8 @@ const MemberHeading = kind({ } }); -const renderExtends = member => { - const baseComponents = getBaseComponents(member); +const renderExtends = async (member) => { + const baseComponents = await getBaseComponents(member); if (baseComponents.length) { return ( @@ -112,8 +112,8 @@ const renderExtends = member => { } }; -const renderAppliedHocs = (member, isHoc) => { - const hocs = getHocs(member); +const renderAppliedHocs = async (member, isHoc) => { + const hocs = await getHocs(member); if (hocs.length) { return ( @@ -129,12 +129,12 @@ const renderAppliedHocs = (member, isHoc) => { } }; -const renderModuleMember = (member, index) => { - const isHoc = hasHOCTag(member), - isDeprecated = hasDeprecatedTag(member), - isFactory = hasFactoryTag(member), +const renderModuleMember = async (member, index) => { + const isHoc = await hasHOCTag(member), + isDeprecated = await hasDeprecatedTag(member), + isFactory = await hasFactoryTag(member), isClass = (member.kind === 'class'), - isUI = hasUITag(member), + isUI = await hasUITag(member), classes = [ css.module, (isDeprecated ? css.deprecated : null), @@ -152,7 +152,7 @@ const renderModuleMember = (member, index) => { return
{member.name} {deprecationNote} - {renderExportedFunction(member)} + {await renderExportedFunction(member)}
; case 'constant': return
@@ -162,15 +162,15 @@ const renderModuleMember = (member, index) => { {member.description} {renderSeeTags(member)}
- {renderStaticProperties(member.members, isHoc)} - {renderInstanceProperties(member.members, isHoc)} - {renderObjectProperties(member.properties)} + {await renderStaticProperties(member.members, isHoc)} + {await renderInstanceProperties(member.members, isHoc)} + {await renderObjectProperties(member.properties)} ; case 'typedef': return
{member.name} {deprecationNote} - {renderTypedef(member)} + {await renderTypedef(member)}
; case 'class': default: @@ -190,25 +190,25 @@ const renderModuleMember = (member, index) => { {renderSeeTags(member)} - {renderExtends(member)} - {renderAppliedHocs(member, isHoc)} - {renderConstructor(member)} - {renderStaticProperties(member.members, isHoc)} - {renderInstanceProperties(member.members, isHoc)} + {await renderExtends(member)} + {await renderAppliedHocs(member, isHoc)} + {await renderConstructor(member)} + {await renderStaticProperties(member.members, isHoc)} + {await renderInstanceProperties(member.members, isHoc)} ; } }; -const renderTypedefMembers = (typedefMembers) => { +const renderTypedefMembers = async (typedefMembers) => { if (typedefMembers.length) { return [

Type Definitions

, - typedefMembers.map(renderModuleMember) + await Promise.all(typedefMembers.map(await renderModuleMember)) ]; } }; -export const renderModuleMembers = (members) => { +export const renderModuleMembers = async (members) => { // All module members will be static, no need to check instance members if (members.static.length) { const moduleName = members.static[0].memberof.split('/').pop(); @@ -233,8 +233,8 @@ export const renderModuleMembers = (members) => { return (

Members

- {moduleMembers.map(renderModuleMember)} - {renderTypedefMembers(typedefMembers)} + {await Promise.all(moduleMembers.map(renderModuleMember))} + {await renderTypedefMembers(typedefMembers)}
); } else { @@ -279,10 +279,10 @@ const ImportBlock = kind({ } }); -export const renderModuleDescription = (doc) => { +export const renderModuleDescription = async (doc) => { if (doc.length) { - const code = getExampleTags(doc[0]); - const isDeprecated = hasDeprecatedTag(doc[0]); + const code = await getExampleTags(doc[0]); + const isDeprecated = await hasDeprecatedTag(doc[0]); const deprecationNote = isDeprecated ? {doc[0].deprecated} : null; return
diff --git a/src/utils/properties.js b/src/utils/properties.js index b95cc566..fb107dde 100644 --- a/src/utils/properties.js +++ b/src/utils/properties.js @@ -15,33 +15,33 @@ import css from '../css/main.module.less'; const Dt = (props) => FloatingAnchor.inline({component: 'dt', ...props}); -const processTypeTag = (tags) => { +const processTypeTag = async (tags) => { // see types.jsonataTypeParser const expression = `$[title="type"].type.[( ${jsonataTypeParser} )]`; - const result = jsonata(expression).evaluate(tags); + const result = await jsonata(expression).evaluate(tags); return result || []; }; -const renderPropertyTypeStrings = (member) => { - const types = processTypeTag(member.tags); +const renderPropertyTypeStrings = async (member) => { + const types = await processTypeTag(member.tags); const typeStr = types.map(renderType); return typeStr; }; -export const renderProperty = (prop, index) => { +export const renderProperty = async (prop, index) => { if ((prop.kind === 'function') || (prop.kind === 'class' && prop.name === 'constructor')) { - return renderFunction(prop, index); + return await renderFunction(prop, index); } else { const parent = prop.memberof ? prop.memberof.match(/[^.]*\.(.*)/) : null; const id = (parent ? parent[1] + '.' : '') + prop.name; - const isDeprecated = hasDeprecatedTag(prop); - const isRequired = hasRequiredTag(prop); + const isDeprecated = await hasDeprecatedTag(prop); + const isRequired = await hasRequiredTag(prop); const requiredIcon = isRequired ? : null; const deprecatedIcon = isDeprecated ? : null; - let defaultStr = renderDefaultTag(processDefaultTag(prop.tags)); + let defaultStr = renderDefaultTag(await processDefaultTag(prop.tags)); return (
@@ -49,7 +49,7 @@ export const renderProperty = (prop, index) => {
{prop.name} {requiredIcon} {deprecatedIcon}
-
{renderPropertyTypeStrings(prop)}
+
{await renderPropertyTypeStrings(prop)}
{prop.description} @@ -64,24 +64,19 @@ export const renderProperty = (prop, index) => { } }; -const renderHocConfig = (config) => { +const renderHocConfig = async (config) => { return (
Configuration
- {config.members.static.map(renderProperty)} + {await Promise.all(config.members.static.map(renderProperty))}
); }; const propSort = (a, b) => { - let aIsRequired = hasRequiredTag(a); - let bIsRequired = hasRequiredTag(b); - - if (aIsRequired !== bIsRequired) { - return aIsRequired ? -1 : 1; - } else if (a.name < b.name) { + if (a.name < b.name) { return -1; } else if (a.name > b.name) { return 1; @@ -90,37 +85,54 @@ const propSort = (a, b) => { } }; -export const renderStaticProperties = (properties, isHoc) => { +export const renderStaticProperties = async (properties, isHoc) => { if (!properties.static.length) { return; } - properties.static = properties.static.sort(propSort); + + // create an array with the required static properties + const isRequiredTag = await Promise.all(properties.static.map(async (prop) => await hasRequiredTag(prop))); + // get all the required static properties and sort them. After that, sort all the non-required properties and concat them to sorted required properties + properties.static = properties.static.filter((el, index) => isRequiredTag[index]).sort(propSort).concat(properties.static.filter((el, index) => !isRequiredTag[index]).sort(propSort)); if (isHoc) { - return renderHocConfig(properties.static[0]); + return await renderHocConfig(properties.static[0]); } else { return (
{properties.static.length ?
Statics
: null}
- {properties.static.map(renderProperty)} + {await Promise.all(properties.static.map(renderProperty))}
); } }; -export const renderInstanceProperties = (properties, isHoc) => { +export const renderInstanceProperties = async (properties, isHoc) => { if (!properties.instance.length) { return; } - const instanceProps = properties.instance.filter(prop => prop.kind !== 'function').sort(propSort); - const instanceMethods = properties.instance.filter(prop => prop.kind === 'function').sort(propSort); + + // create an array with the required properties + const hasRequiredTagMethods = await Promise.all(properties.instance.map(async (prop) => await hasRequiredTag(prop) && prop.kind === 'function')); + // get all the properties that have the required tag and sort them + let instanceMethods = properties.instance.filter((el, index) => hasRequiredTagMethods[index] && el.kind === 'function').sort(propSort); + // sort all non-required properties and concat them to sorted required properties + instanceMethods = instanceMethods.concat(properties.instance.filter((el, index) => !hasRequiredTagMethods[index] && el.kind === 'function').sort(propSort)); + + // create an array with the required methods + const hasRequiredTagProps = await Promise.all(properties.instance.map(async (prop) => await hasRequiredTag(prop) && prop.kind !== 'function')); + // get all the methods that have the required tag and sort them + let instanceProps = properties.instance.filter((el, index) => hasRequiredTagProps[index] && el.kind !== 'function').sort(propSort); + // sort all non-required methods and concat them to sorted required methods + instanceProps = instanceProps.concat(properties.instance.filter((el, index) => !hasRequiredTagProps[index] && el.kind !== 'function').sort(propSort)); + return ([ instanceProps.length ?
Properties{isHoc ? ' added to wrapped component' : ''}
- {instanceProps.map(renderProperty)} + {await Promise.all(instanceProps.map(renderProperty))}
: null, @@ -128,21 +140,24 @@ export const renderInstanceProperties = (properties, isHoc) => {
Methods{isHoc ? ' added to wrapped component' : ''}
- {instanceMethods.map(renderProperty)} + {await Promise.all(instanceMethods.map(renderProperty))}
: null ]); }; -export const renderObjectProperties = (properties) => { +export const renderObjectProperties = async (properties) => { if (properties && properties.length) { - properties = properties.sort(propSort); + // create an array with the required object properties + const isRequiredTag = await Promise.all(properties.map(async prop => await hasRequiredTag(prop))); + // get all the required static properties and sort them. After that, sort all the non-required properties and concat them to sorted required properties + properties = properties.filter((el, index) => isRequiredTag[index]).sort(propSort).concat(properties.filter((el, index) => !isRequiredTag[index]).sort(propSort)); return
Properties
- {properties.map(renderTypedefProp)} + {await Promise.all(properties.map(renderTypedefProp))}
; } diff --git a/src/utils/typedefs.js b/src/utils/typedefs.js index ea4ae629..3c75ed9e 100644 --- a/src/utils/typedefs.js +++ b/src/utils/typedefs.js @@ -10,27 +10,27 @@ import {renderType, jsonataTypeParser} from './types'; import css from '../css/main.module.less'; -const renderTypedefTypeStrings = (member) => { +const renderTypedefTypeStrings = async (member) => { // see types.jsonataTypeParser const expression = `$.type.[( ${jsonataTypeParser} )]`; - const result = jsonata(expression).evaluate(member) || []; + const result = await jsonata(expression).evaluate(member) || []; return result.map(renderType); }; // TODO: Should this move to `properties.js`? -export const renderTypedefProp = (type, index) => { +export const renderTypedefProp = async (type, index) => { const parent = type.memberof ? type.memberof.match(/[^.]*\.(.*)/) : null; const id = (parent ? parent[1] + '.' : '') + type.name; if ((type.kind === 'function') || (type.kind === 'class' && type.name === 'constructor')) { - return renderFunction(type, index); + return await renderFunction(type, index); } else { let isRequired = type.type && type.type.type !== 'OptionalType'; isRequired = isRequired ? : null; - let defaultStr = renderDefaultTag(processDefaultTag(type.tags)); + let defaultStr = renderDefaultTag(await processDefaultTag(type.tags)); return (
@@ -38,7 +38,7 @@ export const renderTypedefProp = (type, index) => {
{type.name} {isRequired}
- {renderTypedefTypeStrings(type)} + {await renderTypedefTypeStrings(type)} {defaultStr}
@@ -50,14 +50,14 @@ export const renderTypedefProp = (type, index) => { } }; -export const renderTypedef = (member) => { +export const renderTypedef = async (member) => { const isFunction = member.type && member.type.name === 'Function'; const isObject = member.type && member.type.name === 'Object'; if (isFunction) { return (
- {renderFunction(member)} + {await renderFunction(member)}
); } else if (isObject) { @@ -68,7 +68,7 @@ export const renderTypedef = (member) => { {renderSeeTags(member)}
- {member.properties.map(renderTypedefProp)} + {await Promise.all(member.properties.map(renderTypedefProp))}
); @@ -80,7 +80,7 @@ export const renderTypedef = (member) => { {renderSeeTags(member)}
- {renderTypedefTypeStrings(member)} + {await renderTypedefTypeStrings(member)}
);