diff --git a/.changeset/hungry-mugs-stare.md b/.changeset/hungry-mugs-stare.md new file mode 100644 index 00000000000..7f01a956231 --- /dev/null +++ b/.changeset/hungry-mugs-stare.md @@ -0,0 +1,5 @@ +--- +"@primer/react": patch +--- + +test: add check for story ids in generated docs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ddcb6795761..5db06240809 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -408,8 +408,12 @@ jobs: cache: 'npm' - name: Install dependencies run: npm ci + - name: Build storybook to generate story IDs + run: npm run build:storybook + working-directory: packages/react - name: Build components.json - run: npm run build:components.json + run: npx tsx script/components-json/build.ts --storybook-data 'storybook-static/index.json' + working-directory: packages/react sizes: runs-on: ubuntu-latest diff --git a/package-lock.json b/package-lock.json index 2749806fe1a..73c7f2fb270 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30482,7 +30482,7 @@ "@oddbird/popover-polyfill": "^0.4.4", "@primer/behaviors": "^1.7.2", "@primer/live-region-element": "^0.7.1", - "@primer/octicons-react": "19.13.0", + "@primer/octicons-react": "^19.13.0", "@primer/primitives": "9.x || 10.x", "@styled-system/css": "^5.1.5", "@styled-system/props": "^5.1.5", diff --git a/packages/react/package.json b/packages/react/package.json index 807ffe3f561..f9a333a6064 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -39,7 +39,7 @@ "clean": "rimraf dist lib lib-esm css", "start": "concurrently npm:start:*", "start:storybook": "STORYBOOK=true storybook dev -p 6006", - "build:storybook": "script/build-storybook", + "build:storybook": "storybook build", "build:docs": "NODE_OPTIONS=--openssl-legacy-provider script/build-docs", "build:docs:preview": "NODE_OPTIONS=--openssl-legacy-provider script/build-docs preview", "build:components.json": "tsx script/components-json/build.ts", diff --git a/packages/react/script/components-json/build.ts b/packages/react/script/components-json/build.ts index 33c7a82f7bf..61a48021c42 100644 --- a/packages/react/script/components-json/build.ts +++ b/packages/react/script/components-json/build.ts @@ -2,6 +2,8 @@ import generate from '@babel/generator' import {parse} from '@babel/parser' import traverse from '@babel/traverse' import type {ArrowFunctionExpression, Identifier, FunctionDeclaration} from '@babel/types' +import path from 'node:path' +import {parseArgs} from 'node:util' import Ajv from 'ajv' import {pascalCase, kebabCase} from 'change-case' import glob from 'fast-glob' @@ -11,6 +13,14 @@ import prettier from '@prettier/sync' import componentSchema from './component.schema.json' import outputSchema from './output.schema.json' +const args = parseArgs({ + options: { + 'storybook-data': { + type: 'string', + }, + }, +}) + // Only includes fields we use in this script type Component = { name: string @@ -40,6 +50,23 @@ const storyPrefix = { stable: '', } +let _storybookData: StorybookData | null = null + +function getStorybookData(): StorybookData { + const input = args.values['storybook-data'] + if (!input) { + throw new Error('Unable to get value for --storybook-data') + } + + if (_storybookData === null) { + const filepath = path.resolve(process.cwd(), args.values['storybook-data']!) + const contents = fs.readFileSync(filepath, 'utf-8') + _storybookData = JSON.parse(contents) + } + + return _storybookData as StorybookData +} + const components = docsFiles.map(docsFilepath => { const docs = JSON.parse(fs.readFileSync(docsFilepath, 'utf-8')) @@ -114,6 +141,18 @@ const components = docsFiles.map(docsFilepath => { } } + if (args.values['storybook-data']) { + const storybookData = getStorybookData() + for (const story of docs.stories) { + const match = Object.values(storybookData.entries).find(entry => { + return entry.id === story.id + }) + if (!match) { + throw new Error(`Story "${story.id}" not found in storybook-data`) + } + } + } + // TODO: Provide default type and description for sx and ref props return { source: `https://github.com/primer/react/tree/main/packages/react/${docsFilepath.substring(0, docsFilepath.lastIndexOf('/'))}`, @@ -236,3 +275,12 @@ function getStoryIds(docs: Component, storyNames: string[]) { return ids.map(id => ({id})) } + +interface StorybookData { + v: number + entries: { + [key: string]: { + id: string + } + } +} diff --git a/packages/react/src/Button/IconButton.docs.json b/packages/react/src/Button/IconButton.docs.json index 88d7ae75938..567264e81b9 100644 --- a/packages/react/src/Button/IconButton.docs.json +++ b/packages/react/src/Button/IconButton.docs.json @@ -35,7 +35,7 @@ "id": "components-iconbutton-features--external-tooltip" }, { - "id": "components-iconbutton-features--external-tooltip-version1" + "id": "components-iconbutton-features--external-tooltip-version-1" }, { "id": "components-iconbutton-features--as-a-menu-anchor" diff --git a/packages/react/src/Button/IconButton.features.stories.tsx b/packages/react/src/Button/IconButton.features.stories.tsx index d8db5c4b4c2..75050d7c805 100644 --- a/packages/react/src/Button/IconButton.features.stories.tsx +++ b/packages/react/src/Button/IconButton.features.stories.tsx @@ -34,7 +34,8 @@ export const ExternalTooltip = () => ( ) -export const ExternalTooltipVersion1 = () => ( +/* eslint-disable-next-line camelcase */ +export const ExternalTooltipVersion_1 = () => ( diff --git a/packages/react/src/Hidden/Hidden.docs.json b/packages/react/src/Hidden/Hidden.docs.json index 2820003d38c..440061f656c 100644 --- a/packages/react/src/Hidden/Hidden.docs.json +++ b/packages/react/src/Hidden/Hidden.docs.json @@ -5,13 +5,13 @@ "a11yReviewed": false, "stories": [ { - "id": "drafts-components-hidden--default" + "id": "experimental-components-hidden--default" }, { - "id": "drafts-components-hidden-features--hide-content" + "id": "experimental-components-hidden-features--hide-content" }, { - "id": "drafts-components-hidden-features--render-content-responsively" + "id": "experimental-components-hidden-features--render-content-responsively" } ], "importPath": "@primer/react/experimental", diff --git a/packages/react/src/InlineMessage/InlineMessage.docs.json b/packages/react/src/InlineMessage/InlineMessage.docs.json index 4547cfe57d5..d88519391bd 100644 --- a/packages/react/src/InlineMessage/InlineMessage.docs.json +++ b/packages/react/src/InlineMessage/InlineMessage.docs.json @@ -6,22 +6,22 @@ "importPath": "@primer/react/experimental", "stories": [ { - "id": "components-inlinemessage--default" + "id": "experimental-components-inlinemessage--default" }, { - "id": "components-inlinemessage-features--critical" + "id": "experimental-components-inlinemessage-features--critical" }, { - "id": "components-inlinemessage-features--success" + "id": "experimental-components-inlinemessage-features--success" }, { - "id": "components-inlinemessage-features--unavailable" + "id": "experimental-components-inlinemessage-features--unavailable" }, { - "id": "components-inlinemessage-features--warning" + "id": "experimental-components-inlinemessage-features--warning" }, { - "id": "components-inlinemessage-features--multiline" + "id": "experimental-components-inlinemessage-features--multiline" } ], "props": [ diff --git a/packages/react/src/Portal/Portal.docs.json b/packages/react/src/Portal/Portal.docs.json index 8d680098767..b73d9921e64 100644 --- a/packages/react/src/Portal/Portal.docs.json +++ b/packages/react/src/Portal/Portal.docs.json @@ -5,16 +5,16 @@ "a11yReviewed": false, "stories": [ { - "id": "components-portal--default" + "id": "behaviors-portal--default" }, { - "id": "components-portal-features--custom-portal-root-by-id" + "id": "behaviors-portal-features--custom-portal-root-by-id" }, { - "id": "components-portal-features--custom-portal-root-by-registration" + "id": "behaviors-portal-features--custom-portal-root-by-registration" }, { - "id": "components-portal-features--multiple-portal-roots" + "id": "behaviors-portal-features--multiple-portal-roots" } ], "importPath": "@primer/react", diff --git a/packages/react/src/TooltipV2/Tooltip.docs.json b/packages/react/src/TooltipV2/Tooltip.docs.json index d8b04275e00..45d4bae1dd5 100644 --- a/packages/react/src/TooltipV2/Tooltip.docs.json +++ b/packages/react/src/TooltipV2/Tooltip.docs.json @@ -7,31 +7,31 @@ "importPath": "@primer/react/next", "stories": [ { - "id": "components-tooltip--default" + "id": "components-tooltipv2--default" }, { - "id": "components-tooltip-features--anchor-has-margin" + "id": "components-tooltipv2-features--anchor-has-margin" }, { - "id": "components-tooltip-features--label-type" + "id": "components-tooltipv2-features--label-type" }, { - "id": "components-tooltip-features--description-type" + "id": "components-tooltipv2-features--description-type" }, { - "id": "components-tooltip-features--icon-button-with-description" + "id": "components-tooltipv2-features--icon-button-with-description" }, { - "id": "components-tooltip-features--all-directions" + "id": "components-tooltipv2-features--all-directions" }, { - "id": "components-tooltip-features--multiline-text" + "id": "components-tooltipv2-features--multiline-text" }, { - "id": "components-tooltip-features--calculated-direction" + "id": "components-tooltipv2-features--calculated-direction" }, { - "id": "components-tooltip-features--on-action-menu-anchor" + "id": "components-tooltipv2-features--on-action-menu-anchor" } ], "props": [