Skip to content

パスの先頭部分を書き換える機能の追加#45

Merged
omochi merged 3 commits intomainfrom
path-alias
Jun 15, 2025
Merged

パスの先頭部分を書き換える機能の追加#45
omochi merged 3 commits intomainfrom
path-alias

Conversation

@omochi
Copy link
Owner

@omochi omochi commented May 30, 2025

インポート文を生成するときに、設定があればエイリアスを使った表記を出力できるようにします。

背景

tsconfig.jsonpaths の設定や、vitejs の resolve.alias のように、
特定のパスのプレフィックスを特定のシンボルに置き換えることがあります。

そのようなビルド環境のプロジェクトにおいては、
自動生成するコードのimport文で、
特定のファイルについてはこのエイリアスを使った表記で出力したいことがあります。

特に、Swift Build Pluginを使用する都合などにより、
自動生成するコードがnpmパッケージから離れた場所に出力される場合、
npmパッケージ側からはこれをシンボリックリンクを辿って参照させれば良くとも、
生成コード側からnpmパッケージ側を参照させる方向の対応は、
エイリアス機能を使わないと困難です。

利用側

最終的にはこのパッチを以下のようにCodableToTypeScriptにおいてAPIとして提供する想定です。
omochi/CodableToTypeScript#131

let base = self.path.absoluteURL.standardized.pathComponents
let full = path.absoluteURL.standardized.pathComponents

guard full.starts(with: base) else {
Copy link
Owner Author

Choose a reason for hiding this comment

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

もしパスの冒頭部分がエイリアスに一致していたら、以下で置き換える


public var entries: [Entry]

public func mapToAlias(path: URL) -> (path: URL, updated: Bool) {
Copy link
Owner Author

Choose a reason for hiding this comment

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

パスに対して登録エントリを順番に試してマッチしたら変換したものを返す

}
}

public var entries: [Entry]
Copy link
Owner Author

@omochi omochi Jun 1, 2025

Choose a reason for hiding this comment

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

一般的にはエイリアス名を実パスに置き換える辞書として表現されるが、
ここではその順方向の解決はしない

また、逆変換にしても foo -> /foo, bar -> /foo/bar みたいな重複のある定義の場合に、
処理結果を安定させるため配列にしている


var file = file
let (newPath, updated) = pathAliasTable.mapToAlias(
path: from.deletingLastPathComponent().appendingPathComponent(file)
Copy link
Owner Author

Choose a reason for hiding this comment

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

1次生成されたimport文を、もう一回このファイルを起点にフルパスに戻して、それをエイリアスの逆変換にかけてみる

@omochi omochi requested a review from sidepelican June 1, 2025 07:37
Copy link
Collaborator

@sidepelican sidepelican left a comment

Choose a reason for hiding this comment

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

Nodeとかのエイリアスって、パスの冒頭が一致しておらずともエイリアスから../で親を辿って解決させる方法があるため、常にエイリアスから変換可能だと思うんですよね。

例えば@/srcにマップされている場合、
/src/foo/A.tsにある以下の記述は、

import B from "./B.ts"

import B from "@/foo/B.ts"

と変換でき、これは直感的ですが
/gen/bar/A.tsにある以下の記述は、

import B from "./B.ts"

import B from "@/../gen/foo/B.ts"

と変換できます。

現在の構造はエイリアスが複数存在できてそのうちのどれか1つが変換できるかも、というインターフェースをしていますが、実際はすべて変換に成功するはずです。
エイリアスごとの優先度の概念は本来存在しえないため、複数のエイリアスを登録できるPathAliasTableは不自然な構造に感じます。

実用的な部分だけ考えると../を禁止してしまっても問題なさそうですが、TypeScriptASTに関してはなるべくTSの仕様に忠実であるべきだと思ったので、違う形のほうが良いと思いました。

buildAutoImportDeclsに関しては今のPathAliasTable.Entry相当の構造体を1つだけ受け取る形式の方が良いかも?

public var alias: String
public var path: URL

public func mapToAlias(path: URL) -> (path: URL, updated: Bool) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

気持ち的な話ですがこの程度の内容なら単にURL?を返すだけの方がシンプルに感じました。
何も起きなかった場合に引数のpathがそのまま返ってくる保証はなくて、利用側に少し混乱を与えそうです

Copy link
Owner Author

Choose a reason for hiding this comment

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

何も起きなかった場合に引数のpathがそのまま返ってくる保証はなく

確かに optional だとそれが表現できますね。
更新されていようがいまいが、処理した値をそのまま使えるのが便利かと思ったんですが、
結果的に利用側でそういう書き方をしてないし、利用側でやることか。
見直します。

@omochi
Copy link
Owner Author

omochi commented Jun 2, 2025

import B from "@/../gen/foo/B.ts"

確かに論理的にはこれが可能なのはそうですね。

TypeScriptASTに関してはなるべくTSの仕様に忠実であるべき

やりたいことが
「import文を生成するときに、特定のパスプレフィックスを置き換えたい」
なので、
TypeScriptAST.PathAliasTable という名前は過度に代表的な名前かもしれません。

実際の用途も逆引きですしね。

buildAutoImportDeclsに関しては今のPathAliasTable.Entry相当の構造体を1つだけ受け取る形式

外向きの特殊な参照ディレクトリが2つ以上ある場合もあるのでN個なインターフェースにはしたいです。


やりたいことがパスプレフィックスの置き換えに過ぎないので、
それを素直に表現するのがいいかもしれません。

Array<PathPrefixReplacement> みたいな。
それなら .. を挿入しない事も示唆します。
どうでしょう?

@sidepelican
Copy link
Collaborator

確かに名前で解決しそうな話ではありますね。PathPrefixReplacement良いと思いました

@omochi omochi marked this pull request as draft June 2, 2025 05:43
@omochi omochi changed the title パスエイリアス機能の追加 [WIP] パスエイリアス機能の追加 Jun 2, 2025
}

public var path: URL
public var replacement: String
Copy link
Owner Author

Choose a reason for hiding this comment

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

変換元は解決された実際のパスを見ています。
変換先は @src のような特殊な表記を考慮して単なる文字列です。

@omochi omochi marked this pull request as ready for review June 14, 2025 04:14
@omochi omochi changed the title [WIP] パスエイリアス機能の追加 パスの先頭部分を書き換える機能の追加 Jun 14, 2025
@omochi
Copy link
Owner Author

omochi commented Jun 14, 2025

@sidepelican 単にパスの先頭部分を特定の文字列に置き換えるということで PathPrefixReplacement という型を導入し、インターフェースをそれに寄せました。

@omochi omochi requested a review from sidepelican June 14, 2025 04:15
Copy link
Collaborator

@sidepelican sidepelican left a comment

Choose a reason for hiding this comment

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

機能と命名がうまく対応して良くなったと思います

@omochi
Copy link
Owner Author

omochi commented Jun 15, 2025

確認ありがとうございました

@omochi omochi merged commit 2d47093 into main Jun 15, 2025
1 check passed
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.

2 participants