diff --git a/eslint.config.mjs b/eslint.config.mjs index 46a4208721..db57827354 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -94,6 +94,13 @@ export default defineConfig([ 'no-console': 'error', + '@typescript-eslint/no-namespace': [ + 'error', + { + allowDeclarations: true, + }, + ], + // enable after migration '@typescript-eslint/ban-ts-comment': 'off', '@typescript-eslint/no-unused-vars': 'off', diff --git a/playground/entries/Radio.tsx b/playground/entries/Radio.tsx index 624e2c272c..5b494eb556 100644 --- a/playground/entries/Radio.tsx +++ b/playground/entries/Radio.tsx @@ -1,4 +1,4 @@ -import type { RadioGroupProps, RadioProps } from '@semcore/ui/radio'; +import type { NSRadio } from '@semcore/ui/radio'; import Radio, { RadioGroup } from '@semcore/ui/radio'; import React from 'react'; @@ -6,7 +6,7 @@ import type { JSXProps } from '../types/JSXProps'; import type { PlaygroundEntry } from '../types/Playground'; import createGithubLink from '../utils/createGHLink'; -export type RadioJSXProps = JSXProps; +export type RadioJSXProps = JSXProps; function getJSX(props: RadioJSXProps) { return ( diff --git a/semcore/feature-highlight/src/components/radio/Radio.tsx b/semcore/feature-highlight/src/components/radio/Radio.tsx index 92f42e59d2..ad08e832ce 100644 --- a/semcore/feature-highlight/src/components/radio/Radio.tsx +++ b/semcore/feature-highlight/src/components/radio/Radio.tsx @@ -1,5 +1,5 @@ import { Component, createComponent, Root, sstyled, CONTEXT_COMPONENT } from '@semcore/core'; -import type { RadioProps } from '@semcore/radio'; +import type { NSRadio } from '@semcore/radio'; import Radio, { RadioGroup } from '@semcore/radio'; import React from 'react'; @@ -7,7 +7,7 @@ import style from './radio.shadow.css'; import type { HighlightedRadioComponent } from './Radio.type'; import { AnimatedSparkles } from '../../inner-components/sparkle/AnimatedSparkles'; -class RadioFHRoot extends Component { +class RadioFHRoot extends Component { static displayName = 'RadioFH'; static style = style; // @ts-ignore diff --git a/semcore/feature-highlight/src/components/radio/Radio.type.ts b/semcore/feature-highlight/src/components/radio/Radio.type.ts index a65f314e2c..9b395c2d94 100644 --- a/semcore/feature-highlight/src/components/radio/Radio.type.ts +++ b/semcore/feature-highlight/src/components/radio/Radio.type.ts @@ -1,11 +1,11 @@ import type { Intergalactic } from '@semcore/core'; -import type { RadioCtx, RadioProps, RadioValueProps } from '@semcore/radio'; +import type { NSRadio } from '@semcore/radio'; import type { Text } from '@semcore/typography'; import type { AnimatedSparklesProps } from '../../inner-components/sparkle/AnimatedSparkles'; -export type HighlightedRadioComponent = Intergalactic.Component<'label', RadioProps, RadioCtx> & { - Value: Intergalactic.Component<'input', RadioValueProps>; +export type HighlightedRadioComponent = Intergalactic.Component<'label', NSRadio.Props, NSRadio.Ctx> & { + Value: Intergalactic.Component<'input', NSRadio.Value.Props>; Text: typeof Text; AnimatedSparkles: Intergalactic.Component<'div', AnimatedSparklesProps>; }; diff --git a/semcore/radio/src/Radio.tsx b/semcore/radio/src/Radio.tsx index bbf66d0c84..abdde146da 100644 --- a/semcore/radio/src/Radio.tsx +++ b/semcore/radio/src/Radio.tsx @@ -9,29 +9,23 @@ import { useColorResolver } from '@semcore/core/lib/utils/use/useColorResolver'; import { Text as TypographyText } from '@semcore/typography'; import React from 'react'; -import type { - IntergalacticRadioGroupComponent, - RadioProps, - RadioComponent, - RadioGroupProps, - RadioValueComponent, - RadioTextComponent, - RadioValueRadioMarkComponent, - RadioRootComponent, - RadioValueControlComponent, -} from './Radio.type'; +import type { NSRadio } from './Radio.type'; import style from './style/radio.shadow.css'; const RadioContext = React.createContext<{ - onChange?: RadioGroupProps['onChange']; - value?: RadioGroupProps['value']; - theme?: RadioGroupProps['theme']; - size?: RadioGroupProps['size']; - name?: RadioGroupProps['name']; - disabled?: RadioGroupProps['disabled']; + onChange?: NSRadio.Group.Props['onChange']; + value?: NSRadio.Group.Props['value']; + theme?: NSRadio.Group.Props['theme']; + size?: NSRadio.Group.Props['size']; + name?: NSRadio.Group.Props['name']; + disabled?: NSRadio.Group.Props['disabled']; }>({}); -class RadioGroupRoot extends Component, [], { value: null }> { +class RadioGroupRoot extends Component< + Intergalactic.InternalTypings.InferComponentProps, + [], + { value: null } +> { static displayName = 'RadioGroup'; static defaultProps = { @@ -68,11 +62,9 @@ class RadioGroupRoot extends Component -> { +class RadioRoot extends Component> { static displayName = 'Radio'; static style = style; static contextType = RadioContext; @@ -83,7 +75,7 @@ class RadioRoot extends Component< hoistedDisabled: undefined, }; - hoistDisabled = (disabled: RadioProps['disabled']) => { + hoistDisabled = (disabled: NSRadio.Props['disabled']) => { logger.warn( true, `Don't set disabled on Radio.Value or Radio.Text, set it on Radio or on RadioGroup (for all items) instead. Otherwise it will produce wrong SSR output.`, @@ -93,11 +85,7 @@ class RadioRoot extends Component< }; getTextProps() { - const { - size = this.context.size ?? 'm', - disabled = this.context.disabled, - label, - } = this.asProps; + const { size = this.context.size ?? 'm', disabled = this.context.disabled, label } = this.asProps; const { hoistedDisabled } = this.state; @@ -159,7 +147,7 @@ class RadioRoot extends Component< } class ValueRoot extends Component< - Intergalactic.InternalTypings.InferChildComponentProps, + Intergalactic.InternalTypings.InferChildComponentProps, typeof ValueRoot.enhance, { checked: (e: React.ChangeEvent) => boolean } > { @@ -175,7 +163,7 @@ class ValueRoot extends Component< static contextType = RadioContext; static style = style; - bindHandlerChange = (value: RadioProps['value']) => (e: React.ChangeEvent) => { + bindHandlerChange = (value: NSRadio.Props['value']) => (e: React.ChangeEvent) => { if (typeof this.context.onChange === 'function' && value !== undefined) { this.context.onChange(value, e); } @@ -205,8 +193,7 @@ class ValueRoot extends Component< checked: currentValue === inputValue, onChange: callAllEventHandlers(onChange, this.bindHandlerChange(inputValue)), } - : {} - ), + : {}), }; } @@ -243,9 +230,7 @@ class ValueRoot extends Component< ? { onClick: callAllEventHandlers(onClick, this.bindHandlerChange(inputValue)), } - : {} - - ), + : {}), }; } @@ -277,17 +262,27 @@ class ValueRoot extends Component< } } -function Control(props: Intergalactic.InternalTypings.InferChildComponentProps) { +function Control( + props: Intergalactic.InternalTypings.InferChildComponentProps< + NSRadio.Value.Control.Component, + typeof ValueRoot, + 'Control' + >, +) { const SControl = Root; const { styles, state } = props; - return sstyled(styles)( - , - ); -}; + return sstyled(styles)(); +} Control.displayName = 'Control'; -function RadioMark(props: Intergalactic.InternalTypings.InferChildComponentProps) { +function RadioMark( + props: Intergalactic.InternalTypings.InferChildComponentProps< + NSRadio.Value.Mark.Component, + typeof ValueRoot, + 'RadioMark' + >, +) { const SValue = Root; const SInvalidPattern = InvalidStateBox; const { theme, styles, resolveColor, state, checked } = props; @@ -300,7 +295,9 @@ function RadioMark(props: Intergalactic.InternalTypings.InferChildComponentProps } RadioMark.displayName = 'RadioMark'; -function Text(props: Intergalactic.InternalTypings.InferChildComponentProps) { +function Text( + props: Intergalactic.InternalTypings.InferChildComponentProps, +) { const SText = Root; const { styles, color } = props; @@ -311,28 +308,28 @@ function Text(props: Intergalactic.InternalTypings.InferChildComponentProps, - ); + return sstyled(styles)(); } Text.displayName = 'Text'; const Value = createComponent(ValueRoot, { Control, RadioMark, -}) as RadioValueComponent; +}) as NSRadio.Value.Component; const Radio = createComponent(RadioRoot, { Text, Value, -}) as RadioComponent; - -export const wrapRadioGroup = (wrapper: ( - props: Intergalactic.InternalTypings.UntypeRefAndTag< - Intergalactic.InternalTypings.ComponentPropsNesting - > & - PropsExtending, -) => React.ReactNode) => wrapper as IntergalacticRadioGroupComponent; +}) as NSRadio.Component; + +export const wrapRadioGroup = ( + wrapper: ( + props: Intergalactic.InternalTypings.UntypeRefAndTag< + Intergalactic.InternalTypings.ComponentPropsNesting + > & + PropsExtending, + ) => React.ReactNode, +) => wrapper as NSRadio.Group.Component; export { inputProps, RadioGroup }; diff --git a/semcore/radio/src/Radio.type.ts b/semcore/radio/src/Radio.type.ts index c0beea4dfa..f305a1734d 100644 --- a/semcore/radio/src/Radio.type.ts +++ b/semcore/radio/src/Radio.type.ts @@ -1,91 +1,110 @@ -import type { Box, BoxProps, Flex } from '@semcore/base-components'; -import type { PropGetterFn, Intergalactic } from '@semcore/core'; -import type { Text, TextProps } from '@semcore/typography'; -import type React from 'react'; +import type { Flex, BoxProps } from '@semcore/base-components'; +import type { Intergalactic, PropGetterFn } from '@semcore/core'; +import type { TextProps } from '@semcore/typography'; -export type RadioSize = 'm' | 'l'; -export type RadioState = 'normal' | 'invalid'; -export type RadioValue = string | number | boolean; +declare namespace NSRadio { + type Size = 'm' | 'l'; + type State = 'normal' | 'invalid'; + type Value = string | number | boolean; + type Props = BoxProps & { + /** Radio item value **/ + value?: NSRadio.Value; + /** Radio item checked flag **/ + checked?: boolean; + /** + * The value displaying the state of the component + * @default normal + */ + state?: NSRadio.State; + /** + * Radio button size + * @default m + **/ + size?: NSRadio.Size; + /** The theme of the radio button that you can send your color to */ + theme?: string; + /** Radio item text **/ + label?: string; + /** Blocks access and changes to the radio item **/ + disabled?: boolean; + }; + type Ctx = { + getValueProps: PropGetterFn; + getTextProps: PropGetterFn; + }; + namespace Value { + type Props = BoxProps & { + /** List of elements that can be put on a hidden input */ + includeInputProps?: string[]; + }; + namespace Control { + type Props = {}; + type Component = Intergalactic.Component<'input', Props>; + } -export type RadioProps = BoxProps & { - /** Radio item value **/ - value?: RadioValue; + namespace Mark { + type Props = {}; + type Component = Intergalactic.Component<'input', Props>; + } - /** Radio item checked flag **/ - checked?: boolean; + type Component = Intergalactic.Component<'input', Props> & { + Control: Control.Component; + RadioMark: Mark.Component; + }; + } - /** - * The value displaying the state of the component - * @default normal - */ - state?: RadioState; - /** - * Radio button size - * @default m - **/ - size?: RadioSize; - /** The theme of the radio button that you can send your color to */ - theme?: string; - /** Radio item text **/ - label?: string; - /** Blocks access and changes to the radio item **/ - disabled?: boolean; -}; + namespace Text { + type Props = TextProps; + type Component = Intergalactic.Component<'span', Props>; + } -export type RadioGroupProps = { - /** Radio group name */ - name?: string; - /** Active default value */ - defaultValue?: T; - /** Active value */ - value?: T; - /** Called when the selected element is changed */ - onChange?: - | ((value: T, e?: React.SyntheticEvent) => void) - | React.Dispatch>; - /** Radio button size */ - size?: RadioSize; - /** The theme of the radio button that you can send your color to */ - theme?: string; - /** Blocks access and changes to the form field */ - disabled?: boolean; -}; + namespace Group { + type Props = { + /** Radio group name */ + name?: string; + /** Active default value */ + defaultValue?: T; + /** Active value */ + value?: T; + /** Called when the selected element is changed */ + onChange?: + | ((value: T, e?: React.SyntheticEvent) => void) + | React.Dispatch>; + /** Radio button size */ + size?: NSRadio.Size; + /** The theme of the radio button that you can send your color to */ + theme?: string; + /** Blocks access and changes to the form field */ + disabled?: boolean; + }; + type Component = (( + props: Intergalactic.InternalTypings.ComponentProps> & PropsExtending, + ) => Intergalactic.InternalTypings.ComponentRenderingResults) & + Intergalactic.InternalTypings.ComponentAdditive<'div', typeof Flex, Props>; + } + type Component = Intergalactic.Component<'label', Props, Ctx> & { + Value: Value.Component; + Text: Text.Component; + }; +} -export type RadioValueProps = BoxProps & { - /** List of elements that can be put on a hidden input */ - includeInputProps?: string[]; -}; +/** @deprecated It will be removed in v18. */ +export type RadioSize = NSRadio.Size; +/** @deprecated It will be removed in v18. */ +export type RadioState = NSRadio.State; +/** @deprecated It will be removed in v18. */ +export type RadioValue = NSRadio.Value; +/** @deprecated It will be removed in v18. */ +export type RadioProps = NSRadio.Props; +/** @deprecated It will be removed in v18. */ +export type RadioGroupProps = NSRadio.Group.Props; +/** @deprecated It will be removed in v18. */ +export type RadioValueProps = NSRadio.Value.Props; +/** @deprecated It will be removed in v18. */ +export type RadioCtx = NSRadio.Ctx; +/** @deprecated It will be removed in v18. */ +export type RadioValueControlProps = NSRadio.Value.Control.Props; +/** @deprecated It will be removed in v18. */ +export type RadioValueMarkProps = NSRadio.Value.Mark.Props; -export type RadioCtx = { - getValueProps: PropGetterFn; - getTextProps: PropGetterFn; -}; - -export type IntergalacticRadioGroupComponent = (< - Value extends RadioValue, - Tag extends Intergalactic.Tag = typeof Flex, ->( - props: Intergalactic.InternalTypings.ComponentProps> & - PropsExtending, -) => Intergalactic.InternalTypings.ComponentRenderingResults) & -Intergalactic.InternalTypings.ComponentAdditive<'div', typeof Flex, RadioGroupProps>; - -export type RadioValueControlProps = {}; -export type RadioValueMarkProps = {}; -export type RadioTextProps = TextProps; - -export type RadioValueControlComponent = Intergalactic.Component<'input', RadioValueControlProps>; -export type RadioValueRadioMarkComponent = Intergalactic.Component; - -export type RadioValueComponent = Intergalactic.Component<'input', RadioValueProps> & { - Control: RadioValueControlComponent; - RadioMark: RadioValueRadioMarkComponent; -}; - -export type RadioTextComponent = typeof Text; - -export type RadioRootComponent = Intergalactic.Component<'label', RadioProps, RadioCtx>; -export type RadioComponent = RadioRootComponent & { - Value: RadioValueComponent; - Text: RadioTextComponent; -}; +export type { NSRadio }; diff --git a/stories/components/feature-highlight/tests/examples/radio.tsx b/stories/components/feature-highlight/tests/examples/radio.tsx index 69c7587c7d..8c54239e6f 100644 --- a/stories/components/feature-highlight/tests/examples/radio.tsx +++ b/stories/components/feature-highlight/tests/examples/radio.tsx @@ -2,11 +2,11 @@ import SummaryAI from '@semcore/icon/SummaryAI/m'; import { Box, Flex, ScreenReaderOnly } from '@semcore/ui/base-components'; import { RadioFH, BadgeFH } from '@semcore/ui/feature-highlight'; import Radio, { RadioGroup } from '@semcore/ui/radio'; -import type { RadioProps } from '@semcore/ui/radio'; +import type { NSRadio } from '@semcore/ui/radio'; import { Text } from '@semcore/ui/typography'; import React from 'react'; -export type RadioFHAdvancedProps = RadioProps & { +export type RadioFHAdvancedProps = NSRadio.Props & { firstOptionText?: string; secondOptionText?: string; showBadge?: boolean; diff --git a/stories/components/radio/docs/Radio.stories.tsx b/stories/components/radio/docs/Radio.stories.tsx index 0f170a29e9..12d114bce9 100644 --- a/stories/components/radio/docs/Radio.stories.tsx +++ b/stories/components/radio/docs/Radio.stories.tsx @@ -1,4 +1,4 @@ -import Radio, { RadioGroup } from '@semcore/ui/radio'; +import Radio from '@semcore/ui/radio'; import type { Meta, StoryObj } from '@storybook/react-vite'; import AdditionalPropsInputExample, { defaultAdditionalInputProps } from './examples/additional_props_for_input'; diff --git a/stories/components/radio/docs/examples/additional_props_for_input.tsx b/stories/components/radio/docs/examples/additional_props_for_input.tsx index 87914a4154..0fe125df10 100644 --- a/stories/components/radio/docs/examples/additional_props_for_input.tsx +++ b/stories/components/radio/docs/examples/additional_props_for_input.tsx @@ -1,8 +1,8 @@ import Radio, { RadioGroup } from '@semcore/ui/radio'; -import type { RadioGroupProps } from '@semcore/ui/radio'; +import type { NSRadio } from '@semcore/ui/radio'; import React from 'react'; -const Demo = (props: RadioGroupProps) => { +const Demo = (props: NSRadio.Group.Props) => { return ( { ); }; -export const defaultAdditionalInputProps: RadioGroupProps = { +export const defaultAdditionalInputProps: NSRadio.Group.Props = { size: 'm', theme: undefined, disabled: false, diff --git a/stories/components/radio/docs/examples/radiogroup_example.tsx b/stories/components/radio/docs/examples/radiogroup_example.tsx index f955be97af..49114bfff6 100644 --- a/stories/components/radio/docs/examples/radiogroup_example.tsx +++ b/stories/components/radio/docs/examples/radiogroup_example.tsx @@ -1,10 +1,10 @@ import { Flex } from '@semcore/ui/base-components'; import Radio, { RadioGroup } from '@semcore/ui/radio'; -import type { RadioGroupProps } from '@semcore/ui/radio'; +import type { NSRadio } from '@semcore/ui/radio'; import { Text } from '@semcore/ui/typography'; import React from 'react'; -const Demo = (props: RadioGroupProps) => { +const Demo = (props: NSRadio.Group.Props) => { const [value, setValue] = React.useState('1'); return (
@@ -31,7 +31,7 @@ const Demo = (props: RadioGroupProps) => { ); }; -export const defaultProps: RadioGroupProps = { +export const defaultProps: NSRadio.Group.Props = { size: 'm', theme: undefined, disabled: false, diff --git a/stories/components/radio/tests/examples/radio-props.tsx b/stories/components/radio/tests/examples/radio-props.tsx index 9714963eb4..a327df40a2 100644 --- a/stories/components/radio/tests/examples/radio-props.tsx +++ b/stories/components/radio/tests/examples/radio-props.tsx @@ -1,9 +1,9 @@ import { Flex } from '@semcore/ui/base-components'; import Radio from '@semcore/ui/radio'; -import type { RadioProps } from '@semcore/ui/radio'; +import type { NSRadio } from '@semcore/ui/radio'; import React from 'react'; -type ExampleProps = RadioProps & { +type ExampleProps = NSRadio.Props & { color?: string; }; diff --git a/website/builder/typings/moduleDeclaration.ts b/website/builder/typings/moduleDeclaration.ts new file mode 100644 index 0000000000..b1ff3ed944 --- /dev/null +++ b/website/builder/typings/moduleDeclaration.ts @@ -0,0 +1,77 @@ +import ts from 'typescript'; + +import { serializeTypeDeclaration } from './typeAliases'; + +const MODULES_TO_SKIP = [ + 'Intergalactic', + 'hoist-non-react-statics', +]; + +type Serialized = { + filePath: string; + dependencies: Array; + declaration: { + name: string; + }; +}; + +type Tree = { + [key: string]: { + types?: Record; + ns?: Tree; + }; +}; + +export function serializeModuleDeclaration( + moduleDeclaration: ts.ModuleDeclaration, + filePath: string, + rootName?: string, +) { + const { name: { text: moduleName }, body } = moduleDeclaration; + + if (MODULES_TO_SKIP.includes(moduleName)) return {}; + + const tree: Tree = { + [moduleName]: {}, + }; + + if (!body) return tree; + + body.forEachChild((child) => { + if (ts.isTypeAliasDeclaration(child)) { + const { name: { text: childName } } = child; + const name = rootName ? `${rootName}.${moduleName}.${childName}` : `${moduleName}.${childName}`; + + try { + const { dependencies, ...declaration } = serializeTypeDeclaration(child); + + tree[moduleName] = { + ...tree[moduleName], + types: { + ...tree[moduleName].types, + [childName]: { + filePath, + dependencies: [...new Set(dependencies)], + declaration: { + ...declaration, + name, + }, + }, + }, + }; + } catch (err) { + console.warn(`[typings.serializeModuleDeclaration]: can't serialize ${name}.`); + } + } else if (ts.isModuleDeclaration(child)) { + tree[moduleName] = { + ...tree[moduleName], + ns: { + ...tree[moduleName].ns, + ...serializeModuleDeclaration(child, filePath, moduleName), + }, + }; + } + }); + + return tree; +} diff --git a/website/builder/typings/serializer.ts b/website/builder/typings/serializer.ts index 818aa8acfb..a80d6330c2 100644 --- a/website/builder/typings/serializer.ts +++ b/website/builder/typings/serializer.ts @@ -24,7 +24,11 @@ const computeTypingStringLength = (typingsParts) => 0, ); -export const serializeTsNode = (node: ts.Node, genericsMap = {}, minimizeMembersOf = []) => { +export const serializeTsNode = ( + node: ts.Node, + genericsMap = {}, + minimizeMembersOf = [], +) => { const traverse = (node: ts.Node) => { switch (node.kind) { case ts.SyntaxKind.NumberKeyword: @@ -256,6 +260,18 @@ export const serializeTsNode = (node: ts.Node, genericsMap = {}, minimizeMembers const { typeName, typeArguments } = node as Omit & { typeName: ts.BinaryExpression & { escapedText: string }; }; + if (typeName.left && typeName.right) { + const reference: string = [ + traverse(typeName.left), + '.', + traverse(typeName.right), + ].flat().join(''); + + return { + referenceTo: reference, + displayText: reference, + }; + } if (typeArguments) { let name = [typeName.escapedText]; if (typeName.left && typeName.right) { @@ -279,9 +295,6 @@ export const serializeTsNode = (node: ts.Node, genericsMap = {}, minimizeMembers result.push('>'); return result; } - if (typeName.left && typeName.right) { - return [traverse(typeName.left), '.', traverse(typeName.right)]; - } if (typeName.escapedText !== undefined) { const genericReference = genericsMap[typeName.escapedText]; if (genericReference) return genericReference; @@ -368,7 +381,7 @@ const serializeJSDoc = (jsDoc: ts.JSDoc[], dependencies: string[], genericsMap) return { description, params }; }; -export const serializeProperty = (propertyDeclaration: ts.PropertySignature, genericsMap) => { +export const serializeProperty = (propertyDeclaration: ts.PropertySignature, genericsMap: Record) => { const name = (propertyDeclaration as { name?: ts.Identifier }).name!.escapedText; const isOptional = propertyDeclaration.questionToken !== undefined; const type = serializeTsNode(propertyDeclaration.type!, genericsMap, []); diff --git a/website/builder/typings/types.data.ts b/website/builder/typings/types.data.ts index 8416ad0a39..4a4885335b 100644 --- a/website/builder/typings/types.data.ts +++ b/website/builder/typings/types.data.ts @@ -5,12 +5,17 @@ import ts from 'typescript'; import { serializeClassDeclaration } from './classes'; import { serializeInterfaceDeclaration } from './interfaces'; +import { serializeModuleDeclaration } from './moduleDeclaration'; import { serializeTypeDeclaration } from './typeAliases'; +const NAMESPACE_PREFIX = 'NS'; + const serializeFileDeclaration = (fileDeclaration: ts.SourceFile, filepath: string) => { const interfaceDec: ts.InterfaceDeclaration[] = []; const typesDec: ts.TypeAliasDeclaration[] = []; const classesDec: ts.ClassDeclaration[] = []; + let namespaces: Record = {}; + fileDeclaration.forEachChild((child) => { if (child.kind === ts.SyntaxKind.InterfaceDeclaration) { const isExported = child.modifiers?.some( @@ -39,6 +44,13 @@ const serializeFileDeclaration = (fileDeclaration: ts.SourceFile, filepath: stri classesDec.push(child as ts.ClassDeclaration); } } + + if (ts.isModuleDeclaration(child)) { + namespaces = { + ...namespaces, + ...serializeModuleDeclaration(child, filepath), + }; + } }); const types = typesDec.map((type) => serializeTypeDeclaration(type)); @@ -50,6 +62,7 @@ const serializeFileDeclaration = (fileDeclaration: ts.SourceFile, filepath: stri types, interfaces, classes, + namespaces, }; }; @@ -75,7 +88,8 @@ export default { const serialized = sourceFiles.map((file, index) => serializeFileDeclaration(file, watchedFiles[index]), ); - const typings = {}; + let typings: Record = {}; + for (const file of serialized) { for (const typing of [...file.types, ...file.interfaces, ...file.classes]) { if (typings[typing.name]) { @@ -132,8 +146,15 @@ export default { declaration, }; } + + typings = { + ...typings, + ...file.namespaces, + }; } for (const typing in typings) { + if (typing.startsWith(NAMESPACE_PREFIX)) continue; + const dependencies = typings[typing].dependencies; const dependencyFiles = dependencies .map((dependency) => typings[dependency]?.filepath) diff --git a/website/docs/.vitepress/theme/FormattedTypeString.vue b/website/docs/.vitepress/theme/FormattedTypeString.vue index 550032fca9..ba638dccaf 100644 --- a/website/docs/.vitepress/theme/FormattedTypeString.vue +++ b/website/docs/.vitepress/theme/FormattedTypeString.vue @@ -8,8 +8,8 @@ - -
+ +

External type

Type {{ subTypeModal.displayText }} is external and not available in the documentation preview. @@ -23,10 +23,28 @@