Skip to content

refactor: replace $features and @ aliases with #features subpath imports - #4191

Merged
KATO-Hiro merged 1 commit into
stagingfrom
refactor/features-subpath-imports
Oct 18, 2026
Merged

KATO-Hiro merged 1 commit into
stagingfrom
refactor/features-subpath-imports

Conversation

@KATO-Hiro

Copy link
Copy Markdown
Collaborator

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 refactor: lib subpath imports for kit v3 #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 refactor: lib subpath imports for kit v3 #4190)

概要

SvelteKit 3 では kit.alias が非推奨になります。#4190($lib → #lib)に続けて、src/features への importも package.json#imports の #features/* に置き換え、svelte.config.js の alias を丸ごと削除します。これで Kit 3 への移行時に kit.alias を使わずに済みます。現行の Kit 2.70.3 のまま動作します。

変更内容

  • package.json の imports に "#features/*": "./src/features/*" を追加
  • 144ファイル・286箇所を #features/... に置換($features 284箇所、@/features 2箇所。下記の codemod で生成)
  • svelte.config.js の alias(@・$lib・$lib/*・$features・$features/*)を削除
  • docs/guides(architecture・testing-e2e)と、tsconfig.json・svelte.config.js のコメントを更新
  • .coderabbit.yaml の DB クライアントの規則を #lib/server/database.js に修正(refactor: lib subpath imports for kit v3 #4190 での取りこぼし)

手で編集したのは package.json・svelte.config.js・tsconfig.json・.coderabbit.yaml と docs/guides の2ファイルです。残りの144ファイルは codemod の出力で、そのうち2ファイル(KanbanTabBar.svelte・workbooks/create/+page.server.ts)だけ pnpm format が行幅で整形しています。

レビューの方法

置換部分は、この PR の base(485ce861)で codemod を再実行すると同じ結果になります。手での確認は、上記の手で編集したファイルに絞れます。

git switch --detach 485ce861
python3 -I codemod_subpath_imports.py . features   # 下記のスクリプトを保存して実行
pnpm format
git diff refactor/features-subpath-imports -- src e2e prisma   # 差分なし

確認したこと

  • pnpm lint、pnpm check(0 errors、警告数は変更前と同じ)、pnpm test:unit(2726件)、pnpm build
  • E2E: signin / redirect_after_login / votes / workbook_edit / workbook_order(56件)
  • seed の import 経路(tsx で解決できる)
  • alias の削除後に $features を import すると、型チェックで Cannot find module になること(一時ファイルで確認)
  • rg -n '\$lib|\$features|@/' src e2e prisma が0件。リポジトリ全体でも、残っているのは lint 規則と説明文だけ
  • Codex の cross-review: Critical・Severe の指摘なし

作業中の branch がある方へ

この PR のマージ後に rebase すると、$features・@/ の import が残っている箇所は型チェックと build で失敗します。rebase 後に codemod を再実行すれば、新しく追加したファイルも含めて置換されます。何度実行しても結果は変わりません。

python3 -I codemod_subpath_imports.py . features
pnpm format
rg -n '\$lib|\$features|@/' src e2e prisma   # 0件になることを確認

#4190 より前から続いている branch で $lib も残っている場合は、先に lib モードを実行してください(python3 -I codemod_subpath_imports.py . lib)。

vi.mock の specifier は型チェックの対象外なので、上の rg で残りを確かめてください。E2E の spec では #features を使わず、相対 import のままにしてください。Playwright のランナーは #features/*.js を .ts の実体に対応付けられないためです。

codemod_subpath_imports.py
"""Rewrite alias specifiers to package.json subpath imports with an explicit extension.

Usage: python3 -I codemod_subpath_imports.py <repo-root> <lib|features>

- lib:      `$lib/...` -> `#lib/...`
- features: `$features/...` and `@/features/...` -> `#features/...`

The rewrite is idempotent, so it can be re-run on a branch after rebasing onto the change.
"""
import os
import re
import sys

root = sys.argv[1]
target = sys.argv[2]

# (specifier prefix, source directory relative to the root, replacement prefix)
RULES = {
    'lib': [('$lib/', 'src/lib', '#lib/')],
    'features': [
        ('$features/', 'src/features', '#features/'),
        ('@/features/', 'src/features', '#features/'),
    ],
}

if target not in RULES:
    sys.exit(f'unknown target: {target} (expected one of {", ".join(RULES)})')

rules = [
    (re.compile(r"""(['"])""" + re.escape(prefix) + r"""([^'"]+)\1"""), os.path.join(root, source), replacement)
    for prefix, source, replacement in RULES[target]
]

unresolved = []
changed_files = 0
changed_specs = 0
file_changes = 0
current_file = ''


def resolve(base_dir, path):
    # a `.js` specifier is kept as is because TypeScript and Vite map it to the `.ts` source;
    # other existing files keep their extension (e.g. `.svelte` components)
    if path.endswith('.js') or os.path.isfile(os.path.join(base_dir, path)):
        return path
    # `x.svelte` that only exists as `x.svelte.ts` is a runes module and becomes `x.svelte.js`
    candidates = [
        (path + '.ts', path + '.js'),
        (path + '.svelte.ts', path + '.svelte.js'),
        (path + '/index.ts', path + '/index.js'),
        (path + '.js', path + '.js'),
    ]
    for source, specifier in candidates:
        if os.path.isfile(os.path.join(base_dir, source)):
            return specifier
    return None


def make_replacer(base_dir, replacement):
    def replace_specifier(match):
        global changed_specs, file_changes
        resolved = resolve(base_dir, match.group(2))
        if resolved is None:
            unresolved.append((current_file, match.group(0)))
            return match.group(0)
        file_changes += 1
        changed_specs += 1
        return f'{match.group(1)}{replacement}{resolved}{match.group(1)}'

    return replace_specifier


for base in ('src', 'e2e', 'prisma'):
    for dirpath, dirnames, filenames in os.walk(os.path.join(root, base)):
        dirnames[:] = [name for name in dirnames if name not in ('node_modules', '.svelte-kit')]
        for filename in filenames:
            if not filename.endswith(('.ts', '.svelte', '.js')):
                continue
            full = os.path.join(dirpath, filename)
            current_file = os.path.relpath(full, root)
            text = open(full, encoding='utf-8').read()
            file_changes = 0
            new_text = text
            for pattern, base_dir, replacement in rules:
                new_text = pattern.sub(make_replacer(base_dir, replacement), new_text)
            if file_changes:
                open(full, 'w', encoding='utf-8').write(new_text)
                changed_files += 1

print(f'files changed: {changed_files}, specifiers changed: {changed_specs}, unresolved: {len(unresolved)}')
for item in unresolved:
    print('UNRESOLVED', item)

🤖 Generated with Claude Code

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 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 150 files, which is 50 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration
  • Configuration used: Repository: AtCoder-NoviSteps/AtCoderNoviSteps/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 38095edc-e975-4a48-8b00-97101d1f9c47
📥 Commits

Reviewing files that changed from the base of the PR and between 485ce86 and bbb40c1.

📒 Files selected for processing: 150
  • .coderabbit.yaml
  • docs/guides/agent-rules/testing-e2e.md
  • docs/guides/architecture.md
  • package.json
  • src/app.d.ts
  • src/features/tasks/components/contest-table/TaskTable.svelte
  • src/features/tasks/components/contest-table/TaskTableBodyCell.svelte
  • src/features/tasks/stores/active_contest_type.svelte.test.ts
  • src/features/tasks/stores/active_contest_type.svelte.ts
  • src/features/tasks/utils/contest-table/aalc_provider.ts
  • src/features/tasks/utils/contest-table/abc_providers.test.ts
  • src/features/tasks/utils/contest-table/abc_providers.ts
  • src/features/tasks/utils/contest-table/abs_provider.test.ts
  • src/features/tasks/utils/contest-table/abs_provider.ts
  • src/features/tasks/utils/contest-table/acl_providers.test.ts
  • src/features/tasks/utils/contest-table/acl_providers.ts
  • src/features/tasks/utils/contest-table/agc_provider.test.ts
  • src/features/tasks/utils/contest-table/agc_provider.ts
  • src/features/tasks/utils/contest-table/aoj_icpc_providers.ts
  • src/features/tasks/utils/contest-table/aoj_jag_providers.ts
  • src/features/tasks/utils/contest-table/aoj_labels.ts
  • src/features/tasks/utils/contest-table/arc_providers.test.ts
  • src/features/tasks/utils/contest-table/arc_providers.ts
  • src/features/tasks/utils/contest-table/awc_provider.test.ts
  • src/features/tasks/utils/contest-table/awc_provider.ts
  • src/features/tasks/utils/contest-table/axc_like_provider.test.ts
  • src/features/tasks/utils/contest-table/axc_like_provider.ts
  • src/features/tasks/utils/contest-table/contest_table_provider_base.test.ts
  • src/features/tasks/utils/contest-table/contest_table_provider_base.ts
  • src/features/tasks/utils/contest-table/contest_table_provider_group.test.ts
  • src/features/tasks/utils/contest-table/contest_table_provider_group.ts
  • src/features/tasks/utils/contest-table/contest_table_provider_groups.test.ts
  • src/features/tasks/utils/contest-table/dp_providers.ts
  • src/features/tasks/utils/contest-table/fps24_provider.ts
  • src/features/tasks/utils/contest-table/game24_provider.ts
  • src/features/tasks/utils/contest-table/joi_providers.ts
  • src/features/tasks/utils/contest-table/math_and_algorithm_provider.ts
  • src/features/tasks/utils/contest-table/tessoku_book_providers.ts
  • src/features/tasks/utils/contest-table/typical90_provider.test.ts
  • src/features/tasks/utils/contest-table/typical90_provider.ts
  • src/features/votes/actions/vote_actions.ts
  • src/features/votes/components/RelativeEvaluationBadge.svelte
  • src/features/votes/components/VotableGrade.svelte
  • src/features/votes/components/VoteDonutChart.svelte
  • src/features/votes/server/cache.test.ts
  • src/features/votes/server/cache.ts
  • src/features/votes/services/vote_grade.test.ts
  • src/features/votes/services/vote_grade.ts
  • src/features/votes/services/vote_statistics.test.ts
  • src/features/votes/services/vote_statistics.ts
  • src/features/votes/utils/donut_chart.ts
  • src/features/votes/utils/median.ts
  • src/features/votes/zod/schema.test.ts
  • src/features/workbooks/components/detail/WorkBookTasksTable.svelte
  • src/features/workbooks/components/list/AcceptedCounter.svelte
  • src/features/workbooks/components/list/CreatedByUserTable.svelte
  • src/features/workbooks/components/list/CurriculumTable.svelte
  • src/features/workbooks/components/list/CurriculumWorkBookList.svelte
  • src/features/workbooks/components/list/SolutionTable.svelte
  • src/features/workbooks/components/list/SolutionWorkBookList.svelte
  • src/features/workbooks/components/list/TitleTableBodyCell.svelte
  • src/features/workbooks/components/list/WorkBookList.svelte
  • src/features/workbooks/components/list/WorkbookAuthorActionsCell.svelte
  • src/features/workbooks/components/list/WorkbookCompletionCell.svelte
  • src/features/workbooks/components/list/WorkbookProgressCell.svelte
  • src/features/workbooks/components/shared/WorkBookForm.svelte
  • src/features/workbooks/components/shared/WorkBookInputFields.svelte
  • src/features/workbooks/fixtures/solution_category_map.ts
  • src/features/workbooks/fixtures/workbook_placements.ts
  • src/features/workbooks/fixtures/workbooks.ts
  • src/features/workbooks/server/cache.ts
  • src/features/workbooks/services/workbook_placements/crud.test.ts
  • src/features/workbooks/services/workbook_placements/crud.ts
  • src/features/workbooks/services/workbook_placements/initializers.test.ts
  • src/features/workbooks/services/workbook_placements/initializers.ts
  • src/features/workbooks/services/workbook_tasks.test.ts
  • src/features/workbooks/services/workbook_tasks.ts
  • src/features/workbooks/services/workbooks.test.ts
  • src/features/workbooks/services/workbooks.ts
  • src/features/workbooks/stores/replenishment_workbook.test.ts
  • src/features/workbooks/types/workbook_placement.ts
  • src/features/workbooks/utils/solution_category_group.test.ts
  • src/features/workbooks/utils/solution_category_group.ts
  • src/features/workbooks/utils/workbook.test.ts
  • src/features/workbooks/utils/workbook_tasks.test.ts
  • src/features/workbooks/utils/workbook_tasks.ts
  • src/features/workbooks/utils/workbook_url_params.test.ts
  • src/features/workbooks/utils/workbook_url_params.ts
  • src/features/workbooks/utils/workbooks.test.ts
  • src/features/workbooks/utils/workbooks.ts
  • src/features/workbooks/zod/schema.test.ts
  • src/features/workbooks/zod/schema.ts
  • src/hooks.server.ts
  • src/lib/components/SubmissionStatus/UpdatingDropdown.svelte
  • src/lib/components/TaskSearchBox.svelte
  • src/lib/components/ThermometerProgressBar.svelte
  • src/lib/components/Trophies/CompletedTasks.svelte
  • src/lib/services/task_results.ts
  • src/lib/services/tasks.ts
  • src/lib/utils/task.ts
  • src/routes/(admin)/account_transfer/+page.server.ts
  • src/routes/(admin)/tags/+page.server.ts
  • src/routes/(admin)/tags/[tag_id]/+page.server.ts
  • src/routes/(admin)/tasks/+page.server.ts
  • src/routes/(admin)/tasks/[task_id]/+page.server.ts
  • src/routes/(admin)/tasks/grade/+page.server.ts
  • src/routes/(admin)/tasks/grade/_components/TaskGradeTable.svelte
  • src/routes/(admin)/tasks/grade/_utils/grade_table_filter.test.ts
  • src/routes/(admin)/tasks/grade/_utils/grade_table_filter.ts
  • src/routes/(admin)/workbooks/order/+page.server.ts
  • src/routes/(admin)/workbooks/order/+server.ts
  • src/routes/(admin)/workbooks/order/_components/KanbanBoard.svelte
  • src/routes/(admin)/workbooks/order/_components/KanbanCard.svelte
  • src/routes/(admin)/workbooks/order/_components/KanbanTabBar.svelte
  • src/routes/(admin)/workbooks/order/_fixtures/kanban.ts
  • src/routes/(admin)/workbooks/order/_types/kanban.ts
  • src/routes/(admin)/workbooks/order/_utils/kanban.test.ts
  • src/routes/(admin)/workbooks/order/_utils/kanban.ts
  • src/routes/(auth)/login/+page.server.ts
  • src/routes/(auth)/login/+page.svelte
  • src/routes/(auth)/logout/+page.server.ts
  • src/routes/(auth)/signup/+page.server.ts
  • src/routes/problems/+page.server.ts
  • src/routes/problems/+page.svelte
  • src/routes/problems/[slug]/+page.server.ts
  • src/routes/problems/getMedianVote/+server.ts
  • src/routes/problems/getMyVote/+server.ts
  • src/routes/problems/page_server.test.ts
  • src/routes/sitemap.xml/+server.ts
  • src/routes/users/[username]/+page.server.ts
  • src/routes/users/edit/+page.server.ts
  • src/routes/users/edit/+page.svelte
  • src/routes/votes/+page.server.ts
  • src/routes/votes/+page.svelte
  • src/routes/votes/[slug]/+page.server.ts
  • src/routes/votes/[slug]/+page.svelte
  • src/routes/votes/page_server.test.ts
  • src/routes/workbooks/+page.server.ts
  • src/routes/workbooks/+page.svelte
  • src/routes/workbooks/[slug]/+page.server.ts
  • src/routes/workbooks/[slug]/+page.svelte
  • src/routes/workbooks/create/+page.server.ts
  • src/routes/workbooks/create/+page.svelte
  • src/routes/workbooks/edit/[slug]/+page.server.ts
  • src/routes/workbooks/edit/[slug]/+page.svelte
  • src/test/lib/services/tasks.test.ts
  • src/test/lib/utils/task.test.ts
  • src/test/lib/utils/test_cases/task_results.ts
  • svelte.config.js
  • tsconfig.json

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@KATO-Hiro KATO-Hiro left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@KATO-Hiro
KATO-Hiro merged commit e3d1145 into staging Oct 18, 2026
3 checks passed
@KATO-Hiro
KATO-Hiro deleted the refactor/features-subpath-imports branch October 18, 2026 22:04

This branch was successfully deployed

1 active deployment
preview — bbb40c1e Deployed Oct 18, 2026 by KATO-Hiro via preview #9018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant