diff --git a/@plotly/dash-generator-test-component-typescript/package-lock.json b/@plotly/dash-generator-test-component-typescript/package-lock.json index 28cf26e996..e79cc14db4 100644 --- a/@plotly/dash-generator-test-component-typescript/package-lock.json +++ b/@plotly/dash-generator-test-component-typescript/package-lock.json @@ -12,6 +12,7 @@ "@babel/preset-env": "^7.19.4", "@babel/preset-react": "^7.18.6", "@types/jest": "^29.2.0", + "@types/ramda": "^0.28.14", "@types/react": "^17.0.39", "babel-loader": "^8.2.5", "jest": "^29.2.1", @@ -2695,6 +2696,15 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", "dev": true }, + "node_modules/@types/ramda": { + "version": "0.28.14", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.28.14.tgz", + "integrity": "sha512-hLgAeKxS5MpIEROaIRHscFqWf+V04CB+A0Kq+OjnTs1fEGHXEs4aeOhXIRovAPe6PfWYKHEwEkVIYWf98OjxnA==", + "dev": true, + "dependencies": { + "ts-toolbelt": "^6.15.1" + } + }, "node_modules/@types/react": { "version": "17.0.47", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.47.tgz", @@ -8173,6 +8183,12 @@ "node": ">=8" } }, + "node_modules/ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "dev": true + }, "node_modules/tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", @@ -10603,6 +10619,15 @@ "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", "dev": true }, + "@types/ramda": { + "version": "0.28.14", + "resolved": "https://registry.npmjs.org/@types/ramda/-/ramda-0.28.14.tgz", + "integrity": "sha512-hLgAeKxS5MpIEROaIRHscFqWf+V04CB+A0Kq+OjnTs1fEGHXEs4aeOhXIRovAPe6PfWYKHEwEkVIYWf98OjxnA==", + "dev": true, + "requires": { + "ts-toolbelt": "^6.15.1" + } + }, "@types/react": { "version": "17.0.47", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.47.tgz", @@ -14689,6 +14714,12 @@ } } }, + "ts-toolbelt": { + "version": "6.15.5", + "resolved": "https://registry.npmjs.org/ts-toolbelt/-/ts-toolbelt-6.15.5.tgz", + "integrity": "sha512-FZIXf1ksVyLcfr7M317jbB67XFJhOO1YqdTcuGaq9q5jLUoTikukZ+98TPjKiP2jC5CgmYdWWYs0s2nLSU0/1A==", + "dev": true + }, "tslib": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", diff --git a/@plotly/dash-generator-test-component-typescript/package.json b/@plotly/dash-generator-test-component-typescript/package.json index 4a4695f2d0..39b0857389 100644 --- a/@plotly/dash-generator-test-component-typescript/package.json +++ b/@plotly/dash-generator-test-component-typescript/package.json @@ -20,6 +20,7 @@ "@babel/preset-env": "^7.19.4", "@babel/preset-react": "^7.18.6", "@types/jest": "^29.2.0", + "@types/ramda": "^0.28.14", "@types/react": "^17.0.39", "babel-loader": "^8.2.5", "jest": "^29.2.1", diff --git a/@plotly/dash-generator-test-component-typescript/src/components/WrappedHTML.tsx b/@plotly/dash-generator-test-component-typescript/src/components/WrappedHTML.tsx index df18d78b4e..1044b70bc6 100644 --- a/@plotly/dash-generator-test-component-typescript/src/components/WrappedHTML.tsx +++ b/@plotly/dash-generator-test-component-typescript/src/components/WrappedHTML.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import {WrappedHTMLProps} from '../props'; +import { WrappedHTMLProps } from '../props'; /** * Component docstring diff --git a/@plotly/dash-generator-test-component-typescript/src/index.ts b/@plotly/dash-generator-test-component-typescript/src/index.ts index d4dacf00c3..93f185ad6e 100644 --- a/@plotly/dash-generator-test-component-typescript/src/index.ts +++ b/@plotly/dash-generator-test-component-typescript/src/index.ts @@ -17,5 +17,5 @@ export { FCComponent, EmptyComponent, MixedComponent, - RequiredChildrenComponent, + RequiredChildrenComponent }; diff --git a/dash/extract-meta.js b/dash/extract-meta.js index 0ed83954bc..431977b873 100755 --- a/dash/extract-meta.js +++ b/dash/extract-meta.js @@ -25,7 +25,7 @@ function help() { console.error('usage: '); console.error( 'extract-meta ^fileIgnorePattern ^forbidden$|^props$|^patterns$' + - ' path/to/component(s) [path/to/more/component(s) ...] > metadata.json' + ' path/to/component(s) [path/to/more/component(s) ...] > metadata.json' ); } @@ -98,7 +98,7 @@ function isReservedPropName(propName) { if (reservedPattern.test(propName)) { process.stderr.write( `\nERROR: "${propName}" matches reserved word ` + - `pattern: ${reservedPattern.toString()}\n` + `pattern: ${reservedPattern.toString()}\n` ); failedBuild = true; } @@ -118,9 +118,15 @@ function checkDocstring(name, value) { function docstringWarning(doc) { checkDocstring(doc.displayName, doc.description); - Object.entries(doc.props || {}).forEach(([name, p]) => - checkDocstring(`${doc.displayName}.${name}`, p.description) - ); + const exportedDisplayName = doc.exportedName || doc.displayName + if (doc && doc.props) { + Object.entries(doc.props || {}).forEach(([name, p]) => + checkDocstring(`${exportedDisplayName}.${name}`, p.description) + ); + } else { + // Soft fail + console.warn(`${exportedDisplayName} does not have any props`) + } } function zipArrays(...arrays) { @@ -160,9 +166,9 @@ function gatherComponents(sources, components = {}) { const extension = path.extname(filepath); if (['.jsx', '.js'].includes(extension)) { components[cleanPath(filepath)] = parseJSX(filepath); - } else if (filepath.endsWith('.tsx')) { + } else if (['.tsx', 'ts'].includes(extension)) { try { - const name = /(.*)\.tsx/.exec(path.basename(filepath))[1]; + const name = /(.*)\.(ts|tsx)/.exec(path.basename(filepath))[1]; filepaths.push(filepath); names.push(name); } catch (err) { @@ -720,6 +726,24 @@ function gatherComponents(sources, components = {}) { } } + const isArrowFunction = ts.isArrowFunction(declaration) + const isClass = ts.isClassDeclaration(declaration); + const isFunction = ts.isFunctionDeclaration(declaration) + + if (!isArrowFunction && !isClass && !isFunction) { + // we do not care about these exports + return null + } + + if (isArrowFunction || isFunction) { + const signature = checker.getSignaturesOfType(type, ts.SignatureKind.Call)[0]; + const returnType = checker.typeToString(signature.getReturnType()); + if (!['Element', 'any', 'null'].includes(returnType)) { + // Not JSX so no need to classifiy as compnent + return null; + } + } + let defaultProps = getDefaultProps(typeSymbol, source); const propsType = getPropsForFunctionalComponent(type); const isContext = !!type.getProperty('isContext'); @@ -764,9 +788,12 @@ function gatherComponents(sources, components = {}) { displayName: name, description, props, - isContext + isContext, + exportedName: rootExp.name }; docstringWarning(doc); + + // todo: Add support for mutiple components in single file components[cleanPath(filepath)] = doc; }); });