VSCode / Vue.jsでコンポーネントの自動Importプラグイン（拡張機能）をつくってみたよ

##はじめに

VSCodeでvueで開発しているとき、コンポーネントのimportを毎回記述するのが煩わしかったので、import挿入してくれるプラグインを作ってみました。
![1.png](https://raw.githubusercontent.com/wiki/ishiyama0530/VueJsAutoImport/gif/1.gif)
先に言い訳します。
えいやっ！の精神で作ったので変数名とかいろいろツッコミどころ満載です。

- [ダウンロード (Vue.js AutoImport)](https://marketplace.visualstudio.com/items?itemName=ishiyama.vue-autoimport)
- [ソースコード (GitHub)](https://github.com/ishiyama0530/VueJsAutoImport)

[こちら](https://marketplace.visualstudio.com/items?itemName=Tyriar.sort-lines)のソートプラグインと合わせて使うと良い感じです。

##感想
[英語のドキュメント](https://code.visualstudio.com/docs/extensions/example-hello-world)しかないし、最終的にvscodeのd.tsから想像しろ的なところがあって辛かった。

##雛形テンプレート
[vscode-generator-code](https://code.visualstudio.com/docs/extensions/yocode)を使用して雛形を作成します。使い方はQiitaにも記事があるのでそちらを見ると良いかと。この段階では「**お、簡単じゃん！**っていう印象。」

##package.json
プラグインの設定はpackage.jsonに書いていきます。要点だけ。

`contributes.configuration`
ユーザー設定を定義。今回はルートディレクトリを設定できるようにしたので、vuejsAutoImport.rootDirectoryをstring型で定義してます。

`contributes.commands`
当プラグインのコマンドを登録します。ctrl+shift+pから機能を使用できるようになります。
 
`contributes.menus.editor/context`
コンテキストメニューにコマンドを追加します。
contributes.commandsで設定したタイトルでコンテキストメニューに追加されます。

`contributes.keybindings`
ショートカットキーにコマンドを割り当てます。
同じくcontributes.commandsで設定したタイトルでコンテキストメニューに追加されます。
ちなみにwindowsとmacでそれぞれ設定できるみたいですが、mac持ってないのでテストしてないです。（**ちゃんとうごくかなー**）

##コマンド登録
extension.tsのactivateメソッドがvscode起動時に実行されます。
なので、この中で、vuejsAutoImportコマンドを登録します。

~~~ts
export function activate(context: vscode.ExtensionContext) {
  context.subscriptions.push(
    vscode.commands.registerCommand('extension.vuejsAutoImport', async () => {...
~~~

##Import文を挿入

流れ
1. 現在選択されているテキストを取得します。
2. そのテキストでファイル名をgrepします。
3. import文とcomponents:{}に追加します。

###1. 現在選択されているテキストを取得します。
vscode.TextDocument.getWordRangeAtPosition()で現在のポジションから選択しているテキストを取得できます。第2引数で正規表現を指定できます。<>内のテキストが欲しいので以下の感じに。
`/<.+?-?.+?(>| )/`

###2. そのテキストでファイル名をgrepします。
grepは[globby](https://github.com/sindresorhus/globby)を、ファイル名の記法がいろいろあるのでファイル名の変換には[voca](https://github.com/panzerdp/voca)を使用してます。
※ファイル名変換 
\<sample-component\> → sample-component → SampleComponent → 'SampleComponent' + '.vue'で検索！
ファイル名はどんなケースで書かれてるか解らないので、とりあえずありそうなケースを舐めてます。

~~~ts
const pathList: string[] = await grepAsync([
  path.join(rootPath, `**/${voca.camelCase(text)}.vue`),
  path.join(rootPath, `**/${voca.kebabCase(text)}.vue`),
  path.join(rootPath, `**/${voca.capitalize(text)}.vue`)
])
~~~

###3. import文とcomponents:{}に追加します。
\<script\>の直下に取得したパスを追加します。
ちなみに、同じ名前のファイルが複数ある場合は選択できるようにしています。
![3.png](https://qiita-image-store.s3.amazonaws.com/0/62209/dc66f56e-e5c6-bfeb-ba78-c8524a4a8bab.png)
制御は以下のようにしてます。

~~~ts
if (pathList.length === 1) {
  importCore(pathList[0])
} else if (pathList.length > 1) {
  vscode.window.showQuickPick(pathList).then(selectedPath => {
    importCore(selectedPath!)
  })
}
~~~

挿入するimport文はこんな感じかと。

`import ${ファイル名} from '${パス}' ${改行コード}`

components:{} への追加は以下の正規表現をしようしています。
`/components( )*:( )*{[\s\S]*?(?=})/`

この正規表現にヒットした文字の最後が`{` か　`,` のときはファイル名をそのまま挿入。
それ以外のときは`,` + ファイル名を挿入しています。

##Marketplaceに公開
こちらも検索すれば良い記事がたくさん出てきます。
ちなみに管理画面はこんな感じ。
![2.png](https://qiita-image-store.s3.amazonaws.com/0/62209/1edd10ac-12e6-326c-b272-6dd3b32cf4ea.png)

##最後に
いつか気分が乗ったらimportとcomponents:{}への追加時にソートしてくれるようにしたいです。
あと、私が見つけられなかっただけで、そのプラグインすでにあるよって場合は教えてくれたら嬉しいです。

######:relaxed: おまけ :relaxed:
このコンポネントのpropなんだろうって毎回確認しに定義に飛ぶのが手間だったので、
タグにマウスオーバーで\<script\>内をツールチップに表示するプラグインも作りました。
[vue-peek](https://marketplace.visualstudio.com/items?itemName=dariofuzinato.vue-peek)のツールチップ版みたいな感じです。

- [ダウンロード (Vue.js Peek)](https://marketplace.visualstudio.com/items?itemName=ishiyama.vuejs-peek)
- [ソースコード (GitHub)](https://github.com/ishiyama0530/VueJsPeek)