コマンドラインオプションの取得が思ったとおりにできていなかったが、Javaとの仕様の違いが原因だった。 -dのオプションをdではなくdstとして取得するなど省略していたので動かなかった。
You:
JSに書き換えて、Commander.jsをつかって相対パスをdstPathにフルパスにして
//出力パス確認
if (commandLine.hasOption("d")) {
dstPath = new File(commandLine.getOptionValue("d"));
if (!dstPath.isDirectory()) {
LogAppender.error("-d : dst path not exist. "+dstPath.getAbsolutePath());
return;
}
}
ChatGPT:
Javaコードの処理は
-dオプションがあるか確認指定されたパスを取得
相対パスならフルパスに変換
ディレクトリか確認
そうでなければエラー
なので、Node.js + Commander.js で書くと次のようになります。
JavaScript
import { Command } from "commander";
import fs from "fs";
import path from "path";
const program \= new Command();
program
.option("-d <dir>", "destination directory");
program.parse(process.argv);
const options \= program.opts();
let dstPath \= null;
// 出力パス確認
if (options.d) {
dstPath \= path.resolve(options.d); // 相対パス → フルパス
if (!fs.existsSync(dstPath) || !fs.statSync(dstPath).isDirectory()) {
LogAppender.error("-d : dst path not exist. " + dstPath);
return;
}
}
Java版との対応
| Java | JS |
|---|---|
commandLine.hasOption("d") |
if (options.d) |
commandLine.getOptionValue("d") |
options.d |
new File(path) |
path.resolve(path) |
getAbsolutePath() |
dstPath (resolve後) |
isDirectory() |
fs.statSync(...).isDirectory() |
ポイント
path.resolve()を使うと 相対パス → フルパス変換されます。existsSyncとstatSync().isDirectory()を両方チェックすると JavaのisDirectory()に近い挙動になります。
もし AozoraEpub3 の Java CLI と完全互換の挙動にするなら、
-dが相対パスの場合 入力ファイル基準でresolve~(home) 展開Windowsパス対応
なども実装できます。必要ならその 完全互換版CLIパス処理も書きます。
You:
coverファイルが取得できない const options = new Command(); options .option('-c, --cover
ChatGPT:
原因はここです。
JavaScript
if (commandLine.cover) {coverFileName \= commandLine.c;}
Commander.js では
opts() のプロパティ名は 長いオプション名になります。
つまり
\-c, --cover <cover>
の場合、取得できるのは
commandLine.cover
であり、commandLine.c は存在しません。
修正コード
JavaScript
import { Command } from "commander";
const program \= new Command();
program
.option('-c, --cover <cover>', '表紙画像\\n\[0:先頭の挿絵\]\\n\[1:ファイル名と同じ画像\]\\n\[ファイル名 or URL\]');
program.parse(process.argv);
if (program.args.length \=== 0) {
program.help();
}
const commandLine \= program.opts();
let coverFileName \= null;
if (commandLine.cover) {
coverFileName \= commandLine.cover;
}
実行例
node AozoraEpub3.js -c "C:\\Users\\Owner\\Downloads\\kokoro.jpg" "C:\\Users\\Owner\\Downloads\\773\_ruby\_5968.zip"
取得結果
commandLine.cover \= C:\\Users\\Owner\\Downloads\\kokoro.jpg
さらに安全な書き方(おすすめ)
Commanderは直接取得もできます。
JavaScript const coverFileName \= program.opts().cover;
参考(Javaとの対応)
| Java (Apache CLI) | Commander.js |
|---|---|
hasOption("c") |
if (opts.cover) |
getOptionValue("c") |
opts.cover |
もしよければ、AozoraEpub3 Java版と完全互換のCLI(30個以上のオプション)をCommander.jsで再現したテンプレートも作れます。
実は かなり短いコードで全部書けます。
You:
let coverFile = new File(coverFileName); node:internal/file:40 throw new ERR_MISSING_ARGS('fileBits', 'fileName'); ^ TypeError [ERR_MISSING_ARGS]: The "fileBits" and "fileName" arguments must be specified at new File (node:internal/file:40:13) at main (file:///C:/Users/Owner/Documents/GitHub/AozoraEpub3JS/src/AozoraEpub3.js:448:25) { code: 'ERR_MISSING_ARGS' }
ChatGPT:
原因は Java の File と Node.js の File が別物だからです。
Java
Java new File(path)
Node.js
Fileは ブラウザ互換APInew File(fileBits, fileName)が必要
つまり
JavaScript new File(coverFileName)
は 引数不足エラーになります。
ERR\_MISSING\_ARGS: The "fileBits" and "fileName" arguments must be specified
Java の File 相当の書き方(Node.js)
Nodeでは パスは単なる文字列です。
必要なら path や fs を使います。
JavaScript
import fs from "fs";
import path from "path";
let coverFile \= null;
if (coverFileName) {
coverFile \= path.resolve(coverFileName);
if (!fs.existsSync(coverFile)) {
LogAppender.error("cover file not exist. " + coverFile);
return;
}
}
Javaコードとの対応
| Java | Node.js |
|---|---|
File file = new File(path) |
const file = path.resolve(path) |
file.exists() |
fs.existsSync(file) |
file.isDirectory() |
fs.statSync(file).isDirectory() |
file.getAbsolutePath() |
path.resolve(file) |
AozoraEpub3移植の場合(おすすめ)
Java版のコード
Java File coverFile \= new File(coverFileName);
は そのまま
JavaScript let coverFile \= coverFileName;
にしてしまう方が Java構造に近くて移植しやすいです。
必要なときだけ
JavaScript fs.existsSync(coverFile)
を使います。
💡 AozoraEpub3のJava→Node移植で一番安全な方法
Javaの
File BufferedReader InputStream ZipOutputStream
を Nodeで対応するクラスにマッピングすると
コード構造をほぼ変えずに移植できます。
もし希望があれば **AozoraEpub3用の Node互換 File クラス(Java互換API)**も作れます。
これを作ると Javaコードを9割そのままJS化できます。
You:
JSに変換して if (coverFileName != null && !coverFileName.startsWith("http")) { File coverFile = new File(coverFileName); if (!coverFile.exists()) { coverFileName = srcFile.getParent()+"/"+coverFileName; if (!new File(coverFileName).exists()) { coverFileName = null; LogAppender.println("[WARN] 表紙画像ファイルが見つかりません : "+coverFile.getAbsolutePath()); } } }
ChatGPT:
Javaの File をそのまま使わず、Node.js の fs と path で書き換えると次の形になります。
JavaScript
import fs from "fs";
import path from "path";
if (coverFileName != null && !coverFileName.startsWith("http")) {
let coverFile \= coverFileName;
if (!fs.existsSync(coverFile)) {
coverFileName \= path.join(path.dirname(srcFile), coverFileName);
if (!fs.existsSync(coverFileName)) {
coverFileName \= null;
LogAppender.println("\[WARN\] 表紙画像ファイルが見つかりません : " + path.resolve(coverFile));
}
}
}
Javaとの対応
| Java | JS |
|---|---|
coverFileName.startsWith("http") |
同じ |
new File(path) |
文字列パス |
file.exists() |
fs.existsSync() |
srcFile.getParent() |
path.dirname(srcFile) |
getAbsolutePath() |
path.resolve() |
重要ポイント
Javaでは
Java srcFile.getParent()
ですが、Nodeでは
JavaScript path.dirname(srcFile)
になります。
AozoraEpub3移植でよくある落とし穴
Java版
Java srcFile.getParent()+"/"+coverFileName
をJSでそのままやると Windowsで壊れます。
そのため
JavaScript path.join(...)
を使うのが安全です。
もしよければ、
**AozoraEpub3 Java → Node 移植で使う File互換ヘルパー(約40行)**も出します。
これを入れると
new File() .exists() .getParent() .getAbsolutePath()
を ほぼJavaのまま書けるようになります。