diff --git a/packages/sync-api-docs/extractDocsFromRN.js b/packages/sync-api-docs/extractDocsFromRN.js deleted file mode 100644 index e6b8511764d..00000000000 --- a/packages/sync-api-docs/extractDocsFromRN.js +++ /dev/null @@ -1,70 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - */ - -import fs from 'node:fs/promises'; -import {glob} from 'glob'; -import path from 'node:path'; -import reactDocs from '@motiz88/react-native-docgen'; - -const GENERATE_ANNOTATION = '@' + 'generate-docs'; - -export default async function extractDocsFromRN(rnRoot) { - const allComponentFiles = await glob.glob( - path.join(rnRoot, '/Libraries/{Components,Image,}/**/*.js'), - { - nodir: true, - absolute: true, - } - ); - - const docs = []; - - for (const file of allComponentFiles) { - const contents = await fs.readFile(file, {encoding: 'utf-8'}); - if (!contents.includes(GENERATE_ANNOTATION)) { - continue; - } - - console.log(file); - - const result = reactDocs.parse( - contents, - reactDocs.resolver.findAllComponentDefinitions, - reactDocs.defaultHandlers.filter( - handler => handler !== reactDocs.handlers.propTypeCompositionHandler - ), - {filename: file} - ); - - const filteredResult = result.filter(item => { - if (item.description) return item; - }); - - docs.push({ - file, - component: cleanComponentResult(...filteredResult), - }); - } - - // Make sure output is JSON-safe - const docsSerialized = JSON.parse(JSON.stringify(docs)); - await fs.writeFile( - path.join(import.meta.dirname, 'extracted.json'), - JSON.stringify(docsSerialized, null, 2), - 'utf8' - ); - return docsSerialized; -} - -function cleanComponentResult(component) { - return { - ...component, - methods: component.methods.filter(method => !method.name.startsWith('_')), - }; -} diff --git a/packages/sync-api-docs/generateMarkdown.js b/packages/sync-api-docs/generateMarkdown.js deleted file mode 100644 index 9d8640457f1..00000000000 --- a/packages/sync-api-docs/generateMarkdown.js +++ /dev/null @@ -1,296 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -import tokenizeComment from 'tokenize-comment'; -import {formatTypeColumn, formatDefaultColumn} from './propFormatter.js'; -import { - formatMethodType, - formatMethodName, - formatMethodDescription, -} from './methodFormatter.js'; - -import {formatMultiplePlatform, maybeLinkifyTypeName} from './utils.js'; - -// 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) - ); - } - } - if (!colWidths.size) { - return ''; - } - 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; -} - -// Formats information about a prop -function generateProp(propName, prop) { - const infoTable = generateTable([ - { - Type: formatTypeColumn(prop), - ...formatDefaultColumn(prop), - }, - ]); - - return ( - '### ' + - (prop.required ? '
Required
' : '') + - '`' + - propName + - '`' + - (prop.rnTags && prop.rnTags.platform - ? formatMultiplePlatform(prop.rnTags.platform) - : '') + - '\n' + - '\n' + - (prop.description ? prop.description + '\n\n' : '') + - infoTable - ); -} - -// Formats information about a prop -function generateMethod(method, component) { - let descriptionTokenized = ''; - let header = 'Valid `params` keys are:'; - let mdPoints = ''; - if (method?.params[0]?.type?.raw) { - let desc = method?.params[0]?.type?.raw; - let len = method?.params[0]?.type?.signature?.properties?.length; - descriptionTokenized = tokenizeComment(desc); - - if ( - descriptionTokenized?.examples && - descriptionTokenized?.examples.length === len - ) { - let obj = []; - for (let i = 0; i < len; i++) { - let newObj = method?.params[0]?.type?.signature?.properties[i]; - newObj['description'] = descriptionTokenized?.examples[i]?.value; - obj.push(newObj); - } - - obj.map(item => { - if (item.description.trim() !== 'missing') - mdPoints += `- '${item.key}' (${item.value.name}) - ${item.description}`; - else mdPoints += `- '${item.key}' (${item.value.name})`; - }); - } - } - - if (method?.docblock) { - let dblock = method.docblock - .split('\n') - .map(line => { - return line.replace(/ /, ''); - }) - .join('\n'); - const docblockTokenized = tokenizeComment(dblock); - method.rnTags = {}; - const platformTag = docblockTokenized.tags.find( - ({key}) => key === 'platform' - ); - - if (platformTag) { - method.rnTags.platform = platformTag.value.split(','); - } - } - - return ( - '### `' + - method.name + - '()`' + - (method.rnTags && method.rnTags.platform - ? formatMultiplePlatform(method.rnTags.platform) - : '') + - '\n' + - '\n' + - (method.description ? method.description + '\n\n' : '') + - generateMethodSignatureTable(method, component) + - (mdPoints && header + '\n' + mdPoints) - ).trim(); -} - -function generateMethodSignatureTable(method) { - if (!method.params.length) { - return ''; - } - - return ( - '**Parameters:**\n\n' + - generateTable( - method.params.map(param => { - return { - Name: formatMethodName(param), - Type: formatMethodType(param), - Required: param.optional ? 'No' : 'Yes', - ...(param.description && { - Description: formatMethodDescription(param), - }), - }; - }) - ) - ); -} - -// Formats information about props -function generateProps({props, composes}) { - if (!props || !Object.keys(props).length) { - return ''; - } - - return ( - '## Props' + - '\n' + - '\n' + - (composes && composes.length - ? composes - .map(parent => 'Inherits ' + maybeLinkifyTypeName(parent) + '.') - .join('\n\n') + '\n\n' - : '') + - Object.keys(props) - .sort((a, b) => a.localeCompare(b)) - .sort((a, b) => props[b].required - props[a].required) - .map(function (propName) { - return generateProp(propName, props[propName]); - }) - .join('\n\n---\n\n') - ); -} - -function generateMethods(component) { - const {methods} = component; - if (!methods || !methods.length) { - return ''; - } - - return ( - '## Methods' + - '\n' + - '\n' + - [...methods] - .sort((a, b) => - a.name.localeCompare( - b.name /* TODO @nocommit what's a neutral locale */ - ) - ) - .map(function (method) { - return generateMethod(method, component); - }) - .join('\n\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 to process example contained description -function preprocessDescription(desc) { - // Playground tabs for the class and functional components - const playgroundTab = `
- -
`; - - //Blocks for different syntax sections - const functionalBlock = ``; - const classBlock = ``; - const endBlock = ``; - - desc = desc - .split('\n') - .map(line => { - return line.replace(/ /, ''); - }) - .join('\n'); - - const descriptionTokenized = tokenizeComment(desc); - // Tabs counter for examples - let tabs = 0; - descriptionTokenized.examples.map(item => { - const matchSnackPlayer = item.language.match(/(SnackPlayer name=).*/g); - if (matchSnackPlayer) { - const matchClassComp = matchSnackPlayer[0].match( - /Class%20Component%20Example/ - ); - const matchFuncComp = matchSnackPlayer[0].match( - /Function%20Component%20Example/ - ); - if (matchClassComp || matchFuncComp) tabs++; - } - }); - - if (tabs === 2) { - const firstExample = desc.slice(desc.search('```SnackPlayer') + 1); - const secondExample = firstExample.slice( - firstExample.search('```SnackPlayer') + 1 - ); - - return ( - desc.substring(0, desc.search('```SnackPlayer')) + - `\n## Example\n` + - `${playgroundTab}\n\n${functionalBlock}\n\n${ - '`' + firstExample.slice(0, firstExample.search('```') + 3) - }\n\n${classBlock}\n\n${ - '`' + secondExample.slice(0, secondExample.search('```') + 3) - }\n\n${endBlock}` + - secondExample.slice(secondExample.search('```') + 3) - ); - } else { - if (desc.search('```SnackPlayer') !== -1) { - return ( - desc.slice(0, desc.search('```SnackPlayer')) + - '\n' + - '\n## Example\n' + - '\n' + - desc.slice(desc.search('```SnackPlayer')) - ); - } else return desc; - } -} - -export default function generateMarkdown({id, title}, component) { - const markdownString = - generateHeader({id, title}) + - '\n' + - preprocessDescription(component.description) + - '\n\n' + - '---\n\n' + - '# Reference\n\n' + - generateProps(component) + - generateMethods(component); - - return markdownString.replace(/\n{3,}/g, '\n\n'); -} diff --git a/packages/sync-api-docs/magic.js b/packages/sync-api-docs/magic.js deleted file mode 100644 index de2098445ca..00000000000 --- a/packages/sync-api-docs/magic.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and 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 -// Ideally this file should go away. - -export default { - linkableTypeAliases: { - NativeColorValue: { - text: 'color', - url: 'colors.md', - }, - ViewProps: { - text: 'View Props', - url: 'view.md#props', - }, - PressEvent: { - text: 'PressEvent', - url: 'pressevent.md', - }, - 'RefreshLayoutConsts.SIZE.DEFAULT': { - text: 'RefreshControl.SIZE', - url: 'refreshcontrol.md#refreshlayoutconstssize', - }, - StatusBarAnimation: { - text: 'StatusBarAnimation', - url: 'statusbar#statusbaranimation', - }, - StatusBarStyle: { - text: 'StatusBarStyle', - url: 'statusbar#statusbarstyle', - }, - ReactNode: { - text: 'React.Node', - url: 'react-node.md', - }, - TextStyleProps: { - text: 'Text Style Props', - url: 'text-style-props', - }, - SectionT: { - text: 'Section', - url: 'sectionlist#section', - }, - ViewStyleProps: { - text: 'View Style Props', - url: 'view-style-props', - }, - Text: { - text: 'Text', - url: 'text#style', - }, - }, -}; diff --git a/packages/sync-api-docs/methodFormatter.js b/packages/sync-api-docs/methodFormatter.js deleted file mode 100644 index 6d4fe063b4e..00000000000 --- a/packages/sync-api-docs/methodFormatter.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import magic from './magic.js'; -import {formatMultiplePlatform} from './utils.js'; - -export function formatMethodType(param) { - let text, url; - if (param?.type?.name === 'union') { - if (param?.type?.alias) { - const {alias} = param.type; - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, alias)) { - ({url, text} = magic.linkableTypeAliases[alias]); - } - if (url) return `[${text}](${url})`; - else return param.type.alias; - } - return param.type.name; - } else { - if (param?.type?.type) return param.type.type; - else return param.type.name; - } -} - -export function formatMethodName(param) { - let tag = param.description; - if (tag) { - const isMatch = tag.match(/{@platform [a-z ,]*}/); - if (isMatch) { - const platform = isMatch[0].match(/ [a-z ,]*/); - tag = tag.replace(/{@platform [a-z ,]*}/g, ''); - tag = formatMultiplePlatform(platform[0].split(',')); - return param.name + tag; - } - } - return param.name; -} - -export function formatMethodDescription(param) { - let tag = param.description; - const isMatch = tag.match(/{@platform [a-z ,]*}/); - if (isMatch) { - // Replaces @platform strings with empty string - // and appends type with formatted platform - tag = tag.replace(/{@platform [a-z ,]*}/g, ''); - } - return tag; -} diff --git a/packages/sync-api-docs/package.json b/packages/sync-api-docs/package.json deleted file mode 100644 index 186711e64f8..00000000000 --- a/packages/sync-api-docs/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@react-native-website/sync-api", - "version": "0.0.1", - "private": true, - "type": "module", - "scripts": { - "prettier": "prettier --write \"**/*.js\"", - "sync": "node sync-api-docs ../../../react-native/packages/react-native" - }, - "devDependencies": { - "@motiz88/react-native-docgen": "0.0.3", - "glob": "^11.0.0", - "he": "^1.2.0", - "react-docgen-markdown-renderer": "^2.1.3", - "tokenize-comment": "^3.0.1" - } -} diff --git a/packages/sync-api-docs/preprocessGeneratedApiDocs.js b/packages/sync-api-docs/preprocessGeneratedApiDocs.js deleted file mode 100644 index 00b9883852b..00000000000 --- a/packages/sync-api-docs/preprocessGeneratedApiDocs.js +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -// 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. - -import tokenizeComment from 'tokenize-comment'; - -function preprocessTagsInDescription(obj) { - if (obj && obj.description) { - obj.description = obj.description - .split('\n') - .map(line => { - return line.replace(/ /, ''); - }) - .join('\n'); - const descriptionTokenized = tokenizeComment(obj.description); - obj.description = obj.description.replace( - /@platform .*|@default .*|@type .*/g, - '' - ); - obj.rnTags = {}; - const platformTag = descriptionTokenized.tags.find( - ({key}) => key === 'platform' - ); - const defaultTag = descriptionTokenized.tags.filter( - tag => tag.key === 'default' - ); - const typeTag = descriptionTokenized.tags.filter(tag => tag.key === 'type'); - - if (platformTag) { - obj.rnTags.platform = platformTag.value.split(','); - } - if (defaultTag.length) { - obj.rnTags.default = []; - defaultTag.forEach(tag => { - obj.rnTags.default.push(tag.value); - }); - } - if (typeTag.length) { - obj.rnTags.type = []; - typeTag.forEach(tag => { - obj.rnTags.type.push(tag.value); - }); - } - } -} - -// NOTE: This function mutates `docs`. -export default function preprocessGeneratedApiDocs(docs) { - for (const {component} of docs) { - if (component.props && component.description) { - for (const prop of Object.values(component.props)) { - preprocessTagsInDescription(prop); - } - for (const prop of component.methods) { - preprocessTagsInDescription(prop); - } - } - } -} diff --git a/packages/sync-api-docs/propFormatter.js b/packages/sync-api-docs/propFormatter.js deleted file mode 100644 index 9bfb3eb60ad..00000000000 --- a/packages/sync-api-docs/propFormatter.js +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and 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'; - -import magic from './magic.js'; -import { - formatMultiplePlatform, - stringToInlineCodeForTable, - formatType, -} from './utils.js'; - -export function formatTypeColumn(prop) { - // Checks for @type pragma comment - if (prop.rnTags && prop.rnTags.type) { - let tableRows = ''; - const typeTags = prop.rnTags.type; - - typeTags.forEach(tag => { - let url, text; - // Checks for @platform pragma in @type string - const isMatch = tag.match(/{@platform [a-z ,]*}/); - if (isMatch) { - // Extracts platforms from matched regex - const platform = isMatch[0].match(/ [a-z ,]*/); - - // Replaces @platform strings with empty string - // and appends type with formatted platform - tag = tag.replace(/{@platform [a-z ,]*}/g, ''); - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, tag)) { - ({url, text} = magic.linkableTypeAliases[tag]); - if (url) tag = `[${text}](${url})`; - } - tag = tag + formatMultiplePlatform(platform[0].split(',')); - } else { - // Check if there are multiple comma separated types in a single line - if (tag.match(/, /)) { - let newTag = ''; - const tags = tag.split(', '); - tags.forEach(item => { - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, item)) { - ({url, text} = magic.linkableTypeAliases[item]); - if (url) newTag += ', ' + `[${text}](${url})`; - } else newTag += ', ' + item; - }); - //Trim comma from beginning - tag = newTag.replace(/^, /, ''); - } - // If there is no comma separated types in rnTags - else if (Object.hasOwnProperty.call(magic.linkableTypeAliases, tag)) { - ({url, text} = magic.linkableTypeAliases[tag]); - if (url) tag = `[${text}](${url})`; - } - } - tableRows = tableRows + tag + '
'; - }); - tableRows = tableRows.replace(/$/, ''); - return tableRows; - } - - // To extract type from prop flowType - else if (prop.flowType && Object.keys(prop.flowType).length >= 1) { - let text, url; - - // Handles flowtype name for signatures - if (prop.flowType.name === 'signature') { - // Handles flowtype for function signature - if (prop.flowType.type === 'function') { - // Extracts EventType from the raw value - const isMatch = prop.flowType.raw.match(/: [a-zA-Z]*/); - if (isMatch) { - // Formats EventType - const eventType = isMatch[0].slice(2); - // Checks for aliases in magic and generates md url - if ( - Object.hasOwnProperty.call(magic.linkableTypeAliases, eventType) - ) { - ({url, text} = magic.linkableTypeAliases[eventType]); - if (url) { - return `${prop.flowType.type}([${text}](${url}))`; - } - } - // TODO: Handling unknown function params - return `${prop.flowType.type}`; - } else { - return prop.flowType.type; - } - } else if (prop.flowType.type === 'object') { - return prop.flowType.type; - } - } else if (prop.flowType.name.includes('$ReadOnlyArray')) { - prop?.flowType?.elements[0]?.elements.forEach(elem => { - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, elem.name)) { - ({url, text} = magic.linkableTypeAliases[elem.name]); - } - }); - if (url) return `array of [${text}](${url})`; - else if (prop?.flowType?.elements[0].name === 'union') { - const unionTypes = prop?.flowType?.elements[0]?.elements.reduce( - (acc, curr) => { - acc.push(curr.value); - return acc; - }, - [] - ); - return `array of enum(${unionTypes.join(', ')})`; - } else if (prop?.flowType?.elements[0]?.name) { - const typeName = prop.flowType.elements[0].name; - //array of number - if (typeName === 'number') return `array of ${typeName}`; - else if ( - Object.hasOwnProperty.call(magic.linkableTypeAliases, typeName) - ) { - ({url, text} = magic.linkableTypeAliases[typeName]); - if (url) return `array of [${text}](${url})`; - } - //default array for all other types - else return 'array'; - } - } else if (prop.flowType.name === '$ReadOnly') { - // Special Case: switch#trackcolor - let markdown = ''; - if (prop.flowType.elements[0]?.type === 'object') { - prop?.flowType?.elements[0]?.signature?.properties.forEach( - ({key, value}) => { - value?.elements?.forEach(elem => { - if ( - Object.hasOwnProperty.call(magic.linkableTypeAliases, elem.name) - ) { - ({url, text} = magic.linkableTypeAliases[elem.name]); - markdown += `${key}: [${text}](${url})` + ', '; - } - }); - if (!url) markdown += `${key}: ${value.name}` + ', '; - } - ); - if (markdown.match(/, $/)) markdown = markdown.replace(/, $/, ''); - return `${prop.flowType.elements[0]?.type}: {${markdown}}`; - } - } else if (prop.flowType.name === 'union') { - let unionTypes = prop.flowType.raw.split('|'); - - // Trim whitespaces and remove any leftover `|` (to avoid table split) - unionTypes = unionTypes - .map(elem => { - return elem.trim().replace(/|/g, ''); - }) - .filter(item => { - if (item) return item; - }); - - // Get text and url from magic aliases - prop?.flowType?.elements?.forEach(elem => { - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, elem.name)) { - ({url, text} = magic.linkableTypeAliases[elem.name]); - } - }); - - if (url) return `[${text}](${url})`; - - return `enum(${unionTypes.join(', ')})`; - } else if (prop.flowType.name === 'ReactElement') { - return 'element'; - } else { - // Get text and url from magic aliases - prop?.flowType?.elements?.forEach(elem => { - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, elem.name)) { - ({url, text} = magic.linkableTypeAliases[elem.name]); - } - }); - } - - // If no text is found, get raw values as text - if (!text) { - // TO BE FIXED - text = - (prop.flowType.raw && stringToInlineCodeForTable(prop.flowType.raw)) || - formatType(prop.flowType.name); - } - - // If URL is found, return text and link in markdown format - if (url) { - return `[${text}](${url})`; - } - - return text; - } -} - -// Adds proper markdown formatting to component's default value. -export function formatDefaultColumn(prop) { - if (prop?.rnTags?.default) { - // Parse from @default annotation - let tableRows = ''; - prop.rnTags.default.forEach(tag => { - const isMatch = tag.match(/{@platform [a-z]*}/); - - if (isMatch) { - const platform = isMatch[0].match(/ [a-z]*/); - tag = tag.replace(/{@platform [a-z]*}/g, ''); - - // Checks component for NativeColorValue in default - let colorBlock = ''; - prop?.flowType?.elements.some(elem => { - if (elem.name === 'NativeColorValue' && !tag.includes('null')) { - colorBlock = ``; - return true; - } - }); - - tag = - colorBlock + - (!tag.includes('null') ? '`' + tag + '`' : tag) + - formatMultiplePlatform(platform[0].split(',')); - } else if (!tag.includes('`')) { - tag = '`' + tag + '`'; - } - tableRows = tableRows + tag + '
'; - }); - tableRows = tableRows.replace(/$/, ''); - return {Default: tableRows}; - } else { - // Parse defaultValue if @default annotation not provided - return prop?.defaultValue?.value - ? {Default: stringToInlineCodeForTable(prop?.defaultValue?.value)} - : ''; - } -} diff --git a/packages/sync-api-docs/sync-api-docs.js b/packages/sync-api-docs/sync-api-docs.js deleted file mode 100644 index ec2ba152f92..00000000000 --- a/packages/sync-api-docs/sync-api-docs.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and 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. - -import fs from 'node:fs/promises'; -import process from 'node:process'; -import path from 'node:path'; - -import extractDocsFromRN from './extractDocsFromRN.js'; -import preprocessGeneratedApiDocs from './preprocessGeneratedApiDocs.js'; -import generateMarkdown from './generateMarkdown.js'; -import {titleToId} from './utils.js'; - -const DOCS_ROOT_DIR = path.resolve(import.meta.dirname, '..', '..', 'docs'); - -async function generateApiDocs(rnPath) { - const apiDocs = await extractDocsFromRN(rnPath); - preprocessGeneratedApiDocs(apiDocs); - await Promise.all( - apiDocs.map(async ({component, file}) => { - if (!component.displayName) { - console.log( - `react-docgen data for ${path.basename(file)} was malformed, skipping` - ); - return; - } - 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, componentMarkdown, 'utf8'); - }) - ); -} - -async function main(args) { - await generateApiDocs(args[0]); -} - -main(process.argv.slice(2)).catch(error => { - console.error(error); -}); diff --git a/packages/sync-api-docs/utils.js b/packages/sync-api-docs/utils.js deleted file mode 100644 index e912fb567d5..00000000000 --- a/packages/sync-api-docs/utils.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import he from 'he'; - -import magic from './magic.js'; - -// Adds multiple platform tags for prop name -export function formatMultiplePlatform(platforms) { - let platformString = ''; - platforms.forEach(platform => { - switch (platform.trim().toLowerCase()) { - case 'ios': - platformString += '
' + 'iOS' + '
'; - break; - case 'android': - platformString += '
' + 'Android' + '
'; - break; - case 'tv': - platformString += '
' + 'TV' + '
'; - break; - //TODO: Add a new CSS class for VR - case 'vr': - platformString += '
' + 'VR' + '
'; - } - }); - return platformString; -} - -// 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. -export function stringToInlineCodeForTable(str) { - let useHtml = /[`|]/.test(str); - str = str.replace(/\n/g, ' '); - if (useHtml) { - return '' + he.encode(str).replace(/\|/g, '|') + ''; - } - return '`' + str + '`'; -} - -export function maybeLinkifyType(flowType) { - let url, text; - flowType.elements?.forEach(elem => { - if (Object.hasOwnProperty.call(magic.linkableTypeAliases, elem.name)) { - ({url, text} = magic.linkableTypeAliases[elem.name]); - } - }); - if (!text) { - text = stringToInlineCodeForTable( - flowType.raw || formatType(flowType.name) - ); - } - if (url) { - return `[${text}](${url})`; - } - return text; -} - -export function formatType(name) { - if (name.toLowerCase() === 'boolean') return 'bool'; - if (name.toLowerCase() === 'stringish') return 'string'; - if (name === '$ReadOnlyArray') return 'array'; - return name; -} - -export 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; -} - -export function titleToId(title) { - return title.toLowerCase().replace(/[^a-z]+/g, '-'); -} diff --git a/yarn.lock b/yarn.lock index aca317dd536..83b35af5c10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -238,7 +238,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.2, @babel/core@npm:^7.25.9, @babel/core@npm:^7.28.3, @babel/core@npm:^7.7.5": +"@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.2, @babel/core@npm:^7.25.9, @babel/core@npm:^7.28.3": version: 7.28.3 resolution: "@babel/core@npm:7.28.3" dependencies: @@ -1682,7 +1682,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.9, @babel/runtime@npm:^7.28.3, @babel/runtime@npm:^7.7.6": +"@babel/runtime@npm:^7.1.2, @babel/runtime@npm:^7.10.3, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.13, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.25.0, @babel/runtime@npm:^7.25.9, @babel/runtime@npm:^7.28.3": version: 7.28.3 resolution: "@babel/runtime@npm:7.28.3" checksum: 10c0/b360f82c2c5114f2a062d4d143d7b4ec690094764853937110585a9497977aed66c102166d0e404766c274e02a50ffb8f6d77fef7251ecf3f607f0e03e6397bc @@ -3657,32 +3657,6 @@ __metadata: languageName: node linkType: hard -"@motiz88/ast-types@npm:^0.13.3": - version: 0.13.3 - resolution: "@motiz88/ast-types@npm:0.13.3" - checksum: 10c0/d45596283fa99cd0d193aecae3f389d02b0aba5ed4f758395f330dde3a315d70cc919f14a9ff95f82a90d0fc105481d8674d03f27a9d9fed10e646bc4700c48c - languageName: node - linkType: hard - -"@motiz88/react-native-docgen@npm:0.0.3": - version: 0.0.3 - resolution: "@motiz88/react-native-docgen@npm:0.0.3" - dependencies: - "@babel/core": "npm:^7.7.5" - "@babel/runtime": "npm:^7.7.6" - "@motiz88/ast-types": "npm:^0.13.3" - commander: "npm:^2.19.0" - doctrine: "npm:^3.0.0" - neo-async: "npm:^2.6.1" - node-dir: "npm:^0.1.10" - resolve: "npm:^1.10.1" - strip-indent: "npm:^3.0.0" - bin: - react-docgen: bin/react-docgen.js - checksum: 10c0/7135f6a52583335c15fb5780d7e41e71787e3cbcbf9c18db333c079dfbd193b347c1cb87f3e0813be9bbc85b0918ca25a6a5925b45e4250ff2d7c0366494c24d - languageName: node - linkType: hard - "@napi-rs/wasm-runtime@npm:^1.0.1": version: 1.0.1 resolution: "@napi-rs/wasm-runtime@npm:1.0.1" @@ -3965,18 +3939,6 @@ __metadata: languageName: unknown linkType: soft -"@react-native-website/sync-api@workspace:packages/sync-api-docs": - version: 0.0.0-use.local - resolution: "@react-native-website/sync-api@workspace:packages/sync-api-docs" - dependencies: - "@motiz88/react-native-docgen": "npm:0.0.3" - glob: "npm:^11.0.0" - he: "npm:^1.2.0" - react-docgen-markdown-renderer: "npm:^2.1.3" - tokenize-comment: "npm:^3.0.1" - languageName: unknown - linkType: soft - "@react-native/assets-registry@npm:0.81.0": version: 0.81.0 resolution: "@react-native/assets-registry@npm:0.81.0" @@ -7401,7 +7363,7 @@ __metadata: languageName: node linkType: hard -"commander@npm:^2.19.0, commander@npm:^2.20.0": +"commander@npm:^2.20.0": version: 2.20.3 resolution: "commander@npm:2.20.3" checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 @@ -8305,15 +8267,6 @@ __metadata: languageName: node linkType: hard -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520 - languageName: node - linkType: hard - "docusaurus-plugin-sass@npm:^0.2.6": version: 0.2.6 resolution: "docusaurus-plugin-sass@npm:0.2.6" @@ -14749,7 +14702,7 @@ __metadata: languageName: node linkType: hard -"min-indent@npm:^1.0.0, min-indent@npm:^1.0.1": +"min-indent@npm:^1.0.1": version: 1.0.1 resolution: "min-indent@npm:1.0.1" checksum: 10c0/7e207bd5c20401b292de291f02913230cb1163abca162044f7db1d951fa245b174dc00869d40dd9a9f32a885ad6a5f3e767ee104cf278f399cb4e92d3f582d5c @@ -14775,7 +14728,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:3.1.2, minimatch@npm:^3.0.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:3.1.2, minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -15016,7 +14969,7 @@ __metadata: languageName: node linkType: hard -"neo-async@npm:^2.6.1, neo-async@npm:^2.6.2": +"neo-async@npm:^2.6.2": version: 2.6.2 resolution: "neo-async@npm:2.6.2" checksum: 10c0/c2f5a604a54a8ec5438a342e1f356dff4bc33ccccdb6dc668d94fe8e5eccfc9d2c2eea6064b0967a767ba63b33763f51ccf2cd2441b461a7322656c1f06b3f5d @@ -15090,15 +15043,6 @@ __metadata: languageName: node linkType: hard -"node-dir@npm:^0.1.10": - version: 0.1.17 - resolution: "node-dir@npm:0.1.17" - dependencies: - minimatch: "npm:^3.0.2" - checksum: 10c0/16222e871708c405079ff8122d4a7e1d522c5b90fc8f12b3112140af871cfc70128c376e845dcd0044c625db0d2efebd2d852414599d240564db61d53402b4c1 - languageName: node - linkType: hard - "node-emoji@npm:^2.1.0": version: 2.2.0 resolution: "node-emoji@npm:2.2.0" @@ -17171,24 +17115,6 @@ __metadata: languageName: node linkType: hard -"react-docgen-markdown-renderer@npm:^2.1.3": - version: 2.1.3 - resolution: "react-docgen-markdown-renderer@npm:2.1.3" - dependencies: - react-docgen-renderer-template: "npm:^0.1.0" - peerDependencies: - react-docgen: ^2 || ^3 - checksum: 10c0/d8c09685384efc453606ac0d50fc145fd70f512c3ccc91f171276444b402cbedf30676fd9ba2b79cda19f762248a7f9aa40c8c7eb6861718dc7a1d1b978a1fb0 - languageName: node - linkType: hard - -"react-docgen-renderer-template@npm:^0.1.0": - version: 0.1.0 - resolution: "react-docgen-renderer-template@npm:0.1.0" - checksum: 10c0/9496ce986014de3041b1f35dbb0eb1bb846000f0ef40167eab4f5951e03cac4f742ab0eca09674e1fc89fd5439f03f129426c87824477d8c8ec7e25f3bce3c5f - languageName: node - linkType: hard - "react-dom@npm:^19.1.1": version: 19.1.1 resolution: "react-dom@npm:19.1.1" @@ -18061,7 +17987,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.1, resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10": +"resolve@npm:^1.20.0, resolve@npm:^1.22.1, resolve@npm:^1.22.10": version: 1.22.10 resolution: "resolve@npm:1.22.10" dependencies: @@ -18087,7 +18013,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.10.1#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin": +"resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.10#optional!builtin": version: 1.22.10 resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" dependencies: @@ -18775,13 +18701,6 @@ __metadata: languageName: node linkType: hard -"snapdragon-lexer@npm:^4.0.0": - version: 4.0.0 - resolution: "snapdragon-lexer@npm:4.0.0" - checksum: 10c0/bbdbd16b1c6eaa80fab22abe0dad6ee5527308d4c82c3fbde26eb90a2f2dbdd1acf58e65df6e801ef1670fd771b92e20747c31859302437e66796420b1f028ff - languageName: node - linkType: hard - "sockjs@npm:^0.3.24": version: 0.3.24 resolution: "sockjs@npm:0.3.24" @@ -19289,15 +19208,6 @@ __metadata: languageName: node linkType: hard -"strip-indent@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-indent@npm:3.0.0" - dependencies: - min-indent: "npm:^1.0.0" - checksum: 10c0/ae0deaf41c8d1001c5d4fbe16cb553865c1863da4fae036683b474fa926af9fc121e155cb3fc57a68262b2ae7d5b8420aa752c97a6428c315d00efe2a3875679 - languageName: node - linkType: hard - "strip-indent@npm:^4.0.0": version: 4.0.0 resolution: "strip-indent@npm:4.0.0" @@ -19664,15 +19574,6 @@ __metadata: languageName: node linkType: hard -"tokenize-comment@npm:^3.0.1": - version: 3.0.1 - resolution: "tokenize-comment@npm:3.0.1" - dependencies: - snapdragon-lexer: "npm:^4.0.0" - checksum: 10c0/a51131a4177de54aef060d9893a11566c7d8e92650f413740a74f3929f85d20b10b1da78429216436e464f39cd929ec6871e4fb174f35eb4936a44c4d619a33e - languageName: node - linkType: hard - "totalist@npm:^3.0.0": version: 3.0.1 resolution: "totalist@npm:3.0.1"