はじめに
MH ソフトウェア & サービスが開発・公開しているアプリケーションは、Microsoft社のVisual Studio Code(以後、VS Code)でコーディングされています。
以前は、有名な日本のテキストエディタを使用していましたが、Pythonと出会い、VS Codeと出会って、全てがVS Codeになりました。
報告書PDFもVS Code(Markdown PDF)。電気配線図・系統図もVS Code(Draw.io)。CSV編集もVS Code(Rainbaow CSV)。Markdown、Qiitaの投稿はもちろん、VS Codeです。
そんな中で、特に思い入れが強い拡張機能は、Run on Saveです。
ファイルを保存した時に、実行するプログラムを指定できます。
.py保存時は、.pyi(スタブファイル)を作成し、.js保存時は、.d.ts(TypeScript型定義ファイル)を作成します。
開発時のソースコードが、とても分かりやすくなります。
WindowsでのVS Codeの設定です。
Run on Saveの設定です。
settings.json内の"emeraldwalk.runonsave"の設定です。
"emeraldwalk.runonsave": {
"autoClearConsole": true,
"commands": [
{
"match": "\\.py$",
"cmd": "pygenstub.bat \"${fileDirname}\" ${fileBasenameNoExt}"
},
{
"isAsync": false,
"match": "\\.ts$",
"cmd": "tsc ${file}"
},
{
"isAsync": false,
"match": "\\.js$",
"cmd": "python js_to_interface.py \"${fileDirname}\" ${fileBasenameNoExt}"
},
],
},
Pythonスタブファイルを作成するpygenstub.batのコード
@echo off
chcp 65001
cd /d %1
pygenstub.exe --generic %2.py
.d.tsファイルを作成するjs_to_interface.pyのコード
tsc.cmdが必要です。
"""
d.ts file support script
========================
"""
import os
import shutil
import subprocess
import sys
import time
folder = f"{sys.argv[1]}\\"
temp_foplder = f"{os.environ['temp']}\\"
BASENAME = sys.argv[2]
js_file_name = f"{folder}{BASENAME}.js"
d_ts_file_name = f"{folder}{BASENAME}.d.ts"
temp_js_file_name = f"{temp_foplder}{BASENAME}~temp.js"
temp_d_ts_file_name = f"{temp_foplder}{BASENAME}~temp.d.ts"
shutil.copy2(js_file_name, temp_js_file_name)
command = (
f'tsc "{temp_js_file_name}" '
"--declaration --emitDeclarationOnly --allowJS "
)
subprocess.run(command, check=False, shell=True)
time.sleep(1)
body: str = ""
with open(temp_d_ts_file_name, encoding="utf-8", mode="r") as wrapper:
body = wrapper.read()
body = body.replace("export class ", "interface I")
# JavaScriptファイルがexport class MyClass {}の場合、
# export class MyClass がファイル先頭になります。
# "export class "を"nterface I"に変更して、interface IMyClassにします。
body = body.replace(" #private;\n", "")
# " #private;\n"も不要なので、削除します。
with open(d_ts_file_name, encoding="utf-8", mode="w") as wrapper:
wrapper.write(body)
os.remove(temp_js_file_name)
os.remove(temp_d_ts_file_name)