-
-
Notifications
You must be signed in to change notification settings - Fork 276
[code-infra] Migrate error code extraction to code-infra #2670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
43d8fdd
4e4f10c
81c053b
3505a82
6308dd2
885dbb9
52d715e
126e002
769a562
990b77c
4e1c986
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| 'use client'; | ||
| import * as React from 'react'; | ||
| import { useSearchParams } from 'next/navigation'; | ||
|
|
||
| export interface ErrorDisplayProps { | ||
| msg: string; | ||
| } | ||
|
|
||
| function ErrorCodeContent() { | ||
| return useSearchParams().get('code') ?? ''; | ||
| } | ||
|
|
||
| /** | ||
| * Client component that interpolates arguments in an error message. Must be | ||
| * a client component because it reads the search params. | ||
| */ | ||
| export default function ErrorCode() { | ||
| return ( | ||
| <React.Suspense fallback="…"> | ||
| <ErrorCodeContent /> | ||
| </React.Suspense> | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| 'use client'; | ||
| import * as React from 'react'; | ||
| import { useSearchParams } from 'next/navigation'; | ||
| import codes from 'docs/src/error-codes.json'; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can have basic inline markdown formatting rendering in a followup. |
||
|
|
||
| function ErrorMessageWithArgs() { | ||
| const searchParams = useSearchParams(); | ||
|
|
||
| return React.useMemo(() => { | ||
| const code = searchParams.get('code'); | ||
| const msg = | ||
| (code ? (codes as Partial<Record<string, string>>)[code ?? ''] : null) ?? | ||
| `Unknown error code: ${code}`; | ||
| const args = searchParams.getAll('args[]'); | ||
| let index = 0; | ||
| return msg.replace(/%s/g, () => { | ||
| const replacement = args[index]; | ||
| index += 1; | ||
| return replacement === undefined ? '[missing argument]' : replacement; | ||
| }); | ||
| }, [searchParams]); | ||
| } | ||
|
|
||
| /** | ||
| * Client component that interpolates arguments in an error message. Must be | ||
| * a client component because it reads the search params. | ||
| */ | ||
| export default function ErrorDisplay() { | ||
| return ( | ||
| <code> | ||
| <React.Suspense fallback="…"> | ||
| <ErrorMessageWithArgs /> | ||
| </React.Suspense> | ||
| </code> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import ErrorCode from './ErrorCode'; | ||
| import ErrorDisplay from './ErrorDisplay'; | ||
|
|
||
| # Production error #<ErrorCode /> | ||
|
|
||
| <Subtitle>Explanation for minified production error message.</Subtitle> | ||
| <Meta | ||
| name="description" | ||
| content="In the production build, error messages are minified to keep your application lightweight." | ||
| /> | ||
|
|
||
| A minified Base UI error occurred in the production build of React. | ||
|
|
||
| The full error message: | ||
|
|
||
| <ErrorDisplay /> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| { | ||
| "1": "Unsupported number of selectors", | ||
| "2": "Unsupported number of arguments", | ||
| "3": "Base UI: CheckboxGroupContext is missing. CheckboxGroup parts must be placed within <CheckboxGroup>.", | ||
| "4": "Base UI: DirectionContext is missing.", | ||
| "5": "Base UI: MenubarContext is missing. Menubar parts must be placed within <Menubar>.", | ||
| "6": "Base UI: useToast must be used within <Toast.Provider>.", | ||
| "7": "Base UI: ToggleGroupContext is missing. ToggleGroup parts must be placed within <ToggleGroup>.", | ||
| "8": "Base UI: Render element or function are not defined.", | ||
| "9": "Base UI: AccordionItemContext is missing. Accordion parts must be placed within <Accordion.Item>.", | ||
| "10": "Base UI: AccordionRootContext is missing. Accordion parts must be placed within <Accordion.Root>.", | ||
| "11": "Base UI: <AlertDialog.Portal> is missing.", | ||
| "12": "Base UI: AlertDialogRootContext is missing. AlertDialog parts must be placed within <AlertDialog.Root>.", | ||
| "13": "Base UI: AvatarRootContext is missing. Avatar parts must be placed within <Avatar.Root>.", | ||
| "14": "Base UI: CheckboxRootContext is missing. Checkbox parts must be placed within <Checkbox.Root>.", | ||
| "15": "Base UI: CollapsibleRootContext is missing. Collapsible parts must be placed within <Collapsible.Root>.", | ||
| "16": "Base UI: CompositeRootContext is missing. Composite parts must be placed within <Composite.Root>.", | ||
| "17": "useComboboxChipContext must be used within a ComboboxChip", | ||
| "18": "Base UI: ComboboxGroupContext is missing. ComboboxGroup parts must be placed within <Combobox.Group>.", | ||
| "19": "Base UI: ComboboxItemContext is missing. ComboboxItem parts must be placed within <Combobox.Item>.", | ||
| "20": "Base UI: <Combobox.Portal> is missing.", | ||
| "21": "Base UI: <Combobox.Popup> and <Combobox.Arrow> must be used within the <Combobox.Positioner> component", | ||
| "22": "Base UI: ComboboxRootContext is missing. Combobox parts must be placed within <Combobox.Root>.", | ||
| "23": "Base UI: ComboboxFloatingContext is missing. Combobox parts must be placed within <Combobox.Root>.", | ||
| "24": "Base UI: ComboboxItemsContext is missing. Combobox parts must be placed within <Combobox.Root>.", | ||
| "25": "Base UI: ContextMenuRootContext is missing. ContextMenu parts must be placed within <ContextMenu.Root>.", | ||
| "26": "Base UI: <Dialog.Portal> is missing.", | ||
| "27": "Base UI: DialogRootContext is missing. Dialog parts must be placed within <Dialog.Root>.", | ||
| "28": "Base UI: FieldRootContext is missing. Field parts must be placed within <Field.Root>.", | ||
| "29": "[Floating UI]: Invalid grid - item width at index %s is greater than grid columns", | ||
| "30": "Base UI: MenuCheckboxItemContext is missing. MenuCheckboxItem parts must be placed within <Menu.CheckboxItem>.", | ||
| "31": "Base UI: MenuGroupRootContext is missing. Menu group parts must be used within <Menu.Group>.", | ||
| "32": "Base UI: <Menu.Portal> is missing.", | ||
| "33": "Base UI: MenuPositionerContext is missing. MenuPositioner parts must be placed within <Menu.Positioner>.", | ||
| "34": "Base UI: MenuRadioGroupContext is missing. MenuRadioGroup parts must be placed within <Menu.RadioGroup>.", | ||
| "35": "Base UI: MenuRadioItemContext is missing. MenuRadioItem parts must be placed within <Menu.RadioItem>.", | ||
| "36": "Base UI: MenuRootContext is missing. Menu parts must be placed within <Menu.Root>.", | ||
| "37": "Base UI: <Menu.SubmenuTrigger> must be placed in <Menu.SubmenuRoot>.", | ||
| "38": "Base UI: MeterRootContext is missing. Meter parts must be placed within <Meter.Root>.", | ||
| "39": "Base UI: NavigationMenuItem parts must be used within a <NavigationMenu.Item>.", | ||
| "40": "Base UI: <NavigationMenu.Portal> is missing.", | ||
| "41": "Base UI: NavigationMenuRootContext is missing. Navigation Menu parts must be placed within <NavigationMenu.Root>.", | ||
| "42": "Base UI: NavigationMenuPositionerContext is missing. NavigationMenuPositioner parts must be placed within <NavigationMenu.Positioner>.", | ||
| "43": "Base UI: NumberFieldRootContext is missing. NumberField parts must be placed within <NumberField.Root>.", | ||
| "44": "Base UI: NumberFieldScrubAreaContext is missing. NumberFieldScrubArea parts must be placed within <NumberField.ScrubArea>.", | ||
| "45": "Base UI: <Popover.Portal> is missing.", | ||
| "46": "Base UI: PopoverPositionerContext is missing. PopoverPositioner parts must be placed within <Popover.Positioner>.", | ||
| "47": "Base UI: PopoverRootContext is missing. Popover parts must be placed within <Popover.Root>.", | ||
| "48": "Base UI: <PreviewCard.Portal> is missing.", | ||
| "49": "Base UI: <PreviewCard.Popup> and <PreviewCard.Arrow> must be used within the <PreviewCard.Positioner> component", | ||
| "50": "Base UI: PreviewCardRootContext is missing. PreviewCard parts must be placed within <PreviewCard.Root>.", | ||
| "51": "Base UI: ProgressRootContext is missing. Progress parts must be placed within <Progress.Root>.", | ||
| "52": "Base UI: RadioRootContext is missing. Radio parts must be placed within <Radio.Root>.", | ||
| "53": "Base UI: ScrollAreaRootContext is missing. ScrollArea parts must be placed within <ScrollArea.Root>.", | ||
| "54": "Base UI: ScrollAreaScrollbarContext is missing. ScrollAreaScrollbar parts must be placed within <ScrollArea.Scrollbar>.", | ||
| "55": "Base UI: ScrollAreaViewportContext missing. ScrollAreaViewport parts must be placed within <ScrollArea.Viewport>.", | ||
| "56": "Base UI: SelectGroupContext is missing. SelectGroup parts must be placed within <Select.Group>.", | ||
| "57": "Base UI: SelectItemContext is missing. SelectItem parts must be placed within <Select.Item>.", | ||
| "58": "Base UI: <Select.Portal> is missing.", | ||
| "59": "Base UI: SelectPositionerContext is missing. SelectPositioner parts must be placed within <Select.Positioner>.", | ||
| "60": "Base UI: SelectRootContext is missing. Select parts must be placed within <Select.Root>.", | ||
| "61": "Base UI: SelectFloatingContext is missing. Select parts must be placed within <Select.Root>.", | ||
| "62": "Base UI: SliderRootContext is missing. Slider parts must be placed within <Slider.Root>.", | ||
| "63": "Base UI: SwitchRootContext is missing. Switch parts must be placed within <Switch.Root>.", | ||
| "64": "Base UI: TabsRootContext is missing. Tabs parts must be placed within <Tabs.Root>.", | ||
| "65": "Base UI: TabsListContext is missing. TabsList parts must be placed within <Tabs.List>.", | ||
| "66": "Base UI: ToastRootContext is missing. Toast parts must be used within <Toast.Root>.", | ||
| "67": "Base UI: ToastViewportContext is missing. Toast parts must be placed within <Toast.Viewport>.", | ||
| "68": "Base UI: ToolbarGroupContext is missing. ToolbarGroup parts must be placed within <Toolbar.Group>.", | ||
| "69": "Base UI: ToolbarRootContext is missing. Toolbar parts must be placed within <Toolbar.Root>.", | ||
| "70": "Base UI: <Tooltip.Portal> is missing.", | ||
| "71": "Base UI: TooltipPositionerContext is missing. TooltipPositioner parts must be placed within <Tooltip.Positioner>.", | ||
| "72": "Base UI: TooltipRootContext is missing. Tooltip parts must be placed within <Tooltip.Root>.", | ||
| "73": "Base UI: useToastManager must be used within <Toast.Provider>.", | ||
| "74": "Base UI: PopoverTrigger must be either used within a PopoverRoot component or have the `handle` prop set.", | ||
| "75": "Base UI: PopoverTrigger must have an `id` prop specified.", | ||
| "76": "Base UI: selectors are required to call useState." | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| /** | ||
| * WARNING: Don't import this directly. It's imported by the code generated by | ||
| * `@mui/interal-babel-plugin-minify-errors`. Make sure to always use string literals in `Error` | ||
| * constructors to ensure the plugin works as expected. Supported patterns include: | ||
| * throw new Error('My message'); | ||
| * throw new Error(`My message: ${foo}`); | ||
| * throw new Error(`My message: ${foo}` + 'another string'); | ||
| * ... | ||
| */ | ||
| export default function formatErrorMessage(code: number, ...args: string[]): string { | ||
| const url = new URL(`https://base-ui.com/production-error/${code}`); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implemented here #1463
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It can be this or |
||
| args.forEach((arg) => url.searchParams.append('args[]', arg)); | ||
| return `Base UI error #${code}; visit ${url} for the full message.`; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,7 +125,7 @@ export const createSelector = (( | |
| } else if (a) { | ||
| selector = a; | ||
| } else { | ||
| throw new Error('Missing arguments'); | ||
| throw /* minify-error-disabled */ new Error('Missing arguments'); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't really save that much. |
||
| } | ||
|
|
||
| return selector; | ||
|
|
@@ -206,7 +206,7 @@ export const createSelectorMemoized: CreateSelectorFunction = (...selectors: any | |
| case 2: return fn(state, a1, a2); | ||
| case 3: return fn(state, a1, a2, a3); | ||
| default: | ||
| throw new Error('unreachable'); | ||
| throw /* minify-error-disabled */ new Error('unreachable'); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same. |
||
| } | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,6 +46,8 @@ function createStableCallback() { | |
|
|
||
| function assertNotCalled() { | ||
| if (process.env.NODE_ENV !== 'production') { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🤔 That's a case we may be able to detect in the babel plugin |
||
| throw new Error('Base UI: Cannot call an event handler while rendering.'); | ||
| throw /* minify-error-disabled */ new Error( | ||
| 'Base UI: Cannot call an event handler while rendering.', | ||
| ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Won't this be "hardish" to maintain without automation as time goes by? 🤔