Deno を使えば TypeScript を使って UXP InDesign スクリプトをバンドルできることがわかった。
以前軽く試したときは、deno bundle した段階で型関連のエラーが出てしまいバンドルできなかった。 でも考えてみたら(考えるほどでもないが)自分で型定義を用意して bundle 時とかコンパイル時に渡せば無問題なのでは? と思い立ち試したところ問題なくバンドルできた。
結論だけ知りたい場合はこちらのレポジトリの hello-world-ts を見てください。
このエントリーではごく簡単な UXP InDesign Scripting の例で説明します。
まずは環境の確認:
$ deno --version
deno 1.30.3 (release, x86_64-apple-darwin)
v8 10.9.194.5
typescript 4.9.4
はじめに TypeScript ではなく JavaScript で題材とする Hello,World! を main.js ファイルに書きます。
const doc = app.documents.add();
const page = doc.pages.item(0);
const textFrame = page.textFrames.add({geometricBounds: ['20mm', '20mm', '30mm', '60mm']});
textFrame.contents = 'Hello,World!';
このコードは 拡張子を idjs にすればそのまま InDesign で実行できますが、一応今後の流れに沿う関係上 deno bundle します。
$ deno bundle main.js > hello-world.idjs
hello-world.idjs を UXP 対応バージョンの InDesign で実行すると(または UDT で実行すると):
このように Hello,World! 文字列がテキストフレームに入った InDesign 文書ができます。
この main.js を TypeScript に書きかえます。 ファイル名を main.ts にして、末尾のセミコロンを削除します(セミコロンは別に削除する必要もないですが、ここではそうします)。
main.ts
const doc = app.documents.add()
const page = doc.pages.item(0)
const textFrame = page.textFrames.add({geometricBounds: ['20mm', '20mm', '30mm', '60mm']})
textFrame.contents = 'Hello,World!'
実行してみる。
$ deno bundle main.ts > hello-world.idjs
Check file:///Users/foo/path-to/main.ts
error: TS2304 [ERROR]: Cannot find name 'app'.
const doc = app.documents.add()
~~~
エラーになりました。 app が問題になりました。
declare を使って型を宣言して問題を回避しましょう。
main.ts の先頭に以下の型定義を追加します。
declare var app: any
これで再度バンドル実行:
deno bundle main.ts > hello-world.idjs
Check file:///Users/foo/path-to/main.ts
Bundle file:///Users/foo/path-to/main.ts
うまくいきました。
これはこれでよいのですが、TypeScript を使いたい理由は、コンパイル時の型チェックが入ることです。 そこで、スクリプトに型を追加して、TypeScript らしくします。
declare var app: any
const doc: Document = app.documents.add()
const page: Page = doc.pages.item(0)
const textFrame: TextFrame = page.textFrames.add({geometricBounds: ['20mm', '20mm', '30mm', '60mm']})
textFrame.contents = 'Hello,World!'
例のための例のような状態ですが、とりあえず型を追記しました。
バンドルを実行。
$ deno bundle main.ts > hello-world.idjs
Check file:///Users/foo/path-to/main.ts
error: TS2304 [ERROR]: Cannot find name 'Document'.
const doc: Document = app.documents.add()
~~~~~~~~
TS2304 [ERROR]: Cannot find name 'Page'.
const page: Page = doc.pages.item(0)
~~~~
TS2304 [ERROR]: Cannot find name 'TextFrame'.
const textFrame: TextFrame = page.textFrames.add({geometricBounds: ['20mm', '20mm', '30mm', '60mm']})
~~~~~~~~~
このエラーを回避するため型宣言を main.ts の先頭部分に書きます。
declare class TextFrame {
contents: string
}
declare class TextFrames {
add(params: any): TextFrame
}
declare class Page {
textFrames: TextFrames
}
declare class Pages {
item(index: number): Page
}
declare class Document {
pages: Pages
}
declare class Documents {
add(): Document
}
declare class Application {
documents: Documents
}
declare var app: Application
実行します。
$ deno bundle main.ts > hello-world.idjs
Check file:///Users/foo/path-to/main.ts
Bundle file:///Users/foo/path-to/main.ts
はいできました。
型宣言部分は別ファイルにわけることができます。
記述方法は こちら https://deno.land/manual@v1.31.2/advanced/typescript/types をご覧ください。
ind.d.ts ファイルを作成して、main.ts の先頭に記述していた型宣言をここに移します。
declare class TextFrame {
contents: string
}
declare class TextFrames {
add(params: any): TextFrame
}
declare class Page {
textFrames: TextFrames
}
declare class Pages {
item(index: number): Page
}
declare class Document {
pages: Pages
}
declare class Documents {
add(): Document
}
declare class Application {
documents: Documents
}
declare var app: Application
main.ts からは型宣言を削除して代わりに、ind.d.ts ファイル参照の記述を追加。
スクリプト全体は次のようになります。
/// <reference types="./ind.d.ts" />
const doc: Document = app.documents.add()
const page: Page = doc.pages.item(0)
const textFrame: TextFrame = page.textFrames.add({geometricBounds: ['20mm', '20mm', '30mm', '60mm']})
bundle を実行します。
$ deno bundle main.ts > hello-world.idjs
Check file:///Users/foo/path-to/main.ts
Bundle file:///Users/foo/path-to/main.ts
できました。 あとは生成された hello-world.idjs を実行して、意図通り Hello,World! ドキュメントが生成されるか確認しましょう。
TypeScript で書けばコンパイル時(バンドル時)に型をチェックしてくれるので助かります。 ここでは、ind.d.ts ファイルを自分で用意しました。 これはそれなりに骨が折れる作業です。 しかし、これは InDesign UXP Scripting に共通する内容なので、 もしかすると既に InDesign 用の d.ts ファイルがネット上に存在しているかも。 もしまだそれが無いのであれば、そのうち Adobe か誰かすごい人がつくってくれるでしょう、たぶん。