From bbb40c1eb1d4058de54581188ae888c36fab3205 Mon Sep 17 00:00:00 2001 From: "k.hiro1818" Date: Sun, 18 Oct 2026 21:50:36 +0000 Subject: [PATCH] refactor: replace $features and @ aliases with #features subpath imports SvelteKit 3 deprecates kit.alias. Following #4190 ($lib to #lib), move src/features imports to package.json#imports and drop the alias block from svelte.config.js, so the Kit 3 migration does not need kit.alias. - Add "#features/*": "./src/features/*" to package.json imports - Rewrite 286 specifiers in 144 files ($features 284, @/features 2) with explicit extensions; the rewrite is script-generated and reproducible - Remove the whole alias block from svelte.config.js; leftover $features or @/ imports now fail type checking, while $lib stays blocked by the lint rules from #4190 - Update docs/guides and the tsconfig/svelte.config comments, cover @/ in the documented rg sweep, and point the CodeRabbit DB rule at #lib/server/database.js (missed in #4190) Co-Authored-By: Claude Opus 5.5 --- .coderabbit.yaml | 2 +- docs/guides/agent-rules/testing-e2e.md | 6 +++--- docs/guides/architecture.md | 12 ++++++------ package.json | 3 ++- src/app.d.ts | 2 +- .../components/contest-table/TaskTable.svelte | 8 ++++---- .../contest-table/TaskTableBodyCell.svelte | 6 +++--- .../stores/active_contest_type.svelte.test.ts | 4 ++-- .../tasks/stores/active_contest_type.svelte.ts | 2 +- .../tasks/utils/contest-table/aalc_provider.ts | 2 +- .../utils/contest-table/abc_providers.test.ts | 2 +- .../tasks/utils/contest-table/abc_providers.ts | 2 +- .../utils/contest-table/abs_provider.test.ts | 2 +- .../tasks/utils/contest-table/abs_provider.ts | 2 +- .../utils/contest-table/acl_providers.test.ts | 2 +- .../tasks/utils/contest-table/acl_providers.ts | 2 +- .../utils/contest-table/agc_provider.test.ts | 2 +- .../tasks/utils/contest-table/agc_provider.ts | 2 +- .../utils/contest-table/aoj_icpc_providers.ts | 2 +- .../utils/contest-table/aoj_jag_providers.ts | 2 +- .../tasks/utils/contest-table/aoj_labels.ts | 2 +- .../utils/contest-table/arc_providers.test.ts | 2 +- .../tasks/utils/contest-table/arc_providers.ts | 2 +- .../utils/contest-table/awc_provider.test.ts | 2 +- .../tasks/utils/contest-table/awc_provider.ts | 2 +- .../contest-table/axc_like_provider.test.ts | 2 +- .../utils/contest-table/axc_like_provider.ts | 2 +- .../contest_table_provider_base.test.ts | 2 +- .../contest-table/contest_table_provider_base.ts | 2 +- .../contest_table_provider_group.test.ts | 2 +- .../contest_table_provider_group.ts | 2 +- .../contest_table_provider_groups.test.ts | 2 +- .../tasks/utils/contest-table/dp_providers.ts | 2 +- .../tasks/utils/contest-table/fps24_provider.ts | 2 +- .../tasks/utils/contest-table/game24_provider.ts | 2 +- .../tasks/utils/contest-table/joi_providers.ts | 2 +- .../contest-table/math_and_algorithm_provider.ts | 2 +- .../contest-table/tessoku_book_providers.ts | 2 +- .../contest-table/typical90_provider.test.ts | 2 +- .../utils/contest-table/typical90_provider.ts | 2 +- src/features/votes/actions/vote_actions.ts | 4 ++-- .../components/RelativeEvaluationBadge.svelte | 2 +- .../votes/components/VotableGrade.svelte | 10 +++++----- .../votes/components/VoteDonutChart.svelte | 6 +++--- src/features/votes/server/cache.test.ts | 2 +- src/features/votes/server/cache.ts | 2 +- src/features/votes/services/vote_grade.test.ts | 4 ++-- src/features/votes/services/vote_grade.ts | 8 ++++---- .../votes/services/vote_statistics.test.ts | 2 +- src/features/votes/services/vote_statistics.ts | 2 +- src/features/votes/utils/donut_chart.ts | 2 +- src/features/votes/utils/median.ts | 2 +- src/features/votes/zod/schema.test.ts | 2 +- .../components/detail/WorkBookTasksTable.svelte | 2 +- .../components/list/AcceptedCounter.svelte | 2 +- .../components/list/CreatedByUserTable.svelte | 16 ++++++++-------- .../components/list/CurriculumTable.svelte | 16 ++++++++-------- .../list/CurriculumWorkBookList.svelte | 10 +++++----- .../components/list/SolutionTable.svelte | 14 +++++++------- .../components/list/SolutionWorkBookList.svelte | 12 ++++++------ .../components/list/TitleTableBodyCell.svelte | 6 +++--- .../components/list/WorkBookList.svelte | 10 +++++----- .../list/WorkbookAuthorActionsCell.svelte | 4 ++-- .../list/WorkbookCompletionCell.svelte | 2 +- .../components/list/WorkbookProgressCell.svelte | 4 ++-- .../components/shared/WorkBookForm.svelte | 6 +++--- .../components/shared/WorkBookInputFields.svelte | 2 +- .../workbooks/fixtures/solution_category_map.ts | 2 +- .../workbooks/fixtures/workbook_placements.ts | 4 ++-- src/features/workbooks/fixtures/workbooks.ts | 2 +- src/features/workbooks/server/cache.ts | 2 +- .../services/workbook_placements/crud.test.ts | 6 +++--- .../services/workbook_placements/crud.ts | 4 ++-- .../workbook_placements/initializers.test.ts | 4 ++-- .../services/workbook_placements/initializers.ts | 4 ++-- .../workbooks/services/workbook_tasks.test.ts | 4 ++-- .../workbooks/services/workbook_tasks.ts | 2 +- .../workbooks/services/workbooks.test.ts | 6 +++--- src/features/workbooks/services/workbooks.ts | 14 +++++++------- .../stores/replenishment_workbook.test.ts | 2 +- .../workbooks/types/workbook_placement.ts | 4 ++-- .../utils/solution_category_group.test.ts | 4 ++-- .../workbooks/utils/solution_category_group.ts | 4 ++-- src/features/workbooks/utils/workbook.test.ts | 2 +- .../workbooks/utils/workbook_tasks.test.ts | 4 ++-- src/features/workbooks/utils/workbook_tasks.ts | 2 +- .../workbooks/utils/workbook_url_params.test.ts | 4 ++-- .../workbooks/utils/workbook_url_params.ts | 4 ++-- src/features/workbooks/utils/workbooks.test.ts | 8 ++++---- src/features/workbooks/utils/workbooks.ts | 6 +++--- src/features/workbooks/zod/schema.test.ts | 6 +++--- src/features/workbooks/zod/schema.ts | 4 ++-- src/hooks.server.ts | 2 +- .../SubmissionStatus/UpdatingDropdown.svelte | 4 ++-- src/lib/components/TaskSearchBox.svelte | 4 ++-- src/lib/components/ThermometerProgressBar.svelte | 2 +- .../components/Trophies/CompletedTasks.svelte | 2 +- src/lib/services/task_results.ts | 2 +- src/lib/services/tasks.ts | 2 +- src/lib/utils/task.ts | 2 +- .../(admin)/account_transfer/+page.server.ts | 2 +- src/routes/(admin)/tags/+page.server.ts | 2 +- src/routes/(admin)/tags/[tag_id]/+page.server.ts | 2 +- src/routes/(admin)/tasks/+page.server.ts | 2 +- .../(admin)/tasks/[task_id]/+page.server.ts | 2 +- src/routes/(admin)/tasks/grade/+page.server.ts | 4 ++-- .../grade/_components/TaskGradeTable.svelte | 4 ++-- .../grade/_utils/grade_table_filter.test.ts | 2 +- .../tasks/grade/_utils/grade_table_filter.ts | 2 +- .../(admin)/workbooks/order/+page.server.ts | 4 ++-- src/routes/(admin)/workbooks/order/+server.ts | 6 +++--- .../order/_components/KanbanBoard.svelte | 2 +- .../order/_components/KanbanCard.svelte | 4 ++-- .../order/_components/KanbanTabBar.svelte | 5 ++++- .../(admin)/workbooks/order/_fixtures/kanban.ts | 4 ++-- .../(admin)/workbooks/order/_types/kanban.ts | 2 +- .../workbooks/order/_utils/kanban.test.ts | 2 +- .../(admin)/workbooks/order/_utils/kanban.ts | 2 +- src/routes/(auth)/login/+page.server.ts | 4 ++-- src/routes/(auth)/login/+page.svelte | 2 +- src/routes/(auth)/logout/+page.server.ts | 2 +- src/routes/(auth)/signup/+page.server.ts | 4 ++-- src/routes/problems/+page.server.ts | 6 +++--- src/routes/problems/+page.svelte | 2 +- src/routes/problems/[slug]/+page.server.ts | 2 +- src/routes/problems/getMedianVote/+server.ts | 4 ++-- src/routes/problems/getMyVote/+server.ts | 2 +- src/routes/problems/page_server.test.ts | 4 ++-- src/routes/sitemap.xml/+server.ts | 4 ++-- src/routes/users/[username]/+page.server.ts | 2 +- src/routes/users/edit/+page.server.ts | 4 ++-- src/routes/users/edit/+page.svelte | 4 ++-- src/routes/votes/+page.server.ts | 2 +- src/routes/votes/+page.svelte | 6 +++--- src/routes/votes/[slug]/+page.server.ts | 8 ++++---- src/routes/votes/[slug]/+page.svelte | 12 ++++++------ src/routes/votes/page_server.test.ts | 4 ++-- src/routes/workbooks/+page.server.ts | 16 ++++++++-------- src/routes/workbooks/+page.svelte | 12 ++++++------ src/routes/workbooks/[slug]/+page.server.ts | 12 ++++++------ src/routes/workbooks/[slug]/+page.svelte | 8 ++++---- src/routes/workbooks/create/+page.server.ts | 9 ++++++--- src/routes/workbooks/create/+page.svelte | 4 ++-- src/routes/workbooks/edit/[slug]/+page.server.ts | 8 ++++---- src/routes/workbooks/edit/[slug]/+page.svelte | 4 ++-- src/test/lib/services/tasks.test.ts | 4 ++-- src/test/lib/utils/task.test.ts | 2 +- src/test/lib/utils/test_cases/task_results.ts | 2 +- svelte.config.js | 11 +---------- tsconfig.json | 2 +- 150 files changed, 306 insertions(+), 308 deletions(-) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index e85513904..f50288895 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -25,7 +25,7 @@ reviews: - path: 'src/lib/server/**' instructions: | - This directory is server-only. Never import from client-side code or Svelte components. - - DB client must be accessed only via `$lib/server/database`. + - DB client must be accessed only via `#lib/server/database.js`. # --- Schema / validation --- - path: 'src/**/zod/**' instructions: | diff --git a/docs/guides/agent-rules/testing-e2e.md b/docs/guides/agent-rules/testing-e2e.md index 1c38e55ae..71e826e21 100644 --- a/docs/guides/agent-rules/testing-e2e.md +++ b/docs/guides/agent-rules/testing-e2e.md @@ -10,14 +10,14 @@ paths: ## Setup - File extension: **must** be `.spec.ts` (`.test.ts` not detected by `playwright.config.ts`) -- No path aliases or subpath imports (`$features` is resolved only by Vite; `#lib/*.js` resolves to `src/lib/*.js`, but the Playwright runner does not map it to the `.ts` source). Use type-only imports for types: +- No runtime imports through subpath imports (`#lib/*.js` and `#features/*.js` resolve to `src/**/*.js`, but the Playwright runner does not map them to the `.ts` source). Use relative imports, or type-only imports for types: ```typescript // Bad: runtime import fails in E2E -import { TAB_SOLUTION } from '$features/workbooks/types/workbook'; +import { TAB_SOLUTION } from '#features/workbooks/types/workbook.js'; // Good: type-only import + local constant -import type { WorkBookTab } from '$features/workbooks/types/workbook'; +import type { WorkBookTab } from '#features/workbooks/types/workbook.js'; const TAB_SOLUTION: WorkBookTab = 'solution'; ``` diff --git a/docs/guides/architecture.md b/docs/guides/architecture.md index 9f35fb9b5..4b7f08bcd 100644 --- a/docs/guides/architecture.md +++ b/docs/guides/architecture.md @@ -139,16 +139,16 @@ include: [ ]; ``` -### 6. path alias と subpath imports +### 6. subpath imports(`#lib`・`#features`) -`src/lib` は `package.json#imports` の `#lib/*` で参照する。SvelteKit 3 で組み込みの `$lib` が削除されるため `$lib` は使わず、oxlint と ESLint の `no-restricted-imports` で禁止している。 -`#lib` には明示的な拡張子が必要で、TS モジュールは `.js`、コンポーネントは `.svelte`、runes モジュール(`.svelte.ts`)は `.svelte.js` と書く。`vi.mock` の specifier も同じ形にする。 -lint が検出するのは import・export 宣言(`import type`・`export … from` を含む)と `.ts` の動的 `import()` で、`vi.mock('$lib/...')` と `.svelte` 内の動的 `import()` は検出しない。import の specifier をまとめて変えたときは、`rg -n '\$lib' src e2e prisma` で残りが無いことも確かめる。 -`$features` は `svelte.config.js` の alias で定義している。 +`src/lib` は `package.json#imports` の `#lib/*`、`src/features` は `#features/*` で参照する。SvelteKit 3 は組み込みの `$lib` を削除し、`kit.alias` も非推奨にするため、`svelte.config.js` に alias は置かない。 +拡張子は明示する。TS モジュールは `.js`、コンポーネントは `.svelte`、runes モジュール(`.svelte.ts`)は `.svelte.js` と書く。`vi.mock` の specifier も同じ形にする。 +`$lib` は Kit 2 が組み込みで解決してしまうため、oxlint と ESLint の `no-restricted-imports` で禁止している。lint が検出するのは import・export 宣言(`import type`・`export … from` を含む)と `.ts` の動的 `import()` で、`vi.mock('$lib/...')` と `.svelte` 内の動的 `import()` は検出しない。`$features` と `@/` は alias が無いので、import すると型チェックで失敗する。 +import の specifier をまとめて変えたときは、`rg -n '\$lib|\$features|@/' src e2e prisma` で残りが無いことも確かめる。 ```typescript import { formatDate } from '#lib/utils/format.js'; -import WorkBookForm from '$features/workbooks/components/shared/WorkBookForm.svelte'; +import WorkBookForm from '#features/workbooks/components/shared/WorkBookForm.svelte'; import type { PageServerLoad } from './$types'; ``` diff --git a/package.json b/package.json index d16d1b94c..4ee8d36dd 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,8 @@ }, "type": "module", "imports": { - "#lib/*": "./src/lib/*" + "#lib/*": "./src/lib/*", + "#features/*": "./src/features/*" }, "dependencies": { "@dnd-kit/helpers": "0.5.1", diff --git a/src/app.d.ts b/src/app.d.ts index ec0f9a009..30b104fb9 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -7,7 +7,7 @@ declare global { namespace App { // interface Error {} interface Locals { - auth: import('$features/auth/server/auth').AuthRequest; + auth: import('#features/auth/server/auth.js').AuthRequest; user: { id: string; name: string; diff --git a/src/features/tasks/components/contest-table/TaskTable.svelte b/src/features/tasks/components/contest-table/TaskTable.svelte index ab635fa87..302492f9b 100644 --- a/src/features/tasks/components/contest-table/TaskTable.svelte +++ b/src/features/tasks/components/contest-table/TaskTable.svelte @@ -18,18 +18,18 @@ ContestTableProvider, ContestTableDisplayConfig, ContestTableMetaData, - } from '$features/tasks/types/contest-table/contest_table_provider'; + } from '#features/tasks/types/contest-table/contest_table_provider.js'; import type { ContestTaskPairKey } from '#lib/types/contest_task_pair.js'; - import type { VoteStatisticsMap } from '$features/votes/types/vote_result'; + import type { VoteStatisticsMap } from '#features/votes/types/vote_result.js'; import TaskTableBodyCell from './TaskTableBodyCell.svelte'; - import { activeContestTypeStore } from '$features/tasks/stores/active_contest_type.svelte'; + import { activeContestTypeStore } from '#features/tasks/stores/active_contest_type.svelte.js'; import { contestTableProviderGroups, type ContestTableProviderGroup, type ContestTableProviderGroups, - } from '$features/tasks/utils/contest-table/contest_table_provider'; + } from '#features/tasks/utils/contest-table/contest_table_provider.js'; import { useLocalStorage } from '#lib/stores/local_storage_helper.svelte.js'; diff --git a/src/features/tasks/components/contest-table/TaskTableBodyCell.svelte b/src/features/tasks/components/contest-table/TaskTableBodyCell.svelte index 47197ed3d..af899be68 100644 --- a/src/features/tasks/components/contest-table/TaskTableBodyCell.svelte +++ b/src/features/tasks/components/contest-table/TaskTableBodyCell.svelte @@ -1,13 +1,13 @@ diff --git a/src/features/workbooks/components/list/SolutionWorkBookList.svelte b/src/features/workbooks/components/list/SolutionWorkBookList.svelte index d82d1a21f..64af06090 100644 --- a/src/features/workbooks/components/list/SolutionWorkBookList.svelte +++ b/src/features/workbooks/components/list/SolutionWorkBookList.svelte @@ -3,24 +3,24 @@ import type { Roles } from '#lib/types/user.js'; import type { TaskResults } from '#lib/types/task.js'; - import type { WorkbooksList } from '$features/workbooks/types/workbook'; + import type { WorkbooksList } from '#features/workbooks/types/workbook.js'; import { SolutionCategory, type SolutionCategories, SOLUTION_LABELS, ALL_SOLUTION_CATEGORIES, type SelectedSolutionCategory, - } from '$features/workbooks/types/workbook_placement'; + } from '#features/workbooks/types/workbook_placement.js'; - import { countReadableWorkbooks } from '$features/workbooks/utils/workbooks'; + import { countReadableWorkbooks } from '#features/workbooks/utils/workbooks.js'; import { groupBySolutionCategory, filterGroupsByRole, type WorkbookGroup, - } from '$features/workbooks/utils/solution_category_group'; + } from '#features/workbooks/utils/solution_category_group.js'; - import SolutionTable from '$features/workbooks/components/list/SolutionTable.svelte'; - import EmptyWorkbookList from '$features/workbooks/components/list/EmptyWorkbookList.svelte'; + import SolutionTable from '#features/workbooks/components/list/SolutionTable.svelte'; + import EmptyWorkbookList from '#features/workbooks/components/list/EmptyWorkbookList.svelte'; interface Props { workbooks: WorkbooksList; diff --git a/src/features/workbooks/components/list/TitleTableBodyCell.svelte b/src/features/workbooks/components/list/TitleTableBodyCell.svelte index f2a747913..cedbba6eb 100644 --- a/src/features/workbooks/components/list/TitleTableBodyCell.svelte +++ b/src/features/workbooks/components/list/TitleTableBodyCell.svelte @@ -3,10 +3,10 @@ import { TableBodyCell } from 'flowbite-svelte'; - import type { WorkbookList } from '$features/workbooks/types/workbook'; + import type { WorkbookList } from '#features/workbooks/types/workbook.js'; - import { getUrlSlugFrom } from '$features/workbooks/utils/workbooks'; - import PublicationStatusLabel from '$features/workbooks/components/shared/PublicationStatusLabel.svelte'; + import { getUrlSlugFrom } from '#features/workbooks/utils/workbooks.js'; + import PublicationStatusLabel from '#features/workbooks/components/shared/PublicationStatusLabel.svelte'; interface Props { paddingLeft?: string; diff --git a/src/features/workbooks/components/list/WorkBookList.svelte b/src/features/workbooks/components/list/WorkBookList.svelte index 6012ed0a5..e728e6d09 100644 --- a/src/features/workbooks/components/list/WorkBookList.svelte +++ b/src/features/workbooks/components/list/WorkBookList.svelte @@ -1,16 +1,16 @@