From 97d0dc773444b459001cce5c2f35f8e986bb2685 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 5 Feb 2020 19:57:23 +0000 Subject: [PATCH 01/11] Add experimental script to sync API docs from code --- website/package.json | 5 +- .../scripts/sync-api-docs/generateMarkdown.js | 146 ++++++++++++++++++ website/scripts/sync-api-docs/magic.js | 25 +++ website/scripts/sync-api-docs/platforms.js | 22 +++ .../preprocessGeneratedApiDocs.js | 52 +++++++ .../scripts/sync-api-docs/sync-api-docs.js | 78 ++++++++++ website/scripts/sync-api-docs/titleToId.js | 12 ++ website/yarn.lock | 22 +++ 8 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 website/scripts/sync-api-docs/generateMarkdown.js create mode 100644 website/scripts/sync-api-docs/magic.js create mode 100644 website/scripts/sync-api-docs/platforms.js create mode 100644 website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js create mode 100644 website/scripts/sync-api-docs/sync-api-docs.js create mode 100644 website/scripts/sync-api-docs/titleToId.js diff --git a/website/package.json b/website/package.json index 858891ba457..8a5f36a12d5 100644 --- a/website/package.json +++ b/website/package.json @@ -44,14 +44,17 @@ "remarkable": "^2.0.0" }, "devDependencies": { + "comment-parser": "^0.7.2", "front-matter": "^2.3.0", "fs-extra": "^5.0.0", "glob": "^7.1.2", "glob-promise": "^3.3.0", + "he": "^1.2.0", "husky": "^1.3.1", "node-fetch": "^2.3.0", "path": "^0.12.7", "prettier": "1.16.4", - "pretty-quick": "^1.10.0" + "pretty-quick": "^1.10.0", + "tokenize-comment": "^3.0.1" } } diff --git a/website/scripts/sync-api-docs/generateMarkdown.js b/website/scripts/sync-api-docs/generateMarkdown.js new file mode 100644 index 00000000000..2066e132951 --- /dev/null +++ b/website/scripts/sync-api-docs/generateMarkdown.js @@ -0,0 +1,146 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +const he = require('he'); +const magic = require('./magic'); +const {formatPlatformName} = require('./platforms'); + +// Formats an array of rows as a Markdown table +function generateTable(rows) { + const colWidths = new Map(); + for (const row of rows) { + for (const col of Object.keys(row)) { + colWidths.set( + col, + Math.max(colWidths.get(col) || col.length, String(row[col]).length) + ); + } + } + let header = '|', + divider = '|'; + for (const [col, width] of colWidths) { + header += ' ' + col.padEnd(width + 1) + '|'; + divider += ' ' + '-'.repeat(width) + ' ' + '|'; + } + + let result = header + '\n' + divider + '\n'; + for (const row of rows) { + result += '|'; + for (const [col, width] of colWidths) { + result += ' ' + String(row[col] || '').padEnd(width + 1) + '|'; + } + result += '\n'; + } + return result; +} + +// Wraps a string in an inline code block in a way that is safe to include in a +// table cell, by wrapping it as HTML if necessary. +function stringToInlineCodeForTable(str) { + let useHtml = /[`|]/.test(str); + str = str.replace(/\n/g, ' '); + if (useHtml) { + return '' + he.encode(str).replace(/\|/g, '|') + ''; + } + return '`' + str + '`'; +} + +// Formats information about a prop +function generateProp(propName, prop) { + const infoTable = generateTable([ + { + Type: prop.flowType ? maybeLinkifyType(prop.flowType) : '', + Required: prop.required ? 'Yes' : 'No', + ...(prop.rnTags && prop.rnTags.platform + ? {Platform: formatPlatformName(prop.rnTags.platform)} + : {}), + }, + ]); + + return ( + '### `' + + propName + + '`' + + '\n' + + '\n' + + (prop.description ? prop.description + '\n\n' : '') + + infoTable + ); +} + +function maybeLinkifyType(flowType) { + let url, text; + if (Object.hasOwnProperty.call(magic.linkableTypeAliases, flowType.name)) { + ({url, text} = magic.linkableTypeAliases[flowType.name]); + } + if (!text) { + text = stringToInlineCodeForTable(flowType.raw || flowType.name); + } + if (url) { + return `[${text}](${url})`; + } + return text; +} + +function maybeLinkifyTypeName(name) { + let url, text; + if (Object.hasOwnProperty.call(magic.linkableTypeAliases, name)) { + ({url, text} = magic.linkableTypeAliases[name]); + } + if (!text) { + text = stringToInlineCodeForTable(name); + } + if (url) { + return `[${text}](${url})`; + } + return text; +} + +// Formats information about props +function generateProps({props, composes}) { + const title = 'Props'; + + return ( + '## ' + + title + + '\n' + + '\n' + + (composes && composes.length + ? composes + .map(parent => 'Inherits ' + maybeLinkifyTypeName(parent) + '.') + .join('\n\n') + '\n\n' + : '') + + Object.keys(props) + .sort() + .map(function(propName) { + return generateProp(propName, props[propName]); + }) + .join('\n---\n\n') + ); +} + +// Generates a Docusaurus header for a component page +function generateHeader({id, title}) { + return ( + '---' + '\n' + 'id: ' + id + '\n' + 'title: ' + title + '\n' + '---' + '\n' + ); +} + +function generateMarkdown({id, title}, reactAPI) { + const markdownString = + generateHeader({id, title}) + + '\n' + + reactAPI.description + + '\n\n' + + '---\n\n' + + '# Reference\n\n' + + generateProps(reactAPI); + + return markdownString; +} + +module.exports = generateMarkdown; diff --git a/website/scripts/sync-api-docs/magic.js b/website/scripts/sync-api-docs/magic.js new file mode 100644 index 00000000000..fb0d0694be5 --- /dev/null +++ b/website/scripts/sync-api-docs/magic.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// Hard-coded knowledge about the React Native codebase and how to document it, +// beyond what is explicitly encoded in the react-docgen artifact +// (generatedComponentApiDocs.js) + +// Ideally this file should go away. + +module.exports = { + linkableTypeAliases: { + ColorValue: { + text: 'color', + url: 'colors.md', + }, + ViewProps: { + text: 'View Props', + url: 'view.md#props', + }, + }, +}; diff --git a/website/scripts/sync-api-docs/platforms.js b/website/scripts/sync-api-docs/platforms.js new file mode 100644 index 00000000000..462ef947b45 --- /dev/null +++ b/website/scripts/sync-api-docs/platforms.js @@ -0,0 +1,22 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +function formatPlatformName(platform) { + switch (platform.toLowerCase()) { + case 'ios': + return 'iOS'; + case 'android': + return 'Android'; + } + return platform; +} + +module.exports = { + formatPlatformName, +}; diff --git a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js new file mode 100644 index 00000000000..ceee91f0e38 --- /dev/null +++ b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js @@ -0,0 +1,52 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +// Preprocess the react-docgen artifact before rendering it to Markdown. +// This file may end up in the React Native repo, as part of the +// `generate-api-docs` script. + +const parseDocComment = require('comment-parser'); +const tokenizeComment = require('tokenize-comment'); + +function joinDescriptionAndExamples(tokenized) { + let sections = []; + if (tokenized.description) { + sections.push(tokenized.description); + } + for (const {raw} of tokenized.examples) { + sections.push(raw); + } + if (tokenized.footer) { + sections.push(tokenized.footer); + } + return sections.join('\n\n'); +} + +// NOTE: This function mutates `docs`. +function preprocessGeneratedApiDocs(docs) { + for (const doc of docs) { + if (doc.props) { + for (const [key, prop] of Object.entries(doc.props)) { + if (prop.description) { + const descriptionTokenized = tokenizeComment(prop.description); + prop.description = joinDescriptionAndExamples(descriptionTokenized); + prop.rnTags = {}; + const platformTag = descriptionTokenized.tags.find( + ({key}) => key === 'platform' + ); + if (platformTag) { + prop.rnTags.platform = platformTag.value; + } + } + } + } + } +} + +module.exports = preprocessGeneratedApiDocs; diff --git a/website/scripts/sync-api-docs/sync-api-docs.js b/website/scripts/sync-api-docs/sync-api-docs.js new file mode 100644 index 00000000000..f29c5809b9b --- /dev/null +++ b/website/scripts/sync-api-docs/sync-api-docs.js @@ -0,0 +1,78 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +// ***** EXPERIMENTAL ***** +// Updates the API docs from the React Native source code. + +'use strict'; + +const process = require('process'); +const fetch = require('node-fetch'); +const fs = require('fs-extra'); +const path = require('path'); + +const preprocessGeneratedApiDocs = require('./preprocessGeneratedApiDocs'); +const generateMarkdown = require('./generateMarkdown'); +const titleToId = require('./titleToId'); + +const DOCS_ROOT_DIR = path.resolve(__dirname, '..', '..', '..', 'docs'); + +const API_DOCS_ARTIFACT_URL = + 'https://raw.githubusercontent.com/facebook/react-native/master/docs/generatedComponentApiDocs.js'; +const API_DOCS_ARTIFACT_LOCAL_PATH = path.join( + __dirname, + 'generatedComponentApiDocs.js' +); + +async function downloadApiDocs(urlOrPath) { + if (await fs.exists(urlOrPath)) { + await fs.copyFile(urlOrPath, API_DOCS_ARTIFACT_LOCAL_PATH); + return; + } + const res = await fetch(API_DOCS_ARTIFACT_URL); + if (!res.ok) { + throw new Error(res.statusText); + } + const apiDocsJs = await res.text(); + await fs.writeFile(API_DOCS_ARTIFACT_LOCAL_PATH, apiDocsJs, 'utf8'); +} + +async function generateApiDocs() { + const apiDocs = require(API_DOCS_ARTIFACT_LOCAL_PATH); + preprocessGeneratedApiDocs(apiDocs); + await Promise.all( + apiDocs.map(async (page, pageIndex) => { + if (!page.displayName) { + console.log( + 'react-docgen data at index ' + + pageIndex + + ' was malformed, skipping.' + ); + return; + } + const id = titleToId(page.displayName); + const pageMarkdown = generateMarkdown( + {title: page.displayName, id: id}, + page + ); + const outFile = path.join(DOCS_ROOT_DIR, id + '.md'); + console.log('Generated ' + outFile); + await fs.writeFile(outFile, pageMarkdown, 'utf8'); + }) + ); +} + +async function syncApiDocs(urlOrPath) { + await downloadApiDocs(urlOrPath || API_DOCS_ARTIFACT_URL); + await generateApiDocs(); +} + +async function main(args) { + await syncApiDocs(args[0]); +} + +main(process.argv.slice(2)); diff --git a/website/scripts/sync-api-docs/titleToId.js b/website/scripts/sync-api-docs/titleToId.js new file mode 100644 index 00000000000..254bc16e335 --- /dev/null +++ b/website/scripts/sync-api-docs/titleToId.js @@ -0,0 +1,12 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +function titleToId(title) { + return title.toLowerCase().replace(/[^a-z]+/g, '-'); +} + +module.exports = titleToId; diff --git a/website/yarn.lock b/website/yarn.lock index fa1392fc890..b51745ccb94 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -1749,6 +1749,11 @@ commander@~2.8.1: dependencies: graceful-readlink ">= 1.0.0" +comment-parser@^0.7.2: + version "0.7.2" + resolved "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.2.tgz#baf6d99b42038678b81096f15b630d18142f4b8a" + integrity sha512-4Rjb1FnxtOcv9qsfuaNuVsmmVn4ooVoBHzYfyKteiXwIU84PClyGA5jASoFMwPV93+FPh9spwueXauxFJZkGAg== + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3621,6 +3626,11 @@ hastscript@^5.0.0: property-information "^5.0.1" space-separated-tokens "^1.0.0" +he@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + hex-color-regex@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" @@ -6988,6 +6998,11 @@ sliced@^1.0.1: resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= +snapdragon-lexer@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/snapdragon-lexer/-/snapdragon-lexer-4.0.0.tgz#86e2fb96931e12060839000995b00d3551658292" + integrity sha512-ddXT9cpKI0PUrs3xeoQVKEjequr0UyW9w281dzu8RTgWtqdIGZSvoWDsnIMPCc8Fupk4dByatSodhwYEGgrdSg== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -7586,6 +7601,13 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== +tokenize-comment@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/tokenize-comment/-/tokenize-comment-3.0.1.tgz#deeffcd57714e6097182a39e032e4ff861c60a1a" + integrity sha512-of5j9zCooBZxcE1EQ9PCjXcuFUPU/h8GxhWqF86cQ3muHQQreIWgY40ZNfuPQUSXyTa6i7oAWqWX4QivzZh26Q== + dependencies: + snapdragon-lexer "^4.0.0" + toml@^2.3.2: version "2.3.6" resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.6.tgz#25b0866483a9722474895559088b436fd11f861b" From 01111875b840f12e891e2ccda2f4e0f6794cf5d7 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Thu, 6 Feb 2020 13:04:26 +0000 Subject: [PATCH 02/11] sync-api-docs: Support methods --- .../scripts/sync-api-docs/generateMarkdown.js | 54 +++++++++++++++++-- .../preprocessGeneratedApiDocs.js | 31 ++++++----- 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/website/scripts/sync-api-docs/generateMarkdown.js b/website/scripts/sync-api-docs/generateMarkdown.js index 2066e132951..46c230db7bf 100644 --- a/website/scripts/sync-api-docs/generateMarkdown.js +++ b/website/scripts/sync-api-docs/generateMarkdown.js @@ -20,6 +20,9 @@ function generateTable(rows) { ); } } + if (!colWidths.size) { + return ''; + } let header = '|', divider = '|'; for (const [col, width] of colWidths) { @@ -72,6 +75,27 @@ function generateProp(propName, prop) { ); } +// Formats information about a prop +function generateMethod(method) { + const infoTable = generateTable([ + { + ...(method.rnTags && method.rnTags.platform + ? {Platform: formatPlatformName(method.rnTags.platform)} + : {}), + }, + ]); + + return ( + '### `' + + method.name + + '`' + + '\n' + + '\n' + + (method.description ? method.description + '\n\n' : '') + + infoTable + ).trim(); +} + function maybeLinkifyType(flowType) { let url, text; if (Object.hasOwnProperty.call(magic.linkableTypeAliases, flowType.name)) { @@ -102,11 +126,12 @@ function maybeLinkifyTypeName(name) { // Formats information about props function generateProps({props, composes}) { - const title = 'Props'; + if (!props || !Object.keys(props).length) { + return ''; + } return ( - '## ' + - title + + '## Props' + '\n' + '\n' + (composes && composes.length @@ -119,7 +144,25 @@ function generateProps({props, composes}) { .map(function(propName) { return generateProp(propName, props[propName]); }) - .join('\n---\n\n') + .join('\n\n---\n\n') + ); +} + +function generateMethods({methods}) { + if (!methods || !methods.length) { + return ''; + } + + return ( + '## Methods' + + '\n' + + '\n' + + [...methods] + .sort() + .map(function(method) { + return generateMethod(method); + }) + .join('\n\n---\n\n') ); } @@ -138,7 +181,8 @@ function generateMarkdown({id, title}, reactAPI) { '\n\n' + '---\n\n' + '# Reference\n\n' + - generateProps(reactAPI); + generateProps(reactAPI) + + generateMethods(reactAPI); return markdownString; } diff --git a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js index ceee91f0e38..2442489f608 100644 --- a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js +++ b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js @@ -28,22 +28,29 @@ function joinDescriptionAndExamples(tokenized) { return sections.join('\n\n'); } +function preprocessTagsInDescription(obj) { + if (obj && obj.description) { + const descriptionTokenized = tokenizeComment(obj.description); + obj.description = joinDescriptionAndExamples(descriptionTokenized); + obj.rnTags = {}; + const platformTag = descriptionTokenized.tags.find( + ({key}) => key === 'platform' + ); + if (platformTag) { + obj.rnTags.platform = platformTag.value; + } + } +} + // NOTE: This function mutates `docs`. function preprocessGeneratedApiDocs(docs) { for (const doc of docs) { if (doc.props) { - for (const [key, prop] of Object.entries(doc.props)) { - if (prop.description) { - const descriptionTokenized = tokenizeComment(prop.description); - prop.description = joinDescriptionAndExamples(descriptionTokenized); - prop.rnTags = {}; - const platformTag = descriptionTokenized.tags.find( - ({key}) => key === 'platform' - ); - if (platformTag) { - prop.rnTags.platform = platformTag.value; - } - } + for (const prop of Object.values(doc.props)) { + preprocessTagsInDescription(prop); + } + for (const prop of doc.methods) { + preprocessTagsInDescription(prop); } } } From f6b4bc07cd44a450845fedb543f8041917c79df8 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Tue, 11 Feb 2020 16:22:10 +0000 Subject: [PATCH 03/11] sync-api-docs: add docs extraction script --- website/package.json | 1 + .../sync-api-docs/extractDocsFromRN.js | 62 ++++++ .../preprocessGeneratedApiDocs.js | 8 +- .../scripts/sync-api-docs/sync-api-docs.js | 51 ++--- website/yarn.lock | 180 +++++++++++++++++- 5 files changed, 256 insertions(+), 46 deletions(-) create mode 100644 website/scripts/sync-api-docs/extractDocsFromRN.js diff --git a/website/package.json b/website/package.json index 8a5f36a12d5..76764c76b9c 100644 --- a/website/package.json +++ b/website/package.json @@ -44,6 +44,7 @@ "remarkable": "^2.0.0" }, "devDependencies": { + "@motiz88/react-native-docgen": "^0.0.0", "comment-parser": "^0.7.2", "front-matter": "^2.3.0", "fs-extra": "^5.0.0", diff --git a/website/scripts/sync-api-docs/extractDocsFromRN.js b/website/scripts/sync-api-docs/extractDocsFromRN.js new file mode 100644 index 00000000000..bc4310dd0de --- /dev/null +++ b/website/scripts/sync-api-docs/extractDocsFromRN.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +'use strict'; + +const fs = require('fs-extra'); +const glob = require('glob'); +const path = require('path'); +const reactDocs = require('@motiz88/react-native-docgen'); + +const GENERATE_ANNOTATION = '@' + 'generate-docs'; + +module.exports = extractDocsFromRN; + +async function extractDocsFromRN(rnRoot) { + // TODO: make implementation async + + const allComponentFiles = glob.sync( + path.join(rnRoot, '/Libraries/{Components,Image,}/**/*.js'), + { + nodir: true, + } + ); + + const docs = []; + + for (const file of allComponentFiles) { + const contents = fs.readFileSync(file, {encoding: 'utf-8'}); + if (!contents.includes(GENERATE_ANNOTATION)) { + continue; + } + + console.log(file); + + const result = reactDocs.parse( + contents, + reactDocs.resolver.findExportedComponentDefinition, + reactDocs.defaultHandlers + ); + + docs.push({ + file, + component: cleanComponentResult(result), + }); + } + + // Make sure output is JSON-safe + return JSON.parse(JSON.stringify(docs)); +} + +function cleanComponentResult(component) { + return { + ...component, + methods: component.methods.filter(method => !method.name.startsWith('_')), + }; +} diff --git a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js index 2442489f608..9f13a6b05b5 100644 --- a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js +++ b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js @@ -44,12 +44,12 @@ function preprocessTagsInDescription(obj) { // NOTE: This function mutates `docs`. function preprocessGeneratedApiDocs(docs) { - for (const doc of docs) { - if (doc.props) { - for (const prop of Object.values(doc.props)) { + for (const {component} of docs) { + if (component.props) { + for (const prop of Object.values(component.props)) { preprocessTagsInDescription(prop); } - for (const prop of doc.methods) { + for (const prop of component.methods) { preprocessTagsInDescription(prop); } } diff --git a/website/scripts/sync-api-docs/sync-api-docs.js b/website/scripts/sync-api-docs/sync-api-docs.js index f29c5809b9b..ec3a4dae50c 100644 --- a/website/scripts/sync-api-docs/sync-api-docs.js +++ b/website/scripts/sync-api-docs/sync-api-docs.js @@ -11,68 +11,41 @@ 'use strict'; const process = require('process'); -const fetch = require('node-fetch'); const fs = require('fs-extra'); const path = require('path'); +const extractDocsFromRN = require('./extractDocsFromRN'); const preprocessGeneratedApiDocs = require('./preprocessGeneratedApiDocs'); const generateMarkdown = require('./generateMarkdown'); const titleToId = require('./titleToId'); const DOCS_ROOT_DIR = path.resolve(__dirname, '..', '..', '..', 'docs'); -const API_DOCS_ARTIFACT_URL = - 'https://raw.githubusercontent.com/facebook/react-native/master/docs/generatedComponentApiDocs.js'; -const API_DOCS_ARTIFACT_LOCAL_PATH = path.join( - __dirname, - 'generatedComponentApiDocs.js' -); - -async function downloadApiDocs(urlOrPath) { - if (await fs.exists(urlOrPath)) { - await fs.copyFile(urlOrPath, API_DOCS_ARTIFACT_LOCAL_PATH); - return; - } - const res = await fetch(API_DOCS_ARTIFACT_URL); - if (!res.ok) { - throw new Error(res.statusText); - } - const apiDocsJs = await res.text(); - await fs.writeFile(API_DOCS_ARTIFACT_LOCAL_PATH, apiDocsJs, 'utf8'); -} - -async function generateApiDocs() { - const apiDocs = require(API_DOCS_ARTIFACT_LOCAL_PATH); +async function generateApiDocs(rnPath) { + const apiDocs = await extractDocsFromRN(rnPath); preprocessGeneratedApiDocs(apiDocs); await Promise.all( - apiDocs.map(async (page, pageIndex) => { - if (!page.displayName) { + apiDocs.map(async ({component, file}, index) => { + if (!component.displayName) { console.log( - 'react-docgen data at index ' + - pageIndex + - ' was malformed, skipping.' + `react-docgen data for ${path.basename(file)} was malformed, skipping` ); return; } - const id = titleToId(page.displayName); - const pageMarkdown = generateMarkdown( - {title: page.displayName, id: id}, - page + const id = titleToId(component.displayName); + const componentMarkdown = generateMarkdown( + {title: component.displayName, id: id}, + component ); const outFile = path.join(DOCS_ROOT_DIR, id + '.md'); console.log('Generated ' + outFile); - await fs.writeFile(outFile, pageMarkdown, 'utf8'); + await fs.writeFile(outFile, componentMarkdown, 'utf8'); }) ); } -async function syncApiDocs(urlOrPath) { - await downloadApiDocs(urlOrPath || API_DOCS_ARTIFACT_URL); - await generateApiDocs(); -} - async function main(args) { - await syncApiDocs(args[0]); + await generateApiDocs(args[0]); } main(process.argv.slice(2)); diff --git a/website/yarn.lock b/website/yarn.lock index b51745ccb94..0fd2d0135fd 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -9,6 +9,13 @@ dependencies: "@babel/highlight" "^7.0.0" +"@babel/code-frame@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" + integrity sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g== + dependencies: + "@babel/highlight" "^7.8.3" + "@babel/core@^7.7.4": version "7.7.5" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.7.5.tgz#ae1323cd035b5160293307f50647e83f8ba62f7e" @@ -29,6 +36,27 @@ semver "^5.4.1" source-map "^0.5.0" +"@babel/core@^7.7.5": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.8.4.tgz#d496799e5c12195b3602d0fddd77294e3e38e80e" + integrity sha512-0LiLrB2PwrVI+a2/IEskBopDYSd8BCb3rOvH7D5tzoWd696TBEduBvuLVm4Nx6rltrLZqvI3MCalB2K2aVzQjA== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helpers" "^7.8.4" + "@babel/parser" "^7.8.4" + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.1" + json5 "^2.1.0" + lodash "^4.17.13" + resolve "^1.3.2" + semver "^5.4.1" + source-map "^0.5.0" + "@babel/generator@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.7.4.tgz#db651e2840ca9aa66f327dcec1dc5f5fa9611369" @@ -39,6 +67,16 @@ lodash "^4.17.13" source-map "^0.5.0" +"@babel/generator@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.8.4.tgz#35bbc74486956fe4251829f9f6c48330e8d0985e" + integrity sha512-PwhclGdRpNAf3IxZb0YVuITPZmmrXz9zf6fH8lT4XbrmfQKr6ryBzhv593P5C6poJRciFCL/eHGW2NuGrgEyxA== + dependencies: + "@babel/types" "^7.8.3" + jsesc "^2.5.1" + lodash "^4.17.13" + source-map "^0.5.0" + "@babel/helper-annotate-as-pure@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.7.4.tgz#bb3faf1e74b74bd547e867e48f551fa6b098b6ce" @@ -117,6 +155,15 @@ "@babel/template" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helper-function-name@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.8.3.tgz#eeeb665a01b1f11068e9fb86ad56a1cb1a824cca" + integrity sha512-BCxgX1BC2hD/oBlIFUgOCQDOPV8nSINxCwM3o93xP4P9Fq6aV5sgv2cOOITDMtCfQ+3PvHp3l689XZvAM9QyOA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/helper-get-function-arity@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.7.4.tgz#cb46348d2f8808e632f0ab048172130e636005f0" @@ -124,6 +171,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-get-function-arity@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" + integrity sha512-FVDR+Gd9iLjUMY1fzE2SR0IuaJToR4RkCDARVfsBBPSP53GEqSFjD8gNyxg246VUyc/ALRxFaAK8rVG7UT7xRA== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-hoist-variables@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.7.4.tgz#612384e3d823fdfaaf9fce31550fe5d4db0f3d12" @@ -212,6 +266,13 @@ dependencies: "@babel/types" "^7.7.4" +"@babel/helper-split-export-declaration@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.8.3.tgz#31a9f30070f91368a7182cf05f831781065fc7a9" + integrity sha512-3x3yOeyBhW851hroze7ElzdkeRXQYQbFIb7gLK1WQYsw2GWDay5gAJNw1sWJ0VFP6z5J1whqeXH/WCdCjZv6dA== + dependencies: + "@babel/types" "^7.8.3" + "@babel/helper-wrap-function@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.7.4.tgz#37ab7fed5150e22d9d7266e830072c0cdd8baace" @@ -231,6 +292,15 @@ "@babel/traverse" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/helpers@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.8.4.tgz#754eb3ee727c165e0a240d6c207de7c455f36f73" + integrity sha512-VPbe7wcQ4chu4TDQjimHv/5tj73qz88o12EPkO2ValS2QiQS/1F2SsjyIGNnAD0vF/nZS6Cf9i+vW6HIlnaR8w== + dependencies: + "@babel/template" "^7.8.3" + "@babel/traverse" "^7.8.4" + "@babel/types" "^7.8.3" + "@babel/highlight@^7.0.0": version "7.5.0" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" @@ -240,11 +310,25 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/highlight@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz#28f173d04223eaaa59bc1d439a3836e6d1265797" + integrity sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg== + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^4.0.0" + "@babel/parser@^7.7.4", "@babel/parser@^7.7.5": version "7.7.5" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.7.5.tgz#cbf45321619ac12d83363fcf9c94bb67fa646d71" integrity sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig== +"@babel/parser@^7.8.3", "@babel/parser@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.8.4.tgz#d1dbe64691d60358a974295fa53da074dd2ce8e8" + integrity sha512-0fKu/QqildpXmPVaRBoXOlyBb3MC+J0A66x97qEfLOMkn3u6nfY5esWogQwi/K0BjASYy4DbnsEWnpNL6qT5Mw== + "@babel/plugin-proposal-async-generator-functions@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.7.4.tgz#0351c5ac0a9e927845fffd5b82af476947b7ce6d" @@ -714,6 +798,13 @@ pirates "^4.0.0" source-map-support "^0.5.16" +"@babel/runtime@^7.7.6": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.8.4.tgz#d79f5a2040f7caa24d53e563aad49cbc05581308" + integrity sha512-neAp3zt80trRVBI1x0azq6c57aNBqYZH8KhMm3TaB7wEI5Q4A2SHfBHE8w9gOhI/lrqxtEbXZgQIrHP+wvSGwQ== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/template@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.7.4.tgz#428a7d9eecffe27deac0a98e23bf8e3675d2a77b" @@ -723,6 +814,15 @@ "@babel/parser" "^7.7.4" "@babel/types" "^7.7.4" +"@babel/template@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.8.3.tgz#e02ad04fe262a657809327f578056ca15fd4d1b8" + integrity sha512-04m87AcQgAFdvuoyiQ2kgELr2tV8B4fP/xJAVUL3Yb3bkNdMedD3d0rlSQr3PegP0cms3eHjl1F7PWlvWbU8FQ== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/parser" "^7.8.3" + "@babel/types" "^7.8.3" + "@babel/traverse@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.7.4.tgz#9c1e7c60fb679fe4fcfaa42500833333c2058558" @@ -738,6 +838,21 @@ globals "^11.1.0" lodash "^4.17.13" +"@babel/traverse@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.8.4.tgz#f0845822365f9d5b0e312ed3959d3f827f869e3c" + integrity sha512-NGLJPZwnVEyBPLI+bl9y9aSnxMhsKz42so7ApAv9D+b4vAFPpY013FTS9LdKxcABoIYFU52HcYga1pPlx454mg== + dependencies: + "@babel/code-frame" "^7.8.3" + "@babel/generator" "^7.8.4" + "@babel/helper-function-name" "^7.8.3" + "@babel/helper-split-export-declaration" "^7.8.3" + "@babel/parser" "^7.8.4" + "@babel/types" "^7.8.3" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.13" + "@babel/types@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.7.4.tgz#516570d539e44ddf308c07569c258ff94fde9193" @@ -747,6 +862,29 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.8.3.tgz#5a383dffa5416db1b73dedffd311ffd0788fb31c" + integrity sha512-jBD+G8+LWpMBBWvVcdr4QysjUE4mU/syrhN17o1u3gx0/WzJB1kwiVZAXRtWbsIPOwW8pF/YJV5+nmetPzepXg== + dependencies: + esutils "^2.0.2" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + +"@motiz88/react-native-docgen@^0.0.0": + version "0.0.0" + resolved "https://registry.npmjs.org/@motiz88/react-native-docgen/-/react-native-docgen-0.0.0.tgz#62b75b7e045e45150c612c8bd08e39c9cd1a530d" + integrity sha512-lL71PvgE7L8jpE+j70/s/aH14gc2AaWeK2gAGNPa+DVs3Sx6DVBk/CszkJSfdK/t7HaeaTIuYdBESj4F600kMg== + dependencies: + "@babel/core" "^7.7.5" + "@babel/runtime" "^7.7.6" + ast-types "^0.13.2" + commander "^2.19.0" + doctrine "^3.0.0" + neo-async "^2.6.1" + node-dir "^0.1.10" + strip-indent "^3.0.0" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -1033,6 +1171,11 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= +ast-types@^0.13.2: + version "0.13.2" + resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" + integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== + async-each@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" @@ -1732,7 +1875,7 @@ comma-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.7.tgz#419cd7fb3258b1ed838dc0953167a25e152f5b59" integrity sha512-Jrx3xsP4pPv4AwJUDWY9wOXGtwPXARej6Xd99h4TUGotmf8APuquKMpK+dnD3UgyxK7OEWaisjZz+3b5jtL6xQ== -commander@^2.15.1, commander@~2.20.3: +commander@^2.15.1, commander@^2.19.0, commander@~2.20.3: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== @@ -2303,6 +2446,13 @@ dir-glob@2.0.0: arrify "^1.0.1" path-type "^3.0.0" +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + docusaurus@1.14.4: version "1.14.4" resolved "https://registry.yarnpkg.com/docusaurus/-/docusaurus-1.14.4.tgz#1ef3ebe8c2aaaf1dec6c2e0e177e83be78aeaca3" @@ -3135,6 +3285,11 @@ gaze@^1.1.3: dependencies: globule "^1.0.0" +gensync@^1.0.0-beta.1: + version "1.0.0-beta.1" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== + get-proxy@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/get-proxy/-/get-proxy-2.1.0.tgz#349f2b4d91d44c4d4d4e9cba2ad90143fac5ef93" @@ -4983,7 +5138,12 @@ mimic-response@^1.0.0, mimic-response@^1.0.1: resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== -minimatch@3.0.4, minimatch@^3.0.4, minimatch@~3.0.2: +min-indent@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256" + integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY= + +minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4, minimatch@~3.0.2: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -5114,7 +5274,7 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== -neo-async@^2.6.0: +neo-async@^2.6.0, neo-async@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== @@ -5152,6 +5312,13 @@ nlcst-to-string@^2.0.0: resolved "https://registry.yarnpkg.com/nlcst-to-string/-/nlcst-to-string-2.0.3.tgz#b7913bb1305263b0561a86de68e179f17f7febe3" integrity sha512-OY2QhGdf6jpYfHqS4vJwqF7aIBZkaMjMUkcHcskMPitvXLuYNGdQvgVWI/5yKwkmIdmhft3ounSJv+Re2yydng== +node-dir@^0.1.10: + version "0.1.17" + resolved "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" + integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= + dependencies: + minimatch "^3.0.2" + node-fetch@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.3.0.tgz#1a1d940bbfb916a1d3e0219f037e89e71f8c5fa5" @@ -7363,6 +7530,13 @@ strip-indent@^2.0.0: resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" From d73b913ac591ded131f8969a5a9234d6e0c6b010 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Tue, 11 Feb 2020 23:32:59 +0000 Subject: [PATCH 04/11] sync-api-docs: Improvements to method docs --- .../scripts/sync-api-docs/generateMarkdown.js | 59 ++++++++++++++++--- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/website/scripts/sync-api-docs/generateMarkdown.js b/website/scripts/sync-api-docs/generateMarkdown.js index 46c230db7bf..8db2247d74b 100644 --- a/website/scripts/sync-api-docs/generateMarkdown.js +++ b/website/scripts/sync-api-docs/generateMarkdown.js @@ -76,7 +76,7 @@ function generateProp(propName, prop) { } // Formats information about a prop -function generateMethod(method) { +function generateMethod(method, component) { const infoTable = generateTable([ { ...(method.rnTags && method.rnTags.platform @@ -88,14 +88,54 @@ function generateMethod(method) { return ( '### `' + method.name + - '`' + + '()`' + '\n' + '\n' + + generateMethodSignatureBlock(method, component) + (method.description ? method.description + '\n\n' : '') + + generateMethodSignatureTable(method, component) + infoTable ).trim(); } +function lowerFirst(s) { + return s[0].toLowerCase() + s.slice(1); +} + +function generateMethodSignatureBlock(method, component) { + return ( + '```jsx\n' + + (method.modifiers.includes('static') + ? component.displayName + '.' + : lowerFirst(component.displayName + '.')) + + method.name + + '(' + + method.params + .map(param => (param.optional ? `[${param.name}]` : param.name)) + .join(', ') + + ');' + + '\n' + + '```\n\n' + ); +} + +function generateMethodSignatureTable(method, component) { + if (!method.params.length) { + return ''; + } + return ( + '**Parameters:**\n\n' + + generateTable( + method.params.map(param => ({ + Name: param.name, + Type: param.type ? maybeLinkifyType(param.type) : '', + Required: param.optional ? 'No' : 'Yes', + Description: param.description, + })) + ) + ); +} + function maybeLinkifyType(flowType) { let url, text; if (Object.hasOwnProperty.call(magic.linkableTypeAliases, flowType.name)) { @@ -148,7 +188,8 @@ function generateProps({props, composes}) { ); } -function generateMethods({methods}) { +function generateMethods(component) { + const {methods} = component; if (!methods || !methods.length) { return ''; } @@ -160,7 +201,7 @@ function generateMethods({methods}) { [...methods] .sort() .map(function(method) { - return generateMethod(method); + return generateMethod(method, component); }) .join('\n\n---\n\n') ); @@ -173,18 +214,18 @@ function generateHeader({id, title}) { ); } -function generateMarkdown({id, title}, reactAPI) { +function generateMarkdown({id, title}, component) { const markdownString = generateHeader({id, title}) + '\n' + - reactAPI.description + + component.description + '\n\n' + '---\n\n' + '# Reference\n\n' + - generateProps(reactAPI) + - generateMethods(reactAPI); + generateProps(component) + + generateMethods(component); - return markdownString; + return markdownString.replace(/\n{3,}/g, '\n\n'); } module.exports = generateMarkdown; From 13837683f232c3ca0c0a082416c89daf5fde5d14 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 00:35:37 +0000 Subject: [PATCH 05/11] sync-api-docs: update docgen fork to 0.0.1 --- website/package.json | 2 +- website/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/website/package.json b/website/package.json index 76764c76b9c..393c0086e47 100644 --- a/website/package.json +++ b/website/package.json @@ -44,7 +44,7 @@ "remarkable": "^2.0.0" }, "devDependencies": { - "@motiz88/react-native-docgen": "^0.0.0", + "@motiz88/react-native-docgen": "0.0.1", "comment-parser": "^0.7.2", "front-matter": "^2.3.0", "fs-extra": "^5.0.0", diff --git a/website/yarn.lock b/website/yarn.lock index 0fd2d0135fd..0a3930c3953 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -871,10 +871,10 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@motiz88/react-native-docgen@^0.0.0": - version "0.0.0" - resolved "https://registry.npmjs.org/@motiz88/react-native-docgen/-/react-native-docgen-0.0.0.tgz#62b75b7e045e45150c612c8bd08e39c9cd1a530d" - integrity sha512-lL71PvgE7L8jpE+j70/s/aH14gc2AaWeK2gAGNPa+DVs3Sx6DVBk/CszkJSfdK/t7HaeaTIuYdBESj4F600kMg== +"@motiz88/react-native-docgen@0.0.1": + version "0.0.1" + resolved "https://registry.npmjs.org/@motiz88/react-native-docgen/-/react-native-docgen-0.0.1.tgz#841352fd6677b1e0ea690717ab533d65f5e5f9d6" + integrity sha512-ywgrygYfst18SZz2Aw73MJhZb6gXDrdPhJepUJShCKzA5ati4aIpLQ1QpW1GHVlZw0xqxWp/3wJIbvUgQn3t2A== dependencies: "@babel/core" "^7.7.5" "@babel/runtime" "^7.7.6" From f9610da52f61035c9dd42953198c7cd7d8a2bbe6 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 11:35:51 +0000 Subject: [PATCH 06/11] sync-api-docs: pass filename into react-docgen --- website/scripts/sync-api-docs/extractDocsFromRN.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/scripts/sync-api-docs/extractDocsFromRN.js b/website/scripts/sync-api-docs/extractDocsFromRN.js index bc4310dd0de..360c79542fb 100644 --- a/website/scripts/sync-api-docs/extractDocsFromRN.js +++ b/website/scripts/sync-api-docs/extractDocsFromRN.js @@ -25,6 +25,7 @@ async function extractDocsFromRN(rnRoot) { path.join(rnRoot, '/Libraries/{Components,Image,}/**/*.js'), { nodir: true, + absolute: true, } ); @@ -41,7 +42,8 @@ async function extractDocsFromRN(rnRoot) { const result = reactDocs.parse( contents, reactDocs.resolver.findExportedComponentDefinition, - reactDocs.defaultHandlers + reactDocs.defaultHandlers, + {filename: file} ); docs.push({ From 55a49ac381d6777a62a317606e4916462c1db43f Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 11:36:25 +0000 Subject: [PATCH 07/11] sync-api-docs: don't use PropTypes composition handler We have Flow types for this. --- website/scripts/sync-api-docs/extractDocsFromRN.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/scripts/sync-api-docs/extractDocsFromRN.js b/website/scripts/sync-api-docs/extractDocsFromRN.js index 360c79542fb..8e9c422b73a 100644 --- a/website/scripts/sync-api-docs/extractDocsFromRN.js +++ b/website/scripts/sync-api-docs/extractDocsFromRN.js @@ -42,7 +42,9 @@ async function extractDocsFromRN(rnRoot) { const result = reactDocs.parse( contents, reactDocs.resolver.findExportedComponentDefinition, - reactDocs.defaultHandlers, + reactDocs.defaultHandlers.filter( + handler => handler !== reactDocs.handlers.propTypeCompositionHandler + ), {filename: file} ); From 7c0bb49cf06ae325f26f9f17b6250b7df793ed0c Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 14:19:45 +0000 Subject: [PATCH 08/11] sync-api-docs: remove unused comment-parser --- website/package.json | 7 +++---- .../scripts/sync-api-docs/preprocessGeneratedApiDocs.js | 1 - website/yarn.lock | 5 ----- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/website/package.json b/website/package.json index 393c0086e47..204f82acd17 100644 --- a/website/package.json +++ b/website/package.json @@ -41,11 +41,11 @@ "alex": "^8.0.0", "docusaurus": "1.14.4", "highlight.js": "^9.15.10", - "remarkable": "^2.0.0" + "remarkable": "^2.0.0", + "tokenize-comment": "^3.0.1" }, "devDependencies": { "@motiz88/react-native-docgen": "0.0.1", - "comment-parser": "^0.7.2", "front-matter": "^2.3.0", "fs-extra": "^5.0.0", "glob": "^7.1.2", @@ -55,7 +55,6 @@ "node-fetch": "^2.3.0", "path": "^0.12.7", "prettier": "1.16.4", - "pretty-quick": "^1.10.0", - "tokenize-comment": "^3.0.1" + "pretty-quick": "^1.10.0" } } diff --git a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js index 9f13a6b05b5..3732e45fa0e 100644 --- a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js +++ b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js @@ -11,7 +11,6 @@ // This file may end up in the React Native repo, as part of the // `generate-api-docs` script. -const parseDocComment = require('comment-parser'); const tokenizeComment = require('tokenize-comment'); function joinDescriptionAndExamples(tokenized) { diff --git a/website/yarn.lock b/website/yarn.lock index 0a3930c3953..25eee9eab50 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -1892,11 +1892,6 @@ commander@~2.8.1: dependencies: graceful-readlink ">= 1.0.0" -comment-parser@^0.7.2: - version "0.7.2" - resolved "https://registry.npmjs.org/comment-parser/-/comment-parser-0.7.2.tgz#baf6d99b42038678b81096f15b630d18142f4b8a" - integrity sha512-4Rjb1FnxtOcv9qsfuaNuVsmmVn4ooVoBHzYfyKteiXwIU84PClyGA5jASoFMwPV93+FPh9spwueXauxFJZkGAg== - commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" From 3ac32632ed784d3f97f077a09e290d52e22fee34 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 14:21:52 +0000 Subject: [PATCH 09/11] sync-api-docs: bump docgen fork to 0.0.2 --- website/package.json | 2 +- website/yarn.lock | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/website/package.json b/website/package.json index 204f82acd17..60befa21d37 100644 --- a/website/package.json +++ b/website/package.json @@ -45,7 +45,7 @@ "tokenize-comment": "^3.0.1" }, "devDependencies": { - "@motiz88/react-native-docgen": "0.0.1", + "@motiz88/react-native-docgen": "0.0.2", "front-matter": "^2.3.0", "fs-extra": "^5.0.0", "glob": "^7.1.2", diff --git a/website/yarn.lock b/website/yarn.lock index 25eee9eab50..7c23e615715 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -871,18 +871,24 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" -"@motiz88/react-native-docgen@0.0.1": - version "0.0.1" - resolved "https://registry.npmjs.org/@motiz88/react-native-docgen/-/react-native-docgen-0.0.1.tgz#841352fd6677b1e0ea690717ab533d65f5e5f9d6" - integrity sha512-ywgrygYfst18SZz2Aw73MJhZb6gXDrdPhJepUJShCKzA5ati4aIpLQ1QpW1GHVlZw0xqxWp/3wJIbvUgQn3t2A== +"@motiz88/ast-types@^0.13.3": + version "0.13.3" + resolved "https://registry.npmjs.org/@motiz88/ast-types/-/ast-types-0.13.3.tgz#0630c411325b145a7ad5632adf8d8d40d28e07d0" + integrity sha512-OzqnfkQv2JjhRqZ0BeuJRuU6rx47LqBYeirDOUfb5C5fFFtpOh0AHTlQRifG4a5kir/OwjWW+x4HlViYxVko/Q== + +"@motiz88/react-native-docgen@0.0.2": + version "0.0.2" + resolved "https://registry.npmjs.org/@motiz88/react-native-docgen/-/react-native-docgen-0.0.2.tgz#0da1170dc601bddb28e255194b480e9dc6e7acd5" + integrity sha512-5knOlVOnHDUZRx6KCE94yGJYuevnckb+Q/+TL2mG9SEqAlDEh/4bMRyZMxcaoKOi/MIj1ZUQlbXVYoUlDAW5Tw== dependencies: "@babel/core" "^7.7.5" "@babel/runtime" "^7.7.6" - ast-types "^0.13.2" + "@motiz88/ast-types" "^0.13.3" commander "^2.19.0" doctrine "^3.0.0" neo-async "^2.6.1" node-dir "^0.1.10" + resolve "^1.10.1" strip-indent "^3.0.0" "@mrmlnc/readdir-enhanced@^2.2.1": @@ -1171,11 +1177,6 @@ assign-symbols@^1.0.0: resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= -ast-types@^0.13.2: - version "0.13.2" - resolved "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" - integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== - async-each@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" @@ -6857,6 +6858,13 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.3.2: dependencies: path-parse "^1.0.6" +resolve@^1.10.1: + version "1.15.1" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" + integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== + dependencies: + path-parse "^1.0.6" + responselike@1.0.2, responselike@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" From 2c0501a9a107a6ad6f22559b2f1d535039ba7b15 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 16:15:15 +0000 Subject: [PATCH 10/11] sync-api-docs: roll our own naive jsdoc tokenizer I'm sure this will end well. --- website/package.json | 3 +- .../preprocessGeneratedApiDocs.js | 43 +++++++++++++------ website/yarn.lock | 12 ------ 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/website/package.json b/website/package.json index 60befa21d37..eb0bef27d89 100644 --- a/website/package.json +++ b/website/package.json @@ -41,8 +41,7 @@ "alex": "^8.0.0", "docusaurus": "1.14.4", "highlight.js": "^9.15.10", - "remarkable": "^2.0.0", - "tokenize-comment": "^3.0.1" + "remarkable": "^2.0.0" }, "devDependencies": { "@motiz88/react-native-docgen": "0.0.2", diff --git a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js index 3732e45fa0e..b699dd0bcf2 100644 --- a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js +++ b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js @@ -11,26 +11,41 @@ // This file may end up in the React Native repo, as part of the // `generate-api-docs` script. -const tokenizeComment = require('tokenize-comment'); - -function joinDescriptionAndExamples(tokenized) { - let sections = []; - if (tokenized.description) { - sections.push(tokenized.description); - } - for (const {raw} of tokenized.examples) { - sections.push(raw); +function tokenizeJsdocish(str) { + const TAG_RE = /^.*?@([\w-_]+)\s*(.*)\s*$/gm; + let match; + let sanitized = ''; + let index = 0; + let tokens = []; + while ((match = TAG_RE.exec(str)) != null) { + if (match.index > index) { + tokens.push({type: 'text', value: str.slice(index, match.index)}); + index = match.index; + } + tokens.push({type: 'tag', key: match[1], value: match[2].trim()}); + index = TAG_RE.lastIndex; } - if (tokenized.footer) { - sections.push(tokenized.footer); + if (str.length > index) { + tokens.push({type: 'text', value: str.slice(index, str.length)}); + index = str.length; } - return sections.join('\n\n'); + return { + tokens, + get text() { + return tokens + .map(token => (token.type === 'text' ? token.value : '')) + .join(''); + }, + get tags() { + return tokens.filter(token => token.type === 'tag'); + }, + }; } function preprocessTagsInDescription(obj) { if (obj && obj.description) { - const descriptionTokenized = tokenizeComment(obj.description); - obj.description = joinDescriptionAndExamples(descriptionTokenized); + const descriptionTokenized = tokenizeJsdocish(obj.description); + obj.description = descriptionTokenized.text; obj.rnTags = {}; const platformTag = descriptionTokenized.tags.find( ({key}) => key === 'platform' diff --git a/website/yarn.lock b/website/yarn.lock index 7c23e615715..00cab5631da 100644 --- a/website/yarn.lock +++ b/website/yarn.lock @@ -7168,11 +7168,6 @@ sliced@^1.0.1: resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= -snapdragon-lexer@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/snapdragon-lexer/-/snapdragon-lexer-4.0.0.tgz#86e2fb96931e12060839000995b00d3551658292" - integrity sha512-ddXT9cpKI0PUrs3xeoQVKEjequr0UyW9w281dzu8RTgWtqdIGZSvoWDsnIMPCc8Fupk4dByatSodhwYEGgrdSg== - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -7778,13 +7773,6 @@ toidentifier@1.0.0: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== -tokenize-comment@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/tokenize-comment/-/tokenize-comment-3.0.1.tgz#deeffcd57714e6097182a39e032e4ff861c60a1a" - integrity sha512-of5j9zCooBZxcE1EQ9PCjXcuFUPU/h8GxhWqF86cQ3muHQQreIWgY40ZNfuPQUSXyTa6i7oAWqWX4QivzZh26Q== - dependencies: - snapdragon-lexer "^4.0.0" - toml@^2.3.2: version "2.3.6" resolved "https://registry.yarnpkg.com/toml/-/toml-2.3.6.tgz#25b0866483a9722474895559088b436fd11f861b" From 9c1f021cefb99dba4f4dc49fd5a7476232e87900 Mon Sep 17 00:00:00 2001 From: Moti Zilberman Date: Wed, 12 Feb 2020 17:38:27 +0000 Subject: [PATCH 11/11] =?UTF-8?q?sync-api-docs:=20don=E2=80=99t=20include?= =?UTF-8?q?=20props=20with=20the=20empty=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js index b699dd0bcf2..b2600d5c199 100644 --- a/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js +++ b/website/scripts/sync-api-docs/preprocessGeneratedApiDocs.js @@ -60,6 +60,11 @@ function preprocessTagsInDescription(obj) { function preprocessGeneratedApiDocs(docs) { for (const {component} of docs) { if (component.props) { + for (const [key, prop] of Object.entries(component.props)) { + if (prop.flowType && prop.flowType.name === 'empty') { + delete component.props[key]; + } + } for (const prop of Object.values(component.props)) { preprocessTagsInDescription(prop); }