diff --git a/docs/architecture/import-aliases-and-file-structure.md b/docs/architecture/import-aliases-and-file-structure.md new file mode 100644 index 00000000..62006497 --- /dev/null +++ b/docs/architecture/import-aliases-and-file-structure.md @@ -0,0 +1,35 @@ +# Import Aliases & File Structure Architecture + +## Overview +In accordance with [Issue #195](https://github.com/MobilityData/mobilitydatabase-web/issues/195), path aliases have been configured to eliminate deep, brittle relative path traversal (e.g. `../../../../../../../screens/Feed/Feed.functions`). + +## Path Aliases Configured + +In `tsconfig.json` and `jest.config.ts`: + +- `@/*`: Points to `./src/*` for top-level source modules. +- `@mdb/*`: Points to `./src/app/*` for application modules, components, screens, services, and utilities. + +### Comparison Example + +#### Before (Brittle Relative Paths) +```typescript +import { formatProvidersSorted } from '../../../../../../../screens/Feed/Feed.functions'; +import { displayFormattedDate } from '../../../../../../../utils/date'; +import SectionContainer from '../../../../../../../components/SectionContainer'; +import FeedReliabilityView from '../../../../../../screens/Feed/components/FeedReliabilityView'; +``` + +#### After (Clean Module Aliases) +```typescript +import { formatProvidersSorted } from '@mdb/screens/Feed/Feed.functions'; +import { displayFormattedDate } from '@mdb/utils/date'; +import SectionContainer from '@mdb/components/SectionContainer'; +import FeedReliabilityView from '@mdb/screens/Feed/components/FeedReliabilityView'; +``` + +## Component Colocation Guidelines +- **Page-specific components:** Placed within the feature route folder (e.g. `src/app/[locale]/feeds/[feedDataType]/[feedId]/components/`). +- **Domain screen components:** Placed in the screen module (e.g. `src/app/screens/Feed/components/`). +- **Global cross-cutting components:** Placed at `@mdb/components/` (e.g. `Header`, `Footer`, `SectionContainer`, `SealOfReliability`). +- **Services and API types:** Placed at `@mdb/services/` for consistent client/server data fetching. diff --git a/jest.config.ts b/jest.config.ts index f12a2ae7..e1257501 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -14,6 +14,7 @@ const config: Config = { moduleNameMapper: { // Handle module aliases (this will be automatically configured for you based on your tsconfig.json paths) '^@/(.*)$': '/src/$1', + '^@mdb/(.*)$': '/src/app/$1', }, testMatch: [ '/src/**/__tests__/**/*.{js,jsx,ts,tsx}', diff --git a/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/page.tsx b/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/page.tsx index 440899ac..6d2bd8ea 100644 --- a/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/page.tsx +++ b/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/page.tsx @@ -1,5 +1,5 @@ import { type ReactElement } from 'react'; -import FeedView from '../../../../../screens/Feed/FeedView'; +import FeedView from '@mdb/screens/Feed/FeedView'; import FeedJsonLd from '../lib/FeedJsonLd'; import type { Metadata, ResolvingMetadata } from 'next'; import { getTranslations } from 'next-intl/server'; @@ -8,7 +8,7 @@ import { generateFeedMetadata } from '../lib/generate-feed-metadata'; import { getCurrentUserFromCookie, isMobilityDatabaseAdmin, -} from '../../../../../utils/auth-server'; +} from '@mdb/utils/auth-server'; interface Props { params: Promise<{ locale: string; feedDataType: string; feedId: string }>; diff --git a/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/seal-of-reliability/page.tsx b/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/seal-of-reliability/page.tsx index a3f5f485..16f6f527 100644 --- a/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/seal-of-reliability/page.tsx +++ b/src/app/[locale]/feeds/[feedDataType]/[feedId]/authed/seal-of-reliability/page.tsx @@ -1,4 +1,4 @@ -import FeedReliabilityView from '../../../../../../screens/Feed/components/FeedReliabilityView'; +import FeedReliabilityView from '@mdb/screens/Feed/components/FeedReliabilityView'; import { type ReactElement } from 'react'; import { fetchCompleteFeedData } from '../../lib/feed-data'; import { fetchAuthedSealAnalysisData } from '../../lib/seal-analysis-data'; diff --git a/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/page.tsx b/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/page.tsx index 7142ea5e..a777523b 100644 --- a/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/page.tsx +++ b/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/page.tsx @@ -1,5 +1,5 @@ import { type ReactElement } from 'react'; -import FeedView from '../../../../../screens/Feed/FeedView'; +import FeedView from '@mdb/screens/Feed/FeedView'; import FeedJsonLd from '../lib/FeedJsonLd'; import type { Metadata, ResolvingMetadata } from 'next'; import { notFound } from 'next/navigation'; diff --git a/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/seal-of-reliability/page.tsx b/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/seal-of-reliability/page.tsx index efa0e920..a9a3b5fd 100644 --- a/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/seal-of-reliability/page.tsx +++ b/src/app/[locale]/feeds/[feedDataType]/[feedId]/static/seal-of-reliability/page.tsx @@ -1,4 +1,4 @@ -import FeedReliabilityView from '../../../../../../screens/Feed/components/FeedReliabilityView'; +import FeedReliabilityView from '@mdb/screens/Feed/components/FeedReliabilityView'; import { type ReactElement } from 'react'; import { notFound } from 'next/navigation'; import { fetchGuestFeedData } from '../../lib/guest-feed-data'; diff --git a/src/app/screens/Feed/components/FeedReliabilityView.tsx b/src/app/screens/Feed/components/FeedReliabilityView.tsx index 14b7d429..70065912 100644 --- a/src/app/screens/Feed/components/FeedReliabilityView.tsx +++ b/src/app/screens/Feed/components/FeedReliabilityView.tsx @@ -15,16 +15,16 @@ import CriterionSection from './CriterionSection'; import CriterionStatusChip from './CriterionStatusChip'; // Utils -import { type AllFeedType } from '../../../services/feeds/utils'; -import { type components } from '../../../services/feeds/types'; -import { type SealAnalysisData } from '../../../[locale]/feeds/[feedDataType]/[feedId]/lib/seal-analysis-data'; +import { type AllFeedType } from '@mdb/services/feeds/utils'; +import { type components } from '@mdb/services/feeds/types'; +import { type SealAnalysisData } from '@mdb/[locale]/feeds/[feedDataType]/[feedId]/lib/seal-analysis-data'; import { getCriterionDisplayStatus, type SealCriterionContext, -} from '../../../constants/sealCriteria'; +} from '@mdb/constants/sealCriteria'; import { formatProvidersSorted } from '../Feed.functions'; -import { displayFormattedDate } from '../../../utils/date'; -import SectionContainer from '../../../components/SectionContainer'; +import { displayFormattedDate } from '@mdb/utils/date'; +import SectionContainer from '@mdb/components/SectionContainer'; interface Props { feed: AllFeedType; diff --git a/tsconfig.json b/tsconfig.json index 9d871cd0..8a7a6f3c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -24,7 +24,10 @@ "jest", "cypress" ], + "baseUrl": ".", "paths": { + "@/*": ["./src/*"], + "@mdb/*": ["./src/app/*"], "react": [ "./node_modules/@types/react" ]