From 891027cab0e2b187d79e5f23677de516f289a9ad Mon Sep 17 00:00:00 2001 From: Vladimir Eremin Date: Sun, 15 Feb 2026 12:23:04 +0300 Subject: [PATCH] refactor: Continue refactoring after migrating to rsbuild --- .eslintignore | 11 -- GEMINI.md | 78 ++++++-- eslint.config.mjs | 5 +- packages/eslint-config/index.js | 182 ------------------ packages/eslint-config/package.json | 9 +- packages/eslint-config/src/dev.js | 1 + packages/eslint-config/src/index.js | 1 + .../eslint-config/src/lib/config/imports.js | 25 +++ .../eslint-config/src/lib/config/index.js | 43 +++++ .../src/lib/config/javascript.js | 25 +++ .../eslint-config/src/lib/config/jsdoc.js | 35 ++++ .../eslint-config/src/lib/config/monorepo.js | 70 +++++++ .../eslint-config/src/lib/config/testing.js | 43 +++++ .../eslint-config/src/lib/config/tooling.js | 29 +++ .../src/lib/config/typescript.js | 61 ++++++ packages/eslint-config/src/lib/dev.js | 13 ++ packages/eslint-config/src/lib/index.js | 2 + packages/eslint-config/src/lib/testing.js | 2 + packages/eslint-config/src/testing.js | 1 + packages/rsbuild-config/package.json | 6 +- packages/rsbuild-config/src/dev.ts | 1 + packages/rsbuild-config/src/index.ts | 60 +----- .../rsbuild-config/src/lib/config/index.ts | 2 + .../rsbuild-config/src/lib/config/rsbuild.ts | 59 ++++++ .../src/{ => lib/config}/vitest.ts | 8 +- packages/rsbuild-config/src/lib/dev.ts | 1 + packages/rsbuild-config/src/lib/index.ts | 2 + packages/rsbuild-config/src/lib/testing.ts | 1 + packages/rsbuild-config/src/testing.ts | 1 + packages/stl/package.json | 8 + packages/stl/rsbuild.config.ts | 6 +- packages/stl/src/dev.ts | 1 + packages/stl/src/index.ts | 4 +- packages/stl/src/lib/dev.ts | 2 + .../stl/src/{ => lib}/functions/cn/cn.test.ts | 0 packages/stl/src/{ => lib}/functions/cn/cn.ts | 0 packages/stl/src/{ => lib}/functions/index.ts | 0 packages/stl/src/lib/index.ts | 3 + .../{ => lib}/react/castRef/castRef.test.ts | 0 .../src/{ => lib}/react/castRef/castRef.ts | 0 .../react/genericMemo/genericMemo.test.tsx | 0 .../react/genericMemo/genericMemo.ts | 0 packages/stl/src/{ => lib}/react/index.ts | 0 packages/stl/src/lib/testing.ts | 2 + .../stl/src/{ => lib}/types/classNameProps.ts | 0 packages/stl/src/{ => lib}/types/index.ts | 0 .../stl/src/{ => lib}/types/testIdProps.ts | 0 packages/stl/src/testing.ts | 1 + packages/stl/tsconfig.json | 5 +- packages/stl/vitest.config.ts | 2 +- packages/storybook-config/package.json | 5 +- packages/storybook-config/src/dev.ts | 1 + packages/storybook-config/src/index.ts | 5 +- .../storybook-config/src/lib/config/index.ts | 2 + .../src/{ => lib/config}/main.ts | 9 +- .../src/{ => lib/config}/preview.ts | 1 + packages/storybook-config/src/lib/dev.ts | 1 + packages/storybook-config/src/lib/index.ts | 2 + packages/storybook-config/src/lib/testing.ts | 2 + packages/storybook-config/src/testing.ts | 1 + .../{.storybook => .config/storybook}/main.ts | 2 +- .../storybook}/preview.tsx | 2 +- .../setupTests.ts => .config/vitest/setup.ts} | 0 packages/ui/package.json | 15 +- packages/ui/rsbuild.config.ts | 7 +- .../src/components/Article/Article.test.tsx | 2 +- .../Breadcrumbs/Breadcrumbs.test.tsx | 2 +- .../ui/src/components/Button/Button.test.tsx | 2 +- packages/ui/src/components/Code/Code.tsx | 15 +- .../components/Container/Container.test.tsx | 2 +- .../ui/src/components/Image/Image.test.tsx | 2 +- packages/ui/src/components/Link/Link.test.tsx | 2 +- .../ui/src/components/Markdown/Markdown.tsx | 2 +- .../components/Paragraph/Paragraph.test.tsx | 2 +- .../ui/src/components/Stack/Stack.test.tsx | 2 +- packages/ui/src/components/Stub/Stub.test.tsx | 2 +- packages/ui/src/components/Text/Text.test.tsx | 2 +- packages/ui/src/components/Time/Time.test.tsx | 2 +- packages/ui/src/components/testing.ts | 1 + packages/ui/src/dev.ts | 1 + packages/ui/src/index.ts | 5 +- packages/ui/src/lib/dev.ts | 1 + packages/ui/src/lib/index.ts | 1 + .../{test-utils.tsx => lib/react/index.ts} | 0 packages/ui/src/lib/testing.ts | 1 + .../{styles/index.css => static/styles.css} | 0 packages/ui/src/testing.ts | 1 + packages/ui/tsconfig.json | 5 +- packages/ui/vitest.config.ts | 2 +- services/static/rsbuild.config.ts | 2 +- services/static/src/app/error.tsx | 33 ++-- services/static/src/app/index.tsx | 6 +- services/static/src/global.css | 2 - .../static/src/lib/{ => core}/createPage.tsx | 2 +- .../static/src/{ => lib}/shared/constants.ts | 0 services/static/src/{ => lib}/shared/utils.ts | 0 services/static/src/static/global.css | 2 + services/static/src/{ => static}/index.html | 0 .../{.storybook => .config/storybook}/main.ts | 10 +- .../storybook}/preview.tsx | 2 +- .../setupTests.ts => .config/vitest/setup.ts} | 0 services/www/content/registry.ts | 18 +- services/www/rsbuild.config.ts | 2 +- services/www/src/app/HomePage.tsx | 26 --- .../www/src/app/articles/2026/ArticlePage.tsx | 26 --- .../src/app/articles/2026/test-article.tsx | 30 ++- .../www/src/app/articles/ArticlesList.tsx | 36 ---- services/www/src/app/articles/index.tsx | 52 ++++- services/www/src/app/index.tsx | 37 +++- .../ArticleLayout/ArticleLayout.stories.tsx | 0 .../layouts/ArticleLayout/ArticleLayout.tsx | 0 .../widgets/Welcome.stories.tsx | 0 .../src/{ => components}/widgets/Welcome.tsx | 0 services/www/src/global.css | 2 - .../www/src/lib/{ => core}/createPage.tsx | 2 +- services/www/src/lib/shared/constants.ts | 9 + services/www/src/shared/constants.ts | 8 - services/www/src/static/global.css | 2 + services/www/src/{ => static}/index.html | 0 services/www/vitest.config.ts | 2 +- 120 files changed, 751 insertions(+), 483 deletions(-) delete mode 100644 .eslintignore delete mode 100644 packages/eslint-config/index.js create mode 100644 packages/eslint-config/src/dev.js create mode 100644 packages/eslint-config/src/index.js create mode 100644 packages/eslint-config/src/lib/config/imports.js create mode 100644 packages/eslint-config/src/lib/config/index.js create mode 100644 packages/eslint-config/src/lib/config/javascript.js create mode 100644 packages/eslint-config/src/lib/config/jsdoc.js create mode 100644 packages/eslint-config/src/lib/config/monorepo.js create mode 100644 packages/eslint-config/src/lib/config/testing.js create mode 100644 packages/eslint-config/src/lib/config/tooling.js create mode 100644 packages/eslint-config/src/lib/config/typescript.js create mode 100644 packages/eslint-config/src/lib/dev.js create mode 100644 packages/eslint-config/src/lib/index.js create mode 100644 packages/eslint-config/src/lib/testing.js create mode 100644 packages/eslint-config/src/testing.js create mode 100644 packages/rsbuild-config/src/dev.ts create mode 100644 packages/rsbuild-config/src/lib/config/index.ts create mode 100644 packages/rsbuild-config/src/lib/config/rsbuild.ts rename packages/rsbuild-config/src/{ => lib/config}/vitest.ts (82%) create mode 100644 packages/rsbuild-config/src/lib/dev.ts create mode 100644 packages/rsbuild-config/src/lib/index.ts create mode 100644 packages/rsbuild-config/src/lib/testing.ts create mode 100644 packages/rsbuild-config/src/testing.ts create mode 100644 packages/stl/src/dev.ts create mode 100644 packages/stl/src/lib/dev.ts rename packages/stl/src/{ => lib}/functions/cn/cn.test.ts (100%) rename packages/stl/src/{ => lib}/functions/cn/cn.ts (100%) rename packages/stl/src/{ => lib}/functions/index.ts (100%) create mode 100644 packages/stl/src/lib/index.ts rename packages/stl/src/{ => lib}/react/castRef/castRef.test.ts (100%) rename packages/stl/src/{ => lib}/react/castRef/castRef.ts (100%) rename packages/stl/src/{ => lib}/react/genericMemo/genericMemo.test.tsx (100%) rename packages/stl/src/{ => lib}/react/genericMemo/genericMemo.ts (100%) rename packages/stl/src/{ => lib}/react/index.ts (100%) create mode 100644 packages/stl/src/lib/testing.ts rename packages/stl/src/{ => lib}/types/classNameProps.ts (100%) rename packages/stl/src/{ => lib}/types/index.ts (100%) rename packages/stl/src/{ => lib}/types/testIdProps.ts (100%) create mode 100644 packages/stl/src/testing.ts create mode 100644 packages/storybook-config/src/dev.ts create mode 100644 packages/storybook-config/src/lib/config/index.ts rename packages/storybook-config/src/{ => lib/config}/main.ts (83%) rename packages/storybook-config/src/{ => lib/config}/preview.ts (99%) create mode 100644 packages/storybook-config/src/lib/dev.ts create mode 100644 packages/storybook-config/src/lib/index.ts create mode 100644 packages/storybook-config/src/lib/testing.ts create mode 100644 packages/storybook-config/src/testing.ts rename packages/ui/{.storybook => .config/storybook}/main.ts (98%) rename packages/ui/{.storybook => .config/storybook}/preview.tsx (86%) rename packages/ui/{src/setupTests.ts => .config/vitest/setup.ts} (100%) create mode 100644 packages/ui/src/components/testing.ts create mode 100644 packages/ui/src/dev.ts create mode 100644 packages/ui/src/lib/dev.ts create mode 100644 packages/ui/src/lib/index.ts rename packages/ui/src/{test-utils.tsx => lib/react/index.ts} (100%) create mode 100644 packages/ui/src/lib/testing.ts rename packages/ui/src/{styles/index.css => static/styles.css} (100%) create mode 100644 packages/ui/src/testing.ts delete mode 100644 services/static/src/global.css rename services/static/src/lib/{ => core}/createPage.tsx (95%) rename services/static/src/{ => lib}/shared/constants.ts (100%) rename services/static/src/{ => lib}/shared/utils.ts (100%) create mode 100644 services/static/src/static/global.css rename services/static/src/{ => static}/index.html (100%) rename services/www/{.storybook => .config/storybook}/main.ts (82%) rename services/www/{.storybook => .config/storybook}/preview.tsx (88%) rename services/www/{src/setupTests.ts => .config/vitest/setup.ts} (100%) delete mode 100644 services/www/src/app/HomePage.tsx delete mode 100644 services/www/src/app/articles/2026/ArticlePage.tsx delete mode 100644 services/www/src/app/articles/ArticlesList.tsx rename services/www/src/{ => components}/layouts/ArticleLayout/ArticleLayout.stories.tsx (100%) rename services/www/src/{ => components}/layouts/ArticleLayout/ArticleLayout.tsx (100%) rename services/www/src/{ => components}/widgets/Welcome.stories.tsx (100%) rename services/www/src/{ => components}/widgets/Welcome.tsx (100%) delete mode 100644 services/www/src/global.css rename services/www/src/lib/{ => core}/createPage.tsx (91%) create mode 100644 services/www/src/lib/shared/constants.ts delete mode 100644 services/www/src/shared/constants.ts create mode 100644 services/www/src/static/global.css rename services/www/src/{ => static}/index.html (100%) diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 8faf693..0000000 --- a/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -node_modules -dist -build -coverage -storybook-static -.next -.astro -public -**/public/** -**/dist/** -**/node_modules/** diff --git a/GEMINI.md b/GEMINI.md index 24e72fb..a275ebc 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -108,6 +108,26 @@ Services consume packages but are independent of each other. They can be develop - **Explicit Dependencies**: All inter-package dependencies declared in package.json - **Build Isolation**: Each package can be built independently - **Configuration Inheritance**: Services inherit from shared configurations +- **Package Entry Points**: + - `.` (Main): Runtime code used in production (e.g., `import { ... } from '@ermnvldmr/stl'`). + - `/testing`: Test-related utilities and mocks (e.g., `import { ... } from '@ermnvldmr/stl/testing'`). + - `/dev`: Build-time dependencies (e.g., `import { ... } from '@ermnvldmr/stl/dev'`). + - All other entry points are forbidden. Strictly build-time packages must still expose via `/dev`. +- **Directory Structure (Packages & Services)**: + - `src/lib/`: Helpers, utilities, and types. + - `{category}/`: Grouped logic. + - `index.ts`: Barrel export for all of `lib/`. + - `testing.ts`: Testing utilities for the library. + - `dev.ts`: Build-time utilities for the library. + - `src/components/`: UI components. + - `{ComponentName}/`: Isolated component directory. + - `index.ts`: Barrel export for all components. + - `testing.ts`: Component-specific testing utilities. + - `src/static/`: Static assets (`.html`, `.css`, `.js`) directly in this directory (no subdirectories). + - `src/app/` (Services only): Page definitions. + - `{page}.tsx`: Single file per page, inlining the component in `createPage`. + - `{path}/{page}.tsx`: Nested routing structure. + - Top-level `src/index.ts`, `src/testing.ts`, and `src/dev.ts` should only re-export from `lib/` or `components/`. ## 📝 Coding Conventions @@ -202,32 +222,50 @@ export const Button = React.forwardRef( ``` packages/ui/ +├── .config/ +│ ├── vitest/ +│ │ └── setup.ts +│ └── storybook/ +│ ├── main.ts +│ └── preview.tsx ├── src/ │ ├── components/ # Component categories -│ │ ├── generic/ # Layout and generic components -│ │ └── paper/ # Themed component variants -│ ├── styles/ # Global styles and CSS -│ ├── test-utils.tsx # Testing utilities -│ └── index.ts # Main package exports +│ │ ├── index.ts # Production barrel +│ │ ├── testing.ts # Testing barrel +│ │ └── Button/ # Isolated component +│ ├── lib/ # Core logic +│ │ ├── index.ts +│ │ ├── testing.ts +│ │ └── dev.ts +│ ├── static/ # Flat static assets (CSS, etc.) +│ ├── index.ts # Main entry point (runtime) +│ ├── testing.ts # Testing entry point +│ └── dev.ts # Dev entry point ├── package.json -├── vite.config.ts -├── tsconfig.json -└── .storybook/ # Storybook configuration +├── rsbuild.config.ts +└── tsconfig.json ``` #### Service Structure (www example) ``` services/www/ +├── .config/ +│ ├── vitest/ +│ │ └── setup.ts +│ └── storybook/ ├── src/ -│ ├── layouts/ # Astro layout components -│ ├── pages/ # Astro pages (file-based routing) -│ ├── shared/ # Shared utilities and constants -│ └── global.css # Service-specific styles -├── public/ # Static assets -├── astro.config.mjs # Astro configuration -├── package.json -└── tailwind.config.mjs # Tailwind configuration +│ ├── app/ # Single file per page +│ │ ├── index.tsx # Inlined createPage +│ │ └── articles/ +│ ├── components/ # layouts, widgets +│ ├── lib/ # core, shared +│ ├── static/ # global.css, index.html +│ ├── index.ts +│ └── ... +├── public/ # Direct static assets (images) +├── rsbuild.config.ts +└── package.json ``` ## 🎨 Design System (UI Package) @@ -269,16 +307,14 @@ Each configuration package provides standardized setups: ```javascript // Provides: base, react, astro configurations -import { base } from '@ermnvldmr/eslint-config'; -import { react } from '@ermnvldmr/eslint-config/react'; -import { astro } from '@ermnvldmr/eslint-config/astro'; +import { baseConfig } from '@ermnvldmr/eslint-config/dev'; ``` #### Vitest Configuration ```typescript // Provides: base, react configurations from rsbuild-config -import { baseVitestConfig } from '@ermnvldmr/rsbuild-config/vitest'; +import { baseVitestConfig, reactVitestConfig } from '@ermnvldmr/rsbuild-config/dev'; import { mergeConfig } from 'vitest/config'; ``` @@ -286,7 +322,7 @@ import { mergeConfig } from 'vitest/config'; ```typescript // Provides: definePackageConfig, defineServiceConfig -import { definePackageConfig } from '@ermnvldmr/rsbuild-config'; +import { definePackageConfig } from '@ermnvldmr/rsbuild-config/dev'; ``` ### Service Configuration Inheritance diff --git a/eslint.config.mjs b/eslint.config.mjs index 420a7c8..49d8d3e 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,5 +1,5 @@ // @ts-check -import { baseConfig } from '@ermnvldmr/eslint-config'; +import { baseConfig } from '@ermnvldmr/eslint-config/dev'; import eslintPluginAstro from 'eslint-plugin-astro'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; @@ -23,6 +23,7 @@ export default [ '**/storybook-static/**', '**/.next/**', '**/.astro/**', + '**/*.d.ts', ], }, @@ -143,5 +144,5 @@ export default [ languageOptions: { globals: globals.node, }, - } + }, ]; diff --git a/packages/eslint-config/index.js b/packages/eslint-config/index.js deleted file mode 100644 index 4d14e72..0000000 --- a/packages/eslint-config/index.js +++ /dev/null @@ -1,182 +0,0 @@ -// @ts-check -import eslint from '@eslint/js'; -import prettier from 'eslint-config-prettier/flat'; -import importPlugin from 'eslint-plugin-import'; -import jsdoc from 'eslint-plugin-jsdoc'; -import globals from 'globals'; -import tseslint from 'typescript-eslint'; - -/** - * Base ESLint configuration - */ -export const baseConfig = [ - { - ignores: [ - '**/dist', - '**/node_modules', - '**/.github', - '**/.changeset', - '**/coverage', - '.config/**/*', - '*.config.{js,ts,mjs,cjs}', - '!.storybook', // Allow linting of .storybook directory - ], - }, - - // JavaScript - eslint.configs.recommended, - - // TypeScript - Strict Configuration (only for .ts/.tsx files) - ...[...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.stylisticTypeChecked].map((config) => ({ - ...config, - files: ['**/*.{ts,tsx,mts,cts}'], - })), - { - files: ['**/*.{ts,tsx,mts,cts}'], - languageOptions: { - parserOptions: { - projectService: true, - tsconfigRootDir: import.meta.dirname, - }, - }, - rules: { - // TypeScript strict rules - '@typescript-eslint/no-explicit-any': 'error', - '@typescript-eslint/no-unused-vars': 'error', - '@typescript-eslint/prefer-nullish-coalescing': 'error', - '@typescript-eslint/prefer-optional-chain': 'error', - '@typescript-eslint/no-unnecessary-condition': 'error', - '@typescript-eslint/no-non-null-assertion': 'error', - '@typescript-eslint/prefer-as-const': 'error', - '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], - '@typescript-eslint/consistent-type-imports': [ - 'error', - { prefer: 'type-imports', disallowTypeAnnotations: false }, - ], - '@typescript-eslint/consistent-type-assertions': [ - 'error', - { - assertionStyle: 'never', - }, - ], - '@typescript-eslint/explicit-function-return-type': [ - 'error', - { allowExpressions: true, allowTypedFunctionExpressions: true }, - ], - }, - }, - - // Allow triple-slash references in `*.d.ts` files. - { - files: ['**/*.d.ts'], - rules: { - '@typescript-eslint/triple-slash-reference': 'off', - }, - }, - - // Import/Export Rules - { - plugins: { import: importPlugin }, - rules: { - 'import/order': [ - 'error', - { - groups: ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'type'], - 'newlines-between': 'always', - alphabetize: { order: 'asc', caseInsensitive: true }, - }, - ], - 'import/no-duplicates': 'error', - 'import/no-unused-modules': 'error', - 'import/no-cycle': 'error', - 'import/no-self-import': 'error', - }, - }, - - // JSDoc Requirements - Only for main source code - { - files: ['src/**/*.{ts,tsx}', 'packages/**/*.{ts,tsx}', 'services/**/*.{ts,tsx}'], - plugins: { jsdoc }, - rules: { - 'jsdoc/require-jsdoc': [ - 'error', - { - contexts: [ - 'ExportNamedDeclaration > FunctionDeclaration', - 'ExportDefaultDeclaration > FunctionDeclaration', - 'TSInterfaceDeclaration', - 'TSTypeAliasDeclaration', - ], - }, - ], - 'jsdoc/require-description': 'error', - 'jsdoc/require-param': 'error', - 'jsdoc/require-returns': 'error', - 'jsdoc/require-example': 'warn', - 'jsdoc/check-alignment': 'error', - 'jsdoc/check-indentation': 'error', - 'jsdoc/check-syntax': 'error', - 'jsdoc/check-tag-names': 'error', - 'jsdoc/check-types': 'error', - 'jsdoc/valid-types': 'error', - }, - }, - - // Test files and Stories - { - files: ['**/*.{test,spec,stories}.{js,jsx,ts,tsx}', '.config/jest/**/*.{js,jsx,ts,tsx}', '**/test-utils.tsx'], - languageOptions: { - globals: { - ...globals.jest, - }, - }, - rules: { - // Relax rules for test files, stories and jest configuration - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-empty-function': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-assertions': 'off', - - // Disable all JSDoc rules - 'jsdoc/require-jsdoc': 'off', - 'jsdoc/require-description': 'off', - 'jsdoc/require-param': 'off', - 'jsdoc/require-returns': 'off', - 'jsdoc/require-example': 'off', - 'jsdoc/check-alignment': 'off', - 'jsdoc/check-indentation': 'off', - 'jsdoc/check-syntax': 'off', - 'jsdoc/check-tag-names': 'off', - 'jsdoc/check-types': 'off', - 'jsdoc/valid-types': 'off', - }, - }, - - // CommonJS files - disable all TypeScript rules - { - files: ['**/*.cjs'], - ...tseslint.configs.disableTypeChecked, - }, - - // Config files and tooling - { - files: ['*.config.{js,ts,mjs,cjs}', '.storybook/**/*.{js,ts,cjs,mjs}'], - rules: { - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/no-unsafe-assignment': 'off', - '@typescript-eslint/no-unsafe-call': 'off', - '@typescript-eslint/no-unsafe-member-access': 'off', - '@typescript-eslint/no-unsafe-argument': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/consistent-type-assertions': 'off', - 'jsdoc/require-jsdoc': 'off', - 'no-undef': 'off', // For CommonJS files - }, - }, - - // Prettier - prettier -]; diff --git a/packages/eslint-config/package.json b/packages/eslint-config/package.json index 7aff33c..8366911 100644 --- a/packages/eslint-config/package.json +++ b/packages/eslint-config/package.json @@ -3,11 +3,12 @@ "version": "1.0.0", "description": "Shared ESLint configuration", "type": "module", - "main": "./index.js", + "exports": { + "./dev": "./src/dev.js", + "./testing": "./src/testing.js" + }, "files": [ - "index.js", - "react.js", - "astro.js" + "src" ], "dependencies": { "@eslint/js": "^9.39.2", diff --git a/packages/eslint-config/src/dev.js b/packages/eslint-config/src/dev.js new file mode 100644 index 0000000..12a7183 --- /dev/null +++ b/packages/eslint-config/src/dev.js @@ -0,0 +1 @@ +export * from './lib/dev.js'; diff --git a/packages/eslint-config/src/index.js b/packages/eslint-config/src/index.js new file mode 100644 index 0000000..09c185e --- /dev/null +++ b/packages/eslint-config/src/index.js @@ -0,0 +1 @@ +export * from './lib/index.js'; diff --git a/packages/eslint-config/src/lib/config/imports.js b/packages/eslint-config/src/lib/config/imports.js new file mode 100644 index 0000000..cd72323 --- /dev/null +++ b/packages/eslint-config/src/lib/config/imports.js @@ -0,0 +1,25 @@ +// @ts-check +import importPlugin from 'eslint-plugin-import'; + +/** + * Import and Export rules. + */ +export const importsConfig = [ + { + plugins: { import: importPlugin }, + rules: { + 'import/order': [ + 'error', + { + groups: ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'type'], + 'newlines-between': 'always', + alphabetize: { order: 'asc', caseInsensitive: true }, + }, + ], + 'import/no-duplicates': 'error', + 'import/no-unused-modules': 'error', + 'import/no-cycle': 'error', + 'import/no-self-import': 'error', + }, + }, +]; diff --git a/packages/eslint-config/src/lib/config/index.js b/packages/eslint-config/src/lib/config/index.js new file mode 100644 index 0000000..09ec0a7 --- /dev/null +++ b/packages/eslint-config/src/lib/config/index.js @@ -0,0 +1,43 @@ +// @ts-check +import { javascriptConfig } from './javascript.js'; +import { getTypescriptConfig } from './typescript.js'; +import { importsConfig } from './imports.js'; +import { jsdocConfig } from './jsdoc.js'; +import { testingConfig } from './testing.js'; +import { toolingConfig } from './tooling.js'; +import { defineMonorepoRestrictedImports } from './monorepo.js'; + +/** + * Common ignores for the entire monorepo. + */ +const ignoresConfig = { + ignores: [ + '**/dist', + '**/node_modules', + '**/.github', + '**/.changeset', + '**/coverage', + '.config/**/*', + '*.config.{js,ts,mjs,cjs}', + '!.storybook', // Allow linting of .storybook directory + ], +}; + +/** + * Assemble the base ESLint configuration. + * + * @param {string} rootDir - The root directory of the project using this config. + * @returns {import('eslint').Linter.Config[]} The assembled configuration. + */ +export function defineBaseConfig(rootDir) { + return [ + ignoresConfig, + ...javascriptConfig, + ...getTypescriptConfig(rootDir), + ...importsConfig, + ...jsdocConfig, + ...testingConfig, + ...toolingConfig, + ...defineMonorepoRestrictedImports(rootDir), + ]; +} diff --git a/packages/eslint-config/src/lib/config/javascript.js b/packages/eslint-config/src/lib/config/javascript.js new file mode 100644 index 0000000..efcf9a9 --- /dev/null +++ b/packages/eslint-config/src/lib/config/javascript.js @@ -0,0 +1,25 @@ +// @ts-check +import eslint from '@eslint/js'; +import prettier from 'eslint-config-prettier/flat'; +import globals from 'globals'; + +/** + * Core JavaScript and Prettier configuration. + */ +export const javascriptConfig = [ + // JavaScript recommended rules + eslint.configs.recommended, + + // Browser and Service Worker globals + { + languageOptions: { + globals: { + ...globals.serviceworker, + ...globals.browser, + }, + }, + }, + + // Prettier integration (must be last in the assembler) + prettier, +]; diff --git a/packages/eslint-config/src/lib/config/jsdoc.js b/packages/eslint-config/src/lib/config/jsdoc.js new file mode 100644 index 0000000..7f7b139 --- /dev/null +++ b/packages/eslint-config/src/lib/config/jsdoc.js @@ -0,0 +1,35 @@ +// @ts-check +import jsdoc from 'eslint-plugin-jsdoc'; + +/** + * JSDoc documentation requirements. + */ +export const jsdocConfig = [ + { + files: ['src/**/*.{ts,tsx}', 'packages/**/*.{ts,tsx}', 'services/**/*.{ts,tsx}'], + plugins: { jsdoc }, + rules: { + 'jsdoc/require-jsdoc': [ + 'error', + { + contexts: [ + 'ExportNamedDeclaration > FunctionDeclaration', + 'ExportDefaultDeclaration > FunctionDeclaration', + 'TSInterfaceDeclaration', + 'TSTypeAliasDeclaration', + ], + }, + ], + 'jsdoc/require-description': 'error', + 'jsdoc/require-param': 'error', + 'jsdoc/require-returns': 'error', + 'jsdoc/require-example': 'warn', + 'jsdoc/check-alignment': 'error', + 'jsdoc/check-indentation': 'error', + 'jsdoc/check-syntax': 'error', + 'jsdoc/check-tag-names': 'error', + 'jsdoc/check-types': 'error', + 'jsdoc/valid-types': 'error', + }, + }, +]; diff --git a/packages/eslint-config/src/lib/config/monorepo.js b/packages/eslint-config/src/lib/config/monorepo.js new file mode 100644 index 0000000..bfeb597 --- /dev/null +++ b/packages/eslint-config/src/lib/config/monorepo.js @@ -0,0 +1,70 @@ +// @ts-check +import fs from 'node:fs'; +import path from 'node:path'; + +/** @type {import('eslint').Linter.Config[] | null} */ +let cachedRules = null; + +/** + * Dynamically generates restricted import rules for monorepo packages + * to ensure they use relative imports for internal code. + * + * @param {string} rootDir - The root directory of the monorepo. + * @returns {import('eslint').Linter.Config[]} An array of ESLint configurations. + */ +export function defineMonorepoRestrictedImports(rootDir) { + if (cachedRules) return cachedRules; + + const workspaces = ['packages', 'services']; + const configs = []; + + for (const workspace of workspaces) { + const workspacePath = path.join(rootDir, workspace); + if (!fs.existsSync(workspacePath)) continue; + + const entries = fs.readdirSync(workspacePath, { withFileTypes: true }); + for (const entry of entries) { + if (!entry.isDirectory()) continue; + + const pkgPath = path.join(workspacePath, entry.name); + const pkgJsonPath = path.join(pkgPath, 'package.json'); + + if (fs.existsSync(pkgJsonPath)) { + try { + const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')); + const pkgName = pkgJson.name; + // Use relative path from root to package for 'files' pattern + const relativePkgPath = path.relative(rootDir, pkgPath); + + configs.push({ + files: [`${relativePkgPath}/**/*`], + rules: { + 'no-restricted-imports': [ + 'error', + { + paths: [ + { + name: pkgName, + message: `Please use relative imports within the package instead of "${pkgName}".`, + }, + ], + patterns: [ + { + group: [`${pkgName}/*`], + message: `Please use relative imports within the package instead of "${pkgName}/*".`, + }, + ], + }, + ], + }, + }); + } catch (e) { + // Skip packages that can't be parsed + } + } + } + } + + cachedRules = configs; + return configs; +} diff --git a/packages/eslint-config/src/lib/config/testing.js b/packages/eslint-config/src/lib/config/testing.js new file mode 100644 index 0000000..31678c0 --- /dev/null +++ b/packages/eslint-config/src/lib/config/testing.js @@ -0,0 +1,43 @@ +// @ts-check +import globals from 'globals'; + +/** + * Relaxation of rules for test files and stories. + */ +export const testingConfig = [ + { + files: [ + '**/*.{test,spec,stories}.{js,jsx,ts,tsx}', + '.config/jest/**/*.{js,jsx,ts,tsx}', + '**/test-utils.tsx', + ], + languageOptions: { + globals: { + ...globals.jest, + }, + }, + rules: { + // Relax rules for test files, stories and jest configuration + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-empty-function': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-assertions': 'off', + + // Disable all JSDoc rules + 'jsdoc/require-jsdoc': 'off', + 'jsdoc/require-description': 'off', + 'jsdoc/require-param': 'off', + 'jsdoc/require-returns': 'off', + 'jsdoc/require-example': 'off', + 'jsdoc/check-alignment': 'off', + 'jsdoc/check-indentation': 'off', + 'jsdoc/check-syntax': 'off', + 'jsdoc/check-tag-names': 'off', + 'jsdoc/check-types': 'off', + 'jsdoc/valid-types': 'off', + }, + }, +]; diff --git a/packages/eslint-config/src/lib/config/tooling.js b/packages/eslint-config/src/lib/config/tooling.js new file mode 100644 index 0000000..885114c --- /dev/null +++ b/packages/eslint-config/src/lib/config/tooling.js @@ -0,0 +1,29 @@ +// @ts-check +import tseslint from 'typescript-eslint'; + +/** + * Rules for tooling, config files, and CommonJS files. + */ +export const toolingConfig = [ + // CommonJS files - disable all TypeScript rules + { + files: ['**/*.cjs'], + ...tseslint.configs.disableTypeChecked, + }, + + // Config files and tooling + { + files: ['*.config.{js,ts,mjs,cjs}', '.storybook/**/*.{js,ts,cjs,mjs}'], + rules: { + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-call': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/consistent-type-assertions': 'off', + 'jsdoc/require-jsdoc': 'off', + 'no-undef': 'off', // For CommonJS files + }, + }, +]; diff --git a/packages/eslint-config/src/lib/config/typescript.js b/packages/eslint-config/src/lib/config/typescript.js new file mode 100644 index 0000000..db46d64 --- /dev/null +++ b/packages/eslint-config/src/lib/config/typescript.js @@ -0,0 +1,61 @@ +// @ts-check +import tseslint from 'typescript-eslint'; + +/** + * TypeScript configuration. + * + * @param {string} rootDir - The root directory for the TypeScript parser. + * @returns {import('eslint').Linter.Config[]} ESLint configurations. + */ +export function getTypescriptConfig(rootDir) { + return [ + // TypeScript - Strict Configuration (only for .ts/.tsx files) + ...[...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.stylisticTypeChecked].map( + (config) => ({ + ...config, + files: ['**/*.{ts,tsx,mts,cts}'], + }) + ), + { + files: ['**/*.{ts,tsx,mts,cts}'], + languageOptions: { + parserOptions: { + projectService: true, + tsconfigRootDir: rootDir, + }, + }, + rules: { + // TypeScript strict rules + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/no-unused-vars': 'error', + '@typescript-eslint/prefer-nullish-coalescing': 'error', + '@typescript-eslint/prefer-optional-chain': 'error', + '@typescript-eslint/no-unnecessary-condition': 'error', + '@typescript-eslint/no-non-null-assertion': 'error', + '@typescript-eslint/prefer-as-const': 'error', + '@typescript-eslint/consistent-type-definitions': ['error', 'interface'], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { prefer: 'type-imports', disallowTypeAnnotations: false }, + ], + '@typescript-eslint/consistent-type-assertions': [ + 'error', + { + assertionStyle: 'never', + }, + ], + '@typescript-eslint/explicit-function-return-type': [ + 'error', + { allowExpressions: true, allowTypedFunctionExpressions: true }, + ], + }, + }, + // Allow triple-slash references in `*.d.ts` files. + { + files: ['**/*.d.ts'], + rules: { + '@typescript-eslint/triple-slash-reference': 'off', + }, + }, + ]; +} diff --git a/packages/eslint-config/src/lib/dev.js b/packages/eslint-config/src/lib/dev.js new file mode 100644 index 0000000..fb926c1 --- /dev/null +++ b/packages/eslint-config/src/lib/dev.js @@ -0,0 +1,13 @@ +// @ts-check +import path from 'node:path'; +import { defineBaseConfig } from './config/index.js'; + +// Resolve the monorepo root relative to this library's location +const rootDir = path.resolve(import.meta.dirname, '../../../../'); + +/** + * Default base configuration for the monorepo. + */ +export const baseConfig = defineBaseConfig(rootDir); + +export { defineBaseConfig }; diff --git a/packages/eslint-config/src/lib/index.js b/packages/eslint-config/src/lib/index.js new file mode 100644 index 0000000..5e7600a --- /dev/null +++ b/packages/eslint-config/src/lib/index.js @@ -0,0 +1,2 @@ +// Runtime entry point (empty) +export {}; diff --git a/packages/eslint-config/src/lib/testing.js b/packages/eslint-config/src/lib/testing.js new file mode 100644 index 0000000..289728f --- /dev/null +++ b/packages/eslint-config/src/lib/testing.js @@ -0,0 +1,2 @@ +// Testing helpers (empty) +export {}; diff --git a/packages/eslint-config/src/testing.js b/packages/eslint-config/src/testing.js new file mode 100644 index 0000000..deecbb9 --- /dev/null +++ b/packages/eslint-config/src/testing.js @@ -0,0 +1 @@ +export * from './lib/testing.js'; diff --git a/packages/rsbuild-config/package.json b/packages/rsbuild-config/package.json index 584c5de..d814c9f 100644 --- a/packages/rsbuild-config/package.json +++ b/packages/rsbuild-config/package.json @@ -2,11 +2,9 @@ "name": "@ermnvldmr/rsbuild-config", "version": "0.0.1", "type": "module", - "main": "./dist/index.js", - "types": "./dist/index.d.ts", "exports": { - ".": "./dist/index.js", - "./vitest": "./dist/vitest.js" + "./dev": "./dist/dev.js", + "./testing": "./dist/testing.js" }, "scripts": { "build": "tsc" diff --git a/packages/rsbuild-config/src/dev.ts b/packages/rsbuild-config/src/dev.ts new file mode 100644 index 0000000..42aea7a --- /dev/null +++ b/packages/rsbuild-config/src/dev.ts @@ -0,0 +1 @@ +export * from './lib/dev'; diff --git a/packages/rsbuild-config/src/index.ts b/packages/rsbuild-config/src/index.ts index 5974f20..f41a696 100644 --- a/packages/rsbuild-config/src/index.ts +++ b/packages/rsbuild-config/src/index.ts @@ -1,59 +1 @@ -import { defineConfig, type RsbuildConfig } from '@rsbuild/core'; -import { pluginReact } from '@rsbuild/plugin-react'; -import { pluginTypeCheck } from '@rsbuild/plugin-type-check'; -import { pluginDts } from 'rsbuild-plugin-dts'; - -/** - * Defines a standard Rsbuild configuration for services (apps). - * - * @param config - Optional Rsbuild configuration overrides - * @returns A complete Rsbuild configuration object - * - * @example - * ```typescript - * import { defineServiceConfig } from '@ermnvldmr/rsbuild-config'; - * export default defineServiceConfig({ - * source: { entry: { index: './src/main.ts' } } - * }); - * ``` - */ -export function defineServiceConfig(config: RsbuildConfig = {}): RsbuildConfig { - return defineConfig({ - plugins: [pluginReact(), pluginTypeCheck()], - html: { - template: './src/index.html', - }, - ...config, - }); -} - -/** - * Defines a standard Rsbuild configuration for packages (libraries). - * - * @param config - Optional Rsbuild configuration overrides - * @returns A complete Rsbuild configuration object - * - * @example - * ```typescript - * import { definePackageConfig } from '@ermnvldmr/rsbuild-config'; - * export default definePackageConfig({ - * output: { target: 'node' } - * }); - * ``` - */ -export function definePackageConfig(config: RsbuildConfig = {}): RsbuildConfig { - return defineConfig({ - plugins: [pluginReact(), pluginTypeCheck(), pluginDts()], - output: { - distPath: { - root: './dist', - js: '.', - }, - target: 'web', - }, - tools: { - htmlPlugin: false, - }, - ...config, - }); -} +export * from './lib'; diff --git a/packages/rsbuild-config/src/lib/config/index.ts b/packages/rsbuild-config/src/lib/config/index.ts new file mode 100644 index 0000000..8c42bb9 --- /dev/null +++ b/packages/rsbuild-config/src/lib/config/index.ts @@ -0,0 +1,2 @@ +export * from './rsbuild'; +export * from './vitest'; diff --git a/packages/rsbuild-config/src/lib/config/rsbuild.ts b/packages/rsbuild-config/src/lib/config/rsbuild.ts new file mode 100644 index 0000000..99e5dc8 --- /dev/null +++ b/packages/rsbuild-config/src/lib/config/rsbuild.ts @@ -0,0 +1,59 @@ +import { defineConfig, type RsbuildConfig } from '@rsbuild/core'; +import { pluginReact } from '@rsbuild/plugin-react'; +import { pluginTypeCheck } from '@rsbuild/plugin-type-check'; +import { pluginDts } from 'rsbuild-plugin-dts'; + +/** + * Defines a standard Rsbuild configuration for services (apps). + * + * @param config - Optional Rsbuild configuration overrides + * @returns A complete Rsbuild configuration object + * + * @example + * ```typescript + * import { defineServiceConfig } from '@ermnvldmr/rsbuild-config/dev'; + * export default defineServiceConfig({ + * source: { entry: { index: './src/main.ts' } } + * }); + * ``` + */ +export function defineServiceConfig(config: RsbuildConfig = {}): RsbuildConfig { + return defineConfig({ + plugins: [pluginReact(), pluginTypeCheck()], + html: { + template: './src/static/index.html', + }, + ...config, + }); +} + +/** + * Defines a standard Rsbuild configuration for packages (libraries). + * + * @param config - Optional Rsbuild configuration overrides + * @returns A complete Rsbuild configuration object + * + * @example + * ```typescript + * import { definePackageConfig } from '@ermnvldmr/rsbuild-config/dev'; + * export default definePackageConfig({ + * output: { target: 'node' } + * }); + * ``` + */ +export function definePackageConfig(config: RsbuildConfig = {}): RsbuildConfig { + return defineConfig({ + plugins: [pluginReact(), pluginTypeCheck(), pluginDts()], + output: { + distPath: { + root: './dist', + js: '.', + }, + target: 'web', + }, + tools: { + htmlPlugin: false, + }, + ...config, + }); +} diff --git a/packages/rsbuild-config/src/vitest.ts b/packages/rsbuild-config/src/lib/config/vitest.ts similarity index 82% rename from packages/rsbuild-config/src/vitest.ts rename to packages/rsbuild-config/src/lib/config/vitest.ts index 2f67dab..958bd46 100644 --- a/packages/rsbuild-config/src/vitest.ts +++ b/packages/rsbuild-config/src/lib/config/vitest.ts @@ -1,6 +1,9 @@ import { defineConfig } from 'vitest/config'; import tsconfigPaths from 'vite-tsconfig-paths'; +/** + * Base Vitest configuration for the monorepo. + */ export const baseVitestConfig = defineConfig({ plugins: [tsconfigPaths()], test: { @@ -15,11 +18,14 @@ export const baseVitestConfig = defineConfig({ }, }); +/** + * React-specific Vitest configuration. + */ export const reactVitestConfig = defineConfig({ test: { ...baseVitestConfig.test, environment: 'jsdom', - setupFiles: ['./src/setupTests.ts'], + setupFiles: ['./.config/vitest/setup.ts'], alias: { // Handle asset mocks if needed '\.(css|less|scss|sass)$': 'identity-obj-proxy', diff --git a/packages/rsbuild-config/src/lib/dev.ts b/packages/rsbuild-config/src/lib/dev.ts new file mode 100644 index 0000000..f03c228 --- /dev/null +++ b/packages/rsbuild-config/src/lib/dev.ts @@ -0,0 +1 @@ +export * from './config'; diff --git a/packages/rsbuild-config/src/lib/index.ts b/packages/rsbuild-config/src/lib/index.ts new file mode 100644 index 0000000..5e7600a --- /dev/null +++ b/packages/rsbuild-config/src/lib/index.ts @@ -0,0 +1,2 @@ +// Runtime entry point (empty) +export {}; diff --git a/packages/rsbuild-config/src/lib/testing.ts b/packages/rsbuild-config/src/lib/testing.ts new file mode 100644 index 0000000..1cada10 --- /dev/null +++ b/packages/rsbuild-config/src/lib/testing.ts @@ -0,0 +1 @@ +export * from './config/vitest'; diff --git a/packages/rsbuild-config/src/testing.ts b/packages/rsbuild-config/src/testing.ts new file mode 100644 index 0000000..4eeb9fe --- /dev/null +++ b/packages/rsbuild-config/src/testing.ts @@ -0,0 +1 @@ +export * from './lib/testing'; diff --git a/packages/stl/package.json b/packages/stl/package.json index c53a86a..8789532 100644 --- a/packages/stl/package.json +++ b/packages/stl/package.json @@ -9,6 +9,14 @@ ".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" + }, + "./testing": { + "import": "./dist/testing.js", + "types": "./dist/testing.d.ts" + }, + "./dev": { + "import": "./dist/dev.js", + "types": "./dist/dev.d.ts" } }, "files": [ diff --git a/packages/stl/rsbuild.config.ts b/packages/stl/rsbuild.config.ts index 5a8f5dc..bd74b49 100644 --- a/packages/stl/rsbuild.config.ts +++ b/packages/stl/rsbuild.config.ts @@ -1,9 +1,11 @@ -import { definePackageConfig } from '@ermnvldmr/rsbuild-config'; +import { definePackageConfig } from '@ermnvldmr/rsbuild-config/dev'; export default definePackageConfig({ source: { entry: { index: './src/index.ts', + testing: './src/testing.ts', + dev: './src/dev.ts', }, alias: { '@': './src', @@ -16,7 +18,7 @@ export default definePackageConfig({ js: '', }, filename: { - js: 'index.js', + js: '[name].js', }, cleanDistPath: true, }, diff --git a/packages/stl/src/dev.ts b/packages/stl/src/dev.ts new file mode 100644 index 0000000..12a7183 --- /dev/null +++ b/packages/stl/src/dev.ts @@ -0,0 +1 @@ +export * from './lib/dev.js'; diff --git a/packages/stl/src/index.ts b/packages/stl/src/index.ts index d7c26a5..09c185e 100644 --- a/packages/stl/src/index.ts +++ b/packages/stl/src/index.ts @@ -1,3 +1 @@ -export * from './types'; -export * from './functions'; -export * from './react'; +export * from './lib/index.js'; diff --git a/packages/stl/src/lib/dev.ts b/packages/stl/src/lib/dev.ts new file mode 100644 index 0000000..aefcc24 --- /dev/null +++ b/packages/stl/src/lib/dev.ts @@ -0,0 +1,2 @@ +// No library-specific development utilities currently +export {}; diff --git a/packages/stl/src/functions/cn/cn.test.ts b/packages/stl/src/lib/functions/cn/cn.test.ts similarity index 100% rename from packages/stl/src/functions/cn/cn.test.ts rename to packages/stl/src/lib/functions/cn/cn.test.ts diff --git a/packages/stl/src/functions/cn/cn.ts b/packages/stl/src/lib/functions/cn/cn.ts similarity index 100% rename from packages/stl/src/functions/cn/cn.ts rename to packages/stl/src/lib/functions/cn/cn.ts diff --git a/packages/stl/src/functions/index.ts b/packages/stl/src/lib/functions/index.ts similarity index 100% rename from packages/stl/src/functions/index.ts rename to packages/stl/src/lib/functions/index.ts diff --git a/packages/stl/src/lib/index.ts b/packages/stl/src/lib/index.ts new file mode 100644 index 0000000..43a975a --- /dev/null +++ b/packages/stl/src/lib/index.ts @@ -0,0 +1,3 @@ +export * from './types/index.js'; +export * from './functions/index.js'; +export * from './react/index.js'; diff --git a/packages/stl/src/react/castRef/castRef.test.ts b/packages/stl/src/lib/react/castRef/castRef.test.ts similarity index 100% rename from packages/stl/src/react/castRef/castRef.test.ts rename to packages/stl/src/lib/react/castRef/castRef.test.ts diff --git a/packages/stl/src/react/castRef/castRef.ts b/packages/stl/src/lib/react/castRef/castRef.ts similarity index 100% rename from packages/stl/src/react/castRef/castRef.ts rename to packages/stl/src/lib/react/castRef/castRef.ts diff --git a/packages/stl/src/react/genericMemo/genericMemo.test.tsx b/packages/stl/src/lib/react/genericMemo/genericMemo.test.tsx similarity index 100% rename from packages/stl/src/react/genericMemo/genericMemo.test.tsx rename to packages/stl/src/lib/react/genericMemo/genericMemo.test.tsx diff --git a/packages/stl/src/react/genericMemo/genericMemo.ts b/packages/stl/src/lib/react/genericMemo/genericMemo.ts similarity index 100% rename from packages/stl/src/react/genericMemo/genericMemo.ts rename to packages/stl/src/lib/react/genericMemo/genericMemo.ts diff --git a/packages/stl/src/react/index.ts b/packages/stl/src/lib/react/index.ts similarity index 100% rename from packages/stl/src/react/index.ts rename to packages/stl/src/lib/react/index.ts diff --git a/packages/stl/src/lib/testing.ts b/packages/stl/src/lib/testing.ts new file mode 100644 index 0000000..d7f62e0 --- /dev/null +++ b/packages/stl/src/lib/testing.ts @@ -0,0 +1,2 @@ +// No library-specific testing utilities currently +export {}; diff --git a/packages/stl/src/types/classNameProps.ts b/packages/stl/src/lib/types/classNameProps.ts similarity index 100% rename from packages/stl/src/types/classNameProps.ts rename to packages/stl/src/lib/types/classNameProps.ts diff --git a/packages/stl/src/types/index.ts b/packages/stl/src/lib/types/index.ts similarity index 100% rename from packages/stl/src/types/index.ts rename to packages/stl/src/lib/types/index.ts diff --git a/packages/stl/src/types/testIdProps.ts b/packages/stl/src/lib/types/testIdProps.ts similarity index 100% rename from packages/stl/src/types/testIdProps.ts rename to packages/stl/src/lib/types/testIdProps.ts diff --git a/packages/stl/src/testing.ts b/packages/stl/src/testing.ts new file mode 100644 index 0000000..deecbb9 --- /dev/null +++ b/packages/stl/src/testing.ts @@ -0,0 +1 @@ +export * from './lib/testing.js'; diff --git a/packages/stl/tsconfig.json b/packages/stl/tsconfig.json index 4d82a20..aad0bbf 100644 --- a/packages/stl/tsconfig.json +++ b/packages/stl/tsconfig.json @@ -3,8 +3,9 @@ "compilerOptions": { "outDir": "./dist", "declaration": true, - "declarationMap": true + "declarationMap": true, + "types": ["vitest/globals"] }, "include": ["src/**/*"], - "exclude": ["dist", "**/*.test.ts", "**/*.test.tsx"] + "exclude": ["dist"] } diff --git a/packages/stl/vitest.config.ts b/packages/stl/vitest.config.ts index a57fdb2..7b421ab 100644 --- a/packages/stl/vitest.config.ts +++ b/packages/stl/vitest.config.ts @@ -1,4 +1,4 @@ -import { baseVitestConfig } from '@ermnvldmr/rsbuild-config/vitest'; +import { baseVitestConfig } from '@ermnvldmr/rsbuild-config/dev'; import { mergeConfig } from 'vitest/config'; export default mergeConfig(baseVitestConfig, { diff --git a/packages/storybook-config/package.json b/packages/storybook-config/package.json index 853cddf..2e50560 100644 --- a/packages/storybook-config/package.json +++ b/packages/storybook-config/package.json @@ -3,10 +3,9 @@ "version": "1.0.0", "description": "Shared Storybook configuration", "type": "module", - "main": "./dist/main.js", "exports": { - ".": "./dist/main.js", - "./preview": "./dist/preview.js" + "./dev": "./dist/dev.js", + "./testing": "./dist/testing.js" }, "files": [ "dist" diff --git a/packages/storybook-config/src/dev.ts b/packages/storybook-config/src/dev.ts new file mode 100644 index 0000000..42aea7a --- /dev/null +++ b/packages/storybook-config/src/dev.ts @@ -0,0 +1 @@ +export * from './lib/dev'; diff --git a/packages/storybook-config/src/index.ts b/packages/storybook-config/src/index.ts index 2ac902e..f41a696 100644 --- a/packages/storybook-config/src/index.ts +++ b/packages/storybook-config/src/index.ts @@ -1,4 +1 @@ -import { basePreviewConfig } from './preview.js'; - -export { baseStorybookConfig } from './main.js'; -export { basePreviewConfig }; +export * from './lib'; diff --git a/packages/storybook-config/src/lib/config/index.ts b/packages/storybook-config/src/lib/config/index.ts new file mode 100644 index 0000000..2b35419 --- /dev/null +++ b/packages/storybook-config/src/lib/config/index.ts @@ -0,0 +1,2 @@ +export * from './main'; +export * from './preview'; diff --git a/packages/storybook-config/src/main.ts b/packages/storybook-config/src/lib/config/main.ts similarity index 83% rename from packages/storybook-config/src/main.ts rename to packages/storybook-config/src/lib/config/main.ts index 346bccf..717949b 100644 --- a/packages/storybook-config/src/main.ts +++ b/packages/storybook-config/src/lib/config/main.ts @@ -1,4 +1,5 @@ import { pluginBabel } from '@rsbuild/plugin-babel'; + import type { StorybookConfig } from 'storybook-react-rsbuild'; export const baseStorybookConfig: Partial = { @@ -18,18 +19,18 @@ export const baseStorybookConfig: Partial = { reactDocgen: 'react-docgen-typescript', reactDocgenTypescriptOptions: { shouldExtractLiteralValuesFromEnum: true, - propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true), + propFilter: (prop) => (prop.parent ? !prop.parent.fileName.includes('node_modules') : true), }, }, - rsbuildFinal: async (config) => { + rsbuildFinal: (config) => { // Add Babel plugin with istanbul for coverage - config.plugins = config.plugins || []; + config.plugins = config.plugins ?? []; config.plugins.push( pluginBabel({ include: /\.(?:jsx|tsx)$/, exclude: /[\\/]node_modules[\\/]/, babelLoaderOptions: (opts) => { - opts.plugins = opts.plugins || []; + opts.plugins = opts.plugins ?? []; opts.plugins.push([ 'babel-plugin-istanbul', { diff --git a/packages/storybook-config/src/preview.ts b/packages/storybook-config/src/lib/config/preview.ts similarity index 99% rename from packages/storybook-config/src/preview.ts rename to packages/storybook-config/src/lib/config/preview.ts index 75a7055..def2949 100644 --- a/packages/storybook-config/src/preview.ts +++ b/packages/storybook-config/src/lib/config/preview.ts @@ -1,4 +1,5 @@ import { withThemeByClassName } from '@storybook/addon-themes'; + import type { Preview } from '@storybook/react'; /** diff --git a/packages/storybook-config/src/lib/dev.ts b/packages/storybook-config/src/lib/dev.ts new file mode 100644 index 0000000..f03c228 --- /dev/null +++ b/packages/storybook-config/src/lib/dev.ts @@ -0,0 +1 @@ +export * from './config'; diff --git a/packages/storybook-config/src/lib/index.ts b/packages/storybook-config/src/lib/index.ts new file mode 100644 index 0000000..5e7600a --- /dev/null +++ b/packages/storybook-config/src/lib/index.ts @@ -0,0 +1,2 @@ +// Runtime entry point (empty) +export {}; diff --git a/packages/storybook-config/src/lib/testing.ts b/packages/storybook-config/src/lib/testing.ts new file mode 100644 index 0000000..59d393e --- /dev/null +++ b/packages/storybook-config/src/lib/testing.ts @@ -0,0 +1,2 @@ +// Testing entry point (empty) +export {}; diff --git a/packages/storybook-config/src/testing.ts b/packages/storybook-config/src/testing.ts new file mode 100644 index 0000000..4eeb9fe --- /dev/null +++ b/packages/storybook-config/src/testing.ts @@ -0,0 +1 @@ +export * from './lib/testing'; diff --git a/packages/ui/.storybook/main.ts b/packages/ui/.config/storybook/main.ts similarity index 98% rename from packages/ui/.storybook/main.ts rename to packages/ui/.config/storybook/main.ts index 8a38cc5..afba678 100644 --- a/packages/ui/.storybook/main.ts +++ b/packages/ui/.config/storybook/main.ts @@ -53,4 +53,4 @@ const config: StorybookConfig = { }, }; -export default config; \ No newline at end of file +export default config; diff --git a/packages/ui/.storybook/preview.tsx b/packages/ui/.config/storybook/preview.tsx similarity index 86% rename from packages/ui/.storybook/preview.tsx rename to packages/ui/.config/storybook/preview.tsx index 51b94a8..c6539e9 100644 --- a/packages/ui/.storybook/preview.tsx +++ b/packages/ui/.config/storybook/preview.tsx @@ -1,5 +1,5 @@ import type { Preview } from '@storybook/react'; -import '../src/styles/index.css'; +import '../../src/static/styles.css'; const preview: Preview = { parameters: { diff --git a/packages/ui/src/setupTests.ts b/packages/ui/.config/vitest/setup.ts similarity index 100% rename from packages/ui/src/setupTests.ts rename to packages/ui/.config/vitest/setup.ts diff --git a/packages/ui/package.json b/packages/ui/package.json index 34464e0..864d081 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -8,9 +8,16 @@ "exports": { ".": { "import": "./dist/index.js", - "types": "./dist/index.d.ts" + "types": "./dist/ui/src/index.d.ts" }, - "./styles": "./dist/styles/index.css" + "./testing": { + "import": "./dist/testing.js", + "types": "./dist/ui/src/testing.d.ts" + }, + "./dev": { + "import": "./dist/dev.js", + "types": "./dist/ui/src/dev.d.ts" + } }, "files": [ "dist" @@ -21,8 +28,8 @@ "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", - "storybook": "storybook dev -p 6007", - "build-storybook": "storybook build", + "storybook": "storybook dev -p 6007 -c .config/storybook", + "build-storybook": "storybook build -c .config/storybook", "test:storybook": "@storybook/test-runner", "test:storybook:ci": "concurrently -k -s first -n \"SB,TEST\" -c \"magenta,blue\" \"http-server storybook-static --port 6006 --silent\" \"wait-on tcp:127.0.0.1:6006 && test-storybook --coverage --url http://127.0.0.1:6006\"", "lint": "eslint src --max-warnings 0", diff --git a/packages/ui/rsbuild.config.ts b/packages/ui/rsbuild.config.ts index 1a91086..4a59799 100644 --- a/packages/ui/rsbuild.config.ts +++ b/packages/ui/rsbuild.config.ts @@ -1,9 +1,11 @@ -import { definePackageConfig } from '@ermnvldmr/rsbuild-config'; +import { definePackageConfig } from '@ermnvldmr/rsbuild-config/dev'; export default definePackageConfig({ source: { entry: { index: './src/index.ts', + testing: './src/testing.ts', + dev: './src/dev.ts', }, }, resolve: { @@ -17,6 +19,9 @@ export default definePackageConfig({ js: '', css: 'styles', }, + filename: { + js: '[name].js', + }, cleanDistPath: true, }, tools: { diff --git a/packages/ui/src/components/Article/Article.test.tsx b/packages/ui/src/components/Article/Article.test.tsx index 747332e..fa78cb3 100644 --- a/packages/ui/src/components/Article/Article.test.tsx +++ b/packages/ui/src/components/Article/Article.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Article } from './Article'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Article', () => { const props = { diff --git a/packages/ui/src/components/Breadcrumbs/Breadcrumbs.test.tsx b/packages/ui/src/components/Breadcrumbs/Breadcrumbs.test.tsx index 0d74b99..2a5f27e 100644 --- a/packages/ui/src/components/Breadcrumbs/Breadcrumbs.test.tsx +++ b/packages/ui/src/components/Breadcrumbs/Breadcrumbs.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Breadcrumbs } from './Breadcrumbs'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; import { Link } from '../Link/Link'; describe('components/Breadcrumbs', () => { diff --git a/packages/ui/src/components/Button/Button.test.tsx b/packages/ui/src/components/Button/Button.test.tsx index 3e203db..4810baf 100644 --- a/packages/ui/src/components/Button/Button.test.tsx +++ b/packages/ui/src/components/Button/Button.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Button } from './Button'; -import { render, screen, fireEvent } from '../../test-utils'; +import { render, screen, fireEvent } from '../../lib/testing'; describe('components/Button', () => { it('renders correctly as a button by default', () => { diff --git a/packages/ui/src/components/Code/Code.tsx b/packages/ui/src/components/Code/Code.tsx index 18828d7..b261c9c 100644 --- a/packages/ui/src/components/Code/Code.tsx +++ b/packages/ui/src/components/Code/Code.tsx @@ -73,13 +73,18 @@ export const Code = memo(function Code({ if (context?.isInCodeBlock) { const { showLineNumbers } = context; - + let content = children; if (typeof children === 'string') { - content = children.trimEnd().split('\n').map((line, i) => ( - // eslint-disable-next-line react/no-array-index-key - {line || '\n'} - )); + content = children + .trimEnd() + .split('\n') + .map((line, i) => ( + // eslint-disable-next-line react/no-array-index-key + + {line || '\n'} + + )); } return ( diff --git a/packages/ui/src/components/Container/Container.test.tsx b/packages/ui/src/components/Container/Container.test.tsx index 8f4ae64..2002bc8 100644 --- a/packages/ui/src/components/Container/Container.test.tsx +++ b/packages/ui/src/components/Container/Container.test.tsx @@ -2,7 +2,7 @@ import userEvent from '@testing-library/user-event'; import React from 'react'; import { Container } from './Container'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Container', () => { it('handles onPress event', async () => { diff --git a/packages/ui/src/components/Image/Image.test.tsx b/packages/ui/src/components/Image/Image.test.tsx index b1712fa..eb22822 100644 --- a/packages/ui/src/components/Image/Image.test.tsx +++ b/packages/ui/src/components/Image/Image.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Image } from './Image'; -import { render, screen, fireEvent } from '../../test-utils'; +import { render, screen, fireEvent } from '../../lib/testing'; describe('components/Image', () => { const defaultProps = { diff --git a/packages/ui/src/components/Link/Link.test.tsx b/packages/ui/src/components/Link/Link.test.tsx index b988b6c..b6278de 100644 --- a/packages/ui/src/components/Link/Link.test.tsx +++ b/packages/ui/src/components/Link/Link.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Link } from './Link'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Link', () => { it('renders correctly as a link when href is provided', () => { diff --git a/packages/ui/src/components/Markdown/Markdown.tsx b/packages/ui/src/components/Markdown/Markdown.tsx index 278d6cc..fe82155 100644 --- a/packages/ui/src/components/Markdown/Markdown.tsx +++ b/packages/ui/src/components/Markdown/Markdown.tsx @@ -79,4 +79,4 @@ export const Markdown = Object.assign(MarkdownComponent, { Pre: MarkdownPre, Hr: MarkdownHR, Img: MarkdownImg, -}); \ No newline at end of file +}); diff --git a/packages/ui/src/components/Paragraph/Paragraph.test.tsx b/packages/ui/src/components/Paragraph/Paragraph.test.tsx index 6873f2b..c7d6acd 100644 --- a/packages/ui/src/components/Paragraph/Paragraph.test.tsx +++ b/packages/ui/src/components/Paragraph/Paragraph.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Paragraph } from './Paragraph'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Paragraph', () => { it('renders as a p tag by default', () => { diff --git a/packages/ui/src/components/Stack/Stack.test.tsx b/packages/ui/src/components/Stack/Stack.test.tsx index f787daa..e23db08 100644 --- a/packages/ui/src/components/Stack/Stack.test.tsx +++ b/packages/ui/src/components/Stack/Stack.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Stack } from './Stack'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Stack', () => { it('renders children correctly', () => { diff --git a/packages/ui/src/components/Stub/Stub.test.tsx b/packages/ui/src/components/Stub/Stub.test.tsx index 8b400dc..478183a 100644 --- a/packages/ui/src/components/Stub/Stub.test.tsx +++ b/packages/ui/src/components/Stub/Stub.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Stub } from './Stub'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Stub', () => { it('renders correctly with default props', () => { diff --git a/packages/ui/src/components/Text/Text.test.tsx b/packages/ui/src/components/Text/Text.test.tsx index 921b609..1be8145 100644 --- a/packages/ui/src/components/Text/Text.test.tsx +++ b/packages/ui/src/components/Text/Text.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Text } from './Text'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Text', () => { it('renders children correctly', () => { diff --git a/packages/ui/src/components/Time/Time.test.tsx b/packages/ui/src/components/Time/Time.test.tsx index ab8be93..cba5e4d 100644 --- a/packages/ui/src/components/Time/Time.test.tsx +++ b/packages/ui/src/components/Time/Time.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { Time } from './Time'; -import { render, screen } from '../../test-utils'; +import { render, screen } from '../../lib/testing'; describe('components/Time', () => { it('renders correctly with a Date object', () => { diff --git a/packages/ui/src/components/testing.ts b/packages/ui/src/components/testing.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/packages/ui/src/components/testing.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/ui/src/dev.ts b/packages/ui/src/dev.ts new file mode 100644 index 0000000..12a7183 --- /dev/null +++ b/packages/ui/src/dev.ts @@ -0,0 +1 @@ +export * from './lib/dev.js'; diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index cc6b8eb..2b92878 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -1,2 +1,3 @@ -export * from './components'; -import './styles/index.css'; +export * from './lib/index.js'; +export * from './components/index.js'; +import './static/styles.css'; diff --git a/packages/ui/src/lib/dev.ts b/packages/ui/src/lib/dev.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/packages/ui/src/lib/dev.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/ui/src/lib/index.ts b/packages/ui/src/lib/index.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/packages/ui/src/lib/index.ts @@ -0,0 +1 @@ +export {}; diff --git a/packages/ui/src/test-utils.tsx b/packages/ui/src/lib/react/index.ts similarity index 100% rename from packages/ui/src/test-utils.tsx rename to packages/ui/src/lib/react/index.ts diff --git a/packages/ui/src/lib/testing.ts b/packages/ui/src/lib/testing.ts new file mode 100644 index 0000000..5d39580 --- /dev/null +++ b/packages/ui/src/lib/testing.ts @@ -0,0 +1 @@ +export * from './react'; diff --git a/packages/ui/src/styles/index.css b/packages/ui/src/static/styles.css similarity index 100% rename from packages/ui/src/styles/index.css rename to packages/ui/src/static/styles.css diff --git a/packages/ui/src/testing.ts b/packages/ui/src/testing.ts new file mode 100644 index 0000000..deecbb9 --- /dev/null +++ b/packages/ui/src/testing.ts @@ -0,0 +1 @@ +export * from './lib/testing.js'; diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index 4d82a20..48706b5 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -3,8 +3,9 @@ "compilerOptions": { "outDir": "./dist", "declaration": true, - "declarationMap": true + "declarationMap": true, + "types": ["vitest/globals", "@testing-library/jest-dom"] }, "include": ["src/**/*"], - "exclude": ["dist", "**/*.test.ts", "**/*.test.tsx"] + "exclude": ["dist"] } diff --git a/packages/ui/vitest.config.ts b/packages/ui/vitest.config.ts index 8ae2c08..1c44d1f 100644 --- a/packages/ui/vitest.config.ts +++ b/packages/ui/vitest.config.ts @@ -1,4 +1,4 @@ -import { reactVitestConfig } from '@ermnvldmr/rsbuild-config/vitest'; +import { reactVitestConfig } from '@ermnvldmr/rsbuild-config/dev'; import { mergeConfig } from 'vitest/config'; export default mergeConfig(reactVitestConfig, { diff --git a/services/static/rsbuild.config.ts b/services/static/rsbuild.config.ts index d6e99f8..decc32f 100644 --- a/services/static/rsbuild.config.ts +++ b/services/static/rsbuild.config.ts @@ -1,4 +1,4 @@ -import { defineServiceConfig } from '@ermnvldmr/rsbuild-config'; +import { defineServiceConfig } from '@ermnvldmr/rsbuild-config/dev'; export default defineServiceConfig({ source: { diff --git a/services/static/src/app/error.tsx b/services/static/src/app/error.tsx index 905a20a..aa6a3f4 100644 --- a/services/static/src/app/error.tsx +++ b/services/static/src/app/error.tsx @@ -1,15 +1,15 @@ import { VStack, HStack, Header, Paragraph, Link } from '@ermnvldmr/ui'; import React, { useEffect, useState } from 'react'; -import { createPage } from '../lib/createPage'; +import { createPage } from '../lib/core/createPage'; import { AUTHOR_EMAIL, AUTHOR_NAME, SITE_URL, ERROR_TITLE, ERROR_DESCRIPTION, -} from '../shared/constants'; -import { getCurrentYear, getHttpStatusUrl } from '../shared/utils'; +} from '../lib/shared/constants'; +import { getCurrentYear, getHttpStatusUrl } from '../lib/shared/utils'; createPage( function ErrorPage() { @@ -25,9 +25,7 @@ createPage( * const isNav = isNavigationTiming(entry); * ``` */ - function isNavigationTiming( - entry: PerformanceEntry - ): entry is PerformanceNavigationTiming { + function isNavigationTiming(entry: PerformanceEntry): entry is PerformanceNavigationTiming { return entry.entryType === 'navigation'; } @@ -42,17 +40,18 @@ createPage(
-
- Exceptional Situation - {status !== null && ( - <> - {' '} - - #{status} - - - )} -
+
+ Exceptional Situation + {status !== null && ( + <> + {' '} + + #{status} + + + )} +
{' '} + This location is unavailable at the moment — static content does not dwell here diff --git a/services/static/src/app/index.tsx b/services/static/src/app/index.tsx index 6ec7888..e535ac7 100644 --- a/services/static/src/app/index.tsx +++ b/services/static/src/app/index.tsx @@ -1,15 +1,15 @@ import { VStack, HStack, Header, Paragraph, Link } from '@ermnvldmr/ui'; import React from 'react'; -import { createPage } from '../lib/createPage'; +import { createPage } from '../lib/core/createPage'; import { AUTHOR_EMAIL, AUTHOR_NAME, SITE_URL, SITE_TITLE, SITE_DESCRIPTION, -} from '../shared/constants'; -import { getCurrentYear } from '../shared/utils'; +} from '../lib/shared/constants'; +import { getCurrentYear } from '../lib/shared/utils'; createPage( function Index() { diff --git a/services/static/src/global.css b/services/static/src/global.css deleted file mode 100644 index 9c35604..0000000 --- a/services/static/src/global.css +++ /dev/null @@ -1,2 +0,0 @@ -@import '../../../packages/ui/src/styles/index.css'; -@source "../../../packages/ui/src"; \ No newline at end of file diff --git a/services/static/src/lib/createPage.tsx b/services/static/src/lib/core/createPage.tsx similarity index 95% rename from services/static/src/lib/createPage.tsx rename to services/static/src/lib/core/createPage.tsx index 5a28cd0..de842b8 100644 --- a/services/static/src/lib/createPage.tsx +++ b/services/static/src/lib/core/createPage.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; -import '../global.css'; +import '../../static/global.css'; /** * Options for page creation diff --git a/services/static/src/shared/constants.ts b/services/static/src/lib/shared/constants.ts similarity index 100% rename from services/static/src/shared/constants.ts rename to services/static/src/lib/shared/constants.ts diff --git a/services/static/src/shared/utils.ts b/services/static/src/lib/shared/utils.ts similarity index 100% rename from services/static/src/shared/utils.ts rename to services/static/src/lib/shared/utils.ts diff --git a/services/static/src/static/global.css b/services/static/src/static/global.css new file mode 100644 index 0000000..1c1bab8 --- /dev/null +++ b/services/static/src/static/global.css @@ -0,0 +1,2 @@ +@import '../../../../packages/ui/src/static/styles.css'; +@source "../../../../packages/ui/src/components"; diff --git a/services/static/src/index.html b/services/static/src/static/index.html similarity index 100% rename from services/static/src/index.html rename to services/static/src/static/index.html diff --git a/services/www/.storybook/main.ts b/services/www/.config/storybook/main.ts similarity index 82% rename from services/www/.storybook/main.ts rename to services/www/.config/storybook/main.ts index 0608a91..3dedabb 100644 --- a/services/www/.storybook/main.ts +++ b/services/www/.config/storybook/main.ts @@ -18,10 +18,10 @@ const config: StorybookConfig = { rsbuildFinal: (config) => { config.resolve ||= {}; config.resolve.alias = { - ...config.resolve.alias, - '#': path.resolve(__dirname, '../src'), - '@ermnvldmr/stl': path.resolve(__dirname, '../../../packages/stl/src'), - '@ermnvldmr/ui': path.resolve(__dirname, '../../../packages/ui/src'), + ...config.resolve.alias, + '#': path.resolve(__dirname, '../src'), + '@ermnvldmr/stl': path.resolve(__dirname, '../../../packages/stl/src'), + '@ermnvldmr/ui': path.resolve(__dirname, '../../../packages/ui/src'), }; // Add Babel plugin with istanbul for coverage @@ -47,4 +47,4 @@ const config: StorybookConfig = { }, }; -export default config; \ No newline at end of file +export default config; diff --git a/services/www/.storybook/preview.tsx b/services/www/.config/storybook/preview.tsx similarity index 88% rename from services/www/.storybook/preview.tsx rename to services/www/.config/storybook/preview.tsx index cc22943..f4c61ba 100644 --- a/services/www/.storybook/preview.tsx +++ b/services/www/.config/storybook/preview.tsx @@ -1,5 +1,5 @@ import type { Preview } from '@storybook/react'; -import '#/global.css'; +import '#/static/global.css'; const preview: Preview = { parameters: { diff --git a/services/www/src/setupTests.ts b/services/www/.config/vitest/setup.ts similarity index 100% rename from services/www/src/setupTests.ts rename to services/www/.config/vitest/setup.ts diff --git a/services/www/content/registry.ts b/services/www/content/registry.ts index 760b612..955f20f 100644 --- a/services/www/content/registry.ts +++ b/services/www/content/registry.ts @@ -9,11 +9,23 @@ export interface Article { updatedDate?: Date; tags?: string[]; image?: string; - Component: React.ComponentType<{ components?: Record> }>; + Component: React.ComponentType<{ components?: Record> }>; } -function register(module: any, slug: string): Article { - const { frontmatter, default: Component } = module; +interface MdxModule { + frontmatter: { + title: string; + description?: string; + createdDate: string; + updatedDate?: string; + tags?: string[]; + image?: string; + }; + default: React.ComponentType<{ components?: Record> }>; +} + +function register(module: unknown, slug: string): Article { + const { frontmatter, default: Component } = module as MdxModule; return { slug, title: frontmatter.title, diff --git a/services/www/rsbuild.config.ts b/services/www/rsbuild.config.ts index decdb5d..4e492c4 100644 --- a/services/www/rsbuild.config.ts +++ b/services/www/rsbuild.config.ts @@ -1,4 +1,4 @@ -import { defineServiceConfig } from '@ermnvldmr/rsbuild-config'; +import { defineServiceConfig } from '@ermnvldmr/rsbuild-config/dev'; import { pluginMdx } from '@rsbuild/plugin-mdx'; import remarkFrontmatter from 'remark-frontmatter'; import remarkMdxFrontmatter from 'remark-mdx-frontmatter'; diff --git a/services/www/src/app/HomePage.tsx b/services/www/src/app/HomePage.tsx deleted file mode 100644 index 54dd45a..0000000 --- a/services/www/src/app/HomePage.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { Container, Header, Paragraph, Link, VStack } from '@ermnvldmr/ui'; -import React from 'react'; - -export const HomePage = (): React.JSX.Element => ( - - -
Welcome to my page!
- - If you see this page, my website is successfuly installed and working. -
- It will be further configured. -
- - For the source code and support please refer to{' '} - ermnvldmr.com monorepo. -
- Pictures of mine are available at{' '} - @deytenit. -
- - Check out my thoughts and articles on various matters. - - Thank you for visiting! -
-
-); diff --git a/services/www/src/app/articles/2026/ArticlePage.tsx b/services/www/src/app/articles/2026/ArticlePage.tsx deleted file mode 100644 index 84dceb8..0000000 --- a/services/www/src/app/articles/2026/ArticlePage.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { MARKDOWN_COMPONENTS } from '@ermnvldmr/ui'; -import React from 'react'; - -import { articles } from '../../../../content/registry'; -import { ArticleLayout } from '../../../layouts/ArticleLayout/ArticleLayout'; - -export const ArticlePage = (): React.JSX.Element => { - const article = articles['test-article']; - - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - if (!article) { - throw new Error('Article not found'); - } - - return ( - - - - ); -}; diff --git a/services/www/src/app/articles/2026/test-article.tsx b/services/www/src/app/articles/2026/test-article.tsx index 5cc9924..bfb5235 100644 --- a/services/www/src/app/articles/2026/test-article.tsx +++ b/services/www/src/app/articles/2026/test-article.tsx @@ -1,6 +1,9 @@ -import { ArticlePage } from './ArticlePage'; +import { MARKDOWN_COMPONENTS } from '@ermnvldmr/ui'; +import React from 'react'; + import { articles } from '../../../../content/registry'; -import { createPage } from '../../../lib/createPage'; +import { ArticleLayout } from '../../../components/layouts/ArticleLayout/ArticleLayout'; +import { createPage } from '../../../lib/core/createPage'; const article = articles['test-article']; @@ -9,7 +12,22 @@ if (!article) { throw new Error('Article not found'); } -createPage(ArticlePage, { - title: `${article.title} - Vladimir Eremin`, - description: article.description, -}); \ No newline at end of file +createPage( + function TestArticlePage(): React.JSX.Element { + return ( + + + + ); + }, + { + title: `${article.title} - Vladimir Eremin`, + description: article.description, + } +); diff --git a/services/www/src/app/articles/ArticlesList.tsx b/services/www/src/app/articles/ArticlesList.tsx deleted file mode 100644 index 4ed1245..0000000 --- a/services/www/src/app/articles/ArticlesList.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Container, Header, Link, Separator, Article } from '@ermnvldmr/ui'; -import React from 'react'; - -import { sortedArticles } from '../../../content/registry'; - -export const ArticlesList = (): React.JSX.Element => ( - -
- Articles -
-
- {sortedArticles.map((article, index) => ( - - {index > 0 && index % 2 === 0 && ( -
- -
- )} - -
- {article.description} -
- -
- ))} -
-
-); diff --git a/services/www/src/app/articles/index.tsx b/services/www/src/app/articles/index.tsx index d0068fd..bbb79e8 100644 --- a/services/www/src/app/articles/index.tsx +++ b/services/www/src/app/articles/index.tsx @@ -1,8 +1,46 @@ -import { ArticlesList } from './ArticlesList'; -import { createPage } from '../../lib/createPage'; -import { SITE_TITLE } from '../../shared/constants'; +import { Container, Header, Link, Separator, Article } from '@ermnvldmr/ui'; +import React from 'react'; -createPage(ArticlesList, { - title: `Articles | ${SITE_TITLE}`, - description: 'Browse all articles and projects.', -}); \ No newline at end of file +import { sortedArticles } from '../../../content/registry'; +import { createPage } from '../../lib/core/createPage'; +import { SITE_TITLE } from '../../lib/shared/constants'; + +createPage( + function ArticlesList(): React.JSX.Element { + return ( + +
+ Articles +
+
+ {sortedArticles.map((article, index) => ( + + {index > 0 && index % 2 === 0 && ( +
+ +
+ )} + +
+ {article.description} +
+ +
+ ))} +
+
+ ); + }, + { + title: `Articles | ${SITE_TITLE}`, + description: 'Browse all articles and projects.', + } +); diff --git a/services/www/src/app/index.tsx b/services/www/src/app/index.tsx index c545d84..5b92bda 100644 --- a/services/www/src/app/index.tsx +++ b/services/www/src/app/index.tsx @@ -1,5 +1,34 @@ -import { HomePage } from './HomePage'; -import { createPage } from '../lib/createPage'; -import { SITE_DESCRIPTION, SITE_TITLE } from '../shared/constants'; +import { Container, Header, Paragraph, Link, VStack } from '@ermnvldmr/ui'; +import React from 'react'; -createPage(HomePage, { title: SITE_TITLE, description: SITE_DESCRIPTION }); \ No newline at end of file +import { createPage } from '../lib/core/createPage'; +import { SITE_DESCRIPTION, SITE_TITLE } from '../lib/shared/constants'; + +createPage( + function HomePage(): React.JSX.Element { + return ( + + +
Welcome to my page!
+ + If you see this page, my website is successfuly installed and working. +
+ It will be further configured. +
+ + For the source code and support please refer to{' '} + ermnvldmr.com monorepo. +
+ Pictures of mine are available at{' '} + @deytenit. +
+ + Check out my thoughts and articles on various matters. + + Thank you for visiting! +
+
+ ); + }, + { title: SITE_TITLE, description: SITE_DESCRIPTION } +); diff --git a/services/www/src/layouts/ArticleLayout/ArticleLayout.stories.tsx b/services/www/src/components/layouts/ArticleLayout/ArticleLayout.stories.tsx similarity index 100% rename from services/www/src/layouts/ArticleLayout/ArticleLayout.stories.tsx rename to services/www/src/components/layouts/ArticleLayout/ArticleLayout.stories.tsx diff --git a/services/www/src/layouts/ArticleLayout/ArticleLayout.tsx b/services/www/src/components/layouts/ArticleLayout/ArticleLayout.tsx similarity index 100% rename from services/www/src/layouts/ArticleLayout/ArticleLayout.tsx rename to services/www/src/components/layouts/ArticleLayout/ArticleLayout.tsx diff --git a/services/www/src/widgets/Welcome.stories.tsx b/services/www/src/components/widgets/Welcome.stories.tsx similarity index 100% rename from services/www/src/widgets/Welcome.stories.tsx rename to services/www/src/components/widgets/Welcome.stories.tsx diff --git a/services/www/src/widgets/Welcome.tsx b/services/www/src/components/widgets/Welcome.tsx similarity index 100% rename from services/www/src/widgets/Welcome.tsx rename to services/www/src/components/widgets/Welcome.tsx diff --git a/services/www/src/global.css b/services/www/src/global.css deleted file mode 100644 index 9de8587..0000000 --- a/services/www/src/global.css +++ /dev/null @@ -1,2 +0,0 @@ -@import '../../../packages/ui/src/styles/index.css'; -@source "../../../packages/ui/src"; diff --git a/services/www/src/lib/createPage.tsx b/services/www/src/lib/core/createPage.tsx similarity index 91% rename from services/www/src/lib/createPage.tsx rename to services/www/src/lib/core/createPage.tsx index 25893eb..4e8b4c6 100644 --- a/services/www/src/lib/createPage.tsx +++ b/services/www/src/lib/core/createPage.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { createRoot } from 'react-dom/client'; -import '../global.css'; // Ensure global styles are available +import '../../static/global.css'; // Ensure global styles are available /** * diff --git a/services/www/src/lib/shared/constants.ts b/services/www/src/lib/shared/constants.ts new file mode 100644 index 0000000..1949f68 --- /dev/null +++ b/services/www/src/lib/shared/constants.ts @@ -0,0 +1,9 @@ +/** + * The main title of the website. + */ +export const SITE_TITLE = 'Vladimir Eremin'; + +/** + * The main description of the website. + */ +export const SITE_DESCRIPTION = 'Thoughts and creations of mine'; diff --git a/services/www/src/shared/constants.ts b/services/www/src/shared/constants.ts deleted file mode 100644 index 76d3c38..0000000 --- a/services/www/src/shared/constants.ts +++ /dev/null @@ -1,8 +0,0 @@ -export /** - * - */ -const SITE_TITLE = 'Vladimir Eremin'; -export /** - * - */ -const SITE_DESCRIPTION = 'Thoughts and creations of mine'; diff --git a/services/www/src/static/global.css b/services/www/src/static/global.css new file mode 100644 index 0000000..1c1bab8 --- /dev/null +++ b/services/www/src/static/global.css @@ -0,0 +1,2 @@ +@import '../../../../packages/ui/src/static/styles.css'; +@source "../../../../packages/ui/src/components"; diff --git a/services/www/src/index.html b/services/www/src/static/index.html similarity index 100% rename from services/www/src/index.html rename to services/www/src/static/index.html diff --git a/services/www/vitest.config.ts b/services/www/vitest.config.ts index cfc8698..b495c18 100644 --- a/services/www/vitest.config.ts +++ b/services/www/vitest.config.ts @@ -1,4 +1,4 @@ -import { reactVitestConfig } from '@ermnvldmr/rsbuild-config/vitest'; +import { reactVitestConfig } from '@ermnvldmr/rsbuild-config/dev'; import { mergeConfig } from 'vitest/config'; export default mergeConfig(reactVitestConfig, {